ide: introduce CONFIG_BLK_DEV_IDEDMA_SFF option
[safe/jmp/linux-2.6] / drivers / ide / ide-dma.c
index b7b663e..d0e7b53 100644 (file)
@@ -1,15 +1,13 @@
 /*
- *  linux/drivers/ide/ide-dma.c                Version 4.10    June 9, 2000
+ *  Copyright (C) 1995-1998   Mark Lord
+ *  Copyright (C) 1999-2000   Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2004, 2007  Bartlomiej Zolnierkiewicz
  *
- *  Copyright (c) 1999-2000    Andre Hedrick <andre@linux-ide.org>
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
  *  Special Thanks to Mark for his Six years of work.
- *
- *  Copyright (c) 1995-1998  Mark Lord
- *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
 #include <linux/ide.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
 static const struct drive_list_entry drive_whitelist [] = {
 
-       { "Micropolis 2112A"    ,       "ALL"           },
-       { "CONNER CTMA 4000"    ,       "ALL"           },
-       { "CONNER CTT8000-A"    ,       "ALL"           },
-       { "ST34342A"            ,       "ALL"           },
+       { "Micropolis 2112A"    ,       NULL            },
+       { "CONNER CTMA 4000"    ,       NULL            },
+       { "CONNER CTT8000-A"    ,       NULL            },
+       { "ST34342A"            ,       NULL            },
        { NULL                  ,       NULL            }
 };
 
 static const struct drive_list_entry drive_blacklist [] = {
 
-       { "WDC AC11000H"        ,       "ALL"           },
-       { "WDC AC22100H"        ,       "ALL"           },
-       { "WDC AC32500H"        ,       "ALL"           },
-       { "WDC AC33100H"        ,       "ALL"           },
-       { "WDC AC31600H"        ,       "ALL"           },
+       { "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"    ,       "ALL"           },
-       { "CRD-8400B"           ,       "ALL"           },
-       { "CRD-8480B",                  "ALL"           },
-       { "CRD-8482B",                  "ALL"           },
-       { "CRD-84"              ,       "ALL"           },
-       { "SanDisk SDP3B"       ,       "ALL"           },
-       { "SanDisk SDP3B-64"    ,       "ALL"           },
-       { "SANYO CD-ROM CRD"    ,       "ALL"           },
-       { "HITACHI CDR-8"       ,       "ALL"           },
-       { "HITACHI CDR-8335"    ,       "ALL"           },
-       { "HITACHI CDR-8435"    ,       "ALL"           },
-       { "Toshiba CD-ROM XM-6202B"     ,       "ALL"           },
-       { "CD-532E-A"           ,       "ALL"           },
-       { "E-IDE CD-ROM CR-840",        "ALL"           },
-       { "CD-ROM Drive/F5A",   "ALL"           },
-       { "WPI CDD-820",                "ALL"           },
-       { "SAMSUNG CD-ROM SC-148C",     "ALL"           },
-       { "SAMSUNG CD-ROM SC",  "ALL"           },
-       { "SanDisk SDP3B-64"    ,       "ALL"           },
-       { "ATAPI CD-ROM DRIVE 40X MAXIMUM",     "ALL"           },
-       { "_NEC DV5800A",               "ALL"           },  
+       { "Compaq CRD-8241B"    ,       NULL            },
+       { "CRD-8400B"           ,       NULL            },
+       { "CRD-8480B",                  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            },
+       { "TOSHIBA CD-ROM XM-1702BC",   NULL            },
+       { "CD-532E-A"           ,       NULL            },
+       { "E-IDE CD-ROM CR-840",        NULL            },
+       { "CD-ROM Drive/F5A",   NULL            },
+       { "WPI CDD-820",                NULL            },
+       { "SAMSUNG CD-ROM SC-148C",     NULL            },
+       { "SAMSUNG CD-ROM SC",  NULL            },
+       { "ATAPI CD-ROM DRIVE 40X MAXIMUM",     NULL            },
+       { "_NEC DV5800A",               NULL            },
+       { "SAMSUNG CD-ROM SN-124",      "N001" },
+       { "Seagate STT20000A",          NULL  },
+       { "CD-ROM CDR_U200",            "1.09" },
        { NULL                  ,       NULL            }
 
 };
 
 /**
- *     ide_in_drive_list       -       look for drive in black/white list
- *     @id: drive identifier
- *     @drive_table: list to inspect
- *
- *     Look for a drive in the blacklist and the whitelist tables
- *     Returns 1 if the drive is found in the table.
- */
-
-int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
-{
-       for ( ; drive_table->id_model ; drive_table++)
-               if ((!strcmp(drive_table->id_model, id->model)) &&
-                   ((strstr(id->fw_rev, drive_table->id_firmware)) ||
-                    (!strcmp(drive_table->id_firmware, "ALL"))))
-                       return 1;
-       return 0;
-}
-
-/**
  *     ide_dma_intr    -       IDE DMA interrupt handler
  *     @drive: the drive the interrupt is for
  *
@@ -164,18 +147,13 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
        u8 stat = 0, dma_stat = 0;
 
        dma_stat = HWIF(drive)->ide_dma_end(drive);
-       stat = HWIF(drive)->INB(IDE_STATUS_REG);        /* get drive status */
+       stat = ide_read_status(drive);
+
        if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
                if (!dma_stat) {
                        struct request *rq = HWGROUP(drive)->rq;
 
-                       if (rq->rq_disk) {
-                               ide_driver_t *drv;
-
-                               drv = *(ide_driver_t **)rq->rq_disk->private_data;
-                               drv->end_request(drive, 1, rq->nr_sectors);
-                       } else
-                               ide_end_request(drive, 1, rq->nr_sectors);
+                       task_end_request(drive, rq, stat);
                        return ide_stopped;
                }
                printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
@@ -186,16 +164,20 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
 
 EXPORT_SYMBOL_GPL(ide_dma_intr);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
+static int ide_dma_good_drive(ide_drive_t *drive)
+{
+       return ide_in_drive_list(drive->id, drive_whitelist);
+}
+
 /**
  *     ide_build_sglist        -       map IDE scatter gather for DMA I/O
  *     @drive: the drive to build the DMA table for
  *     @rq: the request holding the sg list
  *
- *     Perform the PCI mapping magic necessary to access the source or
- *     target buffers of a request via PCI DMA. The lower layers of the
+ *     Perform the DMA mapping magic necessary to access the source or
+ *     target buffers of a request via DMA.  The lower layers of the
  *     kernel provide the necessary cache management so that we can
- *     operate in a portable fashion
+ *     operate in a portable fashion.
  */
 
 int ide_build_sglist(ide_drive_t *drive, struct request *rq)
@@ -203,20 +185,20 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq)
        ide_hwif_t *hwif = HWIF(drive);
        struct scatterlist *sg = hwif->sg_table;
 
-       BUG_ON((rq->cmd_type == REQ_TYPE_ATA_TASKFILE) && rq->nr_sectors > 256);
-
        ide_map_sg(drive, rq);
 
        if (rq_data_dir(rq) == READ)
-               hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+               hwif->sg_dma_direction = DMA_FROM_DEVICE;
        else
-               hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+               hwif->sg_dma_direction = DMA_TO_DEVICE;
 
-       return pci_map_sg(hwif->pci_dev, sg, hwif->sg_nents, hwif->sg_dma_direction);
+       return dma_map_sg(hwif->dev, sg, hwif->sg_nents,
+                         hwif->sg_dma_direction);
 }
 
 EXPORT_SYMBOL_GPL(ide_build_sglist);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
 /**
  *     ide_build_dmatable      -       build IDE DMA table
  *
@@ -292,7 +274,7 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
                        }
                }
 
-               sg++;
+               sg = sg_next(sg);
                i--;
        }
 
@@ -301,16 +283,17 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
                        *--table |= cpu_to_le32(0x80000000);
                return count;
        }
+
        printk(KERN_ERR "%s: empty DMA table?\n", drive->name);
+
 use_pio_instead:
-       pci_unmap_sg(hwif->pci_dev,
-                    hwif->sg_table,
-                    hwif->sg_nents,
-                    hwif->sg_dma_direction);
+       ide_destroy_dmatable(drive);
+
        return 0; /* revert to PIO for this request */
 }
 
 EXPORT_SYMBOL_GPL(ide_build_dmatable);
+#endif
 
 /**
  *     ide_destroy_dmatable    -       clean up DMA mapping
@@ -325,15 +308,15 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable);
  
 void ide_destroy_dmatable (ide_drive_t *drive)
 {
-       struct pci_dev *dev = HWIF(drive)->pci_dev;
-       struct scatterlist *sg = HWIF(drive)->sg_table;
-       int nents = HWIF(drive)->sg_nents;
+       ide_hwif_t *hwif = drive->hwif;
 
-       pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
+       dma_unmap_sg(hwif->dev, hwif->sg_table, hwif->sg_nents,
+                    hwif->sg_dma_direction);
 }
 
 EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
 /**
  *     config_drive_for_dma    -       attempt to activate IDE DMA
  *     @drive: the drive to place in DMA mode
@@ -347,31 +330,35 @@ EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
  
 static int config_drive_for_dma (ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = drive->hwif;
        struct hd_driveid *id = drive->id;
-       ide_hwif_t *hwif = HWIF(drive);
 
-       if ((id->capability & 1) && hwif->autodma) {
-               /*
-                * Enable DMA on any drive that has
-                * UltraDMA (mode 0/1/2/3/4/5/6) enabled
-                */
-               if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
-                       return hwif->ide_dma_on(drive);
-               /*
-                * Enable DMA on any drive that has mode2 DMA
-                * (multi or single) enabled
-                */
-               if (id->field_valid & 2)        /* regular DMA */
-                       if ((id->dma_mword & 0x404) == 0x404 ||
-                           (id->dma_1word & 0x404) == 0x404)
-                               return hwif->ide_dma_on(drive);
-
-               /* Consult the list of known "good" drives */
-               if (__ide_dma_good_drive(drive))
-                       return hwif->ide_dma_on(drive);
+       if (drive->media != ide_disk) {
+               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+                       return 0;
        }
-//     if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);
-       return hwif->ide_dma_off_quietly(drive);
+
+       /*
+        * Enable DMA on any drive that has
+        * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+        */
+       if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
+               return 1;
+
+       /*
+        * Enable DMA on any drive that has mode2 DMA
+        * (multi or single) enabled
+        */
+       if (id->field_valid & 2)        /* regular DMA */
+               if ((id->dma_mword & 0x404) == 0x404 ||
+                   (id->dma_1word & 0x404) == 0x404)
+                       return 1;
+
+       /* Consult the list of known "good" drives */
+       if (ide_dma_good_drive(drive))
+               return 1;
+
+       return 0;
 }
 
 /**
@@ -415,124 +402,79 @@ static int dma_timer_expiry (ide_drive_t *drive)
 }
 
 /**
- *     __ide_dma_host_off      -       Generic DMA kill
+ *     ide_dma_host_set        -       Enable/disable DMA on a host
  *     @drive: drive to control
  *
- *     Perform the generic IDE controller DMA off operation. This
- *     works for most IDE bus mastering controllers
+ *     Enable/disable DMA on an IDE controller following generic
+ *     bus-mastering IDE controller behaviour.
  */
 
-int __ide_dma_host_off (ide_drive_t *drive)
+void ide_dma_host_set(ide_drive_t *drive, int on)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        u8 unit                 = (drive->select.b.unit & 0x01);
        u8 dma_stat             = hwif->INB(hwif->dma_status);
 
-       hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
-       return 0;
+       if (on)
+               dma_stat |= (1 << (5 + unit));
+       else
+               dma_stat &= ~(1 << (5 + unit));
+
+       hwif->OUTB(dma_stat, hwif->dma_status);
 }
 
-EXPORT_SYMBOL(__ide_dma_host_off);
+EXPORT_SYMBOL_GPL(ide_dma_host_set);
+#endif /* CONFIG_BLK_DEV_IDEDMA_SFF  */
 
 /**
- *     __ide_dma_host_off_quietly      -       Generic DMA kill
+ *     ide_dma_off_quietly     -       Generic DMA kill
  *     @drive: drive to control
  *
  *     Turn off the current DMA on this IDE controller. 
  */
 
-int __ide_dma_off_quietly (ide_drive_t *drive)
+void ide_dma_off_quietly(ide_drive_t *drive)
 {
        drive->using_dma = 0;
        ide_toggle_bounce(drive, 0);
 
-       if (HWIF(drive)->ide_dma_host_off(drive))
-               return 1;
-
-       return 0;
+       drive->hwif->dma_host_set(drive, 0);
 }
 
-EXPORT_SYMBOL(__ide_dma_off_quietly);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+EXPORT_SYMBOL(ide_dma_off_quietly);
 
 /**
- *     __ide_dma_off   -       disable DMA on a device
+ *     ide_dma_off     -       disable DMA on a device
  *     @drive: drive to disable DMA on
  *
  *     Disable IDE DMA for a device on this IDE controller.
  *     Inform the user that DMA has been disabled.
  */
 
-int __ide_dma_off (ide_drive_t *drive)
+void ide_dma_off(ide_drive_t *drive)
 {
        printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-       return HWIF(drive)->ide_dma_off_quietly(drive);
+       ide_dma_off_quietly(drive);
 }
 
-EXPORT_SYMBOL(__ide_dma_off);
+EXPORT_SYMBOL(ide_dma_off);
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
- *     __ide_dma_host_on       -       Enable DMA on a host
- *     @drive: drive to enable for DMA
- *
- *     Enable DMA on an IDE controller following generic bus mastering
- *     IDE controller behaviour
- */
-int __ide_dma_host_on (ide_drive_t *drive)
-{
-       if (drive->using_dma) {
-               ide_hwif_t *hwif        = HWIF(drive);
-               u8 unit                 = (drive->select.b.unit & 0x01);
-               u8 dma_stat             = hwif->INB(hwif->dma_status);
-
-               hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
-               return 0;
-       }
-       return 1;
-}
-
-EXPORT_SYMBOL(__ide_dma_host_on);
-
-/**
- *     __ide_dma_on            -       Enable DMA on a device
+ *     ide_dma_on              -       Enable DMA on a device
  *     @drive: drive to enable DMA on
  *
  *     Enable IDE DMA for a device on this IDE controller.
  */
-int __ide_dma_on (ide_drive_t *drive)
-{
-       /* consult the list of known "bad" drives */
-       if (__ide_dma_bad_drive(drive))
-               return 1;
 
+void ide_dma_on(ide_drive_t *drive)
+{
        drive->using_dma = 1;
        ide_toggle_bounce(drive, 1);
 
-       if (HWIF(drive)->ide_dma_host_on(drive))
-               return 1;
-
-       return 0;
-}
-
-EXPORT_SYMBOL(__ide_dma_on);
-
-/**
- *     __ide_dma_check         -       check DMA setup
- *     @drive: drive to check
- *
- *     Don't use - due for extermination
- */
-int __ide_dma_check (ide_drive_t *drive)
-{
-       return config_drive_for_dma(drive);
+       drive->hwif->dma_host_set(drive, 1);
 }
 
-EXPORT_SYMBOL(__ide_dma_check);
-
+#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
 /**
  *     ide_dma_setup   -       begin a DMA phase
  *     @drive: target device
@@ -565,7 +507,7 @@ int ide_dma_setup(ide_drive_t *drive)
        }
 
        /* PRD table */
-       if (hwif->mmio == 2)
+       if (hwif->mmio)
                writel(hwif->dmatable_dma, (void __iomem *)hwif->dma_prdtable);
        else
                outl(hwif->dmatable_dma, hwif->dma_prdtable);
@@ -639,12 +581,6 @@ static int __ide_dma_test_irq(ide_drive_t *drive)
        ide_hwif_t *hwif        = HWIF(drive);
        u8 dma_stat             = hwif->INB(hwif->dma_status);
 
-#if 0  /* do not set unless you know what you are doing */
-       if (dma_stat & 4) {
-               u8 stat = hwif->INB(IDE_STATUS_REG);
-               hwif->OUTB(hwif->dma_status, dma_stat & 0xE4);
-       }
-#endif
        /* return 1 if INTR asserted */
        if ((dma_stat & 4) == 4)
                return 1;
@@ -653,7 +589,9 @@ static int __ide_dma_test_irq(ide_drive_t *drive)
                        drive->name, __FUNCTION__);
        return 0;
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+#else
+static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
+#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */
 
 int __ide_dma_bad_drive (ide_drive_t *drive)
 {
@@ -670,134 +608,269 @@ int __ide_dma_bad_drive (ide_drive_t *drive)
 
 EXPORT_SYMBOL(__ide_dma_bad_drive);
 
-int __ide_dma_good_drive (ide_drive_t *drive)
+static const u8 xfer_mode_bases[] = {
+       XFER_UDMA_0,
+       XFER_MW_DMA_0,
+       XFER_SW_DMA_0,
+};
+
+static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
 {
        struct hd_driveid *id = drive->id;
-       return ide_in_drive_list(id, drive_whitelist);
+       ide_hwif_t *hwif = drive->hwif;
+       unsigned int mask = 0;
+
+       switch(base) {
+       case XFER_UDMA_0:
+               if ((id->field_valid & 4) == 0)
+                       break;
+
+               if (hwif->udma_filter)
+                       mask = hwif->udma_filter(drive);
+               else
+                       mask = hwif->ultra_mask;
+               mask &= id->dma_ultra;
+
+               /*
+                * avoid false cable warning from eighty_ninty_three()
+                */
+               if (req_mode > XFER_UDMA_2) {
+                       if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+                               mask &= 0x07;
+               }
+               break;
+       case XFER_MW_DMA_0:
+               if ((id->field_valid & 2) == 0)
+                       break;
+               if (hwif->mdma_filter)
+                       mask = hwif->mdma_filter(drive);
+               else
+                       mask = hwif->mwdma_mask;
+               mask &= id->dma_mword;
+               break;
+       case XFER_SW_DMA_0:
+               if (id->field_valid & 2) {
+                       mask = id->dma_1word & hwif->swdma_mask;
+               } else if (id->tDMA) {
+                       /*
+                        * ide_fix_driveid() doesn't convert ->tDMA to the
+                        * CPU endianness so we need to do it here
+                        */
+                       u8 mode = le16_to_cpu(id->tDMA);
+
+                       /*
+                        * if the mode is valid convert it to the mask
+                        * (the maximum allowed mode is XFER_SW_DMA_2)
+                        */
+                       if (mode <= 2)
+                               mask = ((2 << mode) - 1) & hwif->swdma_mask;
+               }
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       return mask;
 }
 
-EXPORT_SYMBOL(__ide_dma_good_drive);
+/**
+ *     ide_find_dma_mode       -       compute DMA speed
+ *     @drive: IDE device
+ *     @req_mode: requested mode
+ *
+ *     Checks the drive/host capabilities and finds the speed to use for
+ *     the DMA transfer.  The speed is then limited by the requested mode.
+ *
+ *     Returns 0 if the drive/host combination is incapable of DMA transfers
+ *     or if the requested mode is not a DMA mode.
+ */
 
-int ide_use_dma(ide_drive_t *drive)
+u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
 {
-       struct hd_driveid *id = drive->id;
        ide_hwif_t *hwif = drive->hwif;
+       unsigned int mask;
+       int x, i;
+       u8 mode = 0;
+
+       if (drive->media != ide_disk) {
+               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+                       return 0;
+       }
 
-       if ((id->capability & 1) == 0 || drive->autodma == 0)
+       for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
+               if (req_mode < xfer_mode_bases[i])
+                       continue;
+               mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
+               x = fls(mask) - 1;
+               if (x >= 0) {
+                       mode = xfer_mode_bases[i] + x;
+                       break;
+               }
+       }
+
+       if (hwif->chipset == ide_acorn && mode == 0) {
+               /*
+                * is this correct?
+                */
+               if (ide_dma_good_drive(drive) && drive->id->eide_dma_time < 150)
+                       mode = XFER_MW_DMA_1;
+       }
+
+       mode = min(mode, req_mode);
+
+       printk(KERN_INFO "%s: %s mode selected\n", drive->name,
+                         mode ? ide_xfer_verbose(mode) : "no DMA");
+
+       return mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_find_dma_mode);
+
+static int ide_tune_dma(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       u8 speed;
+
+       if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
                return 0;
 
        /* consult the list of known "bad" drives */
        if (__ide_dma_bad_drive(drive))
                return 0;
 
-       /* capable of UltraDMA modes */
-       if (id->field_valid & 4) {
-               if (hwif->ultra_mask & id->dma_ultra)
-                       return 1;
-       }
+       if (ide_id_dma_bug(drive))
+               return 0;
 
-       /* capable of regular DMA modes */
-       if (id->field_valid & 2) {
-               if (hwif->mwdma_mask & id->dma_mword)
-                       return 1;
-               if (hwif->swdma_mask & id->dma_1word)
+       if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+               return config_drive_for_dma(drive);
+
+       speed = ide_max_dma_mode(drive);
+
+       if (!speed) {
+                /* is this really correct/needed? */
+               if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
+                   ide_dma_good_drive(drive))
                        return 1;
+               else
+                       return 0;
        }
 
-       /* consult the list of known "good" drives */
-       if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150)
-               return 1;
+       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+               return 0;
 
-       return 0;
+       if (ide_set_dma_mode(drive, speed))
+               return 0;
+
+       return 1;
 }
 
-EXPORT_SYMBOL_GPL(ide_use_dma);
+static int ide_dma_check(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+       int vdma = (hwif->host_flags & IDE_HFLAG_VDMA)? 1 : 0;
+
+       if (!vdma && ide_tune_dma(drive))
+               return 0;
+
+       /* TODO: always do PIO fallback */
+       if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+               return -1;
+
+       ide_set_max_pio(drive);
 
-void ide_dma_verbose(ide_drive_t *drive)
+       return vdma ? 0 : -1;
+}
+
+int ide_id_dma_bug(ide_drive_t *drive)
 {
-       struct hd_driveid *id   = drive->id;
-       ide_hwif_t *hwif        = HWIF(drive);
+       struct hd_driveid *id = drive->id;
 
        if (id->field_valid & 4) {
                if ((id->dma_ultra >> 8) && (id->dma_mword >> 8))
-                       goto bug_dma_off;
-               if (id->dma_ultra & ((id->dma_ultra >> 8) & hwif->ultra_mask)) {
-                       if (((id->dma_ultra >> 11) & 0x1F) &&
-                           eighty_ninty_three(drive)) {
-                               if ((id->dma_ultra >> 15) & 1) {
-                                       printk(", UDMA(mode 7)");
-                               } else if ((id->dma_ultra >> 14) & 1) {
-                                       printk(", UDMA(133)");
-                               } else if ((id->dma_ultra >> 13) & 1) {
-                                       printk(", UDMA(100)");
-                               } else if ((id->dma_ultra >> 12) & 1) {
-                                       printk(", UDMA(66)");
-                               } else if ((id->dma_ultra >> 11) & 1) {
-                                       printk(", UDMA(44)");
-                               } else
-                                       goto mode_two;
-                       } else {
-               mode_two:
-                               if ((id->dma_ultra >> 10) & 1) {
-                                       printk(", UDMA(33)");
-                               } else if ((id->dma_ultra >> 9) & 1) {
-                                       printk(", UDMA(25)");
-                               } else if ((id->dma_ultra >> 8) & 1) {
-                                       printk(", UDMA(16)");
-                               }
-                       }
-               } else {
-                       printk(", (U)DMA");     /* Can be BIOS-enabled! */
-               }
+                       goto err_out;
        } else if (id->field_valid & 2) {
                if ((id->dma_mword >> 8) && (id->dma_1word >> 8))
-                       goto bug_dma_off;
-               printk(", DMA");
-       } else if (id->field_valid & 1) {
-               goto bug_dma_off;
+                       goto err_out;
        }
-       return;
-bug_dma_off:
-       printk(", BUG DMA OFF");
-       hwif->ide_dma_off_quietly(drive);
-       return;
+       return 0;
+err_out:
+       printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name);
+       return 1;
 }
 
-EXPORT_SYMBOL(ide_dma_verbose);
+int ide_set_dma(ide_drive_t *drive)
+{
+       int rc;
+
+       /*
+        * Force DMAing for the beginning of the check.
+        * Some chipsets appear to do interesting
+        * things, if not checked and cleared.
+        *   PARANOIA!!!
+        */
+       ide_dma_off_quietly(drive);
+
+       rc = ide_dma_check(drive);
+       if (rc)
+               return rc;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-int __ide_dma_lostirq (ide_drive_t *drive)
+       ide_dma_on(drive);
+
+       return 0;
+}
+
+void ide_check_dma_crc(ide_drive_t *drive)
+{
+       u8 mode;
+
+       ide_dma_off_quietly(drive);
+       drive->crc_count = 0;
+       mode = drive->current_speed;
+       /*
+        * Don't try non Ultra-DMA modes without iCRC's.  Force the
+        * device to PIO and make the user enable SWDMA/MWDMA modes.
+        */
+       if (mode > XFER_UDMA_0 && mode <= XFER_UDMA_7)
+               mode--;
+       else
+               mode = XFER_PIO_4;
+       ide_set_xfer_rate(drive, mode);
+       if (drive->current_speed >= XFER_SW_DMA_0)
+               ide_dma_on(drive);
+}
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_SFF
+void ide_dma_lost_irq (ide_drive_t *drive)
 {
        printk("%s: DMA interrupt recovery\n", drive->name);
-       return 1;
 }
 
-EXPORT_SYMBOL(__ide_dma_lostirq);
+EXPORT_SYMBOL(ide_dma_lost_irq);
 
-int __ide_dma_timeout (ide_drive_t *drive)
+void ide_dma_timeout (ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = HWIF(drive);
+
        printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
-       if (HWIF(drive)->ide_dma_test_irq(drive))
-               return 0;
 
-       return HWIF(drive)->ide_dma_end(drive);
+       if (hwif->ide_dma_test_irq(drive))
+               return;
+
+       hwif->ide_dma_end(drive);
 }
 
-EXPORT_SYMBOL(__ide_dma_timeout);
+EXPORT_SYMBOL(ide_dma_timeout);
 
-/*
- * Needed for allowing full modular support of ide-driver
- */
-static int ide_release_dma_engine(ide_hwif_t *hwif)
+static void ide_release_dma_engine(ide_hwif_t *hwif)
 {
        if (hwif->dmatable_cpu) {
-               pci_free_consistent(hwif->pci_dev,
-                                   PRD_ENTRIES * PRD_BYTES,
-                                   hwif->dmatable_cpu,
-                                   hwif->dmatable_dma);
+               struct pci_dev *pdev = to_pci_dev(hwif->dev);
+
+               pci_free_consistent(pdev, PRD_ENTRIES * PRD_BYTES,
+                                   hwif->dmatable_cpu, hwif->dmatable_dma);
                hwif->dmatable_cpu = NULL;
        }
-       return 1;
 }
 
 static int ide_release_iomio_dma(ide_hwif_t *hwif)
@@ -815,7 +888,7 @@ int ide_release_dma(ide_hwif_t *hwif)
 {
        ide_release_dma_engine(hwif);
 
-       if (hwif->mmio == 2)
+       if (hwif->mmio)
                return 1;
        else
                return ide_release_iomio_dma(hwif);
@@ -823,7 +896,9 @@ int ide_release_dma(ide_hwif_t *hwif)
 
 static int ide_allocate_dma_engine(ide_hwif_t *hwif)
 {
-       hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+       struct pci_dev *pdev = to_pci_dev(hwif->dev);
+
+       hwif->dmatable_cpu = pci_alloc_consistent(pdev,
                                                  PRD_ENTRIES * PRD_BYTES,
                                                  &hwif->dmatable_dma);
 
@@ -836,31 +911,23 @@ static int ide_allocate_dma_engine(ide_hwif_t *hwif)
        return 1;
 }
 
-static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base)
 {
        printk(KERN_INFO "    %s: MMIO-DMA ", hwif->name);
 
-       hwif->dma_base = base;
-
-       if(hwif->mate)
-               hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
-       else
-               hwif->dma_master = base;
        return 0;
 }
 
-static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base)
 {
        printk(KERN_INFO "    %s: BM-DMA at 0x%04lx-0x%04lx",
-              hwif->name, base, base + ports - 1);
+              hwif->name, base, base + 7);
 
-       if (!request_region(base, ports, hwif->name)) {
+       if (!request_region(base, 8, hwif->name)) {
                printk(" -- Error, ports in use.\n");
                return 1;
        }
 
-       hwif->dma_base = base;
-
        if (hwif->cds->extra) {
                hwif->extra_base = base + (hwif->channel ? 8 : 16);
 
@@ -868,34 +935,29 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
                        if (!request_region(hwif->extra_base,
                                            hwif->cds->extra, hwif->cds->name)) {
                                printk(" -- Error, extra ports in use.\n");
-                               release_region(base, ports);
+                               release_region(base, 8);
                                return 1;
                        }
                        hwif->extra_ports = hwif->cds->extra;
                }
        }
 
-       if(hwif->mate)
-               hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base:base;
-       else
-               hwif->dma_master = base;
        return 0;
 }
 
-static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
+static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base)
 {
-       if (hwif->mmio == 2)
-               return ide_mapped_mmio_dma(hwif, base,ports);
-       BUG_ON(hwif->mmio == 1);
-       return ide_iomio_dma(hwif, base, ports);
+       if (hwif->mmio)
+               return ide_mapped_mmio_dma(hwif, base);
+
+       return ide_iomio_dma(hwif, base);
 }
 
-/*
- * 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)
+void ide_setup_dma(ide_hwif_t *hwif, unsigned long base)
 {
-       if (ide_dma_iobase(hwif, dma_base, num_ports))
+       u8 dma_stat;
+
+       if (ide_dma_iobase(hwif, base))
                return;
 
        if (ide_allocate_dma_engine(hwif)) {
@@ -903,27 +965,21 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
                return;
        }
 
-       if (!(hwif->dma_command))
-               hwif->dma_command       = hwif->dma_base;
-       if (!(hwif->dma_vendor1))
-               hwif->dma_vendor1       = (hwif->dma_base + 1);
-       if (!(hwif->dma_status))
-               hwif->dma_status        = (hwif->dma_base + 2);
-       if (!(hwif->dma_vendor3))
-               hwif->dma_vendor3       = (hwif->dma_base + 3);
-       if (!(hwif->dma_prdtable))
-               hwif->dma_prdtable      = (hwif->dma_base + 4);
-
-       if (!hwif->ide_dma_off_quietly)
-               hwif->ide_dma_off_quietly = &__ide_dma_off_quietly;
-       if (!hwif->ide_dma_host_off)
-               hwif->ide_dma_host_off = &__ide_dma_host_off;
-       if (!hwif->ide_dma_on)
-               hwif->ide_dma_on = &__ide_dma_on;
-       if (!hwif->ide_dma_host_on)
-               hwif->ide_dma_host_on = &__ide_dma_host_on;
-       if (!hwif->ide_dma_check)
-               hwif->ide_dma_check = &__ide_dma_check;
+       hwif->dma_base = base;
+
+       if (!hwif->dma_command)
+               hwif->dma_command       = hwif->dma_base + 0;
+       if (!hwif->dma_vendor1)
+               hwif->dma_vendor1       = hwif->dma_base + 1;
+       if (!hwif->dma_status)
+               hwif->dma_status        = hwif->dma_base + 2;
+       if (!hwif->dma_vendor3)
+               hwif->dma_vendor3       = hwif->dma_base + 3;
+       if (!hwif->dma_prdtable)
+               hwif->dma_prdtable      = hwif->dma_base + 4;
+
+       if (!hwif->dma_host_set)
+               hwif->dma_host_set = &ide_dma_host_set;
        if (!hwif->dma_setup)
                hwif->dma_setup = &ide_dma_setup;
        if (!hwif->dma_exec_cmd)
@@ -934,21 +990,16 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
                hwif->ide_dma_end = &__ide_dma_end;
        if (!hwif->ide_dma_test_irq)
                hwif->ide_dma_test_irq = &__ide_dma_test_irq;
-       if (!hwif->ide_dma_timeout)
-               hwif->ide_dma_timeout = &__ide_dma_timeout;
-       if (!hwif->ide_dma_lostirq)
-               hwif->ide_dma_lostirq = &__ide_dma_lostirq;
-
-       if (hwif->chipset != ide_trm290) {
-               u8 dma_stat = hwif->INB(hwif->dma_status);
-               printk(", BIOS settings: %s:%s, %s:%s",
-                      hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-                      hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
-       }
-       printk("\n");
+       if (!hwif->dma_timeout)
+               hwif->dma_timeout = &ide_dma_timeout;
+       if (!hwif->dma_lost_irq)
+               hwif->dma_lost_irq = &ide_dma_lost_irq;
 
-       BUG_ON(!hwif->dma_master);
+       dma_stat = hwif->INB(hwif->dma_status);
+       printk(KERN_CONT ", BIOS settings: %s:%s, %s:%s\n",
+              hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "PIO",
+              hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "PIO");
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_dma);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
+#endif /* CONFIG_BLK_DEV_IDEDMA_SFF */