int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) { struct request rq; blk_rq_init(NULL, &rq); rq.cmd_type = REQ_TYPE_ATA_TASKFILE; rq.buffer = buf; /* * (ks) We transfer currently only whole sectors. * This is suffient for now. But, it would be great, * if we would find a solution to transfer any size. * To support special commands like READ LONG. */ rq.hard_nr_sectors = rq.nr_sectors = nsect; rq.hard_cur_sectors = rq.current_nr_sectors = nsect; if (task->tf_flags & IDE_TFLAG_WRITE) rq.cmd_flags |= REQ_RW; rq.special = task; task->rq = &rq; return ide_do_drive_cmd(drive, &rq, ide_wait); }
static int generic_ide_suspend(struct device *dev, pm_message_t mesg) { ide_drive_t *drive = dev->driver_data; ide_hwif_t *hwif = HWIF(drive); struct request rq; struct request_pm_state rqpm; ide_task_t args; /* Call ACPI _GTM only once */ if (!(drive->dn % 2)) ide_acpi_get_timing(hwif); memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_SUSPEND; rq.special = &args; rq.data = &rqpm; rqpm.pm_step = ide_pm_state_start_suspend; if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; rqpm.pm_state = mesg.event; return ide_do_drive_cmd(drive, &rq, ide_wait); }
static int generic_ide_resume(struct device *dev) { ide_drive_t *drive = dev->driver_data; ide_hwif_t *hwif = HWIF(drive); struct request rq; struct request_pm_state rqpm; ide_task_t args; int err; /* Call ACPI _STM only once */ if (!(drive->dn % 2)) ide_acpi_push_timing(hwif); ide_acpi_exec_tfs(drive); memset(&rq, 0, sizeof(rq)); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_RESUME; rq.special = &args; rq.data = &rqpm; rqpm.pm_step = ide_pm_state_start_resume; rqpm.pm_state = PM_EVENT_ON; err = ide_do_drive_cmd(drive, &rq, ide_head_wait); if (err == 0 && dev->driver) { ide_driver_t *drv = to_ide_driver(dev->driver); if (drv->resume) drv->resume(drive); } return err; }
int set_pio_mode(ide_drive_t *drive, int arg) { struct request rq; if (arg < 0 || arg > 255) return -EINVAL; if (!HWIF(drive)->tuneproc) return -ENOSYS; if (drive->special.b.set_tune) return -EBUSY; ide_init_drive_cmd(&rq); drive->tune_req = (u8) arg; drive->special.b.set_tune = 1; (void) ide_do_drive_cmd(drive, &rq, ide_wait); return 0; }
static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_cmd) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); struct ide_atapi_pc *pc; struct request *rq; u8 *buf; /* stuff a sense request in front of our current request */ pc = kzalloc(sizeof(struct ide_atapi_pc), GFP_ATOMIC); rq = blk_get_request(drive->queue, READ, GFP_ATOMIC); buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC); if (!pc || !rq || !buf) { kfree(buf); if (rq) blk_put_request(rq); kfree(pc); return -ENOMEM; } rq->special = (char *) pc; pc->rq = rq; pc->buf = buf; pc->c[0] = REQUEST_SENSE; pc->c[4] = pc->req_xfer = pc->buf_size = SCSI_SENSE_BUFFERSIZE; rq->cmd_type = REQ_TYPE_SENSE; rq->cmd_flags |= REQ_PREEMPT; pc->timeout = jiffies + WAIT_READY; /* NOTE! Save the failed packet command in "rq->buffer" */ rq->buffer = (void *) failed_cmd->special; pc->scsi_cmd = ((struct ide_atapi_pc *) failed_cmd->special)->scsi_cmd; if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) { printk ("ide-scsi: %s: queue cmd = ", drive->name); ide_scsi_hex_dump(pc->c, 6); } rq->rq_disk = scsi->disk; rq->ref_count++; memcpy(rq->cmd, pc->c, 12); ide_do_drive_cmd(drive, rq); return 0; }
int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) { u8 *buf = NULL; int bufsize = 0, err = 0; u8 args[4], xfer_rate = 0; ide_task_t tfargs; struct ide_taskfile *tf = &tfargs.tf; struct hd_driveid *id = drive->id; if (NULL == (void *) arg) { struct request rq; ide_init_drive_cmd(&rq); rq.cmd_type = REQ_TYPE_ATA_TASKFILE; return ide_do_drive_cmd(drive, &rq, ide_wait); } if (copy_from_user(args, (void __user *)arg, 4)) return -EFAULT; memset(&tfargs, 0, sizeof(ide_task_t)); tf->feature = args[2]; if (args[0] == WIN_SMART) { tf->nsect = args[3]; tf->lbal = args[1]; tf->lbam = 0x4f; tf->lbah = 0xc2; tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT; } else { tf->nsect = args[1]; tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT; } tf->command = args[0]; tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA; if (args[3]) { tfargs.tf_flags |= IDE_TFLAG_IO_16BIT; bufsize = SECTOR_WORDS * 4 * args[3]; buf = kzalloc(bufsize, GFP_KERNEL); if (buf == NULL) return -ENOMEM; } if (tf->command == WIN_SETFEATURES && tf->feature == SETFEATURES_XFER && tf->nsect >= XFER_SW_DMA_0 && (id->dma_ultra || id->dma_mword || id->dma_1word)) { xfer_rate = args[1]; if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) { printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot " "be set\n", drive->name); goto abort; } } err = ide_raw_taskfile(drive, &tfargs, buf, args[3]); args[0] = tf->status; args[1] = tf->error; args[2] = tf->nsect; if (!err && xfer_rate) { /* active-retuning-calls future */ ide_set_xfer_rate(drive, xfer_rate); ide_driveid_update(drive); } abort: if (copy_to_user((void __user *)arg, &args, 4)) err = -EFAULT; if (buf) { if (copy_to_user((void __user *)(arg + 4), buf, bufsize)) err = -EFAULT; kfree(buf); } return err; }