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)); 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 (ata_id_flush_enabled(drive->id) == 0 || (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) { ide_complete_power_step(drive, rq); return ide_stopped; } if (ata_id_flush_ext_enabled(drive->id)) args->tf.command = ATA_CMD_FLUSH_EXT; else args->tf.command = ATA_CMD_FLUSH; goto out_do_tf; case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ args->tf.command = ATA_CMD_STANDBYNOW1; goto out_do_tf; case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ ide_set_max_pio(drive); /* * skip IDE_PM_IDLE for ATAPI devices */ if (drive->media != ide_disk) pm->pm_step = IDE_PM_RESTORE_DMA; else ide_complete_power_step(drive, rq); return ide_stopped; case IDE_PM_IDLE: /* Resume step 2 (idle) */ args->tf.command = ATA_CMD_IDLEIMMEDIATE; goto out_do_tf; case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */ /* * Right now, all we do is call ide_set_dma(drive), * we could be smarter and check for current xfer_speed * in struct drive etc... */ if (drive->hwif->dma_ops == NULL) break; if (drive->dev_flags & IDE_DFLAG_USING_DMA) ide_set_dma(drive); break; } pm->pm_step = IDE_PM_COMPLETED; return ide_stopped; out_do_tf: args->tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; args->data_phase = TASKFILE_NO_DATA; return do_rw_taskfile(drive, args); }
/** * ide_complete_pm_rq - end the current Power Management request * @drive: target drive * @rq: request * * This function cleans up the current PM request and stops the queue * if necessary. */ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) { struct request_queue *q = drive->queue; struct request_pm_state *pm = rq->special; unsigned long flags; ide_complete_power_step(drive, rq); if (pm->pm_step != IDE_PM_COMPLETED) return; #ifdef DEBUG_PM #ifdef CONFIG_DEBUG_PRINTK printk("%s: completing PM request, %s\n", drive->name, (rq->cmd_type == REQ_TYPE_PM_SUSPEND) ? "suspend" : "resume"); #else ; #endif #endif spin_lock_irqsave(q->queue_lock, flags); if (rq->cmd_type == REQ_TYPE_PM_SUSPEND) blk_stop_queue(q); else drive->dev_flags &= ~IDE_DFLAG_BLOCKED; spin_unlock_irqrestore(q->queue_lock, flags); drive->hwif->rq = NULL; if (blk_end_request(rq, 0, 0)) BUG(); }
static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) { ide_task_t *args = rq->special; memset(args, 0, sizeof(*args)); if (drive->media != ide_disk) { /* skip idedisk_pm_idle for ATAPI devices */ if (rq->pm->pm_step == idedisk_pm_idle) rq->pm->pm_step = ide_pm_restore_dma; } switch (rq->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_idle: /* Resume step 1 (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 2 (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; } rq->pm->pm_step = ide_pm_state_completed; return ide_stopped; }
void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) { unsigned long flags; struct request *rq; spin_lock_irqsave(&ide_lock, flags); rq = HWGROUP(drive)->rq; spin_unlock_irqrestore(&ide_lock, flags); if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *task = (ide_task_t *)rq->special; if (rq->errors == 0) rq->errors = !OK_STAT(stat, ATA_DRDY, BAD_STAT); if (task) { struct ide_taskfile *tf = &task->tf; tf->error = err; tf->status = stat; drive->hwif->tp_ops->tf_read(drive, task); if (task->tf_flags & IDE_TFLAG_DYN) kfree(task); } } else if (blk_pm_request(rq)) { struct request_pm_state *pm = rq->data; ide_complete_power_step(drive, rq); if (pm->pm_step == IDE_PM_COMPLETED) ide_complete_pm_request(drive, rq); return; } spin_lock_irqsave(&ide_lock, flags); HWGROUP(drive)->rq = NULL; rq->errors = err; if (unlikely(__blk_end_request(rq, (rq->errors ? -EIO : 0), blk_rq_bytes(rq)))) BUG(); spin_unlock_irqrestore(&ide_lock, flags); }
void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) { ide_hwif_t *hwif = drive->hwif; struct request *rq = hwif->rq; if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *task = (ide_task_t *)rq->special; if (task) { struct ide_taskfile *tf = &task->tf; tf->error = err; tf->status = stat; drive->hwif->tp_ops->tf_read(drive, task); if (task->tf_flags & IDE_TFLAG_DYN) kfree(task); } } else if (blk_pm_request(rq)) { struct request_pm_state *pm = rq->data; ide_complete_power_step(drive, rq); if (pm->pm_step == IDE_PM_COMPLETED) ide_complete_pm_request(drive, rq); return; } hwif->rq = NULL; rq->errors = err; if (unlikely(blk_end_request(rq, (rq->errors ? -EIO : 0), blk_rq_bytes(rq)))) BUG(); }
ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq) { struct request_pm_state *pm = rq->special; struct ide_cmd cmd = { }; 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 (ata_id_flush_enabled(drive->id) == 0 || (drive->dev_flags & IDE_DFLAG_WCACHE) == 0) { ide_complete_power_step(drive, rq); return ide_stopped; } if (ata_id_flush_ext_enabled(drive->id)) cmd.tf.command = ATA_CMD_FLUSH_EXT; else cmd.tf.command = ATA_CMD_FLUSH; goto out_do_tf; case IDE_PM_STANDBY: /* Suspend step 2 (standby) */ cmd.tf.command = ATA_CMD_STANDBYNOW1; goto out_do_tf; case IDE_PM_RESTORE_PIO: /* Resume step 1 (restore PIO) */ ide_set_max_pio(drive); /* * skip IDE_PM_IDLE for ATAPI devices */ if (drive->media != ide_disk) pm->pm_step = IDE_PM_RESTORE_DMA; else ide_complete_power_step(drive, rq); return ide_stopped; case IDE_PM_IDLE: /* Resume step 2 (idle) */ cmd.tf.command = ATA_CMD_IDLEIMMEDIATE; goto out_do_tf; case IDE_PM_RESTORE_DMA: /* Resume step 3 (restore DMA) */ /* * Right now, all we do is call ide_set_dma(drive), * we could be smarter and check for current xfer_speed * in struct drive etc... */ if (drive->hwif->dma_ops == NULL) break; /* * TODO: respect IDE_DFLAG_USING_DMA */ ide_set_dma(drive); break; } pm->pm_step = IDE_PM_COMPLETED; return ide_stopped; out_do_tf: cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; cmd.protocol = ATA_PROT_NODATA; return do_rw_taskfile(drive, &cmd); }
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)); 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->tf.command = WIN_FLUSH_CACHE_EXT; else args->tf.command = WIN_FLUSH_CACHE; goto out_do_tf; case idedisk_pm_standby: /* Suspend step 2 (standby) */ args->tf.command = WIN_STANDBYNOW1; goto out_do_tf; case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */ ide_set_max_pio(drive); /* * skip idedisk_pm_idle for ATAPI devices */ if (drive->media != ide_disk) pm->pm_step = ide_pm_restore_dma; else ide_complete_power_step(drive, rq, 0, 0); return ide_stopped; case idedisk_pm_idle: /* Resume step 2 (idle) */ args->tf.command = WIN_IDLEIMMEDIATE; goto out_do_tf; case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */ /* * Right now, all we do is call ide_set_dma(drive), * we could be smarter and check for current xfer_speed * in struct drive etc... */ if (drive->hwif->dma_host_set == NULL) break; /* * TODO: respect ->using_dma setting */ ide_set_dma(drive); break; } pm->pm_step = ide_pm_state_completed; return ide_stopped; out_do_tf: args->tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; args->data_phase = TASKFILE_NO_DATA; return do_rw_taskfile(drive, args); }