/* * Handler for commands without a data phase */ static ide_startstop_t task_no_data_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; ide_task_t *task = &hwif->task; struct ide_taskfile *tf = &task->tf; int custom = (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0; int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1; u8 stat; local_irq_enable_in_hardirq(); while (1) { stat = hwif->tp_ops->read_status(hwif); if ((stat & ATA_BUSY) == 0 || retries-- == 0) break; udelay(10); }; if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { if (custom && tf->command == ATA_CMD_SET_MULTI) { drive->mult_req = drive->mult_count = 0; drive->special.b.recalibrate = 1; (void)ide_dump_status(drive, __func__, stat); return ide_stopped; } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) { if ((stat & (ATA_ERR | ATA_DRQ)) == 0) { ide_set_handler(drive, &task_no_data_intr, WAIT_WORSTCASE, NULL); return ide_started; } } return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ } if (!custom) ide_end_drive_cmd(drive, stat, ide_read_error(drive)); else if (tf->command == ATA_CMD_IDLEIMMEDIATE) { hwif->tp_ops->tf_read(drive, task); if (tf->lbal != 0xc4) { printk(KERN_ERR "%s: head unload failed!\n", drive->name); ide_tf_dump(drive->name, tf); } else drive->dev_flags |= IDE_DFLAG_PARKED; ide_end_drive_cmd(drive, stat, ide_read_error(drive)); } else if (tf->command == ATA_CMD_SET_MULTI) drive->mult_count = drive->mult_req; return ide_stopped; }
static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { ide_hwif_t *hwif = drive->hwif; ide_task_t *task = rq->special; if (task) { hwif->data_phase = task->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; } return do_rw_taskfile(drive, task); } /* * NULL is actually a valid way of waiting for * all current requests to be flushed from the queue. */ #ifdef DEBUG printk("%s: DRIVE_CMD (null)\n", drive->name); #endif ide_end_drive_cmd(drive, hwif->tp_ops->read_status(hwif), ide_read_error(drive)); return ide_stopped; }
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); if ((rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* retry only "normal" I/O: */ if (!blk_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; } 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); }
static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); struct request *rq = HWGROUP(drive)->rq; struct ide_atapi_pc *pc = (struct ide_atapi_pc *) rq->special; int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); struct Scsi_Host *host; int errors = rq->errors; unsigned long flags; if (!blk_special_request(rq) && !blk_sense_request(rq)) { ide_end_request(drive, uptodate, nrsecs); return 0; } ide_end_drive_cmd (drive, 0, 0); if (blk_sense_request(rq)) { struct ide_atapi_pc *opc = (struct ide_atapi_pc *) rq->buffer; if (log) { printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number); ide_scsi_hex_dump(pc->buf, 16); } memcpy((void *) opc->scsi_cmd->sense_buffer, pc->buf, SCSI_SENSE_BUFFERSIZE); kfree(pc->buf); kfree(pc); blk_put_request(rq); pc = opc; rq = pc->rq; pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (((pc->flags & PC_FLAG_TIMEDOUT) ? DID_TIME_OUT : DID_OK) << 16); } else if (pc->flags & PC_FLAG_TIMEDOUT) { if (log) printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n", drive->name, pc->scsi_cmd->serial_number); pc->scsi_cmd->result = DID_TIME_OUT << 16; } else if (errors >= ERROR_MAX) { pc->scsi_cmd->result = DID_ERROR << 16; if (log) printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number); } else if (errors) { if (log) printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number); if (!idescsi_check_condition(drive, rq)) /* we started a request sense, so we'll be back, exit for now */ return 0; pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); } else { pc->scsi_cmd->result = DID_OK << 16; } host = pc->scsi_cmd->device->host; spin_lock_irqsave(host->host_lock, flags); pc->done(pc->scsi_cmd); spin_unlock_irqrestore(host->host_lock, flags); kfree(pc); blk_put_request(rq); scsi->pc = NULL; return 0; }
void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) { if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { u8 err = ide_read_error(drive); ide_end_drive_cmd(drive, stat, err); return; } if (rq->rq_disk) { struct ide_driver *drv; drv = *(struct ide_driver **)rq->rq_disk->private_data;; drv->end_request(drive, 1, rq->nr_sectors); } else ide_end_request(drive, 1, rq->nr_sectors); }
/* * Handler for commands without a data phase */ static ide_startstop_t task_no_data_intr(ide_drive_t *drive) { ide_task_t *args = HWGROUP(drive)->rq->special; u8 stat; local_irq_enable_in_hardirq(); stat = ide_read_status(drive); if (!OK_STAT(stat, READY_STAT, BAD_STAT)) return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ if (args) ide_end_drive_cmd(drive, stat, ide_read_error(drive)); return ide_stopped; }
/* * Handler for commands without a data phase */ static ide_startstop_t task_no_data_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; ide_task_t *args = hwif->hwgroup->rq->special; u8 stat; local_irq_enable_in_hardirq(); stat = hwif->tp_ops->read_status(hwif); if (!OK_STAT(stat, READY_STAT, BAD_STAT)) return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ if (args) ide_end_drive_cmd(drive, stat, ide_read_error(drive)); return ide_stopped; }
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_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; } return __ide_error(drive, rq, stat, err); }