341 lines · c
1// SPDX-License-Identifier: GPL-2.02/* -*-linux-c-*-3 4 * vendor-specific code for SCSI CD-ROM's goes here.5 *6 * This is needed becauce most of the new features (multisession and7 * the like) are too new to be included into the SCSI-II standard (to8 * be exact: there is'nt anything in my draft copy).9 *10 * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does11 * multisession using the READ TOC command (like SONY).12 *13 * Rearranged stuff here: SCSI-3 is included allways, support14 * for NEC/TOSHIBA/HP commands is optional.15 *16 * Gerd Knorr <kraxel@cs.tu-berlin.de> 17 *18 * --------------------------------------------------------------------------19 *20 * support for XA/multisession-CD's21 * 22 * - NEC: Detection and support of multisession CD's.23 * 24 * - TOSHIBA: Detection and support of multisession CD's.25 * Some XA-Sector tweaking, required for older drives.26 *27 * - SONY: Detection and support of multisession CD's.28 * added by Thomas Quinot <thomas@cuivre.freenix.fr>29 *30 * - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to31 * work with SONY (SCSI3 now) code.32 *33 * - HP: Much like SONY, but a little different... (Thomas)34 * HP-Writers only ??? Maybe other CD-Writers work with this too ?35 * HP 6020 writers now supported.36 */37 38#include <linux/cdrom.h>39#include <linux/errno.h>40#include <linux/string.h>41#include <linux/bcd.h>42#include <linux/blkdev.h>43#include <linux/slab.h>44 45#include <scsi/scsi.h>46#include <scsi/scsi_cmnd.h>47#include <scsi/scsi_device.h>48#include <scsi/scsi_host.h>49#include <scsi/scsi_ioctl.h>50 51#include "sr.h"52 53#if 054#define DEBUG55#endif56 57/* here are some constants to sort the vendors into groups */58 59#define VENDOR_SCSI3 1 /* default: scsi-3 mmc */60 61#define VENDOR_NEC 262#define VENDOR_TOSHIBA 363#define VENDOR_WRITER 4 /* pre-scsi3 writers */64#define VENDOR_CYGNAL_85ED 5 /* CD-on-a-chip */65 66#define VENDOR_TIMEOUT 30*HZ67 68void sr_vendor_init(Scsi_CD *cd)69{70 const char *vendor = cd->device->vendor;71 const char *model = cd->device->model;72 73 /* default */74 cd->vendor = VENDOR_SCSI3;75 if (cd->readcd_known)76 /* this is true for scsi3/mmc drives - no more checks */77 return;78 79 if (cd->device->type == TYPE_WORM) {80 cd->vendor = VENDOR_WRITER;81 82 } else if (!strncmp(vendor, "NEC", 3)) {83 cd->vendor = VENDOR_NEC;84 if (!strncmp(model, "CD-ROM DRIVE:25", 15) ||85 !strncmp(model, "CD-ROM DRIVE:36", 15) ||86 !strncmp(model, "CD-ROM DRIVE:83", 15) ||87 !strncmp(model, "CD-ROM DRIVE:84 ", 16)88#if 089 /* my NEC 3x returns the read-raw data if a read-raw90 is followed by a read for the same sector - aeb */91 || !strncmp(model, "CD-ROM DRIVE:500", 16)92#endif93 )94 /* these can't handle multisession, may hang */95 cd->cdi.mask |= CDC_MULTI_SESSION;96 97 } else if (!strncmp(vendor, "TOSHIBA", 7)) {98 cd->vendor = VENDOR_TOSHIBA;99 100 } else if (!strncmp(vendor, "Beurer", 6) &&101 !strncmp(model, "Gluco Memory", 12)) {102 /* The Beurer GL50 evo uses a Cygnal-manufactured CD-on-a-chip103 that only accepts a subset of SCSI commands. Most of the104 not-implemented commands are fine to fail, but a few,105 particularly around the MMC or Audio commands, will put the106 device into an unrecoverable state, so they need to be107 avoided at all costs.108 */109 cd->vendor = VENDOR_CYGNAL_85ED;110 cd->cdi.mask |= (111 CDC_MULTI_SESSION |112 CDC_CLOSE_TRAY | CDC_OPEN_TRAY |113 CDC_LOCK |114 CDC_GENERIC_PACKET |115 CDC_PLAY_AUDIO116 );117 }118}119 120 121/* small handy function for switching block length using MODE SELECT,122 * used by sr_read_sector() */123 124int sr_set_blocklength(Scsi_CD *cd, int blocklength)125{126 unsigned char *buffer; /* the buffer for the ioctl */127 struct packet_command cgc;128 struct ccs_modesel_head *modesel;129 int rc, density = 0;130 131 if (cd->vendor == VENDOR_TOSHIBA)132 density = (blocklength > 2048) ? 0x81 : 0x83;133 134 buffer = kmalloc(512, GFP_KERNEL);135 if (!buffer)136 return -ENOMEM;137 138#ifdef DEBUG139 sr_printk(KERN_INFO, cd, "MODE SELECT 0x%x/%d\n", density, blocklength);140#endif141 memset(&cgc, 0, sizeof(struct packet_command));142 cgc.cmd[0] = MODE_SELECT;143 cgc.cmd[1] = (1 << 4);144 cgc.cmd[4] = 12;145 modesel = (struct ccs_modesel_head *) buffer;146 memset(modesel, 0, sizeof(*modesel));147 modesel->block_desc_length = 0x08;148 modesel->density = density;149 modesel->block_length_med = (blocklength >> 8) & 0xff;150 modesel->block_length_lo = blocklength & 0xff;151 cgc.buffer = buffer;152 cgc.buflen = sizeof(*modesel);153 cgc.data_direction = DMA_TO_DEVICE;154 cgc.timeout = VENDOR_TIMEOUT;155 if (0 == (rc = sr_do_ioctl(cd, &cgc))) {156 cd->device->sector_size = blocklength;157 }158#ifdef DEBUG159 else160 sr_printk(KERN_INFO, cd,161 "switching blocklength to %d bytes failed\n",162 blocklength);163#endif164 kfree(buffer);165 return rc;166}167 168/* This function gets called after a media change. Checks if the CD is169 multisession, asks for offset etc. */170 171int sr_cd_check(struct cdrom_device_info *cdi)172{173 Scsi_CD *cd = cdi->handle;174 unsigned long sector;175 unsigned char *buffer; /* the buffer for the ioctl */176 struct packet_command cgc;177 int rc, no_multi;178 179 if (cd->cdi.mask & CDC_MULTI_SESSION)180 return 0;181 182 buffer = kmalloc(512, GFP_KERNEL);183 if (!buffer)184 return -ENOMEM;185 186 sector = 0; /* the multisession sector offset goes here */187 no_multi = 0; /* flag: the drive can't handle multisession */188 rc = 0;189 190 memset(&cgc, 0, sizeof(struct packet_command));191 192 switch (cd->vendor) {193 194 case VENDOR_SCSI3:195 cgc.cmd[0] = READ_TOC;196 cgc.cmd[8] = 12;197 cgc.cmd[9] = 0x40;198 cgc.buffer = buffer;199 cgc.buflen = 12;200 cgc.quiet = 1;201 cgc.data_direction = DMA_FROM_DEVICE;202 cgc.timeout = VENDOR_TIMEOUT;203 rc = sr_do_ioctl(cd, &cgc);204 if (rc != 0)205 break;206 if ((buffer[0] << 8) + buffer[1] < 0x0a) {207 sr_printk(KERN_INFO, cd, "Hmm, seems the drive "208 "doesn't support multisession CD's\n");209 no_multi = 1;210 break;211 }212 sector = buffer[11] + (buffer[10] << 8) +213 (buffer[9] << 16) + (buffer[8] << 24);214 if (buffer[6] <= 1) {215 /* ignore sector offsets from first track */216 sector = 0;217 }218 break;219 220 case VENDOR_NEC:{221 unsigned long min, sec, frame;222 cgc.cmd[0] = 0xde;223 cgc.cmd[1] = 0x03;224 cgc.cmd[2] = 0xb0;225 cgc.buffer = buffer;226 cgc.buflen = 0x16;227 cgc.quiet = 1;228 cgc.data_direction = DMA_FROM_DEVICE;229 cgc.timeout = VENDOR_TIMEOUT;230 rc = sr_do_ioctl(cd, &cgc);231 if (rc != 0)232 break;233 if (buffer[14] != 0 && buffer[14] != 0xb0) {234 sr_printk(KERN_INFO, cd, "Hmm, seems the cdrom "235 "doesn't support multisession CD's\n");236 237 no_multi = 1;238 break;239 }240 min = bcd2bin(buffer[15]);241 sec = bcd2bin(buffer[16]);242 frame = bcd2bin(buffer[17]);243 sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;244 break;245 }246 247 case VENDOR_TOSHIBA:{248 unsigned long min, sec, frame;249 250 /* we request some disc information (is it a XA-CD ?,251 * where starts the last session ?) */252 cgc.cmd[0] = 0xc7;253 cgc.cmd[1] = 0x03;254 cgc.buffer = buffer;255 cgc.buflen = 4;256 cgc.quiet = 1;257 cgc.data_direction = DMA_FROM_DEVICE;258 cgc.timeout = VENDOR_TIMEOUT;259 rc = sr_do_ioctl(cd, &cgc);260 if (rc == -EINVAL) {261 sr_printk(KERN_INFO, cd, "Hmm, seems the drive "262 "doesn't support multisession CD's\n");263 no_multi = 1;264 break;265 }266 if (rc != 0)267 break;268 min = bcd2bin(buffer[1]);269 sec = bcd2bin(buffer[2]);270 frame = bcd2bin(buffer[3]);271 sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;272 if (sector)273 sector -= CD_MSF_OFFSET;274 sr_set_blocklength(cd, 2048);275 break;276 }277 278 case VENDOR_WRITER:279 cgc.cmd[0] = READ_TOC;280 cgc.cmd[8] = 0x04;281 cgc.cmd[9] = 0x40;282 cgc.buffer = buffer;283 cgc.buflen = 0x04;284 cgc.quiet = 1;285 cgc.data_direction = DMA_FROM_DEVICE;286 cgc.timeout = VENDOR_TIMEOUT;287 rc = sr_do_ioctl(cd, &cgc);288 if (rc != 0) {289 break;290 }291 if ((rc = buffer[2]) == 0) {292 sr_printk(KERN_WARNING, cd,293 "No finished session\n");294 break;295 }296 cgc.cmd[0] = READ_TOC; /* Read TOC */297 cgc.cmd[6] = rc & 0x7f; /* number of last session */298 cgc.cmd[8] = 0x0c;299 cgc.cmd[9] = 0x40;300 cgc.buffer = buffer;301 cgc.buflen = 12;302 cgc.quiet = 1;303 cgc.data_direction = DMA_FROM_DEVICE;304 cgc.timeout = VENDOR_TIMEOUT;305 rc = sr_do_ioctl(cd, &cgc);306 if (rc != 0) {307 break;308 }309 sector = buffer[11] + (buffer[10] << 8) +310 (buffer[9] << 16) + (buffer[8] << 24);311 break;312 313 default:314 /* should not happen */315 sr_printk(KERN_WARNING, cd,316 "unknown vendor code (%i), not initialized ?\n",317 cd->vendor);318 sector = 0;319 no_multi = 1;320 break;321 }322 cd->ms_offset = sector;323 cd->xa_flag = 0;324 if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(cd))325 cd->xa_flag = 1;326 327 if (2048 != cd->device->sector_size) {328 sr_set_blocklength(cd, 2048);329 }330 if (no_multi)331 cdi->mask |= CDC_MULTI_SESSION;332 333#ifdef DEBUG334 if (sector)335 sr_printk(KERN_DEBUG, cd, "multisession offset=%lu\n",336 sector);337#endif338 kfree(buffer);339 return rc;340}341