diff options
Diffstat (limited to 'drivers/scsi/sr.c')
| -rw-r--r-- | drivers/scsi/sr.c | 470 |
1 files changed, 218 insertions, 252 deletions
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 38ddbbfe5f3c..add13e306898 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * sr.c Copyright (C) 1992 David Giller * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale @@ -37,11 +38,13 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/bio.h> +#include <linux/compat.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/cdrom.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/major.h> #include <linux/blkdev.h> #include <linux/blk-pm.h> #include <linux/mutex.h> @@ -49,6 +52,8 @@ #include <linux/pm_runtime.h> #include <linux/uaccess.h> +#include <linux/unaligned.h> + #include <scsi/scsi.h> #include <scsi/scsi_dbg.h> #include <scsi/scsi_device.h> @@ -77,7 +82,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ CDC_MRW|CDC_MRW_W|CDC_RAM) -static DEFINE_MUTEX(sr_mutex); static int sr_probe(struct device *); static int sr_remove(struct device *); static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt); @@ -91,7 +95,6 @@ static const struct dev_pm_ops sr_pm_ops = { static struct scsi_driver sr_template = { .gendrv = { .name = "sr", - .owner = THIS_MODULE, .probe = sr_probe, .remove = sr_remove, .pm = &sr_pm_ops, @@ -103,20 +106,19 @@ static struct scsi_driver sr_template = { static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG]; static DEFINE_SPINLOCK(sr_index_lock); -/* This semaphore is used to mediate the 0->1 reference get in the - * face of object destruction (i.e. we can't allow a get on an - * object after last put) */ -static DEFINE_MUTEX(sr_ref_mutex); +static struct lock_class_key sr_bio_compl_lkclass; static int sr_open(struct cdrom_device_info *, int); static void sr_release(struct cdrom_device_info *); -static void get_sectorsize(struct scsi_cd *); -static void get_capabilities(struct scsi_cd *); +static int get_sectorsize(struct scsi_cd *); +static int 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, @@ -130,15 +132,14 @@ 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); - static inline struct scsi_cd *scsi_cd(struct gendisk *disk) { - return container_of(disk->private_data, struct scsi_cd, driver); + return disk->private_data; } static int sr_runtime_suspend(struct device *dev) @@ -154,38 +155,6 @@ static int sr_runtime_suspend(struct device *dev) return 0; } -/* - * The get and put routines for the struct scsi_cd. Note this entity - * has a scsi_device pointer and owns a reference to this. - */ -static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk) -{ - struct scsi_cd *cd = NULL; - - mutex_lock(&sr_ref_mutex); - if (disk->private_data == NULL) - goto out; - cd = scsi_cd(disk); - kref_get(&cd->kref); - if (scsi_device_get(cd->device)) { - kref_put(&cd->kref, sr_kref_release); - cd = NULL; - } - out: - mutex_unlock(&sr_ref_mutex); - return cd; -} - -static void scsi_cd_put(struct scsi_cd *cd) -{ - struct scsi_device *sdev = cd->device; - - mutex_lock(&sr_ref_mutex); - kref_put(&cd->kref, sr_kref_release); - scsi_device_put(sdev); - mutex_unlock(&sr_ref_mutex); -} - static unsigned int sr_get_events(struct scsi_device *sdev) { u8 buf[8]; @@ -200,11 +169,15 @@ static unsigned int sr_get_events(struct scsi_device *sdev) struct event_header *eh = (void *)buf; struct media_event_desc *med = (void *)(buf + 4); struct scsi_sense_hdr sshdr; + const struct scsi_exec_args exec_args = { + .sshdr = &sshdr, + }; int result; - result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf), - &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL); - if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) + result = scsi_execute_cmd(sdev, cmd, REQ_OP_DRV_IN, buf, sizeof(buf), + SR_TIMEOUT, MAX_RETRIES, &exec_args); + if (result > 0 && scsi_sense_valid(&sshdr) && + sshdr.sense_key == UNIT_ATTENTION) return DISK_EVENT_MEDIA_CHANGE; if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) @@ -217,6 +190,8 @@ static unsigned int sr_get_events(struct scsi_device *sdev) return DISK_EVENT_EJECT_REQUEST; else if (med->media_event_code == 2) return DISK_EVENT_MEDIA_CHANGE; + else if (med->media_event_code == 3) + return DISK_EVENT_MEDIA_CHANGE; return 0; } @@ -323,7 +298,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->q->disk); #ifdef DEBUG scmd_printk(KERN_INFO, SCpnt, "done: %x\n", result); @@ -335,7 +311,7 @@ static int sr_done(struct scsi_cmnd *SCpnt) * care is taken to avoid unnecessary additional work such as * memcpy's that could be avoided. */ - if (driver_byte(result) != 0 && /* An error occurred */ + if (scsi_status_is_check_condition(result) && (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */ switch (SCpnt->sense_buffer[2]) { case MEDIUM_ERROR: @@ -343,20 +319,16 @@ static int sr_done(struct scsi_cmnd *SCpnt) case ILLEGAL_REQUEST: if (!(SCpnt->sense_buffer[0] & 0x90)) break; - error_sector = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; - if (SCpnt->request->bio != NULL) - block_sectors = - bio_sectors(SCpnt->request->bio); + error_sector = + get_unaligned_be32(&SCpnt->sense_buffer[3]); + 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; /* @@ -388,18 +360,13 @@ 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_init_io(SCpnt); + ret = scsi_alloc_sgtables(SCpnt); if (ret != BLK_STS_OK) - goto out; - WARN_ON_ONCE(SCpnt != rq->special); - cd = scsi_cd(rq->rq_disk); - - /* from here on until we're complete, any goto out - * is used for a killable error condition */ - ret = BLK_STS_IOERR; + return ret; + cd = scsi_cd(rq->q->disk); SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt, "Doing sr request, block = %d\n", block)); @@ -420,19 +387,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) goto out; } - /* - * we do lazy blocksize switching (when reading XA sectors, - * see CDROMREADMODE2 ioctl) - */ s_size = cd->device->sector_size; - if (s_size > 2048) { - if (!in_interrupt()) - sr_set_blocklength(cd, 2048); - else - scmd_printk(KERN_INFO, SCpnt, - "can't switch blocksize: in interrupt\n"); - } - if (s_size != 512 && s_size != 1024 && s_size != 2048) { scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size); goto out; @@ -495,13 +450,9 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) SCpnt->sdb.length = this_count * s_size; } - SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; - SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; - SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; - SCpnt->cmnd[5] = (unsigned char) block & 0xff; + put_unaligned_be32(block, &SCpnt->cmnd[2]); SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0; - SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff; - SCpnt->cmnd[8] = (unsigned char) this_count & 0xff; + put_unaligned_be16(this_count, &SCpnt->cmnd[7]); /* * We shouldn't disconnect in the middle of a sector, so with a dumb @@ -511,128 +462,128 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) SCpnt->transfersize = cd->device->sector_size; SCpnt->underflow = this_count << 9; SCpnt->allowed = MAX_RETRIES; + SCpnt->cmd_len = 10; /* - * This indicates that the command is ready from our end to be - * queued. + * This indicates that the command is ready from our end to be queued. */ - ret = BLK_STS_OK; + return BLK_STS_OK; out: - return ret; + scsi_free_sgtables(SCpnt); + return BLK_STS_IOERR; } -static int sr_block_open(struct block_device *bdev, fmode_t mode) +static int sr_revalidate_disk(struct scsi_cd *cd) { - struct scsi_cd *cd; - struct scsi_device *sdev; - int ret = -ENXIO; + struct request_queue *q = cd->device->request_queue; + struct scsi_sense_hdr sshdr; + struct queue_limits lim; + int sector_size; - cd = scsi_cd_get(bdev->bd_disk); - if (!cd) - goto out; + /* if the unit is not ready, nothing more to do */ + if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) + return 0; + sr_cd_check(&cd->cdi); + sector_size = get_sectorsize(cd); - sdev = cd->device; - scsi_autopm_get_device(sdev); - check_disk_change(bdev); + lim = queue_limits_start_update(q); + lim.logical_block_size = sector_size; + lim.features |= BLK_FEAT_ROTATIONAL; + return queue_limits_commit_update_frozen(q, &lim); +} - mutex_lock(&sr_mutex); - ret = cdrom_open(&cd->cdi, bdev, mode); - mutex_unlock(&sr_mutex); +static int sr_block_open(struct gendisk *disk, blk_mode_t mode) +{ + struct scsi_cd *cd = scsi_cd(disk); + struct scsi_device *sdev = cd->device; + int ret; - scsi_autopm_put_device(sdev); - if (ret) - scsi_cd_put(cd); + if (scsi_device_get(cd->device)) + return -ENXIO; + scsi_autopm_get_device(sdev); + if (disk_check_media_change(disk)) { + ret = sr_revalidate_disk(cd); + if (ret) + goto out; + } + + mutex_lock(&cd->lock); + ret = cdrom_open(&cd->cdi, mode); + mutex_unlock(&cd->lock); out: + scsi_autopm_put_device(sdev); + if (ret) + scsi_device_put(cd->device); return ret; } -static void sr_block_release(struct gendisk *disk, fmode_t mode) +static void sr_block_release(struct gendisk *disk) { struct scsi_cd *cd = scsi_cd(disk); - mutex_lock(&sr_mutex); - cdrom_release(&cd->cdi, mode); - scsi_cd_put(cd); - mutex_unlock(&sr_mutex); + + mutex_lock(&cd->lock); + cdrom_release(&cd->cdi); + mutex_unlock(&cd->lock); + + scsi_device_put(cd->device); } -static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, - unsigned long arg) +static int sr_block_ioctl(struct block_device *bdev, blk_mode_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 = (void __user *)arg; int ret; - mutex_lock(&sr_mutex); + if (bdev_is_partition(bdev) && !capable(CAP_SYS_RAWIO)) + return -ENOIOCTLCMD; + + mutex_lock(&cd->lock); ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, - (mode & FMODE_NDELAY) != 0); + (mode & BLK_OPEN_NDELAY)); 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; + if (cmd != CDROMCLOSETRAY && cmd != CDROMEJECT) { + ret = cdrom_ioctl(&cd->cdi, bdev, cmd, arg); + if (ret != -ENOSYS) + goto put; } - - ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); - if (ret != -ENOSYS) - goto put; - - ret = scsi_ioctl(sdev, cmd, argp); + ret = scsi_ioctl(sdev, mode & BLK_OPEN_WRITE, cmd, argp); put: scsi_autopm_put_device(sdev); - out: - mutex_unlock(&sr_mutex); + mutex_unlock(&cd->lock); return ret; } static unsigned int sr_block_check_events(struct gendisk *disk, unsigned int clearing) { - unsigned int ret = 0; - struct scsi_cd *cd; + struct scsi_cd *cd = disk->private_data; - cd = scsi_cd_get(disk); - if (!cd) + if (atomic_read(&cd->device->disk_events_disable_depth)) return 0; - - if (!atomic_read(&cd->device->disk_events_disable_depth)) - ret = cdrom_check_events(&cd->cdi, clearing); - - scsi_cd_put(cd); - return ret; + return cdrom_check_events(&cd->cdi, clearing); } -static int sr_block_revalidate_disk(struct gendisk *disk) +static void sr_free_disk(struct gendisk *disk) { - struct scsi_sense_hdr sshdr; - struct scsi_cd *cd; + struct scsi_cd *cd = disk->private_data; - cd = scsi_cd_get(disk); - if (!cd) - return -ENXIO; - - /* if the unit is not ready, nothing more to do */ - if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) - goto out; + spin_lock(&sr_index_lock); + clear_bit(MINOR(disk_devt(disk)), sr_index_bits); + spin_unlock(&sr_index_lock); - sr_cd_check(&cd->cdi); - get_sectorsize(cd); -out: - scsi_cd_put(cd); - return 0; + unregister_cdrom(&cd->cdi); + mutex_destroy(&cd->lock); + kfree(cd); } static const struct block_device_operations sr_bdops = @@ -641,41 +592,28 @@ static const struct block_device_operations sr_bdops = .open = sr_block_open, .release = sr_block_release, .ioctl = sr_block_ioctl, + .compat_ioctl = blkdev_compat_ptr_ioctl, .check_events = sr_block_check_events, - .revalidate_disk = sr_block_revalidate_disk, - /* - * No compat_ioctl for now because sr_block_ioctl never - * seems to pass arbitrary ioctls down to host drivers. - */ + .free_disk = sr_free_disk, }; static int sr_open(struct cdrom_device_info *cdi, int purpose) { struct scsi_cd *cd = cdi->handle; struct scsi_device *sdev = cd->device; - int retval; /* * If the device is in error recovery, wait until it is done. * If the device is offline, then disallow any access to it. */ - retval = -ENXIO; if (!scsi_block_when_processing_errors(sdev)) - goto error_out; + return -ENXIO; return 0; - -error_out: - return retval; } static void sr_release(struct cdrom_device_info *cdi) { - struct scsi_cd *cd = cdi->handle; - - if (cd->device->sector_size > 2048) - sr_set_blocklength(cd, 2048); - } static int sr_probe(struct device *dev) @@ -695,11 +633,11 @@ static int sr_probe(struct device *dev) if (!cd) goto fail; - kref_init(&cd->kref); - - disk = alloc_disk(1); + disk = blk_mq_alloc_disk_for_queue(sdev->request_queue, + &sr_bio_compl_lkclass); if (!disk) goto fail_free; + mutex_init(&cd->lock); spin_lock(&sr_index_lock); minor = find_first_zero_bit(sr_index_bits, SR_DISKS); @@ -713,17 +651,18 @@ static int sr_probe(struct device *dev) disk->major = SCSI_CDROM_MAJOR; disk->first_minor = minor; + disk->minors = 1; sprintf(disk->disk_name, "sr%d", minor); disk->fops = &sr_bdops; - disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; + disk->flags |= GENHD_FL_REMOVABLE | GENHD_FL_NO_PART; disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; + disk->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT | + DISK_EVENT_FLAG_BLOCK_ON_EXCL_WRITE; blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); cd->device = sdev; cd->disk = disk; - cd->driver = &sr_template; - cd->disk = disk; cd->capacity = 0x1fffff; cd->device->changed = 1; /* force recheck CD type */ cd->media_present = 1; @@ -739,17 +678,16 @@ static int sr_probe(struct device *dev) sdev->sector_size = 2048; /* A guess, just in case */ - /* FIXME: need to handle a get_capabilities failure properly ?? */ - get_capabilities(cd); + error = -ENOMEM; + if (get_capabilities(cd)) + goto fail_minor; sr_vendor_init(cd); set_capacity(disk, cd->capacity); - disk->private_data = &cd->driver; - disk->queue = sdev->request_queue; - cd->cdi.disk = disk; + disk->private_data = cd; - if (register_cdrom(&cd->cdi)) - goto fail_put; + if (register_cdrom(disk, &cd->cdi)) + goto fail_minor; /* * Initialize block layer runtime PM stuffs before the @@ -758,8 +696,13 @@ static int sr_probe(struct device *dev) blk_pm_runtime_init(sdev->request_queue, dev); dev_set_drvdata(dev, cd); - disk->flags |= GENHD_FL_REMOVABLE; - device_add_disk(&sdev->sdev_gendev, disk, NULL); + error = sr_revalidate_disk(cd); + if (error) + goto unregister_cdrom; + + error = device_add_disk(&sdev->sdev_gendev, disk, NULL); + if (error) + goto unregister_cdrom; sdev_printk(KERN_DEBUG, sdev, "Attached scsi CD-ROM %s\n", cd->cdi.name); @@ -767,8 +710,15 @@ static int sr_probe(struct device *dev) return 0; +unregister_cdrom: + unregister_cdrom(&cd->cdi); +fail_minor: + spin_lock(&sr_index_lock); + clear_bit(minor, sr_index_bits); + spin_unlock(&sr_index_lock); fail_put: put_disk(disk); + mutex_destroy(&cd->lock); fail_free: kfree(cd); fail: @@ -777,37 +727,37 @@ fail: } -static void get_sectorsize(struct scsi_cd *cd) +static int get_sectorsize(struct scsi_cd *cd) { - unsigned char cmd[10]; - unsigned char buffer[8]; - int the_result, retries = 3; + static const u8 cmd[10] = { READ_CAPACITY }; + unsigned char buffer[8] = { }; + int err; int sector_size; - struct request_queue *queue; - - do { - cmd[0] = READ_CAPACITY; - memset((void *) &cmd[1], 0, 9); - memset(buffer, 0, sizeof(buffer)); - - /* Do the command and wait.. */ - the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, - buffer, sizeof(buffer), NULL, - SR_TIMEOUT, MAX_RETRIES, NULL); - - retries--; - - } while (the_result && retries); - + struct scsi_failure failure_defs[] = { + { + .result = SCMD_FAILURE_RESULT_ANY, + .allowed = 3, + }, + {} + }; + struct scsi_failures failures = { + .failure_definitions = failure_defs, + }; + const struct scsi_exec_args exec_args = { + .failures = &failures, + }; - if (the_result) { + /* Do the command and wait.. */ + err = scsi_execute_cmd(cd->device, cmd, REQ_OP_DRV_IN, buffer, + sizeof(buffer), SR_TIMEOUT, MAX_RETRIES, + &exec_args); + if (err) { cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ } else { long last_written; - cd->capacity = 1 + ((buffer[0] << 24) | (buffer[1] << 16) | - (buffer[2] << 8) | buffer[3]); + cd->capacity = 1 + get_unaligned_be32(&buffer[0]); /* * READ_CAPACITY doesn't return the correct size on * certain UDF media. If last_written is larger, use @@ -818,8 +768,7 @@ static void get_sectorsize(struct scsi_cd *cd) if (!cdrom_get_last_written(&cd->cdi, &last_written)) cd->capacity = max_t(long, cd->capacity, last_written); - sector_size = (buffer[4] << 24) | - (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + sector_size = get_unaligned_be32(&buffer[4]); switch (sector_size) { /* * HP 4020i CD-Recorder reports 2340 byte sectors @@ -831,10 +780,10 @@ static void get_sectorsize(struct scsi_cd *cd) case 2340: case 2352: sector_size = 2048; - /* fall through */ + fallthrough; case 2048: cd->capacity *= 4; - /* fall through */ + fallthrough; case 512: break; default: @@ -852,13 +801,10 @@ static void get_sectorsize(struct scsi_cd *cd) set_capacity(cd->disk, cd->capacity); } - queue = cd->device->request_queue; - blk_queue_logical_block_size(queue, sector_size); - - return; + return sector_size; } -static void get_capabilities(struct scsi_cd *cd) +static int get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; struct scsi_mode_data data; @@ -880,20 +826,20 @@ static void get_capabilities(struct scsi_cd *cd) /* allocate transfer buffer */ - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) { sr_printk(KERN_ERR, cd, "out of memory.\n"); - return; + return -ENOMEM; } /* eat unit attentions */ scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); /* ask for mode page 0x2a */ - rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len, + rc = scsi_mode_sense(cd->device, 0, 0x2a, 0, buffer, ms_len, SR_TIMEOUT, 3, &data, NULL); - if (!scsi_status_is_good(rc) || data.length > ms_len || + if (rc < 0 || data.length > ms_len || data.header_length + data.block_descriptor_length > data.length) { /* failed, drive doesn't have capabilities mode page */ cd->cdi.speed = 1; @@ -903,17 +849,17 @@ static void get_capabilities(struct scsi_cd *cd) CDC_MRW | CDC_MRW_W | CDC_RAM); kfree(buffer); sr_printk(KERN_INFO, cd, "scsi-1 drive"); - return; + return 0; } n = data.header_length + data.block_descriptor_length; - cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; + cd->cdi.speed = get_unaligned_be16(&buffer[n + 8]) / 176; cd->readcd_known = 1; cd->readcd_cdda = buffer[n + 5] & 0x01; /* print some capability bits */ sr_printk(KERN_INFO, cd, "scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", - ((buffer[n + 14] << 8) + buffer[n + 15]) / 176, + get_unaligned_be16(&buffer[n + 14]) / 176, cd->cdi.speed, buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */ buffer[n + 3] & 0x20 ? "dvd-ram " : "", @@ -962,6 +908,7 @@ static void get_capabilities(struct scsi_cd *cd) } kfree(buffer); + return 0; } /* @@ -985,31 +932,54 @@ static int sr_packet(struct cdrom_device_info *cdi, return cgc->stat; } -/** - * sr_kref_release - Called to free the scsi_cd structure - * @kref: pointer to embedded kref - * - * sr_ref_mutex must be held entering this routine. Because it is - * called on last put, you should always use the scsi_cd_get() - * scsi_cd_put() helpers which manipulate the semaphore directly - * and never do a direct kref_put(). - **/ -static void sr_kref_release(struct kref *kref) +static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf, + u32 lba, u32 nr, u8 *last_sense) { - struct scsi_cd *cd = container_of(kref, struct scsi_cd, kref); - struct gendisk *disk = cd->disk; - - spin_lock(&sr_index_lock); - clear_bit(MINOR(disk_devt(disk)), sr_index_bits); - spin_unlock(&sr_index_lock); - - unregister_cdrom(&cd->cdi); + struct gendisk *disk = cdi->disk; + u32 len = nr * CD_FRAMESIZE_RAW; + struct scsi_cmnd *scmd; + struct request *rq; + struct bio *bio; + int ret; - disk->private_data = NULL; + rq = scsi_alloc_request(disk->queue, REQ_OP_DRV_IN, 0); + if (IS_ERR(rq)) + return PTR_ERR(rq); + scmd = blk_mq_rq_to_pdu(rq); - put_disk(disk); + ret = blk_rq_map_user(disk->queue, rq, NULL, ubuf, len, GFP_KERNEL); + if (ret) + goto out_put_request; + + scmd->cmnd[0] = GPCMD_READ_CD; + scmd->cmnd[1] = 1 << 2; + scmd->cmnd[2] = (lba >> 24) & 0xff; + scmd->cmnd[3] = (lba >> 16) & 0xff; + scmd->cmnd[4] = (lba >> 8) & 0xff; + scmd->cmnd[5] = lba & 0xff; + scmd->cmnd[6] = (nr >> 16) & 0xff; + scmd->cmnd[7] = (nr >> 8) & 0xff; + scmd->cmnd[8] = nr & 0xff; + scmd->cmnd[9] = 0xf8; + scmd->cmd_len = 12; + rq->timeout = 60 * HZ; + bio = rq->bio; + + blk_execute_rq(rq, false); + if (scmd->result) { + struct scsi_sense_hdr sshdr; + + scsi_normalize_sense(scmd->sense_buffer, scmd->sense_len, + &sshdr); + *last_sense = sshdr.sense_key; + ret = -EIO; + } - kfree(cd); + if (blk_rq_unmap_user(bio)) + ret = -EFAULT; +out_put_request: + blk_mq_free_request(rq); + return ret; } static int sr_remove(struct device *dev) @@ -1019,11 +989,7 @@ static int sr_remove(struct device *dev) scsi_autopm_get_device(cd->device); del_gendisk(cd->disk); - dev_set_drvdata(dev, NULL); - - mutex_lock(&sr_ref_mutex); - kref_put(&cd->kref, sr_kref_release); - mutex_unlock(&sr_ref_mutex); + put_disk(cd->disk); return 0; } |
