ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat) { struct request *rq; u8 err; err = ide_dump_status(drive, msg, stat); rq = drive->hwif->rq; if (rq == NULL) return ide_stopped; /* retry only "normal" I/O: */ if (blk_rq_is_passthrough(rq)) { if (ata_taskfile_request(rq)) { struct ide_cmd *cmd = rq->special; if (cmd) ide_complete_cmd(drive, cmd, stat, err); } else if (ata_pm_request(rq)) { rq->errors = 1; ide_complete_pm_rq(drive, rq); return ide_stopped; } rq->errors = err; ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); return ide_stopped; } return __ide_error(drive, rq, stat, err); }
void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) { const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops; struct ide_taskfile *tf = &cmd->tf; struct request *rq = cmd->rq; u8 tf_cmd = tf->command; tf->error = err; tf->status = stat; if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { u8 data[2]; tp_ops->input_data(drive, cmd, data, 2); cmd->tf.data = data[0]; cmd->hob.data = data[1]; } ide_tf_readback(drive, cmd); if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) && tf_cmd == ATA_CMD_IDLEIMMEDIATE) { if (tf->lbal != 0xc4) { printk(KERN_ERR "%s: head unload failed!\n", drive->name); ide_tf_dump(drive->name, cmd); } else drive->dev_flags |= IDE_DFLAG_PARKED; } if (rq && ata_taskfile_request(rq)) { struct ide_cmd *orig_cmd = rq->special; if (cmd->tf_flags & IDE_TFLAG_DYN) kfree(orig_cmd); else if (cmd != orig_cmd) memcpy(orig_cmd, cmd, sizeof(*cmd)); } }
static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; BUG_ON(!(rq->rq_flags & RQF_STARTED)); #ifdef DEBUG printk("%s: start_request: current=0x%08lx\n", drive->hwif->name, (unsigned long) rq); #endif /* bail early if we've exceeded max_failures */ if (drive->max_failures && (drive->failures > drive->max_failures)) { rq->rq_flags |= RQF_FAILED; goto kill_rq; } if (ata_pm_request(rq)) ide_check_pm_state(drive, rq); drive->hwif->tp_ops->dev_select(drive); if (ide_wait_stat(&startstop, drive, drive->ready_stat, ATA_BUSY | ATA_DRQ, WAIT_READY)) { printk(KERN_ERR "%s: drive not ready for command\n", drive->name); return startstop; } if (drive->special_flags == 0) { struct ide_driver *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 (ata_taskfile_request(rq)) return execute_drive_cmd(drive, rq); else if (ata_pm_request(rq)) { struct ide_pm_state *pm = rq->special; #ifdef DEBUG_PM printk("%s: start_power_step(step: %d)\n", drive->name, pm->pm_step); #endif startstop = ide_start_power_step(drive, rq); if (startstop == ide_stopped && pm->pm_step == IDE_PM_COMPLETED) ide_complete_pm_rq(drive, rq); return startstop; } else if (!rq->rq_disk && ata_misc_request(rq)) /* * TODO: Once all ULDs have been modified to * check for specific op codes rather than * blindly accepting any special request, the * check for ->rq_disk above may be replaced * by a more suitable mechanism or even * dropped entirely. */ return ide_special_rq(drive, rq); drv = *(struct ide_driver **)rq->rq_disk->private_data; return drv->do_request(drive, rq, blk_rq_pos(rq)); } return do_special(drive); kill_rq: ide_kill_rq(drive, rq); return ide_stopped; }