18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/kernel.h>
38c2ecf20Sopenharmony_ci#include <linux/mm.h>
48c2ecf20Sopenharmony_ci#include <linux/fs.h>
58c2ecf20Sopenharmony_ci#include <linux/errno.h>
68c2ecf20Sopenharmony_ci#include <linux/string.h>
78c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/blkpg.h>
108c2ecf20Sopenharmony_ci#include <linux/cdrom.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <asm/io.h>
148c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
178c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h>
188c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
198c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h>
208c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
218c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h>
228c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "sr.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#if 0
278c2ecf20Sopenharmony_ci#define DEBUG
288c2ecf20Sopenharmony_ci#endif
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* The sr_is_xa() seems to trigger firmware bugs with some drives :-(
318c2ecf20Sopenharmony_ci * It is off by default and can be turned on with this module parameter */
328c2ecf20Sopenharmony_cistatic int xa_test = 0;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cimodule_param(xa_test, int, S_IRUGO | S_IWUSR);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* primitive to determine whether we need to have GFP_DMA set based on
378c2ecf20Sopenharmony_ci * the status of the unchecked_isa_dma flag in the host structure */
388c2ecf20Sopenharmony_ci#define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic int sr_read_tochdr(struct cdrom_device_info *cdi,
418c2ecf20Sopenharmony_ci		struct cdrom_tochdr *tochdr)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	struct scsi_cd *cd = cdi->handle;
448c2ecf20Sopenharmony_ci	struct packet_command cgc;
458c2ecf20Sopenharmony_ci	int result;
468c2ecf20Sopenharmony_ci	unsigned char *buffer;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
498c2ecf20Sopenharmony_ci	if (!buffer)
508c2ecf20Sopenharmony_ci		return -ENOMEM;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
538c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
548c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
558c2ecf20Sopenharmony_ci	cgc.cmd[8] = 12;		/* LSB of length */
568c2ecf20Sopenharmony_ci	cgc.buffer = buffer;
578c2ecf20Sopenharmony_ci	cgc.buflen = 12;
588c2ecf20Sopenharmony_ci	cgc.quiet = 1;
598c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_FROM_DEVICE;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	result = sr_do_ioctl(cd, &cgc);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	tochdr->cdth_trk0 = buffer[2];
648c2ecf20Sopenharmony_ci	tochdr->cdth_trk1 = buffer[3];
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	kfree(buffer);
678c2ecf20Sopenharmony_ci	return result;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int sr_read_tocentry(struct cdrom_device_info *cdi,
718c2ecf20Sopenharmony_ci		struct cdrom_tocentry *tocentry)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct scsi_cd *cd = cdi->handle;
748c2ecf20Sopenharmony_ci	struct packet_command cgc;
758c2ecf20Sopenharmony_ci	int result;
768c2ecf20Sopenharmony_ci	unsigned char *buffer;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
798c2ecf20Sopenharmony_ci	if (!buffer)
808c2ecf20Sopenharmony_ci		return -ENOMEM;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
838c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
848c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
858c2ecf20Sopenharmony_ci	cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
868c2ecf20Sopenharmony_ci	cgc.cmd[6] = tocentry->cdte_track;
878c2ecf20Sopenharmony_ci	cgc.cmd[8] = 12;		/* LSB of length */
888c2ecf20Sopenharmony_ci	cgc.buffer = buffer;
898c2ecf20Sopenharmony_ci	cgc.buflen = 12;
908c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_FROM_DEVICE;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	result = sr_do_ioctl(cd, &cgc);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	tocentry->cdte_ctrl = buffer[5] & 0xf;
958c2ecf20Sopenharmony_ci	tocentry->cdte_adr = buffer[5] >> 4;
968c2ecf20Sopenharmony_ci	tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
978c2ecf20Sopenharmony_ci	if (tocentry->cdte_format == CDROM_MSF) {
988c2ecf20Sopenharmony_ci		tocentry->cdte_addr.msf.minute = buffer[9];
998c2ecf20Sopenharmony_ci		tocentry->cdte_addr.msf.second = buffer[10];
1008c2ecf20Sopenharmony_ci		tocentry->cdte_addr.msf.frame = buffer[11];
1018c2ecf20Sopenharmony_ci	} else
1028c2ecf20Sopenharmony_ci		tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
1038c2ecf20Sopenharmony_ci			+ buffer[10]) << 8) + buffer[11];
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	kfree(buffer);
1068c2ecf20Sopenharmony_ci	return result;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define IOCTL_RETRIES 3
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command.  When these drives
1128c2ecf20Sopenharmony_ci   are emulating a SCSI device via the idescsi module, they need to have
1138c2ecf20Sopenharmony_ci   CDROMPLAYTRKIND commands translated into CDROMPLAYMSF commands for them */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct cdrom_tocentry trk0_te, trk1_te;
1188c2ecf20Sopenharmony_ci	struct cdrom_tochdr tochdr;
1198c2ecf20Sopenharmony_ci	struct packet_command cgc;
1208c2ecf20Sopenharmony_ci	int ntracks, ret;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	ret = sr_read_tochdr(cdi, &tochdr);
1238c2ecf20Sopenharmony_ci	if (ret)
1248c2ecf20Sopenharmony_ci		return ret;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	ntracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (ti->cdti_trk1 == ntracks)
1298c2ecf20Sopenharmony_ci		ti->cdti_trk1 = CDROM_LEADOUT;
1308c2ecf20Sopenharmony_ci	else if (ti->cdti_trk1 != CDROM_LEADOUT)
1318c2ecf20Sopenharmony_ci		ti->cdti_trk1 ++;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	trk0_te.cdte_track = ti->cdti_trk0;
1348c2ecf20Sopenharmony_ci	trk0_te.cdte_format = CDROM_MSF;
1358c2ecf20Sopenharmony_ci	trk1_te.cdte_track = ti->cdti_trk1;
1368c2ecf20Sopenharmony_ci	trk1_te.cdte_format = CDROM_MSF;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	ret = sr_read_tocentry(cdi, &trk0_te);
1398c2ecf20Sopenharmony_ci	if (ret)
1408c2ecf20Sopenharmony_ci		return ret;
1418c2ecf20Sopenharmony_ci	ret = sr_read_tocentry(cdi, &trk1_te);
1428c2ecf20Sopenharmony_ci	if (ret)
1438c2ecf20Sopenharmony_ci		return ret;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
1468c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
1478c2ecf20Sopenharmony_ci	cgc.cmd[3] = trk0_te.cdte_addr.msf.minute;
1488c2ecf20Sopenharmony_ci	cgc.cmd[4] = trk0_te.cdte_addr.msf.second;
1498c2ecf20Sopenharmony_ci	cgc.cmd[5] = trk0_te.cdte_addr.msf.frame;
1508c2ecf20Sopenharmony_ci	cgc.cmd[6] = trk1_te.cdte_addr.msf.minute;
1518c2ecf20Sopenharmony_ci	cgc.cmd[7] = trk1_te.cdte_addr.msf.second;
1528c2ecf20Sopenharmony_ci	cgc.cmd[8] = trk1_te.cdte_addr.msf.frame;
1538c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_NONE;
1548c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
1558c2ecf20Sopenharmony_ci	return sr_do_ioctl(cdi->handle, &cgc);
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic int sr_play_trkind(struct cdrom_device_info *cdi,
1598c2ecf20Sopenharmony_ci		struct cdrom_ti *ti)
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct scsi_cd *cd = cdi->handle;
1638c2ecf20Sopenharmony_ci	struct packet_command cgc;
1648c2ecf20Sopenharmony_ci	int result;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
1678c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
1688c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
1698c2ecf20Sopenharmony_ci	cgc.cmd[4] = ti->cdti_trk0;
1708c2ecf20Sopenharmony_ci	cgc.cmd[5] = ti->cdti_ind0;
1718c2ecf20Sopenharmony_ci	cgc.cmd[7] = ti->cdti_trk1;
1728c2ecf20Sopenharmony_ci	cgc.cmd[8] = ti->cdti_ind1;
1738c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_NONE;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	result = sr_do_ioctl(cd, &cgc);
1768c2ecf20Sopenharmony_ci	if (result == -EDRIVE_CANT_DO_THIS)
1778c2ecf20Sopenharmony_ci		result = sr_fake_playtrkind(cdi, ti);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	return result;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/* We do our own retries because we want to know what the specific
1838c2ecf20Sopenharmony_ci   error code is.  Normally the UNIT_ATTENTION code will automatically
1848c2ecf20Sopenharmony_ci   clear after one error */
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ciint sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct scsi_device *SDev;
1898c2ecf20Sopenharmony_ci	struct scsi_sense_hdr local_sshdr, *sshdr = &local_sshdr;
1908c2ecf20Sopenharmony_ci	int result, err = 0, retries = 0;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	SDev = cd->device;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (cgc->sshdr)
1958c2ecf20Sopenharmony_ci		sshdr = cgc->sshdr;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci      retry:
1988c2ecf20Sopenharmony_ci	if (!scsi_block_when_processing_errors(SDev)) {
1998c2ecf20Sopenharmony_ci		err = -ENODEV;
2008c2ecf20Sopenharmony_ci		goto out;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	result = scsi_execute(SDev, cgc->cmd, cgc->data_direction,
2048c2ecf20Sopenharmony_ci			      cgc->buffer, cgc->buflen, NULL, sshdr,
2058c2ecf20Sopenharmony_ci			      cgc->timeout, IOCTL_RETRIES, 0, 0, NULL);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Minimal error checking.  Ignore cases we know about, and report the rest. */
2088c2ecf20Sopenharmony_ci	if (driver_byte(result) != 0) {
2098c2ecf20Sopenharmony_ci		switch (sshdr->sense_key) {
2108c2ecf20Sopenharmony_ci		case UNIT_ATTENTION:
2118c2ecf20Sopenharmony_ci			SDev->changed = 1;
2128c2ecf20Sopenharmony_ci			if (!cgc->quiet)
2138c2ecf20Sopenharmony_ci				sr_printk(KERN_INFO, cd,
2148c2ecf20Sopenharmony_ci					  "disc change detected.\n");
2158c2ecf20Sopenharmony_ci			if (retries++ < 10)
2168c2ecf20Sopenharmony_ci				goto retry;
2178c2ecf20Sopenharmony_ci			err = -ENOMEDIUM;
2188c2ecf20Sopenharmony_ci			break;
2198c2ecf20Sopenharmony_ci		case NOT_READY:	/* This happens if there is no disc in drive */
2208c2ecf20Sopenharmony_ci			if (sshdr->asc == 0x04 &&
2218c2ecf20Sopenharmony_ci			    sshdr->ascq == 0x01) {
2228c2ecf20Sopenharmony_ci				/* sense: Logical unit is in process of becoming ready */
2238c2ecf20Sopenharmony_ci				if (!cgc->quiet)
2248c2ecf20Sopenharmony_ci					sr_printk(KERN_INFO, cd,
2258c2ecf20Sopenharmony_ci						  "CDROM not ready yet.\n");
2268c2ecf20Sopenharmony_ci				if (retries++ < 10) {
2278c2ecf20Sopenharmony_ci					/* sleep 2 sec and try again */
2288c2ecf20Sopenharmony_ci					ssleep(2);
2298c2ecf20Sopenharmony_ci					goto retry;
2308c2ecf20Sopenharmony_ci				} else {
2318c2ecf20Sopenharmony_ci					/* 20 secs are enough? */
2328c2ecf20Sopenharmony_ci					err = -ENOMEDIUM;
2338c2ecf20Sopenharmony_ci					break;
2348c2ecf20Sopenharmony_ci				}
2358c2ecf20Sopenharmony_ci			}
2368c2ecf20Sopenharmony_ci			if (!cgc->quiet)
2378c2ecf20Sopenharmony_ci				sr_printk(KERN_INFO, cd,
2388c2ecf20Sopenharmony_ci					  "CDROM not ready.  Make sure there "
2398c2ecf20Sopenharmony_ci					  "is a disc in the drive.\n");
2408c2ecf20Sopenharmony_ci			err = -ENOMEDIUM;
2418c2ecf20Sopenharmony_ci			break;
2428c2ecf20Sopenharmony_ci		case ILLEGAL_REQUEST:
2438c2ecf20Sopenharmony_ci			err = -EIO;
2448c2ecf20Sopenharmony_ci			if (sshdr->asc == 0x20 &&
2458c2ecf20Sopenharmony_ci			    sshdr->ascq == 0x00)
2468c2ecf20Sopenharmony_ci				/* sense: Invalid command operation code */
2478c2ecf20Sopenharmony_ci				err = -EDRIVE_CANT_DO_THIS;
2488c2ecf20Sopenharmony_ci			break;
2498c2ecf20Sopenharmony_ci		default:
2508c2ecf20Sopenharmony_ci			err = -EIO;
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* Wake up a process waiting for device */
2558c2ecf20Sopenharmony_ci      out:
2568c2ecf20Sopenharmony_ci	cgc->stat = err;
2578c2ecf20Sopenharmony_ci	return err;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/* ---------------------------------------------------------------------- */
2618c2ecf20Sopenharmony_ci/* interface to cdrom.c                                                   */
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ciint sr_tray_move(struct cdrom_device_info *cdi, int pos)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	Scsi_CD *cd = cdi->handle;
2668c2ecf20Sopenharmony_ci	struct packet_command cgc;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
2698c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_START_STOP_UNIT;
2708c2ecf20Sopenharmony_ci	cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
2718c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_NONE;
2728c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
2738c2ecf20Sopenharmony_ci	return sr_do_ioctl(cd, &cgc);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciint sr_lock_door(struct cdrom_device_info *cdi, int lock)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	Scsi_CD *cd = cdi->handle;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return scsi_set_medium_removal(cd->device, lock ?
2818c2ecf20Sopenharmony_ci		       SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ciint sr_drive_status(struct cdrom_device_info *cdi, int slot)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct scsi_cd *cd = cdi->handle;
2878c2ecf20Sopenharmony_ci	struct scsi_sense_hdr sshdr;
2888c2ecf20Sopenharmony_ci	struct media_event_desc med;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (CDSL_CURRENT != slot) {
2918c2ecf20Sopenharmony_ci		/* we have no changer support */
2928c2ecf20Sopenharmony_ci		return -EINVAL;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci	if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr))
2958c2ecf20Sopenharmony_ci		return CDS_DISC_OK;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */
2988c2ecf20Sopenharmony_ci	if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY
2998c2ecf20Sopenharmony_ci			&& sshdr.asc == 0x04 && sshdr.ascq == 0x01)
3008c2ecf20Sopenharmony_ci		return CDS_DRIVE_NOT_READY;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (!cdrom_get_media_event(cdi, &med)) {
3038c2ecf20Sopenharmony_ci		if (med.media_present)
3048c2ecf20Sopenharmony_ci			return CDS_DISC_OK;
3058c2ecf20Sopenharmony_ci		else if (med.door_open)
3068c2ecf20Sopenharmony_ci			return CDS_TRAY_OPEN;
3078c2ecf20Sopenharmony_ci		else
3088c2ecf20Sopenharmony_ci			return CDS_NO_DISC;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/*
3128c2ecf20Sopenharmony_ci	 * SK/ASC/ASCQ of 2/4/2 means "initialization required"
3138c2ecf20Sopenharmony_ci	 * Using CD_TRAY_OPEN results in an START_STOP_UNIT to close
3148c2ecf20Sopenharmony_ci	 * the tray, which resolves the initialization requirement.
3158c2ecf20Sopenharmony_ci	 */
3168c2ecf20Sopenharmony_ci	if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY
3178c2ecf20Sopenharmony_ci			&& sshdr.asc == 0x04 && sshdr.ascq == 0x02)
3188c2ecf20Sopenharmony_ci		return CDS_TRAY_OPEN;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * 0x04 is format in progress .. but there must be a disc present!
3228c2ecf20Sopenharmony_ci	 */
3238c2ecf20Sopenharmony_ci	if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04)
3248c2ecf20Sopenharmony_ci		return CDS_DISC_OK;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	/*
3278c2ecf20Sopenharmony_ci	 * If not using Mt Fuji extended media tray reports,
3288c2ecf20Sopenharmony_ci	 * just return TRAY_OPEN since ATAPI doesn't provide
3298c2ecf20Sopenharmony_ci	 * any other way to detect this...
3308c2ecf20Sopenharmony_ci	 */
3318c2ecf20Sopenharmony_ci	if (scsi_sense_valid(&sshdr) &&
3328c2ecf20Sopenharmony_ci	    /* 0x3a is medium not present */
3338c2ecf20Sopenharmony_ci	    sshdr.asc == 0x3a)
3348c2ecf20Sopenharmony_ci		return CDS_NO_DISC;
3358c2ecf20Sopenharmony_ci	else
3368c2ecf20Sopenharmony_ci		return CDS_TRAY_OPEN;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return CDS_DRIVE_NOT_READY;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ciint sr_disk_status(struct cdrom_device_info *cdi)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	Scsi_CD *cd = cdi->handle;
3448c2ecf20Sopenharmony_ci	struct cdrom_tochdr toc_h;
3458c2ecf20Sopenharmony_ci	struct cdrom_tocentry toc_e;
3468c2ecf20Sopenharmony_ci	int i, rc, have_datatracks = 0;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* look for data tracks */
3498c2ecf20Sopenharmony_ci	rc = sr_read_tochdr(cdi, &toc_h);
3508c2ecf20Sopenharmony_ci	if (rc)
3518c2ecf20Sopenharmony_ci		return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
3548c2ecf20Sopenharmony_ci		toc_e.cdte_track = i;
3558c2ecf20Sopenharmony_ci		toc_e.cdte_format = CDROM_LBA;
3568c2ecf20Sopenharmony_ci		if (sr_read_tocentry(cdi, &toc_e))
3578c2ecf20Sopenharmony_ci			return CDS_NO_INFO;
3588c2ecf20Sopenharmony_ci		if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
3598c2ecf20Sopenharmony_ci			have_datatracks = 1;
3608c2ecf20Sopenharmony_ci			break;
3618c2ecf20Sopenharmony_ci		}
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci	if (!have_datatracks)
3648c2ecf20Sopenharmony_ci		return CDS_AUDIO;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (cd->xa_flag)
3678c2ecf20Sopenharmony_ci		return CDS_XA_2_1;
3688c2ecf20Sopenharmony_ci	else
3698c2ecf20Sopenharmony_ci		return CDS_DATA_1;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ciint sr_get_last_session(struct cdrom_device_info *cdi,
3738c2ecf20Sopenharmony_ci			struct cdrom_multisession *ms_info)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	Scsi_CD *cd = cdi->handle;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	ms_info->addr.lba = cd->ms_offset;
3788c2ecf20Sopenharmony_ci	ms_info->xa_flag = cd->xa_flag || cd->ms_offset > 0;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return 0;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ciint sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	Scsi_CD *cd = cdi->handle;
3868c2ecf20Sopenharmony_ci	struct packet_command cgc;
3878c2ecf20Sopenharmony_ci	char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
3888c2ecf20Sopenharmony_ci	int result;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (!buffer)
3918c2ecf20Sopenharmony_ci		return -ENOMEM;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
3948c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
3958c2ecf20Sopenharmony_ci	cgc.cmd[2] = 0x40;	/* I do want the subchannel info */
3968c2ecf20Sopenharmony_ci	cgc.cmd[3] = 0x02;	/* Give me medium catalog number info */
3978c2ecf20Sopenharmony_ci	cgc.cmd[8] = 24;
3988c2ecf20Sopenharmony_ci	cgc.buffer = buffer;
3998c2ecf20Sopenharmony_ci	cgc.buflen = 24;
4008c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_FROM_DEVICE;
4018c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
4028c2ecf20Sopenharmony_ci	result = sr_do_ioctl(cd, &cgc);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
4058c2ecf20Sopenharmony_ci	mcn->medium_catalog_number[13] = 0;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	kfree(buffer);
4088c2ecf20Sopenharmony_ci	return result;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ciint sr_reset(struct cdrom_device_info *cdi)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	return 0;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ciint sr_select_speed(struct cdrom_device_info *cdi, int speed)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	Scsi_CD *cd = cdi->handle;
4198c2ecf20Sopenharmony_ci	struct packet_command cgc;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	if (speed == 0)
4228c2ecf20Sopenharmony_ci		speed = 0xffff;	/* set to max */
4238c2ecf20Sopenharmony_ci	else
4248c2ecf20Sopenharmony_ci		speed *= 177;	/* Nx to kbyte/s */
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
4278c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
4288c2ecf20Sopenharmony_ci	cgc.cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
4298c2ecf20Sopenharmony_ci	cgc.cmd[3] = speed & 0xff;	/* LSB */
4308c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_NONE;
4318c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (sr_do_ioctl(cd, &cgc))
4348c2ecf20Sopenharmony_ci		return -EIO;
4358c2ecf20Sopenharmony_ci	return 0;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */
4398c2ecf20Sopenharmony_ci/* this is called by the generic cdrom driver. arg is a _kernel_ pointer,  */
4408c2ecf20Sopenharmony_ci/* because the generic cdrom driver does the user access stuff for us.     */
4418c2ecf20Sopenharmony_ci/* only cdromreadtochdr and cdromreadtocentry are left - for use with the  */
4428c2ecf20Sopenharmony_ci/* sr_disk_status interface for the generic cdrom driver.                  */
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ciint sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	switch (cmd) {
4478c2ecf20Sopenharmony_ci	case CDROMREADTOCHDR:
4488c2ecf20Sopenharmony_ci		return sr_read_tochdr(cdi, arg);
4498c2ecf20Sopenharmony_ci	case CDROMREADTOCENTRY:
4508c2ecf20Sopenharmony_ci		return sr_read_tocentry(cdi, arg);
4518c2ecf20Sopenharmony_ci	case CDROMPLAYTRKIND:
4528c2ecf20Sopenharmony_ci		return sr_play_trkind(cdi, arg);
4538c2ecf20Sopenharmony_ci	default:
4548c2ecf20Sopenharmony_ci		return -EINVAL;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci/* -----------------------------------------------------------------------
4598c2ecf20Sopenharmony_ci * a function to read all sorts of funny cdrom sectors using the READ_CD
4608c2ecf20Sopenharmony_ci * scsi-3 mmc command
4618c2ecf20Sopenharmony_ci *
4628c2ecf20Sopenharmony_ci * lba:     linear block address
4638c2ecf20Sopenharmony_ci * format:  0 = data (anything)
4648c2ecf20Sopenharmony_ci *          1 = audio
4658c2ecf20Sopenharmony_ci *          2 = data (mode 1)
4668c2ecf20Sopenharmony_ci *          3 = data (mode 2)
4678c2ecf20Sopenharmony_ci *          4 = data (mode 2 form1)
4688c2ecf20Sopenharmony_ci *          5 = data (mode 2 form2)
4698c2ecf20Sopenharmony_ci * blksize: 2048 | 2336 | 2340 | 2352
4708c2ecf20Sopenharmony_ci */
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	struct packet_command cgc;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci#ifdef DEBUG
4778c2ecf20Sopenharmony_ci	sr_printk(KERN_INFO, cd, "sr_read_cd lba=%d format=%d blksize=%d\n",
4788c2ecf20Sopenharmony_ci		  lba, format, blksize);
4798c2ecf20Sopenharmony_ci#endif
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
4828c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_READ_CD;	/* READ_CD */
4838c2ecf20Sopenharmony_ci	cgc.cmd[1] = ((format & 7) << 2);
4848c2ecf20Sopenharmony_ci	cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
4858c2ecf20Sopenharmony_ci	cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
4868c2ecf20Sopenharmony_ci	cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
4878c2ecf20Sopenharmony_ci	cgc.cmd[5] = (unsigned char) lba & 0xff;
4888c2ecf20Sopenharmony_ci	cgc.cmd[8] = 1;
4898c2ecf20Sopenharmony_ci	switch (blksize) {
4908c2ecf20Sopenharmony_ci	case 2336:
4918c2ecf20Sopenharmony_ci		cgc.cmd[9] = 0x58;
4928c2ecf20Sopenharmony_ci		break;
4938c2ecf20Sopenharmony_ci	case 2340:
4948c2ecf20Sopenharmony_ci		cgc.cmd[9] = 0x78;
4958c2ecf20Sopenharmony_ci		break;
4968c2ecf20Sopenharmony_ci	case 2352:
4978c2ecf20Sopenharmony_ci		cgc.cmd[9] = 0xf8;
4988c2ecf20Sopenharmony_ci		break;
4998c2ecf20Sopenharmony_ci	default:
5008c2ecf20Sopenharmony_ci		cgc.cmd[9] = 0x10;
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci	cgc.buffer = dest;
5048c2ecf20Sopenharmony_ci	cgc.buflen = blksize;
5058c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_FROM_DEVICE;
5068c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
5078c2ecf20Sopenharmony_ci	return sr_do_ioctl(cd, &cgc);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/*
5118c2ecf20Sopenharmony_ci * read sectors with blocksizes other than 2048
5128c2ecf20Sopenharmony_ci */
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct packet_command cgc;
5178c2ecf20Sopenharmony_ci	int rc;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/* we try the READ CD command first... */
5208c2ecf20Sopenharmony_ci	if (cd->readcd_known) {
5218c2ecf20Sopenharmony_ci		rc = sr_read_cd(cd, dest, lba, 0, blksize);
5228c2ecf20Sopenharmony_ci		if (-EDRIVE_CANT_DO_THIS != rc)
5238c2ecf20Sopenharmony_ci			return rc;
5248c2ecf20Sopenharmony_ci		cd->readcd_known = 0;
5258c2ecf20Sopenharmony_ci		sr_printk(KERN_INFO, cd,
5268c2ecf20Sopenharmony_ci			  "CDROM does'nt support READ CD (0xbe) command\n");
5278c2ecf20Sopenharmony_ci		/* fall & retry the other way */
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci	/* ... if this fails, we switch the blocksize using MODE SELECT */
5308c2ecf20Sopenharmony_ci	if (blksize != cd->device->sector_size) {
5318c2ecf20Sopenharmony_ci		if (0 != (rc = sr_set_blocklength(cd, blksize)))
5328c2ecf20Sopenharmony_ci			return rc;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci#ifdef DEBUG
5358c2ecf20Sopenharmony_ci	sr_printk(KERN_INFO, cd, "sr_read_sector lba=%d blksize=%d\n",
5368c2ecf20Sopenharmony_ci		  lba, blksize);
5378c2ecf20Sopenharmony_ci#endif
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	memset(&cgc, 0, sizeof(struct packet_command));
5408c2ecf20Sopenharmony_ci	cgc.cmd[0] = GPCMD_READ_10;
5418c2ecf20Sopenharmony_ci	cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
5428c2ecf20Sopenharmony_ci	cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
5438c2ecf20Sopenharmony_ci	cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
5448c2ecf20Sopenharmony_ci	cgc.cmd[5] = (unsigned char) lba & 0xff;
5458c2ecf20Sopenharmony_ci	cgc.cmd[8] = 1;
5468c2ecf20Sopenharmony_ci	cgc.buffer = dest;
5478c2ecf20Sopenharmony_ci	cgc.buflen = blksize;
5488c2ecf20Sopenharmony_ci	cgc.data_direction = DMA_FROM_DEVICE;
5498c2ecf20Sopenharmony_ci	cgc.timeout = IOCTL_TIMEOUT;
5508c2ecf20Sopenharmony_ci	rc = sr_do_ioctl(cd, &cgc);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return rc;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci/*
5568c2ecf20Sopenharmony_ci * read a sector in raw mode to check the sector format
5578c2ecf20Sopenharmony_ci * ret: 1 == mode2 (XA), 0 == mode1, <0 == error
5588c2ecf20Sopenharmony_ci */
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ciint sr_is_xa(Scsi_CD *cd)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	unsigned char *raw_sector;
5638c2ecf20Sopenharmony_ci	int is_xa;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (!xa_test)
5668c2ecf20Sopenharmony_ci		return 0;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	raw_sector = kmalloc(2048, GFP_KERNEL | SR_GFP_DMA(cd));
5698c2ecf20Sopenharmony_ci	if (!raw_sector)
5708c2ecf20Sopenharmony_ci		return -ENOMEM;
5718c2ecf20Sopenharmony_ci	if (0 == sr_read_sector(cd, cd->ms_offset + 16,
5728c2ecf20Sopenharmony_ci				CD_FRAMESIZE_RAW1, raw_sector)) {
5738c2ecf20Sopenharmony_ci		is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
5748c2ecf20Sopenharmony_ci	} else {
5758c2ecf20Sopenharmony_ci		/* read a raw sector failed for some reason. */
5768c2ecf20Sopenharmony_ci		is_xa = -1;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci	kfree(raw_sector);
5798c2ecf20Sopenharmony_ci#ifdef DEBUG
5808c2ecf20Sopenharmony_ci	sr_printk(KERN_INFO, cd, "sr_is_xa: %d\n", is_xa);
5818c2ecf20Sopenharmony_ci#endif
5828c2ecf20Sopenharmony_ci	return is_xa;
5838c2ecf20Sopenharmony_ci}
584