Merge git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6
[pandora-kernel.git] / drivers / ide / ide-dma.c
index a4cbbba..5bf3203 100644 (file)
@@ -130,6 +130,7 @@ static const struct drive_list_entry drive_blacklist [] = {
        { "_NEC DV5800A",               NULL            },
        { "SAMSUNG CD-ROM SN-124",      "N001" },
        { "Seagate STT20000A",          NULL  },
+       { "CD-ROM CDR_U200",            "1.09" },
        { NULL                  ,       NULL            }
 
 };
@@ -152,13 +153,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
                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", 
@@ -338,35 +333,32 @@ static int config_drive_for_dma (ide_drive_t *drive)
        ide_hwif_t *hwif = drive->hwif;
        struct hd_driveid *id = drive->id;
 
-       /* consult the list of known "bad" drives */
-       if (__ide_dma_bad_drive(drive))
-               return -1;
+       if (drive->media != ide_disk) {
+               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+                       return 0;
+       }
 
-       if (drive->media != ide_disk && hwif->atapi_dma == 0)
-               return -1;
+       /*
+        * 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;
 
-       if ((id->capability & 1) && drive->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 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)
-                               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)
+                       return 1;
 
-               /* Consult the list of known "good" drives */
-               if (ide_dma_good_drive(drive))
-                       return 0;
-       }
+       /* Consult the list of known "good" drives */
+       if (ide_dma_good_drive(drive))
+               return 1;
 
-       return -1;
+       return 0;
 }
 
 /**
@@ -410,23 +402,29 @@ 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.
  */
 
-void 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);
+       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_PCI */
 
 /**
  *     ide_dma_off_quietly     -       Generic DMA kill
@@ -440,11 +438,10 @@ void ide_dma_off_quietly(ide_drive_t *drive)
        drive->using_dma = 0;
        ide_toggle_bounce(drive, 0);
 
-       drive->hwif->dma_host_off(drive);
+       drive->hwif->dma_host_set(drive, 0);
 }
 
 EXPORT_SYMBOL(ide_dma_off_quietly);
-#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 /**
  *     ide_dma_off     -       disable DMA on a device
@@ -457,56 +454,29 @@ EXPORT_SYMBOL(ide_dma_off_quietly);
 void ide_dma_off(ide_drive_t *drive)
 {
        printk(KERN_INFO "%s: DMA disabled\n", drive->name);
-       drive->hwif->dma_off_quietly(drive);
+       ide_dma_off_quietly(drive);
 }
 
 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
- */
-
-void 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);
-       }
-}
-
-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);
 
-       drive->hwif->dma_host_on(drive);
-
-       return 0;
+       drive->hwif->dma_host_set(drive, 1);
 }
 
-EXPORT_SYMBOL(__ide_dma_on);
+EXPORT_SYMBOL(ide_dma_on);
 
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
 /**
  *     ide_dma_setup   -       begin a DMA phase
  *     @drive: target device
@@ -613,12 +583,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;
@@ -627,6 +591,8 @@ static int __ide_dma_test_irq(ide_drive_t *drive)
                        drive->name, __FUNCTION__);
        return 0;
 }
+#else
+static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
 #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 int __ide_dma_bad_drive (ide_drive_t *drive)
@@ -729,8 +695,10 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
        int x, i;
        u8 mode = 0;
 
-       if (drive->media != ide_disk && hwif->atapi_dma == 0)
-               return 0;
+       if (drive->media != ide_disk) {
+               if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+                       return 0;
+       }
 
        for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
                if (req_mode < xfer_mode_bases[i])
@@ -751,30 +719,46 @@ u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
                        mode = XFER_MW_DMA_1;
        }
 
-       printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
+       mode = min(mode, req_mode);
+
+       printk(KERN_INFO "%s: %s mode selected\n", drive->name,
+                         mode ? ide_xfer_verbose(mode) : "no DMA");
 
-       return min(mode, req_mode);
+       return mode;
 }
 
 EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
-int ide_tune_dma(ide_drive_t *drive)
+static int ide_tune_dma(ide_drive_t *drive)
 {
+       ide_hwif_t *hwif = drive->hwif;
        u8 speed;
 
-       if ((drive->id->capability & 1) == 0 || drive->autodma == 0)
+       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;
 
+       if (ide_id_dma_bug(drive))
+               return 0;
+
+       if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+               return config_drive_for_dma(drive);
+
        speed = ide_max_dma_mode(drive);
 
-       if (!speed)
-               return 0;
+       if (!speed) {
+                /* is this really correct/needed? */
+               if ((hwif->host_flags & IDE_HFLAG_CY82C693) &&
+                   ide_dma_good_drive(drive))
+                       return 1;
+               else
+                       return 0;
+       }
 
-       if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+       if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
                return 0;
 
        if (ide_set_dma_mode(drive, speed))
@@ -783,81 +767,59 @@ int ide_tune_dma(ide_drive_t *drive)
        return 1;
 }
 
-EXPORT_SYMBOL_GPL(ide_tune_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;
 
-void ide_dma_verbose(ide_drive_t *drive)
+       ide_set_max_pio(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->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)
 {
-       ide_hwif_t *hwif = drive->hwif;
        int rc;
 
-       rc = hwif->ide_dma_check(drive);
+       /*
+        * 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);
 
-       switch(rc) {
-       case -1: /* DMA needs to be disabled */
-               hwif->dma_off_quietly(drive);
-               return -1;
-       case  0: /* DMA needs to be enabled */
-               return hwif->ide_dma_on(drive);
-       case  1: /* DMA setting cannot be changed */
-               break;
-       default:
-               BUG();
-               break;
-       }
+       rc = ide_dma_check(drive);
+       if (rc)
+               return rc;
+
+       ide_dma_on(drive);
 
-       return rc;
+       return 0;
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PCI
@@ -882,10 +844,7 @@ void ide_dma_timeout (ide_drive_t *drive)
 
 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,
@@ -894,7 +853,6 @@ static int ide_release_dma_engine(ide_hwif_t *hwif)
                                    hwif->dmatable_dma);
                hwif->dmatable_cpu = NULL;
        }
-       return 1;
 }
 
 static int ide_release_iomio_dma(ide_hwif_t *hwif)
@@ -937,12 +895,6 @@ static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned in
 {
        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;
 }
 
@@ -956,8 +908,6 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
                return 1;
        }
 
-       hwif->dma_base = base;
-
        if (hwif->cds->extra) {
                hwif->extra_base = base + (hwif->channel ? 8 : 16);
 
@@ -972,10 +922,6 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
                }
        }
 
-       if(hwif->mate)
-               hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base:base;
-       else
-               hwif->dma_master = base;
        return 0;
 }
 
@@ -987,12 +933,9 @@ static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int por
        return ide_iomio_dma(hwif, base, ports);
 }
 
-/*
- * 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, unsigned num_ports)
 {
-       if (ide_dma_iobase(hwif, dma_base, num_ports))
+       if (ide_dma_iobase(hwif, base, num_ports))
                return;
 
        if (ide_allocate_dma_engine(hwif)) {
@@ -1000,6 +943,8 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
                return;
        }
 
+       hwif->dma_base = base;
+
        if (!(hwif->dma_command))
                hwif->dma_command       = hwif->dma_base;
        if (!(hwif->dma_vendor1))
@@ -1011,16 +956,8 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
        if (!(hwif->dma_prdtable))
                hwif->dma_prdtable      = (hwif->dma_base + 4);
 
-       if (!hwif->dma_off_quietly)
-               hwif->dma_off_quietly = &ide_dma_off_quietly;
-       if (!hwif->dma_host_off)
-               hwif->dma_host_off = &ide_dma_host_off;
-       if (!hwif->ide_dma_on)
-               hwif->ide_dma_on = &__ide_dma_on;
-       if (!hwif->dma_host_on)
-               hwif->dma_host_on = &ide_dma_host_on;
-       if (!hwif->ide_dma_check)
-               hwif->ide_dma_check = &config_drive_for_dma;
+       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)
@@ -1043,8 +980,6 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
                       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
        }
        printk("\n");
-
-       BUG_ON(!hwif->dma_master);
 }
 
 EXPORT_SYMBOL_GPL(ide_setup_dma);