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