162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/kernel.h> 362306a36Sopenharmony_ci#include <linux/mm.h> 462306a36Sopenharmony_ci#include <linux/fs.h> 562306a36Sopenharmony_ci#include <linux/errno.h> 662306a36Sopenharmony_ci#include <linux/string.h> 762306a36Sopenharmony_ci#include <linux/blkdev.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/blkpg.h> 1062306a36Sopenharmony_ci#include <linux/cdrom.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <asm/io.h> 1462306a36Sopenharmony_ci#include <linux/uaccess.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <scsi/scsi.h> 1762306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 1862306a36Sopenharmony_ci#include <scsi/scsi_device.h> 1962306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 2062306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2162306a36Sopenharmony_ci#include <scsi/scsi_ioctl.h> 2262306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "sr.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#if 0 2762306a36Sopenharmony_ci#define DEBUG 2862306a36Sopenharmony_ci#endif 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* The sr_is_xa() seems to trigger firmware bugs with some drives :-( 3162306a36Sopenharmony_ci * It is off by default and can be turned on with this module parameter */ 3262306a36Sopenharmony_cistatic int xa_test = 0; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cimodule_param(xa_test, int, S_IRUGO | S_IWUSR); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int sr_read_tochdr(struct cdrom_device_info *cdi, 3762306a36Sopenharmony_ci struct cdrom_tochdr *tochdr) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 4062306a36Sopenharmony_ci struct packet_command cgc; 4162306a36Sopenharmony_ci int result; 4262306a36Sopenharmony_ci unsigned char *buffer; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci buffer = kzalloc(32, GFP_KERNEL); 4562306a36Sopenharmony_ci if (!buffer) 4662306a36Sopenharmony_ci return -ENOMEM; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 4962306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 5062306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; 5162306a36Sopenharmony_ci cgc.cmd[8] = 12; /* LSB of length */ 5262306a36Sopenharmony_ci cgc.buffer = buffer; 5362306a36Sopenharmony_ci cgc.buflen = 12; 5462306a36Sopenharmony_ci cgc.quiet = 1; 5562306a36Sopenharmony_ci cgc.data_direction = DMA_FROM_DEVICE; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci result = sr_do_ioctl(cd, &cgc); 5862306a36Sopenharmony_ci if (result) 5962306a36Sopenharmony_ci goto err; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci tochdr->cdth_trk0 = buffer[2]; 6262306a36Sopenharmony_ci tochdr->cdth_trk1 = buffer[3]; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cierr: 6562306a36Sopenharmony_ci kfree(buffer); 6662306a36Sopenharmony_ci return result; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic int sr_read_tocentry(struct cdrom_device_info *cdi, 7062306a36Sopenharmony_ci struct cdrom_tocentry *tocentry) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 7362306a36Sopenharmony_ci struct packet_command cgc; 7462306a36Sopenharmony_ci int result; 7562306a36Sopenharmony_ci unsigned char *buffer; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci buffer = kzalloc(32, GFP_KERNEL); 7862306a36Sopenharmony_ci if (!buffer) 7962306a36Sopenharmony_ci return -ENOMEM; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 8262306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 8362306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; 8462306a36Sopenharmony_ci cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; 8562306a36Sopenharmony_ci cgc.cmd[6] = tocentry->cdte_track; 8662306a36Sopenharmony_ci cgc.cmd[8] = 12; /* LSB of length */ 8762306a36Sopenharmony_ci cgc.buffer = buffer; 8862306a36Sopenharmony_ci cgc.buflen = 12; 8962306a36Sopenharmony_ci cgc.data_direction = DMA_FROM_DEVICE; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci result = sr_do_ioctl(cd, &cgc); 9262306a36Sopenharmony_ci if (result) 9362306a36Sopenharmony_ci goto err; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci tocentry->cdte_ctrl = buffer[5] & 0xf; 9662306a36Sopenharmony_ci tocentry->cdte_adr = buffer[5] >> 4; 9762306a36Sopenharmony_ci tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0; 9862306a36Sopenharmony_ci if (tocentry->cdte_format == CDROM_MSF) { 9962306a36Sopenharmony_ci tocentry->cdte_addr.msf.minute = buffer[9]; 10062306a36Sopenharmony_ci tocentry->cdte_addr.msf.second = buffer[10]; 10162306a36Sopenharmony_ci tocentry->cdte_addr.msf.frame = buffer[11]; 10262306a36Sopenharmony_ci } else 10362306a36Sopenharmony_ci tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) 10462306a36Sopenharmony_ci + buffer[10]) << 8) + buffer[11]; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cierr: 10762306a36Sopenharmony_ci kfree(buffer); 10862306a36Sopenharmony_ci return result; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define IOCTL_RETRIES 3 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command. When these drives 11462306a36Sopenharmony_ci are emulating a SCSI device via the idescsi module, they need to have 11562306a36Sopenharmony_ci CDROMPLAYTRKIND commands translated into CDROMPLAYMSF commands for them */ 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct cdrom_tocentry trk0_te, trk1_te; 12062306a36Sopenharmony_ci struct cdrom_tochdr tochdr; 12162306a36Sopenharmony_ci struct packet_command cgc; 12262306a36Sopenharmony_ci int ntracks, ret; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci ret = sr_read_tochdr(cdi, &tochdr); 12562306a36Sopenharmony_ci if (ret) 12662306a36Sopenharmony_ci return ret; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci ntracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (ti->cdti_trk1 == ntracks) 13162306a36Sopenharmony_ci ti->cdti_trk1 = CDROM_LEADOUT; 13262306a36Sopenharmony_ci else if (ti->cdti_trk1 != CDROM_LEADOUT) 13362306a36Sopenharmony_ci ti->cdti_trk1 ++; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci trk0_te.cdte_track = ti->cdti_trk0; 13662306a36Sopenharmony_ci trk0_te.cdte_format = CDROM_MSF; 13762306a36Sopenharmony_ci trk1_te.cdte_track = ti->cdti_trk1; 13862306a36Sopenharmony_ci trk1_te.cdte_format = CDROM_MSF; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci ret = sr_read_tocentry(cdi, &trk0_te); 14162306a36Sopenharmony_ci if (ret) 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci ret = sr_read_tocentry(cdi, &trk1_te); 14462306a36Sopenharmony_ci if (ret) 14562306a36Sopenharmony_ci return ret; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 14862306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; 14962306a36Sopenharmony_ci cgc.cmd[3] = trk0_te.cdte_addr.msf.minute; 15062306a36Sopenharmony_ci cgc.cmd[4] = trk0_te.cdte_addr.msf.second; 15162306a36Sopenharmony_ci cgc.cmd[5] = trk0_te.cdte_addr.msf.frame; 15262306a36Sopenharmony_ci cgc.cmd[6] = trk1_te.cdte_addr.msf.minute; 15362306a36Sopenharmony_ci cgc.cmd[7] = trk1_te.cdte_addr.msf.second; 15462306a36Sopenharmony_ci cgc.cmd[8] = trk1_te.cdte_addr.msf.frame; 15562306a36Sopenharmony_ci cgc.data_direction = DMA_NONE; 15662306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 15762306a36Sopenharmony_ci return sr_do_ioctl(cdi->handle, &cgc); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic int sr_play_trkind(struct cdrom_device_info *cdi, 16162306a36Sopenharmony_ci struct cdrom_ti *ti) 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 16562306a36Sopenharmony_ci struct packet_command cgc; 16662306a36Sopenharmony_ci int result; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 16962306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 17062306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_PLAYAUDIO_TI; 17162306a36Sopenharmony_ci cgc.cmd[4] = ti->cdti_trk0; 17262306a36Sopenharmony_ci cgc.cmd[5] = ti->cdti_ind0; 17362306a36Sopenharmony_ci cgc.cmd[7] = ti->cdti_trk1; 17462306a36Sopenharmony_ci cgc.cmd[8] = ti->cdti_ind1; 17562306a36Sopenharmony_ci cgc.data_direction = DMA_NONE; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci result = sr_do_ioctl(cd, &cgc); 17862306a36Sopenharmony_ci if (result == -EDRIVE_CANT_DO_THIS) 17962306a36Sopenharmony_ci result = sr_fake_playtrkind(cdi, ti); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return result; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* We do our own retries because we want to know what the specific 18562306a36Sopenharmony_ci error code is. Normally the UNIT_ATTENTION code will automatically 18662306a36Sopenharmony_ci clear after one error */ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ciint sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct scsi_device *SDev; 19162306a36Sopenharmony_ci struct scsi_sense_hdr local_sshdr, *sshdr; 19262306a36Sopenharmony_ci int result, err = 0, retries = 0; 19362306a36Sopenharmony_ci const struct scsi_exec_args exec_args = { 19462306a36Sopenharmony_ci .sshdr = cgc->sshdr ? : &local_sshdr, 19562306a36Sopenharmony_ci }; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci SDev = cd->device; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci sshdr = exec_args.sshdr; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci retry: 20262306a36Sopenharmony_ci if (!scsi_block_when_processing_errors(SDev)) { 20362306a36Sopenharmony_ci err = -ENODEV; 20462306a36Sopenharmony_ci goto out; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci result = scsi_execute_cmd(SDev, cgc->cmd, 20862306a36Sopenharmony_ci cgc->data_direction == DMA_TO_DEVICE ? 20962306a36Sopenharmony_ci REQ_OP_DRV_OUT : REQ_OP_DRV_IN, cgc->buffer, 21062306a36Sopenharmony_ci cgc->buflen, cgc->timeout, IOCTL_RETRIES, 21162306a36Sopenharmony_ci &exec_args); 21262306a36Sopenharmony_ci /* Minimal error checking. Ignore cases we know about, and report the rest. */ 21362306a36Sopenharmony_ci if (result < 0) { 21462306a36Sopenharmony_ci err = result; 21562306a36Sopenharmony_ci goto out; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci if (scsi_status_is_check_condition(result)) { 21862306a36Sopenharmony_ci switch (sshdr->sense_key) { 21962306a36Sopenharmony_ci case UNIT_ATTENTION: 22062306a36Sopenharmony_ci SDev->changed = 1; 22162306a36Sopenharmony_ci if (!cgc->quiet) 22262306a36Sopenharmony_ci sr_printk(KERN_INFO, cd, 22362306a36Sopenharmony_ci "disc change detected.\n"); 22462306a36Sopenharmony_ci if (retries++ < 10) 22562306a36Sopenharmony_ci goto retry; 22662306a36Sopenharmony_ci err = -ENOMEDIUM; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci case NOT_READY: /* This happens if there is no disc in drive */ 22962306a36Sopenharmony_ci if (sshdr->asc == 0x04 && 23062306a36Sopenharmony_ci sshdr->ascq == 0x01) { 23162306a36Sopenharmony_ci /* sense: Logical unit is in process of becoming ready */ 23262306a36Sopenharmony_ci if (!cgc->quiet) 23362306a36Sopenharmony_ci sr_printk(KERN_INFO, cd, 23462306a36Sopenharmony_ci "CDROM not ready yet.\n"); 23562306a36Sopenharmony_ci if (retries++ < 10) { 23662306a36Sopenharmony_ci /* sleep 2 sec and try again */ 23762306a36Sopenharmony_ci ssleep(2); 23862306a36Sopenharmony_ci goto retry; 23962306a36Sopenharmony_ci } else { 24062306a36Sopenharmony_ci /* 20 secs are enough? */ 24162306a36Sopenharmony_ci err = -ENOMEDIUM; 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci if (!cgc->quiet) 24662306a36Sopenharmony_ci sr_printk(KERN_INFO, cd, 24762306a36Sopenharmony_ci "CDROM not ready. Make sure there " 24862306a36Sopenharmony_ci "is a disc in the drive.\n"); 24962306a36Sopenharmony_ci err = -ENOMEDIUM; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case ILLEGAL_REQUEST: 25262306a36Sopenharmony_ci err = -EIO; 25362306a36Sopenharmony_ci if (sshdr->asc == 0x20 && 25462306a36Sopenharmony_ci sshdr->ascq == 0x00) 25562306a36Sopenharmony_ci /* sense: Invalid command operation code */ 25662306a36Sopenharmony_ci err = -EDRIVE_CANT_DO_THIS; 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci default: 25962306a36Sopenharmony_ci err = -EIO; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Wake up a process waiting for device */ 26462306a36Sopenharmony_ci out: 26562306a36Sopenharmony_ci cgc->stat = err; 26662306a36Sopenharmony_ci return err; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* ---------------------------------------------------------------------- */ 27062306a36Sopenharmony_ci/* interface to cdrom.c */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ciint sr_tray_move(struct cdrom_device_info *cdi, int pos) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci Scsi_CD *cd = cdi->handle; 27562306a36Sopenharmony_ci struct packet_command cgc; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 27862306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_START_STOP_UNIT; 27962306a36Sopenharmony_ci cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; 28062306a36Sopenharmony_ci cgc.data_direction = DMA_NONE; 28162306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 28262306a36Sopenharmony_ci return sr_do_ioctl(cd, &cgc); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciint sr_lock_door(struct cdrom_device_info *cdi, int lock) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci Scsi_CD *cd = cdi->handle; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return scsi_set_medium_removal(cd->device, lock ? 29062306a36Sopenharmony_ci SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ciint sr_drive_status(struct cdrom_device_info *cdi, int slot) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct scsi_cd *cd = cdi->handle; 29662306a36Sopenharmony_ci struct scsi_sense_hdr sshdr; 29762306a36Sopenharmony_ci struct media_event_desc med; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (CDSL_CURRENT != slot) { 30062306a36Sopenharmony_ci /* we have no changer support */ 30162306a36Sopenharmony_ci return -EINVAL; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) 30462306a36Sopenharmony_ci return CDS_DISC_OK; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ 30762306a36Sopenharmony_ci if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY 30862306a36Sopenharmony_ci && sshdr.asc == 0x04 && sshdr.ascq == 0x01) 30962306a36Sopenharmony_ci return CDS_DRIVE_NOT_READY; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (!cdrom_get_media_event(cdi, &med)) { 31262306a36Sopenharmony_ci if (med.media_present) 31362306a36Sopenharmony_ci return CDS_DISC_OK; 31462306a36Sopenharmony_ci else if (med.door_open) 31562306a36Sopenharmony_ci return CDS_TRAY_OPEN; 31662306a36Sopenharmony_ci else 31762306a36Sopenharmony_ci return CDS_NO_DISC; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* 32162306a36Sopenharmony_ci * SK/ASC/ASCQ of 2/4/2 means "initialization required" 32262306a36Sopenharmony_ci * Using CD_TRAY_OPEN results in an START_STOP_UNIT to close 32362306a36Sopenharmony_ci * the tray, which resolves the initialization requirement. 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY 32662306a36Sopenharmony_ci && sshdr.asc == 0x04 && sshdr.ascq == 0x02) 32762306a36Sopenharmony_ci return CDS_TRAY_OPEN; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* 33062306a36Sopenharmony_ci * 0x04 is format in progress .. but there must be a disc present! 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04) 33362306a36Sopenharmony_ci return CDS_DISC_OK; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * If not using Mt Fuji extended media tray reports, 33762306a36Sopenharmony_ci * just return TRAY_OPEN since ATAPI doesn't provide 33862306a36Sopenharmony_ci * any other way to detect this... 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ci if (scsi_sense_valid(&sshdr) && 34162306a36Sopenharmony_ci /* 0x3a is medium not present */ 34262306a36Sopenharmony_ci sshdr.asc == 0x3a) 34362306a36Sopenharmony_ci return CDS_NO_DISC; 34462306a36Sopenharmony_ci else 34562306a36Sopenharmony_ci return CDS_TRAY_OPEN; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci return CDS_DRIVE_NOT_READY; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ciint sr_disk_status(struct cdrom_device_info *cdi) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci Scsi_CD *cd = cdi->handle; 35362306a36Sopenharmony_ci struct cdrom_tochdr toc_h; 35462306a36Sopenharmony_ci struct cdrom_tocentry toc_e; 35562306a36Sopenharmony_ci int i, rc, have_datatracks = 0; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* look for data tracks */ 35862306a36Sopenharmony_ci rc = sr_read_tochdr(cdi, &toc_h); 35962306a36Sopenharmony_ci if (rc) 36062306a36Sopenharmony_ci return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) { 36362306a36Sopenharmony_ci toc_e.cdte_track = i; 36462306a36Sopenharmony_ci toc_e.cdte_format = CDROM_LBA; 36562306a36Sopenharmony_ci if (sr_read_tocentry(cdi, &toc_e)) 36662306a36Sopenharmony_ci return CDS_NO_INFO; 36762306a36Sopenharmony_ci if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) { 36862306a36Sopenharmony_ci have_datatracks = 1; 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci if (!have_datatracks) 37362306a36Sopenharmony_ci return CDS_AUDIO; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (cd->xa_flag) 37662306a36Sopenharmony_ci return CDS_XA_2_1; 37762306a36Sopenharmony_ci else 37862306a36Sopenharmony_ci return CDS_DATA_1; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ciint sr_get_last_session(struct cdrom_device_info *cdi, 38262306a36Sopenharmony_ci struct cdrom_multisession *ms_info) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci Scsi_CD *cd = cdi->handle; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci ms_info->addr.lba = cd->ms_offset; 38762306a36Sopenharmony_ci ms_info->xa_flag = cd->xa_flag || cd->ms_offset > 0; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return 0; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ciint sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci Scsi_CD *cd = cdi->handle; 39562306a36Sopenharmony_ci struct packet_command cgc; 39662306a36Sopenharmony_ci char *buffer = kzalloc(32, GFP_KERNEL); 39762306a36Sopenharmony_ci int result; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (!buffer) 40062306a36Sopenharmony_ci return -ENOMEM; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 40362306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; 40462306a36Sopenharmony_ci cgc.cmd[2] = 0x40; /* I do want the subchannel info */ 40562306a36Sopenharmony_ci cgc.cmd[3] = 0x02; /* Give me medium catalog number info */ 40662306a36Sopenharmony_ci cgc.cmd[8] = 24; 40762306a36Sopenharmony_ci cgc.buffer = buffer; 40862306a36Sopenharmony_ci cgc.buflen = 24; 40962306a36Sopenharmony_ci cgc.data_direction = DMA_FROM_DEVICE; 41062306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 41162306a36Sopenharmony_ci result = sr_do_ioctl(cd, &cgc); 41262306a36Sopenharmony_ci if (result) 41362306a36Sopenharmony_ci goto err; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci memcpy(mcn->medium_catalog_number, buffer + 9, 13); 41662306a36Sopenharmony_ci mcn->medium_catalog_number[13] = 0; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cierr: 41962306a36Sopenharmony_ci kfree(buffer); 42062306a36Sopenharmony_ci return result; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ciint sr_reset(struct cdrom_device_info *cdi) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ciint sr_select_speed(struct cdrom_device_info *cdi, int speed) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci Scsi_CD *cd = cdi->handle; 43162306a36Sopenharmony_ci struct packet_command cgc; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (speed == 0) 43462306a36Sopenharmony_ci speed = 0xffff; /* set to max */ 43562306a36Sopenharmony_ci else 43662306a36Sopenharmony_ci speed *= 177; /* Nx to kbyte/s */ 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 43962306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ 44062306a36Sopenharmony_ci cgc.cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ 44162306a36Sopenharmony_ci cgc.cmd[3] = speed & 0xff; /* LSB */ 44262306a36Sopenharmony_ci cgc.data_direction = DMA_NONE; 44362306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (sr_do_ioctl(cd, &cgc)) 44662306a36Sopenharmony_ci return -EIO; 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/* ----------------------------------------------------------------------- */ 45162306a36Sopenharmony_ci/* this is called by the generic cdrom driver. arg is a _kernel_ pointer, */ 45262306a36Sopenharmony_ci/* because the generic cdrom driver does the user access stuff for us. */ 45362306a36Sopenharmony_ci/* only cdromreadtochdr and cdromreadtocentry are left - for use with the */ 45462306a36Sopenharmony_ci/* sr_disk_status interface for the generic cdrom driver. */ 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ciint sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci switch (cmd) { 45962306a36Sopenharmony_ci case CDROMREADTOCHDR: 46062306a36Sopenharmony_ci return sr_read_tochdr(cdi, arg); 46162306a36Sopenharmony_ci case CDROMREADTOCENTRY: 46262306a36Sopenharmony_ci return sr_read_tocentry(cdi, arg); 46362306a36Sopenharmony_ci case CDROMPLAYTRKIND: 46462306a36Sopenharmony_ci return sr_play_trkind(cdi, arg); 46562306a36Sopenharmony_ci default: 46662306a36Sopenharmony_ci return -EINVAL; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* ----------------------------------------------------------------------- 47162306a36Sopenharmony_ci * a function to read all sorts of funny cdrom sectors using the READ_CD 47262306a36Sopenharmony_ci * scsi-3 mmc command 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * lba: linear block address 47562306a36Sopenharmony_ci * format: 0 = data (anything) 47662306a36Sopenharmony_ci * 1 = audio 47762306a36Sopenharmony_ci * 2 = data (mode 1) 47862306a36Sopenharmony_ci * 3 = data (mode 2) 47962306a36Sopenharmony_ci * 4 = data (mode 2 form1) 48062306a36Sopenharmony_ci * 5 = data (mode 2 form2) 48162306a36Sopenharmony_ci * blksize: 2048 | 2336 | 2340 | 2352 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci struct packet_command cgc; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci#ifdef DEBUG 48962306a36Sopenharmony_ci sr_printk(KERN_INFO, cd, "sr_read_cd lba=%d format=%d blksize=%d\n", 49062306a36Sopenharmony_ci lba, format, blksize); 49162306a36Sopenharmony_ci#endif 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 49462306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_READ_CD; /* READ_CD */ 49562306a36Sopenharmony_ci cgc.cmd[1] = ((format & 7) << 2); 49662306a36Sopenharmony_ci cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; 49762306a36Sopenharmony_ci cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; 49862306a36Sopenharmony_ci cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; 49962306a36Sopenharmony_ci cgc.cmd[5] = (unsigned char) lba & 0xff; 50062306a36Sopenharmony_ci cgc.cmd[8] = 1; 50162306a36Sopenharmony_ci switch (blksize) { 50262306a36Sopenharmony_ci case 2336: 50362306a36Sopenharmony_ci cgc.cmd[9] = 0x58; 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci case 2340: 50662306a36Sopenharmony_ci cgc.cmd[9] = 0x78; 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case 2352: 50962306a36Sopenharmony_ci cgc.cmd[9] = 0xf8; 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci default: 51262306a36Sopenharmony_ci cgc.cmd[9] = 0x10; 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci cgc.buffer = dest; 51662306a36Sopenharmony_ci cgc.buflen = blksize; 51762306a36Sopenharmony_ci cgc.data_direction = DMA_FROM_DEVICE; 51862306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 51962306a36Sopenharmony_ci return sr_do_ioctl(cd, &cgc); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/* 52362306a36Sopenharmony_ci * read sectors with blocksizes other than 2048 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct packet_command cgc; 52962306a36Sopenharmony_ci int rc; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* we try the READ CD command first... */ 53262306a36Sopenharmony_ci if (cd->readcd_known) { 53362306a36Sopenharmony_ci rc = sr_read_cd(cd, dest, lba, 0, blksize); 53462306a36Sopenharmony_ci if (-EDRIVE_CANT_DO_THIS != rc) 53562306a36Sopenharmony_ci return rc; 53662306a36Sopenharmony_ci cd->readcd_known = 0; 53762306a36Sopenharmony_ci sr_printk(KERN_INFO, cd, 53862306a36Sopenharmony_ci "CDROM doesn't support READ CD (0xbe) command\n"); 53962306a36Sopenharmony_ci /* fall & retry the other way */ 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci /* ... if this fails, we switch the blocksize using MODE SELECT */ 54262306a36Sopenharmony_ci if (blksize != cd->device->sector_size) { 54362306a36Sopenharmony_ci if (0 != (rc = sr_set_blocklength(cd, blksize))) 54462306a36Sopenharmony_ci return rc; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci#ifdef DEBUG 54762306a36Sopenharmony_ci sr_printk(KERN_INFO, cd, "sr_read_sector lba=%d blksize=%d\n", 54862306a36Sopenharmony_ci lba, blksize); 54962306a36Sopenharmony_ci#endif 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci memset(&cgc, 0, sizeof(struct packet_command)); 55262306a36Sopenharmony_ci cgc.cmd[0] = GPCMD_READ_10; 55362306a36Sopenharmony_ci cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; 55462306a36Sopenharmony_ci cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; 55562306a36Sopenharmony_ci cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; 55662306a36Sopenharmony_ci cgc.cmd[5] = (unsigned char) lba & 0xff; 55762306a36Sopenharmony_ci cgc.cmd[8] = 1; 55862306a36Sopenharmony_ci cgc.buffer = dest; 55962306a36Sopenharmony_ci cgc.buflen = blksize; 56062306a36Sopenharmony_ci cgc.data_direction = DMA_FROM_DEVICE; 56162306a36Sopenharmony_ci cgc.timeout = IOCTL_TIMEOUT; 56262306a36Sopenharmony_ci rc = sr_do_ioctl(cd, &cgc); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (blksize != CD_FRAMESIZE) 56562306a36Sopenharmony_ci rc |= sr_set_blocklength(cd, CD_FRAMESIZE); 56662306a36Sopenharmony_ci return rc; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/* 57062306a36Sopenharmony_ci * read a sector in raw mode to check the sector format 57162306a36Sopenharmony_ci * ret: 1 == mode2 (XA), 0 == mode1, <0 == error 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciint sr_is_xa(Scsi_CD *cd) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci unsigned char *raw_sector; 57762306a36Sopenharmony_ci int is_xa; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (!xa_test) 58062306a36Sopenharmony_ci return 0; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci raw_sector = kmalloc(2048, GFP_KERNEL); 58362306a36Sopenharmony_ci if (!raw_sector) 58462306a36Sopenharmony_ci return -ENOMEM; 58562306a36Sopenharmony_ci if (0 == sr_read_sector(cd, cd->ms_offset + 16, 58662306a36Sopenharmony_ci CD_FRAMESIZE_RAW1, raw_sector)) { 58762306a36Sopenharmony_ci is_xa = (raw_sector[3] == 0x02) ? 1 : 0; 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci /* read a raw sector failed for some reason. */ 59062306a36Sopenharmony_ci is_xa = -1; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci kfree(raw_sector); 59362306a36Sopenharmony_ci#ifdef DEBUG 59462306a36Sopenharmony_ci sr_printk(KERN_INFO, cd, "sr_is_xa: %d\n", is_xa); 59562306a36Sopenharmony_ci#endif 59662306a36Sopenharmony_ci return is_xa; 59762306a36Sopenharmony_ci} 598