/* * Add a special packet command request to the tail of the request queue, * and wait for it to be serviced. */ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, struct ide_atapi_pc *pc, void *buf, unsigned int bufflen) { struct request *rq; int error; rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_DRV_PRIV; rq->special = (char *)pc; if (buf && bufflen) { error = blk_rq_map_kern(drive->queue, rq, buf, bufflen, GFP_NOIO); if (error) goto put_req; } memcpy(rq->cmd, pc->c, 12); if (drive->media == ide_tape) rq->cmd[13] = REQ_IDETAPE_PC1; error = blk_execute_rq(drive->queue, disk, rq, 0); put_req: blk_put_request(rq); return error; }
static int send_request(struct request_queue *q, struct bio *bio, struct block_device *bdev, struct tbio_interface *inter, int writing) { struct request *rq; rq = blk_make_request(q, bio, GFP_KERNEL); if (!rq) { prk_err("failed to make request"); return -EFAULT; } rq->cmd_len = inter->cmd_len; if (copy_from_user(rq->cmd, inter->cmd, inter->cmd_len)) goto out_request; if (sizeof(rq->cmd) != inter->cmd_len) { memset(rq->cmd + inter->cmd_len, 0, sizeof(rq->cmd) - inter->cmd_len); } rq->__sector = bio->bi_sector; if (blk_execute_rq(q, bdev->bd_disk, rq, 0)) goto out_request; blk_put_request(rq); return 0; out_request: blk_put_request(rq); return -EFAULT; }
int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) { struct request *rq; int error; rq = blk_get_request(drive->queue, READ, __GFP_WAIT); 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; error = blk_execute_rq(drive->queue, NULL, rq, 0); blk_put_request(rq); return error; }
/* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) { struct request *rq; int err = SCSI_DH_RES_TEMP_UNAVAIL; rq = get_alua_req(sdev, h->buff, h->bufflen, READ); if (!rq) goto done; /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_IN; rq->cmd[1] = MI_REPORT_TARGET_PGS; rq->cmd[6] = (h->bufflen >> 24) & 0xff; rq->cmd[7] = (h->bufflen >> 16) & 0xff; rq->cmd[8] = (h->bufflen >> 8) & 0xff; rq->cmd[9] = h->bufflen & 0xff; rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = h->senselen = 0; err = blk_execute_rq(rq->q, NULL, rq, 1); if (err == -EIO) { sdev_printk(KERN_INFO, sdev, "%s: rtpg failed with %x\n", ALUA_DH_NAME, rq->errors); h->senselen = rq->sense_len; err = SCSI_DH_IO; } blk_put_request(rq); done: return err; }
static int send_inquiry_cmd(struct scsi_device *sdev, int page, struct clariion_dh_data *csdev) { struct request *rq = get_req(sdev, INQUIRY, csdev->buffer); int err; if (!rq) return SCSI_DH_RES_TEMP_UNAVAIL; rq->sense = csdev->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = csdev->senselen = 0; rq->cmd[0] = INQUIRY; if (page != 0) { rq->cmd[1] = 1; rq->cmd[2] = page; } err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); if (err == -EIO) { sdev_printk(KERN_INFO, sdev, "%s: failed to send %s INQUIRY: %x\n", CLARIION_NAME, page?"EVPD":"standard", rq->errors); csdev->senselen = rq->sense_len; err = SCSI_DH_IO; } blk_put_request(rq); return err; }
/* * submit_rtpg - Issue a REPORT TARGET GROUP STATES command * @sdev: sdev the command should be sent to */ static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) { struct request *rq; int err = 0; rq = get_alua_req(sdev, h->buff, h->bufflen, READ); if (!rq) { err = DRIVER_BUSY << 24; goto done; } /* Prepare the command. */ rq->cmd[0] = MAINTENANCE_IN; if (!(h->flags & ALUA_RTPG_EXT_HDR_UNSUPP)) rq->cmd[1] = MI_REPORT_TARGET_PGS | MI_EXT_HDR_PARAM_FMT; else rq->cmd[1] = MI_REPORT_TARGET_PGS; put_unaligned_be32(h->bufflen, &rq->cmd[6]); rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; blk_execute_rq(rq->q, NULL, rq, 1); if (rq->errors) err = rq->errors; blk_put_request(rq); done: return err; }
/* * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command * @sdev: sdev the command should be sent to */ static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) { struct request *rq; int err = SCSI_DH_RES_TEMP_UNAVAIL; rq = get_alua_req(sdev, h->buff, h->bufflen, READ); if (!rq) goto done; /* Prepare the command. */ rq->cmd[0] = INQUIRY; rq->cmd[1] = 1; rq->cmd[2] = 0x83; rq->cmd[4] = h->bufflen; rq->cmd_len = COMMAND_SIZE(INQUIRY); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = h->senselen = 0; err = blk_execute_rq(rq->q, NULL, rq, 1); if (err == -EIO) { sdev_printk(KERN_INFO, sdev, "%s: evpd inquiry failed with %x\n", ALUA_DH_NAME, rq->errors); h->senselen = rq->sense_len; err = SCSI_DH_IO; } blk_put_request(rq); done: return err; }
int generic_ide_suspend(struct device *dev, pm_message_t mesg) { ide_drive_t *drive = dev_get_drvdata(dev); ide_drive_t *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; int ret; if (ide_port_acpi(hwif)) { /* call ACPI _GTM only once */ if ((drive->dn & 1) == 0 || pair == NULL) ide_acpi_get_timing(hwif); } memset(&rqpm, 0, sizeof(rqpm)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_PM_SUSPEND; rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_SUSPEND; if (mesg.event == PM_EVENT_PRETHAW) mesg.event = PM_EVENT_FREEZE; rqpm.pm_state = mesg.event; ret = blk_execute_rq(drive->queue, NULL, rq, 0); blk_put_request(rq); if (ret == 0 && ide_port_acpi(hwif)) { /* call ACPI _PS3 only after both devices are suspended */ if ((drive->dn & 1) || pair == NULL) ide_acpi_set_state(hwif, 0); } return ret; }
static int nvme_nvm_submit_io_sync(struct nvm_dev *dev, struct nvm_rq *rqd) { struct request_queue *q = dev->q; struct request *rq; struct nvme_nvm_command cmd; int ret = 0; memset(&cmd, 0, sizeof(struct nvme_nvm_command)); rq = nvme_nvm_alloc_request(q, rqd, &cmd); if (IS_ERR(rq)) return PTR_ERR(rq); /* I/Os can fail and the error is signaled through rqd. Callers must * handle the error accordingly. */ blk_execute_rq(q, NULL, rq, 0); if (nvme_req(rq)->flags & NVME_REQ_CANCELLED) ret = -EINTR; rqd->ppa_status = le64_to_cpu(nvme_req(rq)->result.u64); rqd->error = nvme_req(rq)->status; blk_mq_free_request(rq); return ret; }
static int send_cmd(struct scsi_device *sdev, int cmd) { struct request *rq = get_req(sdev, cmd); if (!rq) return SCSI_DH_RES_TEMP_UNAVAIL; return blk_execute_rq(sdev->request_queue, NULL, rq, 1); }
static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) { ide_hwif_t *hwif = drive->hwif; struct request_queue *q = drive->queue; struct request *rq; int rc; timeout += jiffies; spin_lock_irq(&hwif->lock); if (drive->dev_flags & IDE_DFLAG_PARKED) { int reset_timer = time_before(timeout, drive->sleep); int start_queue = 0; drive->sleep = timeout; wake_up_all(&ide_park_wq); if (reset_timer && del_timer(&hwif->timer)) start_queue = 1; spin_unlock_irq(&hwif->lock); if (start_queue) blk_run_queue(q); return; } spin_unlock_irq(&hwif->lock); rq = blk_get_request(q, READ, __GFP_WAIT); rq->cmd[0] = REQ_PARK_HEADS; rq->cmd_len = 1; rq->cmd_type = REQ_TYPE_SPECIAL; rq->special = &timeout; rc = blk_execute_rq(q, NULL, rq, 1); blk_put_request(rq); if (rc) goto out; /* */ rq = blk_get_request(q, READ, GFP_NOWAIT); if (unlikely(!rq)) goto out; rq->cmd[0] = REQ_UNPARK_HEADS; rq->cmd_len = 1; rq->cmd_type = REQ_TYPE_SPECIAL; elv_add_request(q, rq, ELEVATOR_INSERT_FRONT); out: return; }
static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) { ide_hwif_t *hwif = drive->hwif; struct request_queue *q = drive->queue; struct request *rq; int rc; timeout += jiffies; spin_lock_irq(&hwif->lock); if (drive->dev_flags & IDE_DFLAG_PARKED) { int reset_timer = time_before(timeout, drive->sleep); int start_queue = 0; drive->sleep = timeout; wake_up_all(&ide_park_wq); if (reset_timer && del_timer(&hwif->timer)) start_queue = 1; spin_unlock_irq(&hwif->lock); if (start_queue) blk_run_queue(q); return; } spin_unlock_irq(&hwif->lock); rq = blk_get_request(q, READ, __GFP_WAIT); rq->cmd[0] = REQ_PARK_HEADS; rq->cmd_len = 1; rq->cmd_type = REQ_TYPE_DRV_PRIV; rq->special = &timeout; rc = blk_execute_rq(q, NULL, rq, 1); blk_put_request(rq); if (rc) goto out; /* * Make sure that *some* command is sent to the drive after the * timeout has expired, so power management will be reenabled. */ rq = blk_get_request(q, READ, GFP_NOWAIT); if (IS_ERR(rq)) goto out; rq->cmd[0] = REQ_UNPARK_HEADS; rq->cmd_len = 1; rq->cmd_type = REQ_TYPE_DRV_PRIV; elv_add_request(q, rq, ELEVATOR_INSERT_FRONT); out: return; }
static int send_trespass_cmd(struct scsi_device *sdev, struct clariion_dh_data *csdev) { struct request *rq; unsigned char *page22; int err, len, cmd; if (csdev->flags & CLARIION_SHORT_TRESPASS) { page22 = short_trespass; if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) /* Set Honor Reservations bit */ page22[6] |= 0x80; len = sizeof(short_trespass); cmd = MODE_SELECT; } else { page22 = long_trespass; if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) /* Set Honor Reservations bit */ page22[10] |= 0x80; len = sizeof(long_trespass); cmd = MODE_SELECT_10; } BUG_ON((len > CLARIION_BUFFER_SIZE)); memcpy(csdev->buffer, page22, len); rq = get_req(sdev, cmd, csdev->buffer); if (!rq) return SCSI_DH_RES_TEMP_UNAVAIL; rq->sense = csdev->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = csdev->senselen = 0; err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); if (err == -EIO) { if (rq->sense_len) { err = trespass_endio(sdev, csdev->sense); } else { sdev_printk(KERN_INFO, sdev, "%s: failed to send MODE SELECT: %x\n", CLARIION_NAME, rq->errors); } } blk_put_request(rq); return err; }
/* * hp_sw_tur - Send TEST UNIT READY * @sdev: sdev command should be sent to * * Use the TEST UNIT READY command to determine * the path state. */ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) { struct request *req; int ret; retry: req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); if (IS_ERR(req)) return SCSI_DH_RES_TEMP_UNAVAIL; blk_rq_set_block_pc(req); req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); req->cmd[0] = TEST_UNIT_READY; req->timeout = HP_SW_TIMEOUT; req->sense = h->sense; memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); req->sense_len = 0; ret = blk_execute_rq(req->q, NULL, req, 1); if (ret == -EIO) { if (req->sense_len > 0) { ret = tur_done(sdev, h->sense); } else { sdev_printk(KERN_WARNING, sdev, "%s: sending tur failed with %x\n", HP_SW_NAME, req->errors); ret = SCSI_DH_IO; } } else { h->path_state = HP_SW_PATH_ACTIVE; ret = SCSI_DH_OK; } if (ret == SCSI_DH_IMM_RETRY) { blk_put_request(req); goto retry; } if (ret == SCSI_DH_DEV_OFFLINED) { h->path_state = HP_SW_PATH_PASSIVE; ret = SCSI_DH_OK; } blk_put_request(req); return ret; }
/* Send basic block requests */ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, int cmd, int data) { struct request *rq; int err; rq = blk_get_request(q, WRITE, __GFP_WAIT); rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; rq->cmd[4] = data; rq->cmd_len = 6; err = blk_execute_rq(q, bd_disk, rq, 0); blk_put_request(rq); return err; }
/* Send basic block requests */ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int cmd, int data) { struct request *rq; int err; rq = blk_get_request(q, WRITE, __GFP_WAIT); rq->flags |= REQ_BLOCK_PC; rq->data = NULL; rq->data_len = 0; rq->timeout = BLK_DEFAULT_TIMEOUT; memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = cmd; rq->cmd[4] = data; rq->cmd_len = 6; err = blk_execute_rq(q, bd_disk, rq, 0); blk_put_request(rq); return err; }
/* Send basic block requests */ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, int cmd, int data) { struct request *rq; int err; rq = blk_get_request(q, WRITE, __GFP_RECLAIM); if (IS_ERR(rq)) return PTR_ERR(rq); blk_rq_set_block_pc(rq); rq->timeout = BLK_DEFAULT_SG_TIMEOUT; rq->cmd[0] = cmd; rq->cmd[4] = data; rq->cmd_len = 6; err = blk_execute_rq(q, bd_disk, rq, 0); blk_put_request(rq); return err; }
/* Send basic block requests */ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, int cmd, int data) { struct request *rq; int err; rq = blk_get_request(q, REQ_OP_SCSI_OUT, 0); if (IS_ERR(rq)) return PTR_ERR(rq); rq->timeout = BLK_DEFAULT_SG_TIMEOUT; scsi_req(rq)->cmd[0] = cmd; scsi_req(rq)->cmd[4] = data; scsi_req(rq)->cmd_len = 6; blk_execute_rq(q, bd_disk, rq, 0); err = scsi_req(rq)->result ? -EIO : 0; blk_put_request(rq); return err; }
/* return id (s/n) string for *disk to *id_str */ static int virtblk_get_id(struct gendisk *disk, char *id_str) { struct virtio_blk *vblk = disk->private_data; struct request_queue *q = vblk->disk->queue; struct request *req; int err; req = blk_get_request(q, REQ_OP_DRV_IN, GFP_KERNEL); if (IS_ERR(req)) return PTR_ERR(req); err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL); if (err) goto out; err = blk_execute_rq(vblk->disk->queue, vblk->disk, req, false); out: blk_put_request(req); return err; }
int generic_ide_resume(struct device *dev) { ide_drive_t *drive = dev_get_drvdata(dev); ide_drive_t *pair = ide_get_pair_dev(drive); ide_hwif_t *hwif = drive->hwif; struct request *rq; struct request_pm_state rqpm; int err; if (ide_port_acpi(hwif)) { /* call ACPI _PS0 / _STM only once */ if ((drive->dn & 1) == 0 || pair == NULL) { ide_acpi_set_state(hwif, 1); ide_acpi_push_timing(hwif); } ide_acpi_exec_tfs(drive); } memset(&rqpm, 0, sizeof(rqpm)); rq = blk_get_request(drive->queue, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_PM_RESUME; rq->cmd_flags |= REQ_PREEMPT; rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_RESUME; rqpm.pm_state = PM_EVENT_ON; err = blk_execute_rq(drive->queue, NULL, rq, 1); blk_put_request(rq); if (err == 0 && dev->driver) { struct ide_driver *drv = to_ide_driver(dev->driver); if (drv->resume) drv->resume(drive); } return err; }
int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, int arg) { struct request_queue *q = drive->queue; struct request *rq; int ret = 0; if (!(setting->flags & DS_SYNC)) return setting->set(drive, arg); rq = blk_get_request(q, READ, __GFP_WAIT); rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd_len = 5; rq->cmd[0] = REQ_DEVSET_EXEC; *(int *)&rq->cmd[1] = arg; rq->special = setting->set; if (blk_execute_rq(q, NULL, rq, 0)) ret = rq->errors; blk_put_request(rq); return ret; }
int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, int arg) { struct request_queue *q = drive->queue; struct request *rq; int ret = 0; if (!(setting->flags & DS_SYNC)) return setting->set(drive, arg); rq = blk_get_request(q, REQ_OP_DRV_IN, 0); ide_req(rq)->type = ATA_PRIV_MISC; scsi_req(rq)->cmd_len = 5; scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC; *(int *)&scsi_req(rq)->cmd[1] = arg; ide_req(rq)->special = setting->set; blk_execute_rq(q, NULL, rq, 0); ret = scsi_req(rq)->result; blk_put_request(rq); return ret; }
/* return id (s/n) string for *disk to *id_str */ static int virtblk_get_id(struct gendisk *disk, char *id_str) { struct virtio_blk *vblk = disk->private_data; struct request *req; struct bio *bio; int err; bio = bio_map_kern(vblk->disk->queue, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL); if (IS_ERR(bio)) return PTR_ERR(bio); req = blk_make_request(vblk->disk->queue, bio, GFP_KERNEL); if (IS_ERR(req)) { bio_put(bio); return PTR_ERR(req); } req->cmd_type = REQ_TYPE_DRV_PRIV; err = blk_execute_rq(vblk->disk->queue, vblk->disk, req, false); blk_put_request(req); return err; }
static int sg_io(struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr, fmode_t mode) { unsigned long start_time; ssize_t ret = 0; int writing = 0; int at_head = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } if (hdr->flags & SG_FLAG_Q_AT_HEAD) at_head = 1; ret = -ENOMEM; rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (IS_ERR(rq)) return PTR_ERR(rq); blk_rq_set_block_pc(rq); if (hdr->cmd_len > BLK_MAX_CDB) { rq->cmd = kzalloc(hdr->cmd_len, GFP_KERNEL); if (!rq->cmd) goto out_put_request; } ret = blk_fill_sghdr_rq(q, rq, hdr, mode); if (ret < 0) goto out_free_cdb; ret = 0; if (hdr->iovec_count) { struct iov_iter i; struct iovec *iov = NULL; ret = import_iovec(rq_data_dir(rq), hdr->dxferp, hdr->iovec_count, 0, &iov, &i); if (ret < 0) goto out_free_cdb; /* SG_IO howto says that the shorter of the two wins */ iov_iter_truncate(&i, hdr->dxfer_len); ret = blk_rq_map_user_iov(q, rq, NULL, &i, GFP_KERNEL); kfree(iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, GFP_KERNEL); if (ret) goto out_free_cdb; bio = rq->bio; memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->retries = 0; start_time = jiffies; /* ignore return value. All information is passed back to caller * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ blk_execute_rq(q, bd_disk, rq, at_head); hdr->duration = jiffies_to_msecs(jiffies - start_time); ret = blk_complete_sghdr_rq(rq, hdr, bio); out_free_cdb: if (rq->cmd != rq->__cmd) kfree(rq->cmd); out_put_request: blk_put_request(rq); return ret; }
/** * sg_scsi_ioctl -- handle deprecated SCSI_IOCTL_SEND_COMMAND ioctl * @file: file this ioctl operates on (optional) * @q: request queue to send scsi commands down * @disk: gendisk to operate on (option) * @sic: userspace structure describing the command to perform * * Send down the scsi command described by @sic to the device below * the request queue @q. If @file is non-NULL it's used to perform * fine-grained permission checks that allow users to send down * non-destructive SCSI commands. If the caller has a struct gendisk * available it should be passed in as @disk to allow the low level * driver to use the information contained in it. A non-NULL @disk * is only allowed if the caller knows that the low level driver doesn't * need it (e.g. in the scsi subsystem). * * Notes: * - This interface is deprecated - users should use the SG_IO * interface instead, as this is a more flexible approach to * performing SCSI commands on a device. * - The SCSI command length is determined by examining the 1st byte * of the given command. There is no way to override this. * - Data transfers are limited to PAGE_SIZE * - The length (x + y) must be at least OMAX_SB_LEN bytes long to * accommodate the sense buffer when an error occurs. * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that * old code will not be surprised. * - If a Unix error occurs (e.g. ENOMEM) then the user will receive * a negative return and the Unix error code in 'errno'. * If the SCSI command succeeds then 0 is returned. * Positive numbers returned are the compacted SCSI error codes (4 * bytes in one int) where the lowest byte is the SCSI status. */ #define OMAX_SB_LEN 16 /* For backward compatibility */ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, struct scsi_ioctl_command __user *sic) { struct request *rq; int err; unsigned int in_len, out_len, bytes, opcode, cmdlen; char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; if (!sic) return -EINVAL; /* * get in an out lengths, verify they don't exceed a page worth of data */ if (get_user(in_len, &sic->inlen)) return -EFAULT; if (get_user(out_len, &sic->outlen)) return -EFAULT; if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) return -EINVAL; if (get_user(opcode, sic->data)) return -EFAULT; bytes = max(in_len, out_len); if (bytes) { buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN); if (!buffer) return -ENOMEM; } rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT); cmdlen = COMMAND_SIZE(opcode); /* * get command and data to send to device, if any */ err = -EFAULT; rq->cmd_len = cmdlen; if (copy_from_user(rq->cmd, sic->data, cmdlen)) goto error; if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; err = blk_verify_command(rq->cmd, mode & FMODE_WRITE); if (err) goto error; /* default. possible overriden later */ rq->retries = 5; switch (opcode) { case SEND_DIAGNOSTIC: case FORMAT_UNIT: rq->timeout = FORMAT_UNIT_TIMEOUT; rq->retries = 1; break; case START_STOP: rq->timeout = START_STOP_TIMEOUT; break; case MOVE_MEDIUM: rq->timeout = MOVE_MEDIUM_TIMEOUT; break; case READ_ELEMENT_STATUS: rq->timeout = READ_ELEMENT_STATUS_TIMEOUT; break; case READ_DEFECT_DATA: rq->timeout = READ_DEFECT_DATA_TIMEOUT; rq->retries = 1; break; default: rq->timeout = BLK_DEFAULT_SG_TIMEOUT; break; } if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_WAIT)) { err = DRIVER_ERROR << 24; goto out; } memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->cmd_type = REQ_TYPE_BLOCK_PC; blk_execute_rq(q, disk, rq, 0); out: err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len && rq->sense) { bytes = (OMAX_SB_LEN > rq->sense_len) ? rq->sense_len : OMAX_SB_LEN; if (copy_to_user(sic->data, rq->sense, bytes)) err = -EFAULT; } } else { if (copy_to_user(sic->data, buffer, out_len)) err = -EFAULT; } error: kfree(buffer); blk_put_request(rq); return err; }
static int sg_io(struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr, fmode_t mode) { unsigned long start_time; int writing = 0, ret = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) return -ENOMEM; if (blk_fill_sghdr_rq(q, rq, hdr, mode)) { blk_put_request(rq); return -EFAULT; } if (hdr->iovec_count) { const int size = sizeof(struct sg_iovec) * hdr->iovec_count; size_t iov_data_len; struct sg_iovec *sg_iov; struct iovec *iov; int i; sg_iov = kmalloc(size, GFP_KERNEL); if (!sg_iov) { ret = -ENOMEM; goto out; } if (copy_from_user(sg_iov, hdr->dxferp, size)) { kfree(sg_iov); ret = -EFAULT; goto out; } /* * Sum up the vecs, making sure they don't overflow */ iov = (struct iovec *) sg_iov; iov_data_len = 0; for (i = 0; i < hdr->iovec_count; i++) { if (iov_data_len + iov[i].iov_len < iov_data_len) { kfree(sg_iov); ret = -EINVAL; goto out; } iov_data_len += iov[i].iov_len; } /* SG_IO howto says that the shorter of the two wins */ if (hdr->dxfer_len < iov_data_len) { hdr->iovec_count = iov_shorten(iov, hdr->iovec_count, hdr->dxfer_len); iov_data_len = hdr->dxfer_len; } ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count, iov_data_len, GFP_KERNEL); kfree(sg_iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, GFP_KERNEL); if (ret) goto out; bio = rq->bio; memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->retries = 0; start_time = jiffies; /* ignore return value. All information is passed back to caller * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ blk_execute_rq(q, bd_disk, rq, 0); hdr->duration = jiffies_to_msecs(jiffies - start_time); return blk_complete_sghdr_rq(rq, hdr, bio); out: blk_put_request(rq); return ret; }
static int sg_io(struct file *file, request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; int reading, writing; struct request *rq; struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char cmd[BLK_MAX_CDB]; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len)) return -EFAULT; if (verify_command(file, cmd)) return -EPERM; /* * we'll do that later */ if (hdr->iovec_count) return -EOPNOTSUPP; if (hdr->dxfer_len > (q->max_sectors << 9)) return -EIO; reading = writing = 0; if (hdr->dxfer_len) { switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_FROM_DEV: reading = 1; /* fall through */ case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_FROM_DEV: reading = 1; break; } rq = blk_rq_map_user(q, writing ? WRITE : READ, hdr->dxferp, hdr->dxfer_len); if (IS_ERR(rq)) return PTR_ERR(rq); } else rq = blk_get_request(q, READ, __GFP_WAIT); /* * fill in request structure */ rq->cmd_len = hdr->cmd_len; memcpy(rq->cmd, cmd, hdr->cmd_len); if (sizeof(rq->cmd) != hdr->cmd_len) memset(rq->cmd + hdr->cmd_len, 0, sizeof(rq->cmd) - hdr->cmd_len); memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->flags |= REQ_BLOCK_PC; bio = rq->bio; /* * bounce this after holding a reference to the original bio, it's * needed for proper unmapping */ if (rq->bio) blk_queue_bounce(q, &rq->bio); rq->timeout = (hdr->timeout * HZ) / 1000; if (!rq->timeout) rq->timeout = q->sg_timeout; if (!rq->timeout) rq->timeout = BLK_DEFAULT_TIMEOUT; start_time = jiffies; /* ignore return value. All information is passed back to caller * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ blk_execute_rq(q, bd_disk, rq); /* write to all output members */ hdr->status = rq->errors; hdr->masked_status = (hdr->status >> 1) & 0x1f; hdr->msg_status = 0; hdr->host_status = 0; hdr->driver_status = 0; hdr->info = 0; if (hdr->masked_status || hdr->host_status || hdr->driver_status) hdr->info |= SG_INFO_CHECK; hdr->resid = rq->data_len; hdr->duration = ((jiffies - start_time) * 1000) / HZ; hdr->sb_len_wr = 0; if (rq->sense_len && hdr->sbp) { int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len); if (!copy_to_user(hdr->sbp, rq->sense, len)) hdr->sb_len_wr = len; } if (blk_rq_unmap_user(rq, bio, hdr->dxfer_len)) return -EFAULT; /* may not have succeeded, but output values written to control * structure (struct sg_io_hdr). */ return 0; }
static int sg_scsi_ioctl(struct file *file, request_queue_t *q, struct gendisk *bd_disk, Scsi_Ioctl_Command __user *sic) { struct request *rq; int err, in_len, out_len, bytes, opcode, cmdlen; char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; /* * get in an out lengths, verify they don't exceed a page worth of data */ if (get_user(in_len, &sic->inlen)) return -EFAULT; if (get_user(out_len, &sic->outlen)) return -EFAULT; if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) return -EINVAL; if (get_user(opcode, sic->data)) return -EFAULT; bytes = max(in_len, out_len); if (bytes) { buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER); if (!buffer) return -ENOMEM; memset(buffer, 0, bytes); } rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT); cmdlen = COMMAND_SIZE(opcode); /* * get command and data to send to device, if any */ err = -EFAULT; rq->cmd_len = cmdlen; if (copy_from_user(rq->cmd, sic->data, cmdlen)) goto error; if (copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; err = verify_command(file, rq->cmd); if (err) goto error; switch (opcode) { case SEND_DIAGNOSTIC: case FORMAT_UNIT: rq->timeout = FORMAT_UNIT_TIMEOUT; break; case START_STOP: rq->timeout = START_STOP_TIMEOUT; break; case MOVE_MEDIUM: rq->timeout = MOVE_MEDIUM_TIMEOUT; break; case READ_ELEMENT_STATUS: rq->timeout = READ_ELEMENT_STATUS_TIMEOUT; break; case READ_DEFECT_DATA: rq->timeout = READ_DEFECT_DATA_TIMEOUT; break; default: rq->timeout = BLK_DEFAULT_TIMEOUT; break; } memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->data = buffer; rq->data_len = bytes; rq->flags |= REQ_BLOCK_PC; blk_execute_rq(q, bd_disk, rq); err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len && rq->sense) { bytes = (OMAX_SB_LEN > rq->sense_len) ? rq->sense_len : OMAX_SB_LEN; if (copy_to_user(sic->data, rq->sense, bytes)) err = -EFAULT; } } else { if (copy_to_user(sic->data, buffer, out_len)) err = -EFAULT; } error: kfree(buffer); blk_put_request(rq); return err; }
int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, void __user *arg) { request_queue_t *q; struct request *rq; int close = 0, err; q = bd_disk->queue; if (!q) return -ENXIO; if (blk_get_queue(q)) return -ENXIO; switch (cmd) { /* * new sgv3 interface */ case SG_GET_VERSION_NUM: err = sg_get_version(arg); break; case SCSI_IOCTL_GET_IDLUN: err = scsi_get_idlun(q, arg); break; case SCSI_IOCTL_GET_BUS_NUMBER: err = scsi_get_bus(q, arg); break; case SG_SET_TIMEOUT: err = sg_set_timeout(q, arg); break; case SG_GET_TIMEOUT: err = sg_get_timeout(q); break; case SG_GET_RESERVED_SIZE: err = sg_get_reserved_size(q, arg); break; case SG_SET_RESERVED_SIZE: err = sg_set_reserved_size(q, arg); break; case SG_EMULATED_HOST: err = sg_emulated_host(q, arg); break; case SG_IO: { struct sg_io_hdr hdr; err = -EFAULT; if (copy_from_user(&hdr, arg, sizeof(hdr))) break; err = sg_io(file, q, bd_disk, &hdr); if (err == -EFAULT) break; if (copy_to_user(arg, &hdr, sizeof(hdr))) err = -EFAULT; break; } case CDROM_SEND_PACKET: { struct cdrom_generic_command cgc; struct sg_io_hdr hdr; err = -EFAULT; if (copy_from_user(&cgc, arg, sizeof(cgc))) break; cgc.timeout = clock_t_to_jiffies(cgc.timeout); memset(&hdr, 0, sizeof(hdr)); hdr.interface_id = 'S'; hdr.cmd_len = sizeof(cgc.cmd); hdr.dxfer_len = cgc.buflen; err = 0; switch (cgc.data_direction) { case CGC_DATA_UNKNOWN: hdr.dxfer_direction = SG_DXFER_UNKNOWN; break; case CGC_DATA_WRITE: hdr.dxfer_direction = SG_DXFER_TO_DEV; break; case CGC_DATA_READ: hdr.dxfer_direction = SG_DXFER_FROM_DEV; break; case CGC_DATA_NONE: hdr.dxfer_direction = SG_DXFER_NONE; break; default: err = -EINVAL; } if (err) break; hdr.dxferp = cgc.buffer; hdr.sbp = cgc.sense; if (hdr.sbp) hdr.mx_sb_len = sizeof(struct request_sense); hdr.timeout = cgc.timeout; hdr.cmdp = ((struct cdrom_generic_command __user*) arg)->cmd; hdr.cmd_len = sizeof(cgc.cmd); err = sg_io(file, q, bd_disk, &hdr); if (err == -EFAULT) break; if (hdr.status) err = -EIO; cgc.stat = err; cgc.buflen = hdr.resid; if (copy_to_user(arg, &cgc, sizeof(cgc))) err = -EFAULT; break; } /* * old junk scsi send command ioctl */ case SCSI_IOCTL_SEND_COMMAND: err = -EINVAL; if (!arg) break; err = sg_scsi_ioctl(file, q, bd_disk, arg); break; case CDROMCLOSETRAY: close = 1; case CDROMEJECT: rq = blk_get_request(q, WRITE, __GFP_WAIT); rq->flags |= REQ_BLOCK_PC; rq->data = NULL; rq->data_len = 0; rq->timeout = BLK_DEFAULT_TIMEOUT; memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = GPCMD_START_STOP_UNIT; rq->cmd[4] = 0x02 + (close != 0); rq->cmd_len = 6; err = blk_execute_rq(q, bd_disk, rq); blk_put_request(rq); break; default: err = -ENOTTY; } blk_put_queue(q); return err; }
static int sg_io(struct file *file, request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time, timeout; int writing = 0, ret = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char cmd[BLK_MAX_CDB]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len)) return -EFAULT; if (verify_command(file, cmd)) return -EPERM; if (hdr->dxfer_len > (q->max_hw_sectors << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) return -ENOMEM; /* * fill in request structure */ rq->cmd_len = hdr->cmd_len; memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ memcpy(rq->cmd, cmd, hdr->cmd_len); memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->cmd_type = REQ_TYPE_BLOCK_PC; timeout = msecs_to_jiffies(hdr->timeout); rq->timeout = (timeout < INT_MAX) ? timeout : INT_MAX; if (!rq->timeout) rq->timeout = q->sg_timeout; if (!rq->timeout) rq->timeout = BLK_DEFAULT_TIMEOUT; if (hdr->iovec_count) { const int size = sizeof(struct sg_iovec) * hdr->iovec_count; struct sg_iovec *iov; iov = kmalloc(size, GFP_KERNEL); if (!iov) { ret = -ENOMEM; goto out; } if (copy_from_user(iov, hdr->dxferp, size)) { kfree(iov); ret = -EFAULT; goto out; } ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count, hdr->dxfer_len); kfree(iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); if (ret) goto out; bio = rq->bio; rq->retries = 0; start_time = jiffies; /* ignore return value. All information is passed back to caller * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ blk_execute_rq(q, bd_disk, rq, 0); /* write to all output members */ hdr->status = 0xff & rq->errors; hdr->masked_status = status_byte(rq->errors); hdr->msg_status = msg_byte(rq->errors); hdr->host_status = host_byte(rq->errors); hdr->driver_status = driver_byte(rq->errors); hdr->info = 0; if (hdr->masked_status || hdr->host_status || hdr->driver_status) hdr->info |= SG_INFO_CHECK; hdr->resid = rq->data_len; hdr->duration = ((jiffies - start_time) * 1000) / HZ; hdr->sb_len_wr = 0; if (rq->sense_len && hdr->sbp) { int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len); if (!copy_to_user(hdr->sbp, rq->sense, len)) hdr->sb_len_wr = len; } if (blk_rq_unmap_user(bio)) ret = -EFAULT; /* may not have succeeded, but output values written to control * structure (struct sg_io_hdr). */ out: blk_put_request(rq); return ret; }