11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -*-linux-c-*-
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vendor-specific code for SCSI CD-ROM's goes here.
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is needed becauce most of the new features (multisession and
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the like) are too new to be included into the SCSI-II standard (to
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be exact: there is'nt anything in my draft copy).
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           multisession using the READ TOC command (like SONY).
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           Rearranged stuff here: SCSI-3 is included allways, support
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *           for NEC/TOSHIBA/HP commands is optional.
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Gerd Knorr <kraxel@cs.tu-berlin.de>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * --------------------------------------------------------------------------
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * support for XA/multisession-CD's
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - NEC:     Detection and support of multisession CD's.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - TOSHIBA: Detection and support of multisession CD's.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              Some XA-Sector tweaking, required for older drives.
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - SONY:    Detection and support of multisession CD's.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              added by Thomas Quinot <thomas@cuivre.freenix.fr>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              work with SONY (SCSI3 now)  code.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   - HP:      Much like SONY, but a little different... (Thomas)
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              HP 6020 writers now supported.
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/cdrom.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bcd.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
425a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_cmnd.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_device.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_ioctl.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sr.h"
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* here are some constants to sort the vendors into groups */
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_SCSI3           1	/* default: scsi-3 mmc */
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_NEC             2
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_TOSHIBA         3
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_WRITER          4	/* pre-scsi3 writers */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VENDOR_TIMEOUT	30*HZ
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sr_vendor_init(Scsi_CD *cd)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_BLK_DEV_SR_VENDOR
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cd->vendor = VENDOR_SCSI3;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
717b32b8e018d8f8cc94c808a5fa84a3f889441b91Matthew Wilcox	const char *vendor = cd->device->vendor;
727b32b8e018d8f8cc94c808a5fa84a3f889441b91Matthew Wilcox	const char *model = cd->device->model;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* default */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cd->vendor = VENDOR_SCSI3;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cd->readcd_known)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this is true for scsi3/mmc drives - no more checks */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cd->device->type == TYPE_WORM) {
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cd->vendor = VENDOR_WRITER;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (!strncmp(vendor, "NEC", 3)) {
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cd->vendor = VENDOR_NEC;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(model, "CD-ROM DRIVE:25", 15) ||
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    !strncmp(model, "CD-ROM DRIVE:36", 15) ||
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    !strncmp(model, "CD-ROM DRIVE:83", 15) ||
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    !strncmp(model, "CD-ROM DRIVE:84 ", 16)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* my NEC 3x returns the read-raw data if a read-raw
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   is followed by a read for the same sector - aeb */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    || !strncmp(model, "CD-ROM DRIVE:500", 16)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    )
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* these can't handle multisession, may hang */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cd->cdi.mask |= CDC_MULTI_SESSION;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (!strncmp(vendor, "TOSHIBA", 7)) {
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cd->vendor = VENDOR_TOSHIBA;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* small handy function for switching block length using MODE SELECT,
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * used by sr_read_sector() */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sr_set_blocklength(Scsi_CD *cd, int blocklength)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buffer;	/* the buffer for the ioctl */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct packet_command cgc;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ccs_modesel_head *modesel;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc, density = 0;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BLK_DEV_SR_VENDOR
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cd->vendor == VENDOR_TOSHIBA)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		density = (blocklength > 2048) ? 0x81 : 0x83;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1215cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buffer)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
12696eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke	sr_printk(KERN_INFO, cd, "MODE SELECT 0x%x/%d\n", density, blocklength);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&cgc, 0, sizeof(struct packet_command));
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cgc.cmd[0] = MODE_SELECT;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cgc.cmd[1] = (1 << 4);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cgc.cmd[4] = 12;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	modesel = (struct ccs_modesel_head *) buffer;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(modesel, 0, sizeof(*modesel));
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	modesel->block_desc_length = 0x08;
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	modesel->density = density;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	modesel->block_length_med = (blocklength >> 8) & 0xff;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	modesel->block_length_lo = blocklength & 0xff;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cgc.buffer = buffer;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cgc.buflen = sizeof(*modesel);
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cgc.data_direction = DMA_TO_DEVICE;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cgc.timeout = VENDOR_TIMEOUT;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (0 == (rc = sr_do_ioctl(cd, &cgc))) {
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cd->device->sector_size = blocklength;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
14796eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke		sr_printk(KERN_INFO, cd,
14896eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			  "switching blocklength to %d bytes failed\n",
14996eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			  blocklength);
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buffer);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This function gets called after a media change. Checks if the CD is
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   multisession, asks for offset etc. */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sr_cd_check(struct cdrom_device_info *cdi)
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Scsi_CD *cd = cdi->handle;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long sector;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *buffer;	/* the buffer for the ioctl */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct packet_command cgc;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int rc, no_multi;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cd->cdi.mask & CDC_MULTI_SESSION)
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1695cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!buffer)
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sector = 0;		/* the multisession sector offset goes here  */
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	no_multi = 0;		/* flag: the drive can't handle multisession */
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = 0;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(&cgc, 0, sizeof(struct packet_command));
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cd->vendor) {
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VENDOR_SCSI3:
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[0] = READ_TOC;
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[8] = 12;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[9] = 0x40;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.buffer = buffer;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.buflen = 12;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.quiet = 1;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.data_direction = DMA_FROM_DEVICE;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.timeout = VENDOR_TIMEOUT;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = sr_do_ioctl(cd, &cgc);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rc != 0)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
19496eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			sr_printk(KERN_INFO, cd, "Hmm, seems the drive "
19596eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			   "doesn't support multisession CD's\n");
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			no_multi = 1;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sector = buffer[11] + (buffer[10] << 8) +
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (buffer[9] << 16) + (buffer[8] << 24);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (buffer[6] <= 1) {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ignore sector offsets from first track */
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sector = 0;
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_BLK_DEV_SR_VENDOR
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VENDOR_NEC:{
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long min, sec, frame;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.cmd[0] = 0xde;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.cmd[1] = 0x03;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.cmd[2] = 0xb0;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.buffer = buffer;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.buflen = 0x16;
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.quiet = 1;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.data_direction = DMA_FROM_DEVICE;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.timeout = VENDOR_TIMEOUT;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = sr_do_ioctl(cd, &cgc);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc != 0)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (buffer[14] != 0 && buffer[14] != 0xb0) {
22296eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke				sr_printk(KERN_INFO, cd, "Hmm, seems the cdrom "
22396eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke					  "doesn't support multisession CD's\n");
22496eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				no_multi = 1;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2282cee5dfa8b01524a1d937d56ee518677b7acfb38Adrian Bunk			min = bcd2bin(buffer[15]);
2292cee5dfa8b01524a1d937d56ee518677b7acfb38Adrian Bunk			sec = bcd2bin(buffer[16]);
2302cee5dfa8b01524a1d937d56ee518677b7acfb38Adrian Bunk			frame = bcd2bin(buffer[17]);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VENDOR_TOSHIBA:{
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long min, sec, frame;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* we request some disc information (is it a XA-CD ?,
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * where starts the last session ?) */
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.cmd[0] = 0xc7;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.cmd[1] = 0x03;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.buffer = buffer;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.buflen = 4;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.quiet = 1;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.data_direction = DMA_FROM_DEVICE;
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cgc.timeout = VENDOR_TIMEOUT;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rc = sr_do_ioctl(cd, &cgc);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc == -EINVAL) {
24996eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke				sr_printk(KERN_INFO, cd, "Hmm, seems the drive "
25096eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke					  "doesn't support multisession CD's\n");
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				no_multi = 1;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (rc != 0)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				break;
2562cee5dfa8b01524a1d937d56ee518677b7acfb38Adrian Bunk			min = bcd2bin(buffer[1]);
2572cee5dfa8b01524a1d937d56ee518677b7acfb38Adrian Bunk			sec = bcd2bin(buffer[2]);
2582cee5dfa8b01524a1d937d56ee518677b7acfb38Adrian Bunk			frame = bcd2bin(buffer[3]);
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (sector)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sector -= CD_MSF_OFFSET;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sr_set_blocklength(cd, 2048);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VENDOR_WRITER:
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[0] = READ_TOC;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[8] = 0x04;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[9] = 0x40;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.buffer = buffer;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.buflen = 0x04;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.quiet = 1;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.data_direction = DMA_FROM_DEVICE;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.timeout = VENDOR_TIMEOUT;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = sr_do_ioctl(cd, &cgc);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rc != 0) {
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((rc = buffer[2]) == 0) {
28096eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			sr_printk(KERN_WARNING, cd,
28196eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke				  "No finished session\n");
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[0] = READ_TOC;	/* Read TOC */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[6] = rc & 0x7f;	/* number of last session */
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[8] = 0x0c;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.cmd[9] = 0x40;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.buffer = buffer;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.buflen = 12;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.quiet = 1;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.data_direction = DMA_FROM_DEVICE;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cgc.timeout = VENDOR_TIMEOUT;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rc = sr_do_ioctl(cd, &cgc);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rc != 0) {
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sector = buffer[11] + (buffer[10] << 8) +
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (buffer[9] << 16) + (buffer[8] << 24);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif				/* CONFIG_BLK_DEV_SR_VENDOR */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* should not happen */
30496eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke		sr_printk(KERN_WARNING, cd,
30596eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			  "unknown vendor code (%i), not initialized ?\n",
30696eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			  cd->vendor);
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sector = 0;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		no_multi = 1;
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cd->ms_offset = sector;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cd->xa_flag = 0;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(cd))
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cd->xa_flag = 1;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (2048 != cd->device->sector_size) {
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sr_set_blocklength(cd, 2048);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (no_multi)
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cdi->mask |= CDC_MULTI_SESSION;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sector)
32496eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke		sr_printk(KERN_DEBUG, cd, "multisession offset=%lu\n",
32596eefad2d9e5a0d988cdfee85193b6154c0ae1d2Hannes Reinecke			  sector);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(buffer);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rc;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
330