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