diff options
Diffstat (limited to 'drivers/ide/ide.c')
-rw-r--r-- | drivers/ide/ide.c | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 9d3482d907c..73e1cc5839d 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -314,9 +314,32 @@ out: #endif } +/* + * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away + */ +static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) +{ + switch (req_pio) { + case 202: + case 201: + case 200: + case 102: + case 101: + case 100: + return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; + case 9: + case 8: + return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; + case 7: + case 6: + return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; + default: + return 0; + } +} + static int set_pio_mode(ide_drive_t *drive, int arg) { - struct request *rq; ide_hwif_t *hwif = drive->hwif; const struct ide_port_ops *port_ops = hwif->port_ops; @@ -327,17 +350,26 @@ static int set_pio_mode(ide_drive_t *drive, int arg) (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) return -ENOSYS; - if (drive->special.b.set_tune) - return -EBUSY; + if (set_pio_mode_abuse(drive->hwif, arg)) { + if (arg == 8 || arg == 9) { + unsigned long flags; - rq = blk_get_request(drive->queue, READ, __GFP_WAIT); - rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ + spin_lock_irqsave(&ide_lock, flags); + port_ops->set_pio_mode(drive, arg); + spin_unlock_irqrestore(&ide_lock, flags); + } else + port_ops->set_pio_mode(drive, arg); + } else { + int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); - drive->tune_req = (u8) arg; - drive->special.b.set_tune = 1; + ide_set_pio(drive, arg); - blk_execute_rq(drive->queue, NULL, rq, 0); - blk_put_request(rq); + if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { + if (keep_dma) + ide_dma_on(drive); + } + } return 0; } @@ -367,7 +399,7 @@ ide_gen_devset_rw(io_32bit, io_32bit); ide_gen_devset_rw(keepsettings, ksettings); ide_gen_devset_rw(unmaskirq, unmaskirq); ide_gen_devset_rw(using_dma, using_dma); -__IDE_DEVSET(pio_mode, 0, NULL, set_pio_mode); +__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode); static int generic_ide_suspend(struct device *dev, pm_message_t mesg) { |