X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fide-io.c;h=d6ff4f2292cb48a7a0b5ec6e4cdd342ac7152195;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=8ae49745556234ea17fb392476c0c65fdcc63066;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 8ae497455..d6ff4f229 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -24,7 +24,6 @@ */ -#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include #include @@ -54,38 +54,220 @@ #include #include +static int __ide_end_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + int ret = 1; + + /* + * if failfast is set on a request, override number of sectors and + * complete the whole request right now + */ + if (blk_noretry_request(rq) && end_io_error(uptodate)) + nr_sectors = rq->hard_nr_sectors; + + if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + rq->errors = -EIO; + + /* + * decide whether to reenable DMA -- 3 is a random magic for now, + * if we DMA timeout more than 3 times, just stay in PIO + */ + if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { + drive->state = 0; + HWGROUP(drive)->hwif->ide_dma_on(drive); + } + + if (!end_that_request_first(rq, uptodate, nr_sectors)) { + add_disk_randomness(rq->rq_disk); + if (!list_empty(&rq->queuelist)) + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq, uptodate); + ret = 0; + } + + return ret; +} + /** * ide_end_request - complete an IDE I/O * @drive: IDE device for the I/O - * @uptodate: + * @uptodate: * @nr_sectors: number of sectors completed * * This is our end_request wrapper function. We complete the I/O * update random number input and dequeue the request, which if * it was tagged may be out of order. */ - + int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) { struct request *rq; unsigned long flags; int ret = 1; + /* + * room for locking improvements here, the calls below don't + * need the queue lock held at all + */ spin_lock_irqsave(&ide_lock, flags); rq = HWGROUP(drive)->rq; - BUG_ON(!(rq->flags & REQ_STARTED)); - if (!nr_sectors) nr_sectors = rq->hard_cur_sectors; + ret = __ide_end_request(drive, rq, uptodate, nr_sectors); + + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} +EXPORT_SYMBOL(ide_end_request); + +/* + * Power Management state machine. This one is rather trivial for now, + * we should probably add more, like switching back to PIO on suspend + * to help some BIOSes, re-do the door locking on resume, etc... + */ + +enum { + ide_pm_flush_cache = ide_pm_state_start_suspend, + idedisk_pm_standby, + + idedisk_pm_restore_pio = ide_pm_state_start_resume, + idedisk_pm_idle, + ide_pm_restore_dma, +}; + +static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error) +{ + struct request_pm_state *pm = rq->data; + + if (drive->media != ide_disk) + return; + + switch (pm->pm_step) { + case ide_pm_flush_cache: /* Suspend step 1 (flush cache) complete */ + if (pm->pm_state == PM_EVENT_FREEZE) + pm->pm_step = ide_pm_state_completed; + else + pm->pm_step = idedisk_pm_standby; + break; + case idedisk_pm_standby: /* Suspend step 2 (standby) complete */ + pm->pm_step = ide_pm_state_completed; + break; + case idedisk_pm_restore_pio: /* Resume step 1 complete */ + pm->pm_step = idedisk_pm_idle; + break; + case idedisk_pm_idle: /* Resume step 2 (idle) complete */ + pm->pm_step = ide_pm_restore_dma; + break; + } +} + +static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) +{ + struct request_pm_state *pm = rq->data; + ide_task_t *args = rq->special; + + memset(args, 0, sizeof(*args)); + + if (drive->media != ide_disk) { + /* + * skip idedisk_pm_restore_pio and idedisk_pm_idle for ATAPI + * devices + */ + if (pm->pm_step == idedisk_pm_restore_pio) + pm->pm_step = ide_pm_restore_dma; + } + + switch (pm->pm_step) { + case ide_pm_flush_cache: /* Suspend step 1 (flush cache) */ + if (drive->media != ide_disk) + break; + /* Not supported? Switch to next step now. */ + if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) { + ide_complete_power_step(drive, rq, 0, 0); + return ide_stopped; + } + if (ide_id_has_flush_cache_ext(drive->id)) + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT; + else + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + args->handler = &task_no_data_intr; + return do_rw_taskfile(drive, args); + + case idedisk_pm_standby: /* Suspend step 2 (standby) */ + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + args->handler = &task_no_data_intr; + return do_rw_taskfile(drive, args); + + case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */ + if (drive->hwif->tuneproc != NULL) + drive->hwif->tuneproc(drive, 255); + ide_complete_power_step(drive, rq, 0, 0); + return ide_stopped; + + case idedisk_pm_idle: /* Resume step 2 (idle) */ + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + args->handler = task_no_data_intr; + return do_rw_taskfile(drive, args); + + case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */ + /* + * Right now, all we do is call hwif->ide_dma_check(drive), + * we could be smarter and check for current xfer_speed + * in struct drive etc... + */ + if ((drive->id->capability & 1) == 0) + break; + if (drive->hwif->ide_dma_check == NULL) + break; + drive->hwif->ide_dma_check(drive); + break; + } + pm->pm_step = ide_pm_state_completed; + return ide_stopped; +} + +/** + * ide_end_dequeued_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * Complete an I/O that is no longer on the request queue. This + * typically occurs when we pull the request and issue a REQUEST_SENSE. + * We must still finish the old request but we must not tamper with the + * queue in the meantime. + * + * NOTE: This path does not handle barrier, but barrier is not supported + * on ide-cd anyway. + */ + +int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + + BUG_ON(!blk_rq_started(rq)); + /* * if failfast is set on a request, override number of sectors and * complete the whole request right now */ - if (blk_noretry_request(rq) && !uptodate) + if (blk_noretry_request(rq) && end_io_error(uptodate)) nr_sectors = rq->hard_nr_sectors; + if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + rq->errors = -EIO; + /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO @@ -97,19 +279,16 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) if (!end_that_request_first(rq, uptodate, nr_sectors)) { add_disk_randomness(rq->rq_disk); - if (!blk_rq_tagged(rq)) - blkdev_dequeue_request(rq); - else + if (blk_rq_tagged(rq)) blk_queue_end_tag(drive->queue, rq); - HWGROUP(drive)->rq = NULL; - end_that_request_last(rq); + end_that_request_last(rq, uptodate); ret = 0; } spin_unlock_irqrestore(&ide_lock, flags); return ret; } +EXPORT_SYMBOL_GPL(ide_end_dequeued_request); -EXPORT_SYMBOL(ide_end_request); /** * ide_complete_pm_request - end the current Power Management request @@ -136,10 +315,45 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) } blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - end_that_request_last(rq); + end_that_request_last(rq, 1); spin_unlock_irqrestore(&ide_lock, flags); } +/* + * FIXME: probably move this somewhere else, name is bad too :) + */ +u64 ide_get_error_location(ide_drive_t *drive, char *args) +{ + u32 high, low; + u8 hcyl, lcyl, sect; + u64 sector; + + high = 0; + hcyl = args[5]; + lcyl = args[4]; + sect = args[3]; + + if (ide_id_has_flush_cache_ext(drive->id)) { + low = (hcyl << 16) | (lcyl << 8) | sect; + HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + high = ide_read_24(drive); + } else { + u8 cur = HWIF(drive)->INB(IDE_SELECT_REG); + if (cur & 0x40) { + high = cur & 0xf; + low = (hcyl << 16) | (lcyl << 8) | sect; + } else { + low = hcyl * drive->head * drive->sect; + low += lcyl * drive->sect; + low += sect - 1; + } + } + + sector = ((u64) high << 24) | low; + return sector; +} +EXPORT_SYMBOL(ide_get_error_location); + /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -164,7 +378,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) rq = HWGROUP(drive)->rq; spin_unlock_irqrestore(&ide_lock, flags); - if (rq->flags & REQ_DRIVE_CMD) { + if (rq->cmd_type == REQ_TYPE_ATA_CMD) { u8 *args = (u8 *) rq->buffer; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); @@ -174,7 +388,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) args[1] = err; args[2] = hwif->INB(IDE_NSECTOR_REG); } - } else if (rq->flags & REQ_DRIVE_TASK) { + } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { u8 *args = (u8 *) rq->buffer; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); @@ -188,7 +402,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) args[5] = hwif->INB(IDE_HCYL_REG); args[6] = hwif->INB(IDE_SELECT_REG); } - } else if (rq->flags & REQ_DRIVE_TASKFILE) { + } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = (ide_task_t *) rq->special; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); @@ -200,6 +414,8 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) args->hobRegister[IDE_DATA_OFFSET] = (data >> 8) & 0xFF; } args->tfRegister[IDE_ERROR_OFFSET] = err; + /* be sure we're looking at the low order bits */ + hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); @@ -217,12 +433,13 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) } } } else if (blk_pm_request(rq)) { + struct request_pm_state *pm = rq->data; #ifdef DEBUG_PM printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n", drive->name, rq->pm->pm_step, stat, err); #endif - DRIVER(drive)->complete_power_step(drive, rq, stat, err); - if (rq->pm->pm_step == ide_pm_state_completed) + ide_complete_power_step(drive, rq, stat, err); + if (pm->pm_step == ide_pm_state_completed) ide_complete_pm_request(drive, rq); return; } @@ -230,7 +447,8 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) spin_lock_irqsave(&ide_lock, flags); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - end_that_request_last(rq); + rq->errors = err; + end_that_request_last(rq, !rq->errors); spin_unlock_irqrestore(&ide_lock, flags); } @@ -246,7 +464,7 @@ EXPORT_SYMBOL(ide_end_drive_cmd); * by read a sector's worth of data from the drive. Of course, * this may not help if the drive is *waiting* for data from *us*. */ -void try_to_flush_leftover_data (ide_drive_t *drive) +static void try_to_flush_leftover_data (ide_drive_t *drive) { int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; @@ -261,11 +479,104 @@ void try_to_flush_leftover_data (ide_drive_t *drive) } } -EXPORT_SYMBOL(try_to_flush_leftover_data); +static void ide_kill_rq(ide_drive_t *drive, struct request *rq) +{ + if (rq->rq_disk) { + ide_driver_t *drv; -/* - * FIXME Add an ATAPI error - */ + drv = *(ide_driver_t **)rq->rq_disk->private_data; + drv->end_request(drive, 0, 0); + } else + ide_end_request(drive, 0, 0); +} + +static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) +{ + ide_hwif_t *hwif = drive->hwif; + + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { + /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } else if (stat & ERR_STAT) { + /* err has different meaning on cdrom and tape */ + if (err == ABRT_ERR) { + if (drive->select.b.lba && + /* some newer drives don't support WIN_SPECIFY */ + hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY) + return ide_stopped; + } else if ((err & BAD_CRC) == BAD_CRC) { + /* UDMA crc error, just retry the operation */ + drive->crc_count++; + } else if (err & (BBD_ERR | ECC_ERR)) { + /* retries won't help these */ + rq->errors = ERROR_MAX; + } else if (err & TRK0_ERR) { + /* help it find track zero */ + rq->errors |= ERROR_RECAL; + } + } + + 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)) + rq->errors |= ERROR_RESET; + + 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; +} + +static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) +{ + ide_hwif_t *hwif = drive->hwif; + + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { + /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } else { + /* add decoding error stuff */ + } + + if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) + /* force an abort */ + hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); + + if (rq->errors >= ERROR_MAX) { + ide_kill_rq(drive, rq); + } else { + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + ++rq->errors; + return ide_do_reset(drive); + } + ++rq->errors; + } + + return ide_stopped; +} + +ide_startstop_t +__ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) +{ + if (drive->media == ide_disk) + return ide_ata_error(drive, rq, stat, err); + return ide_atapi_error(drive, rq, stat, err); +} + +EXPORT_SYMBOL_GPL(__ide_error); /** * ide_error - handle an error on the IDE @@ -282,80 +593,46 @@ EXPORT_SYMBOL(try_to_flush_leftover_data); ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat) { - ide_hwif_t *hwif; struct request *rq; u8 err; err = ide_dump_status(drive, msg, stat); - if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + + if ((rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; - hwif = HWIF(drive); /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { - rq->errors = 1; - ide_end_drive_cmd(drive, stat, err); - return ide_stopped; - } - if (rq->flags & REQ_DRIVE_TASKFILE) { + if (!blk_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; } - if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { - /* other bits are useless when BUSY */ + if (rq->rq_disk) { + ide_driver_t *drv; + + drv = *(ide_driver_t **)rq->rq_disk->private_data; + return drv->error(drive, rq, stat, err); + } else + return __ide_error(drive, rq, stat, err); +} + +EXPORT_SYMBOL_GPL(ide_error); + +ide_startstop_t __ide_abort(ide_drive_t *drive, struct request *rq) +{ + if (drive->media != ide_disk) rq->errors |= ERROR_RESET; - } else { - if (drive->media != ide_disk) - goto media_out; - - if (stat & ERR_STAT) { - /* err has different meaning on cdrom and tape */ - if (err == ABRT_ERR) { - if (drive->select.b.lba && - (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)) - /* some newer drives don't - * support WIN_SPECIFY - */ - return ide_stopped; - } else if ((err & BAD_CRC) == BAD_CRC) { - drive->crc_count++; - /* UDMA crc error -- just retry the operation */ - } else if (err & (BBD_ERR | ECC_ERR)) { - /* retries won't help these */ - rq->errors = ERROR_MAX; - } else if (err & TRK0_ERR) { - /* help it find track zero */ - rq->errors |= ERROR_RECAL; - } - } -media_out: - if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE) - try_to_flush_leftover_data(drive); - } - if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { - /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); - } - if (rq->errors >= ERROR_MAX) { - DRIVER(drive)->end_request(drive, 0, 0); - } 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; - ++rq->errors; - } + + ide_kill_rq(drive, rq); + return ide_stopped; } -EXPORT_SYMBOL(ide_error); +EXPORT_SYMBOL_GPL(__ide_abort); /** - * ide_abort - abort pending IDE operatins + * ide_abort - abort pending IDE operations * @drive: drive the error occurred on * @msg: message to report * @@ -370,31 +647,26 @@ EXPORT_SYMBOL(ide_error); ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg) { - ide_hwif_t *hwif; struct request *rq; if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; - hwif = HWIF(drive); /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { - rq->errors = 1; - ide_end_drive_cmd(drive, BUSY_STAT, 0); - return ide_stopped; - } - if (rq->flags & REQ_DRIVE_TASKFILE) { + if (!blk_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } - rq->errors |= ERROR_RESET; - DRIVER(drive)->end_request(drive, 0, 0); - return ide_stopped; -} + if (rq->rq_disk) { + ide_driver_t *drv; -EXPORT_SYMBOL(ide_abort); + drv = *(ide_driver_t **)rq->rq_disk->private_data; + return drv->abort(drive, rq); + } else + return __ide_abort(drive, rq); +} /** * ide_cmd - issue a simple drive command @@ -407,7 +679,8 @@ EXPORT_SYMBOL(ide_abort); * The drive must be selected beforehand. */ -void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler) +static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, + ide_handler_t *handler) { ide_hwif_t *hwif = HWIF(drive); if (IDE_CONTROL_REG) @@ -417,19 +690,17 @@ void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler) ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL); } -EXPORT_SYMBOL(ide_cmd); - /** * drive_cmd_intr - drive command completion interrupt * @drive: drive the completion interrupt occurred on * * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. - * We do any necessary daya reading and then wait for the drive to + * We do any necessary data reading and then wait for the drive to * go non busy. At that point we may read the error data and complete * the request */ -ide_startstop_t drive_cmd_intr (ide_drive_t *drive) +static ide_startstop_t drive_cmd_intr (ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); @@ -437,7 +708,7 @@ ide_startstop_t drive_cmd_intr (ide_drive_t *drive) u8 stat = hwif->INB(IDE_STATUS_REG); int retries = 10; - local_irq_enable(); + local_irq_enable_in_hardirq(); if ((stat & DRQ_STAT) && args && args[3]) { u8 io_32bit = drive->io_32bit; drive->io_32bit = 0; @@ -447,14 +718,71 @@ ide_startstop_t drive_cmd_intr (ide_drive_t *drive) udelay(100); } - if (!OK_STAT(stat, READY_STAT, BAD_STAT) && DRIVER(drive) != NULL) - return DRIVER(drive)->error(drive, "drive_cmd", stat); + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) + return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); return ide_stopped; } -EXPORT_SYMBOL(drive_cmd_intr); +static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task) +{ + task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; + task->tfRegister[IDE_SECTOR_OFFSET] = drive->sect; + task->tfRegister[IDE_LCYL_OFFSET] = drive->cyl; + task->tfRegister[IDE_HCYL_OFFSET] = drive->cyl>>8; + task->tfRegister[IDE_SELECT_OFFSET] = ((drive->head-1)|drive->select.all)&0xBF; + task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY; + + task->handler = &set_geometry_intr; +} + +static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task) +{ + task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; + task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE; + + task->handler = &recal_intr; +} + +static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task) +{ + task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req; + task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT; + + task->handler = &set_multmode_intr; +} + +static ide_startstop_t ide_disk_special(ide_drive_t *drive) +{ + special_t *s = &drive->special; + ide_task_t args; + + memset(&args, 0, sizeof(ide_task_t)); + args.command_type = IDE_DRIVE_TASK_NO_DATA; + + if (s->b.set_geometry) { + s->b.set_geometry = 0; + ide_init_specify_cmd(drive, &args); + } else if (s->b.recalibrate) { + s->b.recalibrate = 0; + ide_init_restore_cmd(drive, &args); + } else if (s->b.set_multmode) { + s->b.set_multmode = 0; + if (drive->mult_req > drive->id->max_multsect) + drive->mult_req = drive->id->max_multsect; + ide_init_setmult_cmd(drive, &args); + } else if (s->all) { + int special = s->all; + s->all = 0; + printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special); + return ide_stopped; + } + + do_rw_taskfile(drive, &args); + + return ide_started; +} /** * do_special - issue some special commands @@ -465,7 +793,7 @@ EXPORT_SYMBOL(drive_cmd_intr); * back. */ -ide_startstop_t do_special (ide_drive_t *drive) +static ide_startstop_t do_special (ide_drive_t *drive) { special_t *s = &drive->special; @@ -477,16 +805,47 @@ ide_startstop_t do_special (ide_drive_t *drive) if (HWIF(drive)->tuneproc != NULL) HWIF(drive)->tuneproc(drive, drive->tune_req); return ide_stopped; + } else { + if (drive->media == ide_disk) + return ide_disk_special(drive); + + s->all = 0; + drive->mult_req = 0; + return ide_stopped; } - else - return DRIVER(drive)->special(drive); } -EXPORT_SYMBOL(do_special); +void ide_map_sg(ide_drive_t *drive, struct request *rq) +{ + ide_hwif_t *hwif = drive->hwif; + struct scatterlist *sg = hwif->sg_table; + + if (hwif->sg_mapped) /* needed by ide-scsi */ + return; + + if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) { + hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); + } else { + sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE); + hwif->sg_nents = 1; + } +} + +EXPORT_SYMBOL_GPL(ide_map_sg); + +void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq) +{ + ide_hwif_t *hwif = drive->hwif; + + hwif->nsect = hwif->nleft = rq->nr_sectors; + hwif->cursg = hwif->cursg_ofs = 0; +} + +EXPORT_SYMBOL_GPL(ide_init_sg_cmd); /** * execute_drive_command - issue special drive command - * @drive: the drive to issue th command on + * @drive: the drive to issue the command on * @rq: the request structure holding the command * * execute_drive_cmd() issues a special drive command, usually @@ -496,19 +855,33 @@ EXPORT_SYMBOL(do_special); * all commands to finish. Don't do this as that is due to change */ -ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) +static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, + struct request *rq) { ide_hwif_t *hwif = HWIF(drive); - if (rq->flags & REQ_DRIVE_TASKFILE) { + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = rq->special; if (!args) goto done; - + + hwif->data_phase = args->data_phase; + + switch (hwif->data_phase) { + case TASKFILE_MULTI_OUT: + case TASKFILE_OUT: + case TASKFILE_MULTI_IN: + case TASKFILE_IN: + ide_init_sg_cmd(drive, rq); + ide_map_sg(drive, rq); + default: + break; + } + if (args->tf_out_flags.all != 0) return flagged_taskfile(drive, args); return do_rw_taskfile(drive, args); - } else if (rq->flags & REQ_DRIVE_TASK) { + } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { u8 *args = rq->buffer; u8 sel; @@ -534,7 +907,7 @@ ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) hwif->OUTB(sel, IDE_SELECT_REG); ide_cmd(drive, args[0], args[2], &drive_cmd_intr); return ide_started; - } else if (rq->flags & REQ_DRIVE_CMD) { + } else if (rq->cmd_type == REQ_TYPE_ATA_CMD) { u8 *args = rq->buffer; if (!args) @@ -573,7 +946,38 @@ done: return ide_stopped; } -EXPORT_SYMBOL(execute_drive_cmd); +static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) +{ + struct request_pm_state *pm = rq->data; + + if (blk_pm_suspend_request(rq) && + pm->pm_step == ide_pm_state_start_suspend) + /* Mark drive blocked when starting the suspend sequence. */ + drive->blocked = 1; + else if (blk_pm_resume_request(rq) && + pm->pm_step == ide_pm_state_start_resume) { + /* + * The first thing we do on wakeup is to wait for BSY bit to + * go away (with a looong timeout) as a drive on this hwif may + * just be POSTing itself. + * We do that before even selecting as the "other" device on + * the bus may be broken enough to walk on our toes at this + * point. + */ + int rc; +#ifdef DEBUG_PM + printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name); +#endif + rc = ide_wait_not_busy(HWIF(drive), 35000); + if (rc) + printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); + SELECT_DRIVE(drive); + HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); + rc = ide_wait_not_busy(HWIF(drive), 100000); + if (rc) + printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); + } +} /** * start_request - start of I/O and command issuing for IDE @@ -586,12 +990,12 @@ EXPORT_SYMBOL(execute_drive_cmd); * FIXME: this function needs a rename */ -ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) +static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; sector_t block; - BUG_ON(!(rq->flags & REQ_STARTED)); + BUG_ON(!blk_rq_started(rq)); #ifdef DEBUG printk("%s: start_request: current=0x%08lx\n", @@ -603,13 +1007,6 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) goto kill_rq; } - /* - * bail early if we've sent a device to sleep, however how to wake - * this needs to be a masked flag. FIXME for proper operations. - */ - if (drive->suspend_reset) - goto kill_rq; - block = rq->sector; if (blk_fs_request(rq) && (drive->media == ide_disk || drive->media == ide_floppy)) { @@ -620,33 +1017,8 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (block == 0 && drive->remap_0_to_1 == 1) block = 1; /* redirect MBR access to EZ-Drive partn table */ - if (blk_pm_suspend_request(rq) && - rq->pm->pm_step == ide_pm_state_start_suspend) - /* Mark drive blocked when starting the suspend sequence. */ - drive->blocked = 1; - else if (blk_pm_resume_request(rq) && - rq->pm->pm_step == ide_pm_state_start_resume) { - /* - * The first thing we do on wakeup is to wait for BSY bit to - * go away (with a looong timeout) as a drive on this hwif may - * just be POSTing itself. - * We do that before even selecting as the "other" device on - * the bus may be broken enough to walk on our toes at this - * point. - */ - int rc; -#ifdef DEBUG_PM - printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name); -#endif - rc = ide_wait_not_busy(HWIF(drive), 35000); - if (rc) - printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); - SELECT_DRIVE(drive); - HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]); - rc = ide_wait_not_busy(HWIF(drive), 10000); - if (rc) - printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); - } + if (blk_pm_request(rq)) + ide_check_pm_state(drive, rq); SELECT_DRIVE(drive); if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { @@ -654,31 +1026,41 @@ ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) return startstop; } if (!drive->special.all) { - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) - return execute_drive_cmd(drive, rq); - else if (rq->flags & REQ_DRIVE_TASKFILE) + 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) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { + struct request_pm_state *pm = rq->data; #ifdef DEBUG_PM printk("%s: start_power_step(step: %d)\n", drive->name, rq->pm->pm_step); #endif - startstop = DRIVER(drive)->start_power_step(drive, rq); + startstop = ide_start_power_step(drive, rq); if (startstop == ide_stopped && - rq->pm->pm_step == ide_pm_state_completed) + pm->pm_step == ide_pm_state_completed) ide_complete_pm_request(drive, rq); return startstop; } - return (DRIVER(drive)->do_request(drive, rq, block)); + + drv = *(ide_driver_t **)rq->rq_disk->private_data; + return drv->do_request(drive, rq, block); } return do_special(drive); kill_rq: - DRIVER(drive)->end_request(drive, 0, 0); + ide_kill_rq(drive, rq); return ide_stopped; } -EXPORT_SYMBOL(start_request); - /** * ide_stall_queue - pause an IDE device * @drive: drive to stall @@ -693,6 +1075,7 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) if (timeout > WAIT_WORSTCASE) timeout = WAIT_WORSTCASE; drive->sleep = timeout + jiffies; + drive->sleeping = 1; } EXPORT_SYMBOL(ide_stall_queue); @@ -715,19 +1098,35 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) repeat: best = NULL; drive = hwgroup->drive; + + /* + * drive is doing pre-flush, ordered write, post-flush sequence. even + * though that is 3 requests, it must be seen as a single transaction. + * we must not preempt this drive until that is complete + */ + if (blk_queue_flushing(drive->queue)) { + /* + * small race where queue could get replugged during + * the 3-request flush cycle, just yank the plug since + * we want it to finish asap + */ + blk_remove_plug(drive->queue); + return drive; + } + do { - if ((!drive->sleep || time_after_eq(jiffies, drive->sleep)) + if ((!drive->sleeping || time_after_eq(jiffies, drive->sleep)) && !elv_queue_empty(drive->queue)) { if (!best - || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) - || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) + || (drive->sleeping && (!best->sleeping || time_before(drive->sleep, best->sleep))) + || (!best->sleeping && time_before(WAKEUP(drive), WAKEUP(best)))) { if (!blk_queue_plugged(drive->queue)) best = drive; } } } while ((drive = drive->next) != hwgroup->drive); - if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { + if (best && best->nice1 && !best->sleeping && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { long t = (signed long)(WAKEUP(best) - jiffies); if (t >= WAIT_MIN_SLEEP) { /* @@ -736,10 +1135,9 @@ repeat: */ drive = best->next; do { - if (!drive->sleep - /* FIXME: use time_before */ - && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time)) - && 0 < (signed long)((jiffies + t) - WAKEUP(drive))) + if (!drive->sleeping + && time_before(jiffies - best->service_time, WAKEUP(drive)) + && time_before(WAKEUP(drive), jiffies + t)) { ide_stall_queue(best, min_t(long, t, 10 * WAIT_MIN_SLEEP)); goto repeat; @@ -785,15 +1183,13 @@ repeat: * the driver. This makes the driver much more friendlier to shared IRQs * than previous designs, while remaining 100% (?) SMP safe and capable. */ -/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back - * into life on wakeup from machine sleep. - */ -void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) +static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) { ide_drive_t *drive; ide_hwif_t *hwif; struct request *rq; ide_startstop_t startstop; + int loops = 0; /* for atari only: POSSIBLY BROKEN HERE(?) */ ide_get_lock(ide_intr, hwgroup); @@ -805,14 +1201,17 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) hwgroup->busy = 1; drive = choose_drive(hwgroup); if (drive == NULL) { - unsigned long sleep = 0; + int sleeping = 0; + unsigned long sleep = 0; /* shut up, gcc */ hwgroup->rq = NULL; drive = hwgroup->drive; do { - if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep))) + if (drive->sleeping && (!sleeping || time_before(drive->sleep, sleep))) { + sleeping = 1; sleep = drive->sleep; + } } while ((drive = drive->next) != hwgroup->drive); - if (sleep) { + if (sleeping) { /* * Take a short snooze, and then wake up this hwgroup again. * This gives other hwgroups on the same a chance to @@ -843,6 +1242,7 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) /* no more work for this hwgroup (for now) */ return; } + again: hwif = HWIF(drive); if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && @@ -852,21 +1252,10 @@ void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) } hwgroup->hwif = hwif; hwgroup->drive = drive; - drive->sleep = 0; + drive->sleeping = 0; drive->service_start = jiffies; -queue_next: - if (!ata_can_queue(drive)) { - if (!ata_pending_commands(drive)) - hwgroup->busy = 0; - - break; - } - if (blk_queue_plugged(drive->queue)) { - if (drive->using_tcq) - break; - printk(KERN_ERR "ide: huh? queue was plugged!\n"); break; } @@ -877,7 +1266,7 @@ queue_next: */ rq = elv_next_request(drive->queue); if (!rq) { - hwgroup->busy = !!ata_pending_commands(drive); + hwgroup->busy = 0; break; } @@ -893,16 +1282,19 @@ queue_next: * though. I hope that doesn't happen too much, hopefully not * unless the subdriver triggers such a thing in its own PM * state machine. + * + * We count how many times we loop here to make sure we service + * all drives in the hwgroup without looping for ever */ - if (drive->blocked && !blk_pm_request(rq) && !(rq->flags & REQ_PREEMPT)) { + if (drive->blocked && !blk_pm_request(rq) && !(rq->cmd_flags & REQ_PREEMPT)) { + drive = drive->next ? drive->next : hwgroup->drive; + if (loops++ < 4 && !blk_queue_plugged(drive->queue)) + goto again; /* We clear busy, there should be no pending ATA command at this point. */ hwgroup->busy = 0; break; } - if (!rq->bio && ata_pending_commands(drive)) - break; - hwgroup->rq = rq; /* @@ -913,30 +1305,28 @@ queue_next: * happens anyway when any interrupt comes in, IDE or otherwise * -- the kernel masks the IRQ while it is being handled. */ - if (hwif->irq != masked_irq) + if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq) disable_irq_nosync(hwif->irq); spin_unlock(&ide_lock); - local_irq_enable(); + local_irq_enable_in_hardirq(); /* allow other IRQs while we start this request */ startstop = start_request(drive, rq); spin_lock_irq(&ide_lock); - if (hwif->irq != masked_irq) + if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq) enable_irq(hwif->irq); - if (startstop == ide_released) - goto queue_next; if (startstop == ide_stopped) hwgroup->busy = 0; } } -EXPORT_SYMBOL(ide_do_request); - /* * Passes the stuff to ide_do_request */ void do_ide_request(request_queue_t *q) { - ide_do_request(q->queuedata, IDE_NO_IRQ); + ide_drive_t *drive = q->queuedata; + + ide_do_request(HWGROUP(drive), IDE_NO_IRQ); } /* @@ -957,7 +1347,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) if (error < 0) { printk(KERN_WARNING "%s: DMA timeout error\n", drive->name); (void)HWIF(drive)->ide_dma_end(drive); - ret = DRIVER(drive)->error(drive, "dma timeout error", + ret = ide_error(drive, "dma timeout error", hwif->INB(IDE_STATUS_REG)); } else { printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name); @@ -978,15 +1368,22 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) * make sure request is sane */ rq = HWGROUP(drive)->rq; + + if (!rq) + goto out; + HWGROUP(drive)->rq = NULL; rq->errors = 0; + + if (!rq->bio) + goto out; + rq->sector = rq->bio->bi_sector; rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; rq->hard_cur_sectors = rq->current_nr_sectors; - if (rq->bio) - rq->buffer = NULL; - + rq->buffer = bio_data(rq->bio); +out: return ret; } @@ -1064,7 +1461,7 @@ void ide_timer_expiry (unsigned long data) /* local CPU only, * as if we were handling an interrupt */ local_irq_disable(); - if (hwgroup->poll_timeout != 0) { + if (hwgroup->polling) { startstop = handler(drive); } else if (drive_is_ready(drive)) { if (drive->waiting_for_dma) @@ -1077,7 +1474,7 @@ void ide_timer_expiry (unsigned long data) startstop = ide_dma_timeout_retry(drive, wait); } else startstop = - DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); + ide_error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); } drive->service_time = jiffies - drive->service_start; spin_lock_irq(&ide_lock); @@ -1090,8 +1487,6 @@ void ide_timer_expiry (unsigned long data) spin_unlock_irqrestore(&ide_lock, flags); } -EXPORT_SYMBOL(ide_timer_expiry); - /** * unexpected_intr - handle an unexpected IDE interrupt * @irq: interrupt line @@ -1177,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; @@ -1194,8 +1589,7 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } - if ((handler = hwgroup->handler) == NULL || - hwgroup->poll_timeout != 0) { + if ((handler = hwgroup->handler) == NULL || hwgroup->polling) { /* * Not expecting an interrupt from this drive. * That means this could be: @@ -1262,8 +1656,19 @@ 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(); + local_irq_enable_in_hardirq(); /* service this interrupt, may set handler for next interrupt */ startstop = handler(drive); spin_lock_irq(&ide_lock); @@ -1289,8 +1694,6 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -EXPORT_SYMBOL(ide_intr); - /** * ide_init_drive_cmd - initialize a drive command request * @rq: request object @@ -1298,13 +1701,14 @@ EXPORT_SYMBOL(ide_intr); * Initialize a request before we fill it in and send it down to * ide_do_drive_cmd. Commands must be set up by this function. Right * now it doesn't do a lot, but if that changes abusers will have a - * nasty suprise. + * nasty surprise. */ void ide_init_drive_cmd (struct request *rq) { memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_DRIVE_CMD; + rq->cmd_type = REQ_TYPE_ATA_CMD; + rq->ref_count = 1; } EXPORT_SYMBOL(ide_init_drive_cmd); @@ -1328,12 +1732,6 @@ EXPORT_SYMBOL(ide_init_drive_cmd); * for the new rq to be completed. This is VERY DANGEROUS, and is * intended for careful use by the ATAPI tape/cdrom driver code. * - * If action is ide_next, then the rq is queued immediately after - * the currently-being-processed-request (if any), and the function - * returns without waiting for the new rq to be completed. As above, - * This is VERY DANGEROUS, and is intended for careful use by the - * ATAPI tape/cdrom driver code. - * * If action is ide_end, then the rq is queued at the end of the * request queue, and the function returns immediately without waiting * for the new rq to be completed. This is again intended for careful @@ -1344,26 +1742,11 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio { unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); - DECLARE_COMPLETION(wait); + DECLARE_COMPLETION_ONSTACK(wait); int where = ELEVATOR_INSERT_BACK, err; int must_wait = (action == ide_wait || action == ide_head_wait); -#ifdef CONFIG_BLK_DEV_PDC4030 - /* - * FIXME: there should be a drive or hwif->special - * handler that points here by default, not hacks - * in the ide-io.c code - * - * FIXME2: That code breaks power management if used with - * this chipset, that really doesn't belong here ! - */ - if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL) - return -ENOSYS; /* special drive cmds not supported */ -#endif rq->errors = 0; - rq->rq_status = RQ_ACTIVE; - - rq->rq_disk = drive->disk; /* * we need to hold an extra reference to request for safe inspection @@ -1371,7 +1754,8 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio */ if (must_wait) { rq->ref_count++; - rq->waiting = &wait; + rq->end_io_data = &wait; + rq->end_io = blk_end_sync_rq; } spin_lock_irqsave(&ide_lock, flags); @@ -1379,7 +1763,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio hwgroup->rq = NULL; if (action == ide_preempt || action == ide_head_wait) { where = ELEVATOR_INSERT_FRONT; - rq->flags |= REQ_PREEMPT; + rq->cmd_flags |= REQ_PREEMPT; } __elv_add_request(drive->queue, rq, where, 0); ide_do_request(hwgroup, IDE_NO_IRQ);