]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/ide/ide-io.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mfashe...
[linux-2.6-omap-h63xx.git] / drivers / ide / ide-io.c
index ba6039b55b41ebb348223db10dc4f9a9ea9cfd0e..0e0280076fcde4b1274d5dee331e547509a3f335 100644 (file)
@@ -226,7 +226,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
                        break;
                if (drive->hwif->ide_dma_check == NULL)
                        break;
-               drive->hwif->ide_dma_check(drive);
+               ide_set_dma(drive);
                break;
        }
        pm->pm_step = ide_pm_state_completed;
@@ -519,21 +519,24 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
        if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ && hwif->err_stops_fifo == 0)
                try_to_flush_leftover_data(drive);
 
+       if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {
+               ide_kill_rq(drive, rq);
+               return ide_stopped;
+       }
+
        if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
-               /* force an abort */
-               hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);
+               rq->errors |= ERROR_RESET;
 
-       if (rq->errors >= ERROR_MAX || blk_noretry_request(rq))
-               ide_kill_rq(drive, rq);
-       else {
-               if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
-                       ++rq->errors;
-                       return ide_do_reset(drive);
-               }
-               if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
-                       drive->special.b.recalibrate = 1;
+       if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
                ++rq->errors;
+               return ide_do_reset(drive);
        }
+
+       if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+               drive->special.b.recalibrate = 1;
+
+       ++rq->errors;
+
        return ide_stopped;
 }
 
@@ -1025,6 +1028,13 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
        if (!drive->special.all) {
                ide_driver_t *drv;
 
+               /*
+                * We reset the drive so we need to issue a SETFEATURES.
+                * Do it _after_ do_special() restored device parameters.
+                */
+               if (drive->current_speed == 0xff)
+                       ide_config_drive_speed(drive, drive->desired_speed);
+
                if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
                    rq->cmd_type == REQ_TYPE_ATA_TASK ||
                    rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
@@ -1351,7 +1361,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
         */
        drive->retry_pio++;
        drive->state = DMA_PIO_RETRY;
-       (void) hwif->ide_dma_off_quietly(drive);
+       hwif->dma_off_quietly(drive);
 
        /*
         * un-busy drive etc (hwgroup->busy is cleared on return) and
@@ -1562,7 +1572,7 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
  *     on the hwgroup and the process begins again.
  */
  
-irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t ide_intr (int irq, void *dev_id)
 {
        unsigned long flags;
        ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
@@ -1646,6 +1656,17 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
        del_timer(&hwgroup->timer);
        spin_unlock(&ide_lock);
 
+       /* Some controllers might set DMA INTR no matter DMA or PIO;
+        * bmdma status might need to be cleared even for
+        * PIO interrupts to prevent spurious/lost irq.
+        */
+       if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma))
+               /* ide_dma_end() needs bmdma status for error checking.
+                * So, skip clearing bmdma status here and leave it
+                * to ide_dma_end() if this is dma interrupt.
+                */
+               hwif->ide_dma_clear_irq(drive);
+
        if (drive->unmask)
                local_irq_enable_in_hardirq();
        /* service this interrupt, may set handler for next interrupt */