diff options
Diffstat (limited to 'drivers/scsi/sr.c')
-rw-r--r-- | drivers/scsi/sr.c | 143 |
1 files changed, 71 insertions, 72 deletions
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 2942a4ec9bdd..8b17b35283aa 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -122,6 +122,8 @@ static void get_capabilities(struct scsi_cd *); static unsigned int sr_check_events(struct cdrom_device_info *cdi, unsigned int clearing, int slot); static int sr_packet(struct cdrom_device_info *, struct packet_command *); +static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf, + u32 lba, u32 nr, u8 *last_sense); static const struct cdrom_device_ops sr_dops = { .open = sr_open, @@ -135,8 +137,9 @@ static const struct cdrom_device_ops sr_dops = { .get_mcn = sr_get_mcn, .reset = sr_reset, .audio_ioctl = sr_audio_ioctl, - .capability = SR_CAPABILITIES, .generic_packet = sr_packet, + .read_cdda_bpc = sr_read_cdda_bpc, + .capability = SR_CAPABILITIES, }; static void sr_kref_release(struct kref *kref); @@ -330,7 +333,8 @@ static int sr_done(struct scsi_cmnd *SCpnt) int good_bytes = (result == 0 ? this_count : 0); int block_sectors = 0; long error_sector; - struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); + struct request *rq = scsi_cmd_to_rq(SCpnt); + struct scsi_cd *cd = scsi_cd(rq->rq_disk); #ifdef DEBUG scmd_printk(KERN_INFO, SCpnt, "done: %x\n", result); @@ -352,16 +356,14 @@ static int sr_done(struct scsi_cmnd *SCpnt) break; error_sector = get_unaligned_be32(&SCpnt->sense_buffer[3]); - if (SCpnt->request->bio != NULL) - block_sectors = - bio_sectors(SCpnt->request->bio); + if (rq->bio != NULL) + block_sectors = bio_sectors(rq->bio); if (block_sectors < 4) block_sectors = 4; if (cd->device->sector_size == 2048) error_sector <<= 2; error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - - blk_rq_pos(SCpnt->request)) << 9; + good_bytes = (error_sector - blk_rq_pos(rq)) << 9; if (good_bytes < 0 || good_bytes >= this_count) good_bytes = 0; /* @@ -393,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) { int block = 0, this_count, s_size; struct scsi_cd *cd; - struct request *rq = SCpnt->request; + struct request *rq = scsi_cmd_to_rq(SCpnt); blk_status_t ret; ret = scsi_alloc_sgtables(SCpnt); @@ -558,53 +560,14 @@ static void sr_block_release(struct gendisk *disk, fmode_t mode) static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg) { - struct scsi_cd *cd = scsi_cd(bdev->bd_disk); + struct gendisk *disk = bdev->bd_disk; + struct scsi_cd *cd = scsi_cd(disk); struct scsi_device *sdev = cd->device; void __user *argp = (void __user *)arg; int ret; - mutex_lock(&cd->lock); - - ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, - (mode & FMODE_NDELAY) != 0); - if (ret) - goto out; - - scsi_autopm_get_device(sdev); - - /* - * Send SCSI addressing ioctls directly to mid level, send other - * ioctls to cdrom/block level. - */ - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - ret = scsi_ioctl(sdev, cmd, argp); - goto put; - } - - ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); - if (ret != -ENOSYS) - goto put; - - ret = scsi_ioctl(sdev, cmd, argp); - -put: - scsi_autopm_put_device(sdev); - -out: - mutex_unlock(&cd->lock); - return ret; -} - -#ifdef CONFIG_COMPAT -static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, - unsigned long arg) -{ - struct scsi_cd *cd = scsi_cd(bdev->bd_disk); - struct scsi_device *sdev = cd->device; - void __user *argp = compat_ptr(arg); - int ret; + if (bdev_is_partition(bdev) && !capable(CAP_SYS_RAWIO)) + return -ENOIOCTLCMD; mutex_lock(&cd->lock); @@ -615,32 +578,19 @@ static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsign scsi_autopm_get_device(sdev); - /* - * Send SCSI addressing ioctls directly to mid level, send other - * ioctls to cdrom/block level. - */ - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - ret = scsi_compat_ioctl(sdev, cmd, argp); - goto put; + if (ret != CDROMCLOSETRAY && ret != CDROMEJECT) { + ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); + if (ret != -ENOSYS) + goto put; } - - ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, (unsigned long)argp); - if (ret != -ENOSYS) - goto put; - - ret = scsi_compat_ioctl(sdev, cmd, argp); + ret = scsi_ioctl(sdev, disk, mode, cmd, argp); put: scsi_autopm_put_device(sdev); - out: mutex_unlock(&cd->lock); return ret; - } -#endif static unsigned int sr_block_check_events(struct gendisk *disk, unsigned int clearing) @@ -665,9 +615,7 @@ static const struct block_device_operations sr_bdops = .open = sr_block_open, .release = sr_block_release, .ioctl = sr_block_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = sr_block_compat_ioctl, -#endif + .compat_ioctl = blkdev_compat_ptr_ioctl, .check_events = sr_block_check_events, }; @@ -1008,6 +956,57 @@ static int sr_packet(struct cdrom_device_info *cdi, return cgc->stat; } +static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf, + u32 lba, u32 nr, u8 *last_sense) +{ + struct gendisk *disk = cdi->disk; + u32 len = nr * CD_FRAMESIZE_RAW; + struct scsi_request *req; + struct request *rq; + struct bio *bio; + int ret; + + rq = blk_get_request(disk->queue, REQ_OP_DRV_IN, 0); + if (IS_ERR(rq)) + return PTR_ERR(rq); + req = scsi_req(rq); + + ret = blk_rq_map_user(disk->queue, rq, NULL, ubuf, len, GFP_KERNEL); + if (ret) + goto out_put_request; + + req->cmd[0] = GPCMD_READ_CD; + req->cmd[1] = 1 << 2; + req->cmd[2] = (lba >> 24) & 0xff; + req->cmd[3] = (lba >> 16) & 0xff; + req->cmd[4] = (lba >> 8) & 0xff; + req->cmd[5] = lba & 0xff; + req->cmd[6] = (nr >> 16) & 0xff; + req->cmd[7] = (nr >> 8) & 0xff; + req->cmd[8] = nr & 0xff; + req->cmd[9] = 0xf8; + req->cmd_len = 12; + rq->timeout = 60 * HZ; + bio = rq->bio; + + blk_execute_rq(disk, rq, 0); + if (scsi_req(rq)->result) { + struct scsi_sense_hdr sshdr; + + scsi_normalize_sense(req->sense, req->sense_len, + &sshdr); + *last_sense = sshdr.sense_key; + ret = -EIO; + } + + if (blk_rq_unmap_user(bio)) + ret = -EFAULT; +out_put_request: + blk_put_request(rq); + return ret; +} + + /** * sr_kref_release - Called to free the scsi_cd structure * @kref: pointer to embedded kref |