int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout) { int err; u8 stat; if (drive->max_failures && (drive->failures > drive->max_failures)) { *startstop = ide_stopped; return 1; } err = __ide_wait_stat(drive, good, bad, timeout, &stat); if (err) { char *s = (err == -EBUSY) ? "status timeout" : "status error"; *startstop = ide_error(drive, s, stat); } return err; }
int ide_config_drive_speed(ide_drive_t *drive, u8 speed) { ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; struct ide_taskfile tf; u16 *id = drive->id, i; int error = 0; u8 stat; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_ops) hwif->dma_ops->dma_host_set(drive, 0); #endif if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0) goto skip; udelay(1); tp_ops->dev_select(drive); SELECT_MASK(drive, 1); udelay(1); tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); memset(&tf, 0, sizeof(tf)); tf.feature = SETFEATURES_XFER; tf.nsect = speed; tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE | IDE_VALID_NSECT); tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES); if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); error = __ide_wait_stat(drive, drive->ready_stat, ATA_BUSY | ATA_DRQ | ATA_ERR, WAIT_CMD, &stat); SELECT_MASK(drive, 0); if (error) { (void) ide_dump_status(drive, "set_drive_speed_status", stat); return error; } if (speed >= XFER_SW_DMA_0) { id[ATA_ID_UDMA_MODES] &= ~0xFF00; id[ATA_ID_MWDMA_MODES] &= ~0x0700; id[ATA_ID_SWDMA_MODES] &= ~0x0700; if (ata_id_is_cfa(id)) id[ATA_ID_CFA_MODES] &= ~0x0E00; } else if (ata_id_is_cfa(id)) id[ATA_ID_CFA_MODES] &= ~0x01C0; skip: #ifdef CONFIG_BLK_DEV_IDEDMA if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA)) hwif->dma_ops->dma_host_set(drive, 1); else if (hwif->dma_ops) ide_dma_off_quietly(drive); #endif if (speed >= XFER_UDMA_0) { i = 1 << (speed - XFER_UDMA_0); id[ATA_ID_UDMA_MODES] |= (i << 8 | i); } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) { i = speed - XFER_MW_DMA_2; id[ATA_ID_CFA_MODES] |= i << 9; } else if (speed >= XFER_MW_DMA_0) { i = 1 << (speed - XFER_MW_DMA_0); id[ATA_ID_MWDMA_MODES] |= (i << 8 | i); } else if (speed >= XFER_SW_DMA_0) { i = 1 << (speed - XFER_SW_DMA_0); id[ATA_ID_SWDMA_MODES] |= (i << 8 | i); } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) { i = speed - XFER_PIO_4; id[ATA_ID_CFA_MODES] |= i << 6; } if (!drive->init_speed) drive->init_speed = speed; drive->current_speed = speed; return error; }
int ide_config_drive_speed(ide_drive_t *drive, u8 speed) { ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; struct ide_taskfile tf; u16 *id = drive->id, i; int error = 0; u8 stat; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_ops) /* check if host supports DMA */ hwif->dma_ops->dma_host_set(drive, 0); #endif /* Skip setting PIO flow-control modes on pre-EIDE drives */ if ((speed & 0xf8) == XFER_PIO_0 && ata_id_has_iordy(drive->id) == 0) goto skip; /* * Don't use ide_wait_cmd here - it will * attempt to set_geometry and recalibrate, * but for some reason these don't work at * this point (lost interrupt). */ /* * FIXME: we race against the running IRQ here if * this is called from non IRQ context. If we use * disable_irq() we hang on the error path. Work * is needed. */ disable_irq_nosync(hwif->irq); udelay(1); tp_ops->dev_select(drive); SELECT_MASK(drive, 1); udelay(1); tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); memset(&tf, 0, sizeof(tf)); tf.feature = SETFEATURES_XFER; tf.nsect = speed; tp_ops->tf_load(drive, &tf, IDE_VALID_FEATURE | IDE_VALID_NSECT); tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES); if (drive->dev_flags & IDE_DFLAG_NIEN_QUIRK) tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); error = __ide_wait_stat(drive, drive->ready_stat, ATA_BUSY | ATA_DRQ | ATA_ERR, WAIT_CMD, &stat); SELECT_MASK(drive, 0); enable_irq(hwif->irq); if (error) { (void) ide_dump_status(drive, "set_drive_speed_status", stat); return error; } if (speed >= XFER_SW_DMA_0) { id[ATA_ID_UDMA_MODES] &= ~0xFF00; id[ATA_ID_MWDMA_MODES] &= ~0x0700; id[ATA_ID_SWDMA_MODES] &= ~0x0700; if (ata_id_is_cfa(id)) id[ATA_ID_CFA_MODES] &= ~0x0E00; } else if (ata_id_is_cfa(id)) id[ATA_ID_CFA_MODES] &= ~0x01C0; skip: #ifdef CONFIG_BLK_DEV_IDEDMA if (speed >= XFER_SW_DMA_0 && (drive->dev_flags & IDE_DFLAG_USING_DMA)) hwif->dma_ops->dma_host_set(drive, 1); else if (hwif->dma_ops) /* check if host supports DMA */ ide_dma_off_quietly(drive); #endif if (speed >= XFER_UDMA_0) { i = 1 << (speed - XFER_UDMA_0); id[ATA_ID_UDMA_MODES] |= (i << 8 | i); } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) { i = speed - XFER_MW_DMA_2; id[ATA_ID_CFA_MODES] |= i << 9; } else if (speed >= XFER_MW_DMA_0) { i = 1 << (speed - XFER_MW_DMA_0); id[ATA_ID_MWDMA_MODES] |= (i << 8 | i); } else if (speed >= XFER_SW_DMA_0) { i = 1 << (speed - XFER_SW_DMA_0); id[ATA_ID_SWDMA_MODES] |= (i << 8 | i); } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) { i = speed - XFER_PIO_4; id[ATA_ID_CFA_MODES] |= i << 6; } if (!drive->init_speed) drive->init_speed = speed; drive->current_speed = speed; return error; }