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