ide: add ide_tf_read() helper
[pandora-kernel.git] / drivers / ide / ide-lib.c
index d97390c..15736d4 100644 (file)
  *     Add common non I/O op stuff here. Make sure it has proper
  *     kernel-doc function headers or your patch will be rejected
  */
+
+static const char *udma_str[] =
+        { "UDMA/16", "UDMA/25",  "UDMA/33",  "UDMA/44",
+          "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" };
+static const char *mwdma_str[] =
+       { "MWDMA0", "MWDMA1", "MWDMA2" };
+static const char *swdma_str[] =
+       { "SWDMA0", "SWDMA1", "SWDMA2" };
+static const char *pio_str[] =
+       { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" };
 
 /**
  *     ide_xfer_verbose        -       return IDE mode names
- *     @xfer_rate: rate to name
+ *     @mode: transfer mode
  *
  *     Returns a constant string giving the name of the mode
  *     requested.
  */
 
-char *ide_xfer_verbose (u8 xfer_rate)
+const char *ide_xfer_verbose(u8 mode)
 {
-        switch(xfer_rate) {
-                case XFER_UDMA_7:      return("UDMA 7");
-                case XFER_UDMA_6:      return("UDMA 6");
-                case XFER_UDMA_5:      return("UDMA 5");
-                case XFER_UDMA_4:      return("UDMA 4");
-                case XFER_UDMA_3:      return("UDMA 3");
-                case XFER_UDMA_2:      return("UDMA 2");
-                case XFER_UDMA_1:      return("UDMA 1");
-                case XFER_UDMA_0:      return("UDMA 0");
-                case XFER_MW_DMA_2:    return("MW DMA 2");
-                case XFER_MW_DMA_1:    return("MW DMA 1");
-                case XFER_MW_DMA_0:    return("MW DMA 0");
-                case XFER_SW_DMA_2:    return("SW DMA 2");
-                case XFER_SW_DMA_1:    return("SW DMA 1");
-                case XFER_SW_DMA_0:    return("SW DMA 0");
-                case XFER_PIO_4:       return("PIO 4");
-                case XFER_PIO_3:       return("PIO 3");
-                case XFER_PIO_2:       return("PIO 2");
-                case XFER_PIO_1:       return("PIO 1");
-                case XFER_PIO_0:       return("PIO 0");
-                case XFER_PIO_SLOW:    return("PIO SLOW");
-                default:               return("XFER ERROR");
-        }
+       const char *s;
+       u8 i = mode & 0xf;
+
+       if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7)
+               s = udma_str[i];
+       else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2)
+               s = mwdma_str[i];
+       else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2)
+               s = swdma_str[i];
+       else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5)
+               s = pio_str[i & 0x7];
+       else if (mode == XFER_PIO_SLOW)
+               s = "PIO SLOW";
+       else
+               s = "XFER ERROR";
+
+       return s;
 }
 
 EXPORT_SYMBOL(ide_xfer_verbose);
@@ -96,21 +99,6 @@ static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
        return min(speed, mode);
 }
 
-int ide_use_fast_pio(ide_drive_t *drive)
-{
-       struct hd_driveid *id = drive->id;
-
-       if ((id->capability & 1) && drive->autodma)
-               return 1;
-
-       if ((id->capability & 8) || (id->field_valid & 2))
-               return 1;
-
-       return 0;
-}
-
-EXPORT_SYMBOL_GPL(ide_use_fast_pio);
-
 /*
  * Standard (generic) timings for PIO modes, from ATA2 specification.
  * These timings are for access to the IDE data port register *only*.
@@ -349,7 +337,7 @@ void ide_set_pio(ide_drive_t *drive, u8 req_pio)
                          drive->name, host_pio, req_pio,
                          req_pio == 255 ? "(auto-tune)" : "", pio);
 
-       hwif->set_pio_mode(drive, pio);
+       (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
 }
 
 EXPORT_SYMBOL_GPL(ide_set_pio);
@@ -378,39 +366,83 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
                blk_queue_bounce_limit(drive->queue, addr);
 }
 
+int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       if (hwif->set_pio_mode == NULL)
+               return -1;
+
+       /*
+        * TODO: temporary hack for some legacy host drivers that didn't
+        * set transfer mode on the device in ->set_pio_mode method...
+        */
+       if (hwif->set_dma_mode == NULL) {
+               hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+               return 0;
+       }
+
+       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+               if (ide_config_drive_speed(drive, mode))
+                       return -1;
+               hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+               return 0;
+       } else {
+               hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+               return ide_config_drive_speed(drive, mode);
+       }
+}
+
+int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       if (hwif->set_dma_mode == NULL)
+               return -1;
+
+       if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+               if (ide_config_drive_speed(drive, mode))
+                       return -1;
+               hwif->set_dma_mode(drive, mode);
+               return 0;
+       } else {
+               hwif->set_dma_mode(drive, mode);
+               return ide_config_drive_speed(drive, mode);
+       }
+}
+
+EXPORT_SYMBOL_GPL(ide_set_dma_mode);
+
 /**
  *     ide_set_xfer_rate       -       set transfer rate
  *     @drive: drive to set
- *     @speed: speed to attempt to set
+ *     @rate: speed to attempt to set
  *     
  *     General helper for setting the speed of an IDE device. This
  *     function knows about user enforced limits from the configuration
- *     which speedproc() does not.  High level drivers should never
- *     invoke speedproc() directly.
+ *     which ->set_pio_mode/->set_dma_mode does not.
  */
+
 int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 {
        ide_hwif_t *hwif = drive->hwif;
 
-       if (hwif->speedproc == NULL)
+       if (hwif->set_dma_mode == NULL)
                return -1;
 
        rate = ide_rate_filter(drive, rate);
 
-       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) {
-               if (hwif->set_pio_mode)
-                       hwif->set_pio_mode(drive, rate - XFER_PIO_0);
+       if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+               return ide_set_pio_mode(drive, rate);
 
-               /*
-                * FIXME: this is incorrect to return zero here but
-                * since all users of ide_set_xfer_rate() ignore
-                * the return value it is not a problem currently
-                */
-               return 0;
-       }
+       /*
+        * TODO: transfer modes 0x00-0x07 passed from the user-space are
+        * currently handled here which needs fixing (please note that such
+        * case could happen iff the transfer mode has already been set on
+        * the device by ide-proc.c::set_xfer_rate()).
+        */
 
-       return hwif->speedproc(drive, rate);
+       return ide_set_dma_mode(drive, rate);
 }
 
 static void ide_dump_opcode(ide_drive_t *drive)
@@ -426,8 +458,7 @@ static void ide_dump_opcode(ide_drive_t *drive)
        spin_unlock(&ide_lock);
        if (!rq)
                return;
-       if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
-           rq->cmd_type == REQ_TYPE_ATA_TASK) {
+       if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
                char *args = rq->buffer;
                if (args) {
                        opcode = args[0];
@@ -436,8 +467,7 @@ static void ide_dump_opcode(ide_drive_t *drive)
        } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
                ide_task_t *args = rq->special;
                if (args) {
-                       task_struct_t *tf = (task_struct_t *) args->tfRegister;
-                       opcode = tf->command;
+                       opcode = args->tf.command;
                        found = 1;
                }
        }
@@ -449,6 +479,42 @@ static void ide_dump_opcode(ide_drive_t *drive)
                printk("0x%02x\n", opcode);
 }
 
+static u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48)
+{
+       u32 high, low;
+
+       if (lba48)
+               high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) |
+                       tf->hob_lbal;
+       else
+               high = tf->device & 0xf;
+       low  = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal;
+
+       return ((u64)high << 24) | low;
+}
+
+static void ide_dump_sector(ide_drive_t *drive)
+{
+       ide_task_t task;
+       struct ide_taskfile *tf = &task.tf;
+       int lba48 = (drive->addressing == 1) ? 1 : 0;
+
+       memset(&task, 0, sizeof(task));
+       if (lba48)
+               task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA |
+                               IDE_TFLAG_LBA48;
+       else
+               task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE;
+
+       ide_tf_read(drive, &task);
+
+       if (lba48 || (tf->device & ATA_LBA))
+               printk(", LBAsect=%llu", ide_get_lba_addr(tf, lba48));
+       else
+               printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam,
+                                        tf->device & 0xf, tf->lbal);
+}
+
 static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
 {
        ide_hwif_t *hwif = HWIF(drive);
@@ -482,32 +548,7 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
                printk("}");
                if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||
                    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
-                       if (drive->addressing == 1) {
-                               __u64 sectors = 0;
-                               u32 low = 0, high = 0;
-                               low = ide_read_24(drive);
-                               hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
-                               high = ide_read_24(drive);
-                               sectors = ((__u64)high << 24) | low;
-                               printk(", LBAsect=%llu, high=%d, low=%d",
-                                      (unsigned long long) sectors,
-                                      high, low);
-                       } else {
-                               u8 cur = hwif->INB(IDE_SELECT_REG);
-                               if (cur & 0x40) {       /* using LBA? */
-                                       printk(", LBAsect=%ld", (unsigned long)
-                                        ((cur&0xf)<<24)
-                                        |(hwif->INB(IDE_HCYL_REG)<<16)
-                                        |(hwif->INB(IDE_LCYL_REG)<<8)
-                                        | hwif->INB(IDE_SECTOR_REG));
-                               } else {
-                                       printk(", CHS=%d/%d/%d",
-                                        (hwif->INB(IDE_HCYL_REG)<<8) +
-                                         hwif->INB(IDE_LCYL_REG),
-                                         cur & 0xf,
-                                         hwif->INB(IDE_SECTOR_REG));
-                               }
-                       }
+                       ide_dump_sector(drive);
                        if (HWGROUP(drive) && HWGROUP(drive)->rq)
                                printk(", sector=%llu",
                                        (unsigned long long)HWGROUP(drive)->rq->sector);
@@ -531,40 +572,36 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
 static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
 {
        unsigned long flags;
+       u8 err = 0;
 
-       atapi_status_t status;
-       atapi_error_t error;
-
-       status.all = stat;
-       error.all = 0;
        local_irq_save(flags);
        printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
-       if (status.b.bsy)
+       if (stat & BUSY_STAT)
                printk("Busy ");
        else {
-               if (status.b.drdy)      printk("DriveReady ");
-               if (status.b.df)        printk("DeviceFault ");
-               if (status.b.dsc)       printk("SeekComplete ");
-               if (status.b.drq)       printk("DataRequest ");
-               if (status.b.corr)      printk("CorrectedError ");
-               if (status.b.idx)       printk("Index ");
-               if (status.b.check)     printk("Error ");
+               if (stat & READY_STAT)  printk("DriveReady ");
+               if (stat & WRERR_STAT)  printk("DeviceFault ");
+               if (stat & SEEK_STAT)   printk("SeekComplete ");
+               if (stat & DRQ_STAT)    printk("DataRequest ");
+               if (stat & ECC_STAT)    printk("CorrectedError ");
+               if (stat & INDEX_STAT)  printk("Index ");
+               if (stat & ERR_STAT)    printk("Error ");
        }
        printk("}\n");
-       if (status.b.check && !status.b.bsy) {
-               error.all = HWIF(drive)->INB(IDE_ERROR_REG);
-               printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all);
-               if (error.b.ili)        printk("IllegalLengthIndication ");
-               if (error.b.eom)        printk("EndOfMedia ");
-               if (error.b.abrt)       printk("AbortedCommand ");
-               if (error.b.mcr)        printk("MediaChangeRequested ");
-               if (error.b.sense_key)  printk("LastFailedSense=0x%02x ",
-                                               error.b.sense_key);
+       if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+               err = drive->hwif->INB(IDE_ERROR_REG);
+               printk("%s: %s: error=0x%02x { ", drive->name, msg, err);
+               if (err & ILI_ERR)      printk("IllegalLengthIndication ");
+               if (err & EOM_ERR)      printk("EndOfMedia ");
+               if (err & ABRT_ERR)     printk("AbortedCommand ");
+               if (err & MCR_ERR)      printk("MediaChangeRequested ");
+               if (err & LFS_ERR)      printk("LastFailedSense=0x%02x ",
+                                               (err & LFS_ERR) >> 4);
                printk("}\n");
        }
        ide_dump_opcode(drive);
        local_irq_restore(flags);
-       return error.all;
+       return err;
 }
 
 /**