18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * sr.c Copyright (C) 1992 David Giller 48c2ecf20Sopenharmony_ci * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * adapted from: 78c2ecf20Sopenharmony_ci * sd.c Copyright (C) 1992 Drew Eckhardt 88c2ecf20Sopenharmony_ci * Linux scsi disk driver by 98c2ecf20Sopenharmony_ci * Drew Eckhardt <drew@colorado.edu> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Modified by Eric Youngdale ericy@andante.org to 128c2ecf20Sopenharmony_ci * add scatter-gather, multiple outstanding request, and other 138c2ecf20Sopenharmony_ci * enhancements. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Modified by Eric Youngdale eric@andante.org to support loadable 168c2ecf20Sopenharmony_ci * low-level scsi drivers. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to 198c2ecf20Sopenharmony_ci * provide auto-eject. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Modified by Gerd Knorr <kraxel@cs.tu-berlin.de> to support the 228c2ecf20Sopenharmony_ci * generic cdrom interface 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Modified by Jens Axboe <axboe@suse.de> - Uniform sr_packet() 258c2ecf20Sopenharmony_ci * interface, capabilities probe additions, ioctl cleanups, etc. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Modified by Richard Gooch <rgooch@atnf.csiro.au> to support devfs 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * Modified by Jens Axboe <axboe@suse.de> - support DVD-RAM 308c2ecf20Sopenharmony_ci * transparently and lose the GHOST hack 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Modified by Arnaldo Carvalho de Melo <acme@conectiva.com.br> 338c2ecf20Sopenharmony_ci * check resource allocation in sr_init and some cleanups 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/module.h> 378c2ecf20Sopenharmony_ci#include <linux/fs.h> 388c2ecf20Sopenharmony_ci#include <linux/kernel.h> 398c2ecf20Sopenharmony_ci#include <linux/mm.h> 408c2ecf20Sopenharmony_ci#include <linux/bio.h> 418c2ecf20Sopenharmony_ci#include <linux/compat.h> 428c2ecf20Sopenharmony_ci#include <linux/string.h> 438c2ecf20Sopenharmony_ci#include <linux/errno.h> 448c2ecf20Sopenharmony_ci#include <linux/cdrom.h> 458c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 468c2ecf20Sopenharmony_ci#include <linux/init.h> 478c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 488c2ecf20Sopenharmony_ci#include <linux/blk-pm.h> 498c2ecf20Sopenharmony_ci#include <linux/mutex.h> 508c2ecf20Sopenharmony_ci#include <linux/slab.h> 518c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 528c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 578c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 588c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 598c2ecf20Sopenharmony_ci#include <scsi/scsi_driver.h> 608c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 618c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h> 628c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 638c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h> /* For the door lock/unlock commands */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#include "scsi_logging.h" 668c2ecf20Sopenharmony_ci#include "sr.h" 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SCSI cdrom (sr) driver"); 708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 718c2ecf20Sopenharmony_ciMODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR); 728c2ecf20Sopenharmony_ciMODULE_ALIAS_SCSI_DEVICE(TYPE_ROM); 738c2ecf20Sopenharmony_ciMODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define SR_DISKS 256 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define SR_CAPABILITIES \ 788c2ecf20Sopenharmony_ci (CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \ 798c2ecf20Sopenharmony_ci CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \ 808c2ecf20Sopenharmony_ci CDC_PLAY_AUDIO|CDC_RESET|CDC_DRIVE_STATUS| \ 818c2ecf20Sopenharmony_ci CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ 828c2ecf20Sopenharmony_ci CDC_MRW|CDC_MRW_W|CDC_RAM) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int sr_probe(struct device *); 858c2ecf20Sopenharmony_cistatic int sr_remove(struct device *); 868c2ecf20Sopenharmony_cistatic blk_status_t sr_init_command(struct scsi_cmnd *SCpnt); 878c2ecf20Sopenharmony_cistatic int sr_done(struct scsi_cmnd *); 888c2ecf20Sopenharmony_cistatic int sr_runtime_suspend(struct device *dev); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sr_pm_ops = { 918c2ecf20Sopenharmony_ci .runtime_suspend = sr_runtime_suspend, 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic struct scsi_driver sr_template = { 958c2ecf20Sopenharmony_ci .gendrv = { 968c2ecf20Sopenharmony_ci .name = "sr", 978c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 988c2ecf20Sopenharmony_ci .probe = sr_probe, 998c2ecf20Sopenharmony_ci .remove = sr_remove, 1008c2ecf20Sopenharmony_ci .pm = &sr_pm_ops, 1018c2ecf20Sopenharmony_ci }, 1028c2ecf20Sopenharmony_ci .init_command = sr_init_command, 1038c2ecf20Sopenharmony_ci .done = sr_done, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG]; 1078c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(sr_index_lock); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* This semaphore is used to mediate the 0->1 reference get in the 1108c2ecf20Sopenharmony_ci * face of object destruction (i.e. we can't allow a get on an 1118c2ecf20Sopenharmony_ci * object after last put) */ 1128c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(sr_ref_mutex); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int sr_open(struct cdrom_device_info *, int); 1158c2ecf20Sopenharmony_cistatic void sr_release(struct cdrom_device_info *); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void get_sectorsize(struct scsi_cd *); 1188c2ecf20Sopenharmony_cistatic void get_capabilities(struct scsi_cd *); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic unsigned int sr_check_events(struct cdrom_device_info *cdi, 1218c2ecf20Sopenharmony_ci unsigned int clearing, int slot); 1228c2ecf20Sopenharmony_cistatic int sr_packet(struct cdrom_device_info *, struct packet_command *); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic const struct cdrom_device_ops sr_dops = { 1258c2ecf20Sopenharmony_ci .open = sr_open, 1268c2ecf20Sopenharmony_ci .release = sr_release, 1278c2ecf20Sopenharmony_ci .drive_status = sr_drive_status, 1288c2ecf20Sopenharmony_ci .check_events = sr_check_events, 1298c2ecf20Sopenharmony_ci .tray_move = sr_tray_move, 1308c2ecf20Sopenharmony_ci .lock_door = sr_lock_door, 1318c2ecf20Sopenharmony_ci .select_speed = sr_select_speed, 1328c2ecf20Sopenharmony_ci .get_last_session = sr_get_last_session, 1338c2ecf20Sopenharmony_ci .get_mcn = sr_get_mcn, 1348c2ecf20Sopenharmony_ci .reset = sr_reset, 1358c2ecf20Sopenharmony_ci .audio_ioctl = sr_audio_ioctl, 1368c2ecf20Sopenharmony_ci .capability = SR_CAPABILITIES, 1378c2ecf20Sopenharmony_ci .generic_packet = sr_packet, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void sr_kref_release(struct kref *kref); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline struct scsi_cd *scsi_cd(struct gendisk *disk) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return container_of(disk->private_data, struct scsi_cd, driver); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int sr_runtime_suspend(struct device *dev) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct scsi_cd *cd = dev_get_drvdata(dev); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (!cd) /* E.g.: runtime suspend following sr_remove() */ 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (cd->media_present) 1558c2ecf20Sopenharmony_ci return -EBUSY; 1568c2ecf20Sopenharmony_ci else 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* 1618c2ecf20Sopenharmony_ci * The get and put routines for the struct scsi_cd. Note this entity 1628c2ecf20Sopenharmony_ci * has a scsi_device pointer and owns a reference to this. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_cistatic inline struct scsi_cd *scsi_cd_get(struct gendisk *disk) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct scsi_cd *cd = NULL; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mutex_lock(&sr_ref_mutex); 1698c2ecf20Sopenharmony_ci if (disk->private_data == NULL) 1708c2ecf20Sopenharmony_ci goto out; 1718c2ecf20Sopenharmony_ci cd = scsi_cd(disk); 1728c2ecf20Sopenharmony_ci kref_get(&cd->kref); 1738c2ecf20Sopenharmony_ci if (scsi_device_get(cd->device)) { 1748c2ecf20Sopenharmony_ci kref_put(&cd->kref, sr_kref_release); 1758c2ecf20Sopenharmony_ci cd = NULL; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci out: 1788c2ecf20Sopenharmony_ci mutex_unlock(&sr_ref_mutex); 1798c2ecf20Sopenharmony_ci return cd; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cistatic void scsi_cd_put(struct scsi_cd *cd) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct scsi_device *sdev = cd->device; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci mutex_lock(&sr_ref_mutex); 1878c2ecf20Sopenharmony_ci kref_put(&cd->kref, sr_kref_release); 1888c2ecf20Sopenharmony_ci scsi_device_put(sdev); 1898c2ecf20Sopenharmony_ci mutex_unlock(&sr_ref_mutex); 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic unsigned int sr_get_events(struct scsi_device *sdev) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci u8 buf[8]; 1958c2ecf20Sopenharmony_ci u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION, 1968c2ecf20Sopenharmony_ci 1, /* polled */ 1978c2ecf20Sopenharmony_ci 0, 0, /* reserved */ 1988c2ecf20Sopenharmony_ci 1 << 4, /* notification class: media */ 1998c2ecf20Sopenharmony_ci 0, 0, /* reserved */ 2008c2ecf20Sopenharmony_ci 0, sizeof(buf), /* allocation length */ 2018c2ecf20Sopenharmony_ci 0, /* control */ 2028c2ecf20Sopenharmony_ci }; 2038c2ecf20Sopenharmony_ci struct event_header *eh = (void *)buf; 2048c2ecf20Sopenharmony_ci struct media_event_desc *med = (void *)(buf + 4); 2058c2ecf20Sopenharmony_ci struct scsi_sense_hdr sshdr; 2068c2ecf20Sopenharmony_ci int result; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf), 2098c2ecf20Sopenharmony_ci &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL); 2108c2ecf20Sopenharmony_ci if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) 2118c2ecf20Sopenharmony_ci return DISK_EVENT_MEDIA_CHANGE; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (eh->nea || eh->notification_class != 0x4) 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (med->media_event_code == 1) 2208c2ecf20Sopenharmony_ci return DISK_EVENT_EJECT_REQUEST; 2218c2ecf20Sopenharmony_ci else if (med->media_event_code == 2) 2228c2ecf20Sopenharmony_ci return DISK_EVENT_MEDIA_CHANGE; 2238c2ecf20Sopenharmony_ci else if (med->media_event_code == 3) 2248c2ecf20Sopenharmony_ci return DISK_EVENT_MEDIA_CHANGE; 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* 2298c2ecf20Sopenharmony_ci * This function checks to see if the media has been changed or eject 2308c2ecf20Sopenharmony_ci * button has been pressed. It is possible that we have already 2318c2ecf20Sopenharmony_ci * sensed a change, or the drive may have sensed one and not yet 2328c2ecf20Sopenharmony_ci * reported it. The past events are accumulated in sdev->changed and 2338c2ecf20Sopenharmony_ci * returned together with the current state. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_cistatic unsigned int sr_check_events(struct cdrom_device_info *cdi, 2368c2ecf20Sopenharmony_ci unsigned int clearing, int slot) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 2398c2ecf20Sopenharmony_ci bool last_present; 2408c2ecf20Sopenharmony_ci struct scsi_sense_hdr sshdr; 2418c2ecf20Sopenharmony_ci unsigned int events; 2428c2ecf20Sopenharmony_ci int ret; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* no changer support */ 2458c2ecf20Sopenharmony_ci if (CDSL_CURRENT != slot) 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci events = sr_get_events(cd->device); 2498c2ecf20Sopenharmony_ci cd->get_event_changed |= events & DISK_EVENT_MEDIA_CHANGE; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * If earlier GET_EVENT_STATUS_NOTIFICATION and TUR did not agree 2538c2ecf20Sopenharmony_ci * for several times in a row. We rely on TUR only for this likely 2548c2ecf20Sopenharmony_ci * broken device, to prevent generating incorrect media changed 2558c2ecf20Sopenharmony_ci * events for every open(). 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci if (cd->ignore_get_event) { 2588c2ecf20Sopenharmony_ci events &= ~DISK_EVENT_MEDIA_CHANGE; 2598c2ecf20Sopenharmony_ci goto do_tur; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* 2638c2ecf20Sopenharmony_ci * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE 2648c2ecf20Sopenharmony_ci * is being cleared. Note that there are devices which hang 2658c2ecf20Sopenharmony_ci * if asked to execute TUR repeatedly. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci if (cd->device->changed) { 2688c2ecf20Sopenharmony_ci events |= DISK_EVENT_MEDIA_CHANGE; 2698c2ecf20Sopenharmony_ci cd->device->changed = 0; 2708c2ecf20Sopenharmony_ci cd->tur_changed = true; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) 2748c2ecf20Sopenharmony_ci return events; 2758c2ecf20Sopenharmony_cido_tur: 2768c2ecf20Sopenharmony_ci /* let's see whether the media is there with TUR */ 2778c2ecf20Sopenharmony_ci last_present = cd->media_present; 2788c2ecf20Sopenharmony_ci ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * Media is considered to be present if TUR succeeds or fails with 2828c2ecf20Sopenharmony_ci * sense data indicating something other than media-not-present 2838c2ecf20Sopenharmony_ci * (ASC 0x3a). 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci cd->media_present = scsi_status_is_good(ret) || 2868c2ecf20Sopenharmony_ci (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (last_present != cd->media_present) 2898c2ecf20Sopenharmony_ci cd->device->changed = 1; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (cd->device->changed) { 2928c2ecf20Sopenharmony_ci events |= DISK_EVENT_MEDIA_CHANGE; 2938c2ecf20Sopenharmony_ci cd->device->changed = 0; 2948c2ecf20Sopenharmony_ci cd->tur_changed = true; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (cd->ignore_get_event) 2988c2ecf20Sopenharmony_ci return events; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* check whether GET_EVENT is reporting spurious MEDIA_CHANGE */ 3018c2ecf20Sopenharmony_ci if (!cd->tur_changed) { 3028c2ecf20Sopenharmony_ci if (cd->get_event_changed) { 3038c2ecf20Sopenharmony_ci if (cd->tur_mismatch++ > 8) { 3048c2ecf20Sopenharmony_ci sr_printk(KERN_WARNING, cd, 3058c2ecf20Sopenharmony_ci "GET_EVENT and TUR disagree continuously, suppress GET_EVENT events\n"); 3068c2ecf20Sopenharmony_ci cd->ignore_get_event = true; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci } else { 3098c2ecf20Sopenharmony_ci cd->tur_mismatch = 0; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci cd->tur_changed = false; 3138c2ecf20Sopenharmony_ci cd->get_event_changed = false; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return events; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/* 3198c2ecf20Sopenharmony_ci * sr_done is the interrupt routine for the device driver. 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * It will be notified on the end of a SCSI read / write, and will take one 3228c2ecf20Sopenharmony_ci * of several actions based on success or failure. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_cistatic int sr_done(struct scsi_cmnd *SCpnt) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci int result = SCpnt->result; 3278c2ecf20Sopenharmony_ci int this_count = scsi_bufflen(SCpnt); 3288c2ecf20Sopenharmony_ci int good_bytes = (result == 0 ? this_count : 0); 3298c2ecf20Sopenharmony_ci int block_sectors = 0; 3308c2ecf20Sopenharmony_ci long error_sector; 3318c2ecf20Sopenharmony_ci struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci#ifdef DEBUG 3348c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, SCpnt, "done: %x\n", result); 3358c2ecf20Sopenharmony_ci#endif 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* 3388c2ecf20Sopenharmony_ci * Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial 3398c2ecf20Sopenharmony_ci * success. Since this is a relatively rare error condition, no 3408c2ecf20Sopenharmony_ci * care is taken to avoid unnecessary additional work such as 3418c2ecf20Sopenharmony_ci * memcpy's that could be avoided. 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci if (driver_byte(result) != 0 && /* An error occurred */ 3448c2ecf20Sopenharmony_ci (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */ 3458c2ecf20Sopenharmony_ci switch (SCpnt->sense_buffer[2]) { 3468c2ecf20Sopenharmony_ci case MEDIUM_ERROR: 3478c2ecf20Sopenharmony_ci case VOLUME_OVERFLOW: 3488c2ecf20Sopenharmony_ci case ILLEGAL_REQUEST: 3498c2ecf20Sopenharmony_ci if (!(SCpnt->sense_buffer[0] & 0x90)) 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci error_sector = 3528c2ecf20Sopenharmony_ci get_unaligned_be32(&SCpnt->sense_buffer[3]); 3538c2ecf20Sopenharmony_ci if (SCpnt->request->bio != NULL) 3548c2ecf20Sopenharmony_ci block_sectors = 3558c2ecf20Sopenharmony_ci bio_sectors(SCpnt->request->bio); 3568c2ecf20Sopenharmony_ci if (block_sectors < 4) 3578c2ecf20Sopenharmony_ci block_sectors = 4; 3588c2ecf20Sopenharmony_ci if (cd->device->sector_size == 2048) 3598c2ecf20Sopenharmony_ci error_sector <<= 2; 3608c2ecf20Sopenharmony_ci error_sector &= ~(block_sectors - 1); 3618c2ecf20Sopenharmony_ci good_bytes = (error_sector - 3628c2ecf20Sopenharmony_ci blk_rq_pos(SCpnt->request)) << 9; 3638c2ecf20Sopenharmony_ci if (good_bytes < 0 || good_bytes >= this_count) 3648c2ecf20Sopenharmony_ci good_bytes = 0; 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * The SCSI specification allows for the value 3678c2ecf20Sopenharmony_ci * returned by READ CAPACITY to be up to 75 2K 3688c2ecf20Sopenharmony_ci * sectors past the last readable block. 3698c2ecf20Sopenharmony_ci * Therefore, if we hit a medium error within the 3708c2ecf20Sopenharmony_ci * last 75 2K sectors, we decrease the saved size 3718c2ecf20Sopenharmony_ci * value. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci if (error_sector < get_capacity(cd->disk) && 3748c2ecf20Sopenharmony_ci cd->capacity - error_sector < 4 * 75) 3758c2ecf20Sopenharmony_ci set_capacity(cd->disk, error_sector); 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci case RECOVERED_ERROR: 3798c2ecf20Sopenharmony_ci good_bytes = this_count; 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci default: 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return good_bytes; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic blk_status_t sr_init_command(struct scsi_cmnd *SCpnt) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int block = 0, this_count, s_size; 3938c2ecf20Sopenharmony_ci struct scsi_cd *cd; 3948c2ecf20Sopenharmony_ci struct request *rq = SCpnt->request; 3958c2ecf20Sopenharmony_ci blk_status_t ret; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci ret = scsi_alloc_sgtables(SCpnt); 3988c2ecf20Sopenharmony_ci if (ret != BLK_STS_OK) 3998c2ecf20Sopenharmony_ci return ret; 4008c2ecf20Sopenharmony_ci cd = scsi_cd(rq->rq_disk); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt, 4038c2ecf20Sopenharmony_ci "Doing sr request, block = %d\n", block)); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (!cd->device || !scsi_device_online(cd->device)) { 4068c2ecf20Sopenharmony_ci SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, 4078c2ecf20Sopenharmony_ci "Finishing %u sectors\n", blk_rq_sectors(rq))); 4088c2ecf20Sopenharmony_ci SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, 4098c2ecf20Sopenharmony_ci "Retry with 0x%p\n", SCpnt)); 4108c2ecf20Sopenharmony_ci goto out; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (cd->device->changed) { 4148c2ecf20Sopenharmony_ci /* 4158c2ecf20Sopenharmony_ci * quietly refuse to do anything to a changed disc until the 4168c2ecf20Sopenharmony_ci * changed bit has been reset 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci goto out; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* 4228c2ecf20Sopenharmony_ci * we do lazy blocksize switching (when reading XA sectors, 4238c2ecf20Sopenharmony_ci * see CDROMREADMODE2 ioctl) 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci s_size = cd->device->sector_size; 4268c2ecf20Sopenharmony_ci if (s_size > 2048) { 4278c2ecf20Sopenharmony_ci if (!in_interrupt()) 4288c2ecf20Sopenharmony_ci sr_set_blocklength(cd, 2048); 4298c2ecf20Sopenharmony_ci else 4308c2ecf20Sopenharmony_ci scmd_printk(KERN_INFO, SCpnt, 4318c2ecf20Sopenharmony_ci "can't switch blocksize: in interrupt\n"); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (s_size != 512 && s_size != 1024 && s_size != 2048) { 4358c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size); 4368c2ecf20Sopenharmony_ci goto out; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci switch (req_op(rq)) { 4408c2ecf20Sopenharmony_ci case REQ_OP_WRITE: 4418c2ecf20Sopenharmony_ci if (!cd->writeable) 4428c2ecf20Sopenharmony_ci goto out; 4438c2ecf20Sopenharmony_ci SCpnt->cmnd[0] = WRITE_10; 4448c2ecf20Sopenharmony_ci cd->cdi.media_written = 1; 4458c2ecf20Sopenharmony_ci break; 4468c2ecf20Sopenharmony_ci case REQ_OP_READ: 4478c2ecf20Sopenharmony_ci SCpnt->cmnd[0] = READ_10; 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci default: 4508c2ecf20Sopenharmony_ci blk_dump_rq_flags(rq, "Unknown sr command"); 4518c2ecf20Sopenharmony_ci goto out; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci { 4558c2ecf20Sopenharmony_ci struct scatterlist *sg; 4568c2ecf20Sopenharmony_ci int i, size = 0, sg_count = scsi_sg_count(SCpnt); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci scsi_for_each_sg(SCpnt, sg, sg_count, i) 4598c2ecf20Sopenharmony_ci size += sg->length; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (size != scsi_bufflen(SCpnt)) { 4628c2ecf20Sopenharmony_ci scmd_printk(KERN_ERR, SCpnt, 4638c2ecf20Sopenharmony_ci "mismatch count %d, bytes %d\n", 4648c2ecf20Sopenharmony_ci size, scsi_bufflen(SCpnt)); 4658c2ecf20Sopenharmony_ci if (scsi_bufflen(SCpnt) > size) 4668c2ecf20Sopenharmony_ci SCpnt->sdb.length = size; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* 4718c2ecf20Sopenharmony_ci * request doesn't start on hw block boundary, add scatter pads 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci if (((unsigned int)blk_rq_pos(rq) % (s_size >> 9)) || 4748c2ecf20Sopenharmony_ci (scsi_bufflen(SCpnt) % s_size)) { 4758c2ecf20Sopenharmony_ci scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n"); 4768c2ecf20Sopenharmony_ci goto out; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci this_count = (scsi_bufflen(SCpnt) >> 9) / (s_size >> 9); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, 4838c2ecf20Sopenharmony_ci "%s %d/%u 512 byte blocks.\n", 4848c2ecf20Sopenharmony_ci (rq_data_dir(rq) == WRITE) ? 4858c2ecf20Sopenharmony_ci "writing" : "reading", 4868c2ecf20Sopenharmony_ci this_count, blk_rq_sectors(rq))); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci SCpnt->cmnd[1] = 0; 4898c2ecf20Sopenharmony_ci block = (unsigned int)blk_rq_pos(rq) / (s_size >> 9); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (this_count > 0xffff) { 4928c2ecf20Sopenharmony_ci this_count = 0xffff; 4938c2ecf20Sopenharmony_ci SCpnt->sdb.length = this_count * s_size; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci put_unaligned_be32(block, &SCpnt->cmnd[2]); 4978c2ecf20Sopenharmony_ci SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0; 4988c2ecf20Sopenharmony_ci put_unaligned_be16(this_count, &SCpnt->cmnd[7]); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* 5018c2ecf20Sopenharmony_ci * We shouldn't disconnect in the middle of a sector, so with a dumb 5028c2ecf20Sopenharmony_ci * host adapter, it's safe to assume that we can at least transfer 5038c2ecf20Sopenharmony_ci * this many bytes between each connect / disconnect. 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci SCpnt->transfersize = cd->device->sector_size; 5068c2ecf20Sopenharmony_ci SCpnt->underflow = this_count << 9; 5078c2ecf20Sopenharmony_ci SCpnt->allowed = MAX_RETRIES; 5088c2ecf20Sopenharmony_ci SCpnt->cmd_len = 10; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* 5118c2ecf20Sopenharmony_ci * This indicates that the command is ready from our end to be queued. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci return BLK_STS_OK; 5148c2ecf20Sopenharmony_ci out: 5158c2ecf20Sopenharmony_ci scsi_free_sgtables(SCpnt); 5168c2ecf20Sopenharmony_ci return BLK_STS_IOERR; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic void sr_revalidate_disk(struct scsi_cd *cd) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct scsi_sense_hdr sshdr; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* if the unit is not ready, nothing more to do */ 5248c2ecf20Sopenharmony_ci if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) 5258c2ecf20Sopenharmony_ci return; 5268c2ecf20Sopenharmony_ci sr_cd_check(&cd->cdi); 5278c2ecf20Sopenharmony_ci get_sectorsize(cd); 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int sr_block_open(struct block_device *bdev, fmode_t mode) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct scsi_cd *cd; 5338c2ecf20Sopenharmony_ci struct scsi_device *sdev; 5348c2ecf20Sopenharmony_ci int ret = -ENXIO; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci cd = scsi_cd_get(bdev->bd_disk); 5378c2ecf20Sopenharmony_ci if (!cd) 5388c2ecf20Sopenharmony_ci goto out; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci sdev = cd->device; 5418c2ecf20Sopenharmony_ci scsi_autopm_get_device(sdev); 5428c2ecf20Sopenharmony_ci if (bdev_check_media_change(bdev)) 5438c2ecf20Sopenharmony_ci sr_revalidate_disk(cd); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci mutex_lock(&cd->lock); 5468c2ecf20Sopenharmony_ci ret = cdrom_open(&cd->cdi, bdev, mode); 5478c2ecf20Sopenharmony_ci mutex_unlock(&cd->lock); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci scsi_autopm_put_device(sdev); 5508c2ecf20Sopenharmony_ci if (ret) 5518c2ecf20Sopenharmony_ci scsi_cd_put(cd); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ciout: 5548c2ecf20Sopenharmony_ci return ret; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic void sr_block_release(struct gendisk *disk, fmode_t mode) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct scsi_cd *cd = scsi_cd(disk); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci mutex_lock(&cd->lock); 5628c2ecf20Sopenharmony_ci cdrom_release(&cd->cdi, mode); 5638c2ecf20Sopenharmony_ci mutex_unlock(&cd->lock); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci scsi_cd_put(cd); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, 5698c2ecf20Sopenharmony_ci unsigned long arg) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct scsi_cd *cd = scsi_cd(bdev->bd_disk); 5728c2ecf20Sopenharmony_ci struct scsi_device *sdev = cd->device; 5738c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 5748c2ecf20Sopenharmony_ci int ret; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci mutex_lock(&cd->lock); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, 5798c2ecf20Sopenharmony_ci (mode & FMODE_NDELAY) != 0); 5808c2ecf20Sopenharmony_ci if (ret) 5818c2ecf20Sopenharmony_ci goto out; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci scsi_autopm_get_device(sdev); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * Send SCSI addressing ioctls directly to mid level, send other 5878c2ecf20Sopenharmony_ci * ioctls to cdrom/block level. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci switch (cmd) { 5908c2ecf20Sopenharmony_ci case SCSI_IOCTL_GET_IDLUN: 5918c2ecf20Sopenharmony_ci case SCSI_IOCTL_GET_BUS_NUMBER: 5928c2ecf20Sopenharmony_ci ret = scsi_ioctl(sdev, cmd, argp); 5938c2ecf20Sopenharmony_ci goto put; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); 5978c2ecf20Sopenharmony_ci if (ret != -ENOSYS) 5988c2ecf20Sopenharmony_ci goto put; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci ret = scsi_ioctl(sdev, cmd, argp); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ciput: 6038c2ecf20Sopenharmony_ci scsi_autopm_put_device(sdev); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ciout: 6068c2ecf20Sopenharmony_ci mutex_unlock(&cd->lock); 6078c2ecf20Sopenharmony_ci return ret; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 6118c2ecf20Sopenharmony_cistatic int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, 6128c2ecf20Sopenharmony_ci unsigned long arg) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct scsi_cd *cd = scsi_cd(bdev->bd_disk); 6158c2ecf20Sopenharmony_ci struct scsi_device *sdev = cd->device; 6168c2ecf20Sopenharmony_ci void __user *argp = compat_ptr(arg); 6178c2ecf20Sopenharmony_ci int ret; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci mutex_lock(&cd->lock); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, 6228c2ecf20Sopenharmony_ci (mode & FMODE_NDELAY) != 0); 6238c2ecf20Sopenharmony_ci if (ret) 6248c2ecf20Sopenharmony_ci goto out; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci scsi_autopm_get_device(sdev); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* 6298c2ecf20Sopenharmony_ci * Send SCSI addressing ioctls directly to mid level, send other 6308c2ecf20Sopenharmony_ci * ioctls to cdrom/block level. 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci switch (cmd) { 6338c2ecf20Sopenharmony_ci case SCSI_IOCTL_GET_IDLUN: 6348c2ecf20Sopenharmony_ci case SCSI_IOCTL_GET_BUS_NUMBER: 6358c2ecf20Sopenharmony_ci ret = scsi_compat_ioctl(sdev, cmd, argp); 6368c2ecf20Sopenharmony_ci goto put; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, (unsigned long)argp); 6408c2ecf20Sopenharmony_ci if (ret != -ENOSYS) 6418c2ecf20Sopenharmony_ci goto put; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci ret = scsi_compat_ioctl(sdev, cmd, argp); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ciput: 6468c2ecf20Sopenharmony_ci scsi_autopm_put_device(sdev); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ciout: 6498c2ecf20Sopenharmony_ci mutex_unlock(&cd->lock); 6508c2ecf20Sopenharmony_ci return ret; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci#endif 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic unsigned int sr_block_check_events(struct gendisk *disk, 6568c2ecf20Sopenharmony_ci unsigned int clearing) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci unsigned int ret = 0; 6598c2ecf20Sopenharmony_ci struct scsi_cd *cd; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci cd = scsi_cd_get(disk); 6628c2ecf20Sopenharmony_ci if (!cd) 6638c2ecf20Sopenharmony_ci return 0; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (!atomic_read(&cd->device->disk_events_disable_depth)) 6668c2ecf20Sopenharmony_ci ret = cdrom_check_events(&cd->cdi, clearing); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci scsi_cd_put(cd); 6698c2ecf20Sopenharmony_ci return ret; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic const struct block_device_operations sr_bdops = 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 6758c2ecf20Sopenharmony_ci .open = sr_block_open, 6768c2ecf20Sopenharmony_ci .release = sr_block_release, 6778c2ecf20Sopenharmony_ci .ioctl = sr_block_ioctl, 6788c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 6798c2ecf20Sopenharmony_ci .compat_ioctl = sr_block_compat_ioctl, 6808c2ecf20Sopenharmony_ci#endif 6818c2ecf20Sopenharmony_ci .check_events = sr_block_check_events, 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic int sr_open(struct cdrom_device_info *cdi, int purpose) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 6878c2ecf20Sopenharmony_ci struct scsi_device *sdev = cd->device; 6888c2ecf20Sopenharmony_ci int retval; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * If the device is in error recovery, wait until it is done. 6928c2ecf20Sopenharmony_ci * If the device is offline, then disallow any access to it. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_ci retval = -ENXIO; 6958c2ecf20Sopenharmony_ci if (!scsi_block_when_processing_errors(sdev)) 6968c2ecf20Sopenharmony_ci goto error_out; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cierror_out: 7018c2ecf20Sopenharmony_ci return retval; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void sr_release(struct cdrom_device_info *cdi) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (cd->device->sector_size > 2048) 7098c2ecf20Sopenharmony_ci sr_set_blocklength(cd, 2048); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic int sr_probe(struct device *dev) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 7168c2ecf20Sopenharmony_ci struct gendisk *disk; 7178c2ecf20Sopenharmony_ci struct scsi_cd *cd; 7188c2ecf20Sopenharmony_ci int minor, error; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci scsi_autopm_get_device(sdev); 7218c2ecf20Sopenharmony_ci error = -ENODEV; 7228c2ecf20Sopenharmony_ci if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM) 7238c2ecf20Sopenharmony_ci goto fail; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci error = -ENOMEM; 7268c2ecf20Sopenharmony_ci cd = kzalloc(sizeof(*cd), GFP_KERNEL); 7278c2ecf20Sopenharmony_ci if (!cd) 7288c2ecf20Sopenharmony_ci goto fail; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci kref_init(&cd->kref); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci disk = alloc_disk(1); 7338c2ecf20Sopenharmony_ci if (!disk) 7348c2ecf20Sopenharmony_ci goto fail_free; 7358c2ecf20Sopenharmony_ci mutex_init(&cd->lock); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci spin_lock(&sr_index_lock); 7388c2ecf20Sopenharmony_ci minor = find_first_zero_bit(sr_index_bits, SR_DISKS); 7398c2ecf20Sopenharmony_ci if (minor == SR_DISKS) { 7408c2ecf20Sopenharmony_ci spin_unlock(&sr_index_lock); 7418c2ecf20Sopenharmony_ci error = -EBUSY; 7428c2ecf20Sopenharmony_ci goto fail_put; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci __set_bit(minor, sr_index_bits); 7458c2ecf20Sopenharmony_ci spin_unlock(&sr_index_lock); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci disk->major = SCSI_CDROM_MAJOR; 7488c2ecf20Sopenharmony_ci disk->first_minor = minor; 7498c2ecf20Sopenharmony_ci sprintf(disk->disk_name, "sr%d", minor); 7508c2ecf20Sopenharmony_ci disk->fops = &sr_bdops; 7518c2ecf20Sopenharmony_ci disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; 7528c2ecf20Sopenharmony_ci disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; 7538c2ecf20Sopenharmony_ci disk->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci cd->device = sdev; 7588c2ecf20Sopenharmony_ci cd->disk = disk; 7598c2ecf20Sopenharmony_ci cd->driver = &sr_template; 7608c2ecf20Sopenharmony_ci cd->disk = disk; 7618c2ecf20Sopenharmony_ci cd->capacity = 0x1fffff; 7628c2ecf20Sopenharmony_ci cd->device->changed = 1; /* force recheck CD type */ 7638c2ecf20Sopenharmony_ci cd->media_present = 1; 7648c2ecf20Sopenharmony_ci cd->use = 1; 7658c2ecf20Sopenharmony_ci cd->readcd_known = 0; 7668c2ecf20Sopenharmony_ci cd->readcd_cdda = 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci cd->cdi.ops = &sr_dops; 7698c2ecf20Sopenharmony_ci cd->cdi.handle = cd; 7708c2ecf20Sopenharmony_ci cd->cdi.mask = 0; 7718c2ecf20Sopenharmony_ci cd->cdi.capacity = 1; 7728c2ecf20Sopenharmony_ci sprintf(cd->cdi.name, "sr%d", minor); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci sdev->sector_size = 2048; /* A guess, just in case */ 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* FIXME: need to handle a get_capabilities failure properly ?? */ 7778c2ecf20Sopenharmony_ci get_capabilities(cd); 7788c2ecf20Sopenharmony_ci sr_vendor_init(cd); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci set_capacity(disk, cd->capacity); 7818c2ecf20Sopenharmony_ci disk->private_data = &cd->driver; 7828c2ecf20Sopenharmony_ci disk->queue = sdev->request_queue; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (register_cdrom(disk, &cd->cdi)) 7858c2ecf20Sopenharmony_ci goto fail_minor; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* 7888c2ecf20Sopenharmony_ci * Initialize block layer runtime PM stuffs before the 7898c2ecf20Sopenharmony_ci * periodic event checking request gets started in add_disk. 7908c2ecf20Sopenharmony_ci */ 7918c2ecf20Sopenharmony_ci blk_pm_runtime_init(sdev->request_queue, dev); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci dev_set_drvdata(dev, cd); 7948c2ecf20Sopenharmony_ci disk->flags |= GENHD_FL_REMOVABLE; 7958c2ecf20Sopenharmony_ci sr_revalidate_disk(cd); 7968c2ecf20Sopenharmony_ci device_add_disk(&sdev->sdev_gendev, disk, NULL); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci sdev_printk(KERN_DEBUG, sdev, 7998c2ecf20Sopenharmony_ci "Attached scsi CD-ROM %s\n", cd->cdi.name); 8008c2ecf20Sopenharmony_ci scsi_autopm_put_device(cd->device); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci return 0; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cifail_minor: 8058c2ecf20Sopenharmony_ci spin_lock(&sr_index_lock); 8068c2ecf20Sopenharmony_ci clear_bit(minor, sr_index_bits); 8078c2ecf20Sopenharmony_ci spin_unlock(&sr_index_lock); 8088c2ecf20Sopenharmony_cifail_put: 8098c2ecf20Sopenharmony_ci put_disk(disk); 8108c2ecf20Sopenharmony_ci mutex_destroy(&cd->lock); 8118c2ecf20Sopenharmony_cifail_free: 8128c2ecf20Sopenharmony_ci kfree(cd); 8138c2ecf20Sopenharmony_cifail: 8148c2ecf20Sopenharmony_ci scsi_autopm_put_device(sdev); 8158c2ecf20Sopenharmony_ci return error; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic void get_sectorsize(struct scsi_cd *cd) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci unsigned char cmd[10]; 8228c2ecf20Sopenharmony_ci unsigned char buffer[8]; 8238c2ecf20Sopenharmony_ci int the_result, retries = 3; 8248c2ecf20Sopenharmony_ci int sector_size; 8258c2ecf20Sopenharmony_ci struct request_queue *queue; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci do { 8288c2ecf20Sopenharmony_ci cmd[0] = READ_CAPACITY; 8298c2ecf20Sopenharmony_ci memset((void *) &cmd[1], 0, 9); 8308c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(buffer)); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci /* Do the command and wait.. */ 8338c2ecf20Sopenharmony_ci the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, 8348c2ecf20Sopenharmony_ci buffer, sizeof(buffer), NULL, 8358c2ecf20Sopenharmony_ci SR_TIMEOUT, MAX_RETRIES, NULL); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci retries--; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci } while (the_result && retries); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (the_result) { 8438c2ecf20Sopenharmony_ci cd->capacity = 0x1fffff; 8448c2ecf20Sopenharmony_ci sector_size = 2048; /* A guess, just in case */ 8458c2ecf20Sopenharmony_ci } else { 8468c2ecf20Sopenharmony_ci long last_written; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci cd->capacity = 1 + get_unaligned_be32(&buffer[0]); 8498c2ecf20Sopenharmony_ci /* 8508c2ecf20Sopenharmony_ci * READ_CAPACITY doesn't return the correct size on 8518c2ecf20Sopenharmony_ci * certain UDF media. If last_written is larger, use 8528c2ecf20Sopenharmony_ci * it instead. 8538c2ecf20Sopenharmony_ci * 8548c2ecf20Sopenharmony_ci * http://bugzilla.kernel.org/show_bug.cgi?id=9668 8558c2ecf20Sopenharmony_ci */ 8568c2ecf20Sopenharmony_ci if (!cdrom_get_last_written(&cd->cdi, &last_written)) 8578c2ecf20Sopenharmony_ci cd->capacity = max_t(long, cd->capacity, last_written); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci sector_size = get_unaligned_be32(&buffer[4]); 8608c2ecf20Sopenharmony_ci switch (sector_size) { 8618c2ecf20Sopenharmony_ci /* 8628c2ecf20Sopenharmony_ci * HP 4020i CD-Recorder reports 2340 byte sectors 8638c2ecf20Sopenharmony_ci * Philips CD-Writers report 2352 byte sectors 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * Use 2k sectors for them.. 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci case 0: 8688c2ecf20Sopenharmony_ci case 2340: 8698c2ecf20Sopenharmony_ci case 2352: 8708c2ecf20Sopenharmony_ci sector_size = 2048; 8718c2ecf20Sopenharmony_ci fallthrough; 8728c2ecf20Sopenharmony_ci case 2048: 8738c2ecf20Sopenharmony_ci cd->capacity *= 4; 8748c2ecf20Sopenharmony_ci fallthrough; 8758c2ecf20Sopenharmony_ci case 512: 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci default: 8788c2ecf20Sopenharmony_ci sr_printk(KERN_INFO, cd, 8798c2ecf20Sopenharmony_ci "unsupported sector size %d.", sector_size); 8808c2ecf20Sopenharmony_ci cd->capacity = 0; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci cd->device->sector_size = sector_size; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* 8868c2ecf20Sopenharmony_ci * Add this so that we have the ability to correctly gauge 8878c2ecf20Sopenharmony_ci * what the device is capable of. 8888c2ecf20Sopenharmony_ci */ 8898c2ecf20Sopenharmony_ci set_capacity(cd->disk, cd->capacity); 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci queue = cd->device->request_queue; 8938c2ecf20Sopenharmony_ci blk_queue_logical_block_size(queue, sector_size); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void get_capabilities(struct scsi_cd *cd) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci unsigned char *buffer; 9018c2ecf20Sopenharmony_ci struct scsi_mode_data data; 9028c2ecf20Sopenharmony_ci struct scsi_sense_hdr sshdr; 9038c2ecf20Sopenharmony_ci unsigned int ms_len = 128; 9048c2ecf20Sopenharmony_ci int rc, n; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci static const char *loadmech[] = 9078c2ecf20Sopenharmony_ci { 9088c2ecf20Sopenharmony_ci "caddy", 9098c2ecf20Sopenharmony_ci "tray", 9108c2ecf20Sopenharmony_ci "pop-up", 9118c2ecf20Sopenharmony_ci "", 9128c2ecf20Sopenharmony_ci "changer", 9138c2ecf20Sopenharmony_ci "cartridge changer", 9148c2ecf20Sopenharmony_ci "", 9158c2ecf20Sopenharmony_ci "" 9168c2ecf20Sopenharmony_ci }; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* allocate transfer buffer */ 9208c2ecf20Sopenharmony_ci buffer = kmalloc(512, GFP_KERNEL); 9218c2ecf20Sopenharmony_ci if (!buffer) { 9228c2ecf20Sopenharmony_ci sr_printk(KERN_ERR, cd, "out of memory.\n"); 9238c2ecf20Sopenharmony_ci return; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* eat unit attentions */ 9278c2ecf20Sopenharmony_ci scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* ask for mode page 0x2a */ 9308c2ecf20Sopenharmony_ci rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len, 9318c2ecf20Sopenharmony_ci SR_TIMEOUT, 3, &data, NULL); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (rc < 0 || data.length > ms_len || 9348c2ecf20Sopenharmony_ci data.header_length + data.block_descriptor_length > data.length) { 9358c2ecf20Sopenharmony_ci /* failed, drive doesn't have capabilities mode page */ 9368c2ecf20Sopenharmony_ci cd->cdi.speed = 1; 9378c2ecf20Sopenharmony_ci cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R | 9388c2ecf20Sopenharmony_ci CDC_DVD | CDC_DVD_RAM | 9398c2ecf20Sopenharmony_ci CDC_SELECT_DISC | CDC_SELECT_SPEED | 9408c2ecf20Sopenharmony_ci CDC_MRW | CDC_MRW_W | CDC_RAM); 9418c2ecf20Sopenharmony_ci kfree(buffer); 9428c2ecf20Sopenharmony_ci sr_printk(KERN_INFO, cd, "scsi-1 drive"); 9438c2ecf20Sopenharmony_ci return; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci n = data.header_length + data.block_descriptor_length; 9478c2ecf20Sopenharmony_ci cd->cdi.speed = get_unaligned_be16(&buffer[n + 8]) / 176; 9488c2ecf20Sopenharmony_ci cd->readcd_known = 1; 9498c2ecf20Sopenharmony_ci cd->readcd_cdda = buffer[n + 5] & 0x01; 9508c2ecf20Sopenharmony_ci /* print some capability bits */ 9518c2ecf20Sopenharmony_ci sr_printk(KERN_INFO, cd, 9528c2ecf20Sopenharmony_ci "scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", 9538c2ecf20Sopenharmony_ci get_unaligned_be16(&buffer[n + 14]) / 176, 9548c2ecf20Sopenharmony_ci cd->cdi.speed, 9558c2ecf20Sopenharmony_ci buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */ 9568c2ecf20Sopenharmony_ci buffer[n + 3] & 0x20 ? "dvd-ram " : "", 9578c2ecf20Sopenharmony_ci buffer[n + 2] & 0x02 ? "cd/rw " : "", /* can read rewriteable */ 9588c2ecf20Sopenharmony_ci buffer[n + 4] & 0x20 ? "xa/form2 " : "", /* can read xa/from2 */ 9598c2ecf20Sopenharmony_ci buffer[n + 5] & 0x01 ? "cdda " : "", /* can read audio data */ 9608c2ecf20Sopenharmony_ci loadmech[buffer[n + 6] >> 5]); 9618c2ecf20Sopenharmony_ci if ((buffer[n + 6] >> 5) == 0) 9628c2ecf20Sopenharmony_ci /* caddy drives can't close tray... */ 9638c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_CLOSE_TRAY; 9648c2ecf20Sopenharmony_ci if ((buffer[n + 2] & 0x8) == 0) 9658c2ecf20Sopenharmony_ci /* not a DVD drive */ 9668c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_DVD; 9678c2ecf20Sopenharmony_ci if ((buffer[n + 3] & 0x20) == 0) 9688c2ecf20Sopenharmony_ci /* can't write DVD-RAM media */ 9698c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_DVD_RAM; 9708c2ecf20Sopenharmony_ci if ((buffer[n + 3] & 0x10) == 0) 9718c2ecf20Sopenharmony_ci /* can't write DVD-R media */ 9728c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_DVD_R; 9738c2ecf20Sopenharmony_ci if ((buffer[n + 3] & 0x2) == 0) 9748c2ecf20Sopenharmony_ci /* can't write CD-RW media */ 9758c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_CD_RW; 9768c2ecf20Sopenharmony_ci if ((buffer[n + 3] & 0x1) == 0) 9778c2ecf20Sopenharmony_ci /* can't write CD-R media */ 9788c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_CD_R; 9798c2ecf20Sopenharmony_ci if ((buffer[n + 6] & 0x8) == 0) 9808c2ecf20Sopenharmony_ci /* can't eject */ 9818c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_OPEN_TRAY; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if ((buffer[n + 6] >> 5) == mechtype_individual_changer || 9848c2ecf20Sopenharmony_ci (buffer[n + 6] >> 5) == mechtype_cartridge_changer) 9858c2ecf20Sopenharmony_ci cd->cdi.capacity = 9868c2ecf20Sopenharmony_ci cdrom_number_of_slots(&cd->cdi); 9878c2ecf20Sopenharmony_ci if (cd->cdi.capacity <= 1) 9888c2ecf20Sopenharmony_ci /* not a changer */ 9898c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_SELECT_DISC; 9908c2ecf20Sopenharmony_ci /*else I don't think it can close its tray 9918c2ecf20Sopenharmony_ci cd->cdi.mask |= CDC_CLOSE_TRAY; */ 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* 9948c2ecf20Sopenharmony_ci * if DVD-RAM, MRW-W or CD-RW, we are randomly writable 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != 9978c2ecf20Sopenharmony_ci (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { 9988c2ecf20Sopenharmony_ci cd->writeable = 1; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci kfree(buffer); 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci/* 10058c2ecf20Sopenharmony_ci * sr_packet() is the entry point for the generic commands generated 10068c2ecf20Sopenharmony_ci * by the Uniform CD-ROM layer. 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_cistatic int sr_packet(struct cdrom_device_info *cdi, 10098c2ecf20Sopenharmony_ci struct packet_command *cgc) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 10128c2ecf20Sopenharmony_ci struct scsi_device *sdev = cd->device; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (cgc->cmd[0] == GPCMD_READ_DISC_INFO && sdev->no_read_disc_info) 10158c2ecf20Sopenharmony_ci return -EDRIVE_CANT_DO_THIS; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (cgc->timeout <= 0) 10188c2ecf20Sopenharmony_ci cgc->timeout = IOCTL_TIMEOUT; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci sr_do_ioctl(cd, cgc); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci return cgc->stat; 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci/** 10268c2ecf20Sopenharmony_ci * sr_kref_release - Called to free the scsi_cd structure 10278c2ecf20Sopenharmony_ci * @kref: pointer to embedded kref 10288c2ecf20Sopenharmony_ci * 10298c2ecf20Sopenharmony_ci * sr_ref_mutex must be held entering this routine. Because it is 10308c2ecf20Sopenharmony_ci * called on last put, you should always use the scsi_cd_get() 10318c2ecf20Sopenharmony_ci * scsi_cd_put() helpers which manipulate the semaphore directly 10328c2ecf20Sopenharmony_ci * and never do a direct kref_put(). 10338c2ecf20Sopenharmony_ci **/ 10348c2ecf20Sopenharmony_cistatic void sr_kref_release(struct kref *kref) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct scsi_cd *cd = container_of(kref, struct scsi_cd, kref); 10378c2ecf20Sopenharmony_ci struct gendisk *disk = cd->disk; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci spin_lock(&sr_index_lock); 10408c2ecf20Sopenharmony_ci clear_bit(MINOR(disk_devt(disk)), sr_index_bits); 10418c2ecf20Sopenharmony_ci spin_unlock(&sr_index_lock); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci unregister_cdrom(&cd->cdi); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci disk->private_data = NULL; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci put_disk(disk); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci mutex_destroy(&cd->lock); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci kfree(cd); 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic int sr_remove(struct device *dev) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci struct scsi_cd *cd = dev_get_drvdata(dev); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci scsi_autopm_get_device(cd->device); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci del_gendisk(cd->disk); 10618c2ecf20Sopenharmony_ci dev_set_drvdata(dev, NULL); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci mutex_lock(&sr_ref_mutex); 10648c2ecf20Sopenharmony_ci kref_put(&cd->kref, sr_kref_release); 10658c2ecf20Sopenharmony_ci mutex_unlock(&sr_ref_mutex); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic int __init init_sr(void) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci int rc; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); 10758c2ecf20Sopenharmony_ci if (rc) 10768c2ecf20Sopenharmony_ci return rc; 10778c2ecf20Sopenharmony_ci rc = scsi_register_driver(&sr_template.gendrv); 10788c2ecf20Sopenharmony_ci if (rc) 10798c2ecf20Sopenharmony_ci unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci return rc; 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic void __exit exit_sr(void) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci scsi_unregister_driver(&sr_template.gendrv); 10878c2ecf20Sopenharmony_ci unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cimodule_init(init_sr); 10918c2ecf20Sopenharmony_cimodule_exit(exit_sr); 10928c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1093