3 * vendor-specific code for SCSI CD-ROM's goes here.
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).
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).
12 * Rearranged stuff here: SCSI-3 is included allways, support
13 * for NEC/TOSHIBA/HP commands is optional.
15 * Gerd Knorr <kraxel@cs.tu-berlin.de>
17 * --------------------------------------------------------------------------
19 * support for XA/multisession-CD's
21 * - NEC: Detection and support of multisession CD's.
23 * - TOSHIBA: Detection and support of multisession CD's.
24 * Some XA-Sector tweaking, required for older drives.
26 * - SONY: Detection and support of multisession CD's.
27 * added by Thomas Quinot <thomas@cuivre.freenix.fr>
29 * - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to
30 * work with SONY (SCSI3 now) code.
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.
37 #include <linux/config.h>
38 #include <linux/errno.h>
39 #include <linux/string.h>
41 #include <linux/blk.h>
44 #include <scsi/scsi_ioctl.h>
46 #include <linux/cdrom.h>
53 /* here are some constants to sort the vendors into groups */
55 #define VENDOR_SCSI3 1 /* default: scsi-3 mmc */
58 #define VENDOR_TOSHIBA 3
59 #define VENDOR_WRITER 4 /* pre-scsi3 writers */
61 #define VENDOR_ID (scsi_CDs[minor].vendor)
63 void sr_vendor_init(int minor
)
65 #ifndef CONFIG_BLK_DEV_SR_VENDOR
66 VENDOR_ID
= VENDOR_SCSI3
;
68 char *vendor
= scsi_CDs
[minor
].device
->vendor
;
69 char *model
= scsi_CDs
[minor
].device
->model
;
72 VENDOR_ID
= VENDOR_SCSI3
;
73 if (scsi_CDs
[minor
].readcd_known
)
74 /* this is true for scsi3/mmc drives - no more checks */
77 if (scsi_CDs
[minor
].device
->type
== TYPE_WORM
) {
78 VENDOR_ID
= VENDOR_WRITER
;
80 } else if (!strncmp(vendor
, "NEC", 3)) {
81 VENDOR_ID
= 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)
87 /* my NEC 3x returns the read-raw data if a read-raw
88 is followed by a read for the same sector - aeb */
89 || !strncmp(model
, "CD-ROM DRIVE:500", 16)
92 /* these can't handle multisession, may hang */
93 scsi_CDs
[minor
].cdi
.mask
|= CDC_MULTI_SESSION
;
95 } else if (!strncmp(vendor
, "TOSHIBA", 7)) {
96 VENDOR_ID
= VENDOR_TOSHIBA
;
103 /* small handy function for switching block length using MODE SELECT,
104 * used by sr_read_sector() */
106 int sr_set_blocklength(int minor
, int blocklength
)
108 unsigned char *buffer
; /* the buffer for the ioctl */
109 unsigned char cmd
[MAX_COMMAND_SIZE
]; /* the scsi-command */
110 struct ccs_modesel_head
*modesel
;
113 #ifdef CONFIG_BLK_DEV_SR_VENDOR
114 if (VENDOR_ID
== VENDOR_TOSHIBA
)
115 density
= (blocklength
> 2048) ? 0x81 : 0x83;
118 buffer
= (unsigned char *) scsi_malloc(512);
123 printk("sr%d: MODE SELECT 0x%x/%d\n", minor
, density
, blocklength
);
125 memset(cmd
, 0, MAX_COMMAND_SIZE
);
126 cmd
[0] = MODE_SELECT
;
127 cmd
[1] = (scsi_CDs
[minor
].device
->lun
<< 5) | (1 << 4);
129 modesel
= (struct ccs_modesel_head
*) buffer
;
130 memset(modesel
, 0, sizeof(*modesel
));
131 modesel
->block_desc_length
= 0x08;
132 modesel
->density
= density
;
133 modesel
->block_length_med
= (blocklength
>> 8) & 0xff;
134 modesel
->block_length_lo
= blocklength
& 0xff;
135 if (0 == (rc
= sr_do_ioctl(minor
, cmd
, buffer
, sizeof(*modesel
), 0, SCSI_DATA_WRITE
, NULL
))) {
136 scsi_CDs
[minor
].device
->sector_size
= blocklength
;
140 printk("sr%d: switching blocklength to %d bytes failed\n",
143 scsi_free(buffer
, 512);
147 /* This function gets called after a media change. Checks if the CD is
148 multisession, asks for offset etc. */
150 #define BCD_TO_BIN(x) ((((int)x & 0xf0) >> 4)*10 + ((int)x & 0x0f))
152 int sr_cd_check(struct cdrom_device_info
*cdi
)
154 unsigned long sector
;
155 unsigned char *buffer
; /* the buffer for the ioctl */
156 unsigned char cmd
[MAX_COMMAND_SIZE
]; /* the scsi-command */
157 int rc
, no_multi
, minor
;
159 minor
= MINOR(cdi
->dev
);
160 if (scsi_CDs
[minor
].cdi
.mask
& CDC_MULTI_SESSION
)
163 buffer
= (unsigned char *) scsi_malloc(512);
167 sector
= 0; /* the multisession sector offset goes here */
168 no_multi
= 0; /* flag: the drive can't handle multisession */
174 memset(cmd
, 0, MAX_COMMAND_SIZE
);
176 cmd
[1] = (scsi_CDs
[minor
].device
->lun
<< 5);
179 rc
= sr_do_ioctl(minor
, cmd
, buffer
, 12, 1, SCSI_DATA_READ
, NULL
);
182 if ((buffer
[0] << 8) + buffer
[1] < 0x0a) {
183 printk(KERN_INFO
"sr%d: Hmm, seems the drive "
184 "doesn't support multisession CD's\n", minor
);
188 sector
= buffer
[11] + (buffer
[10] << 8) +
189 (buffer
[9] << 16) + (buffer
[8] << 24);
190 if (buffer
[6] <= 1) {
191 /* ignore sector offsets from first track */
196 #ifdef CONFIG_BLK_DEV_SR_VENDOR
198 unsigned long min
, sec
, frame
;
199 memset(cmd
, 0, MAX_COMMAND_SIZE
);
201 cmd
[1] = (scsi_CDs
[minor
].device
->lun
<< 5) | 0x03;
203 rc
= sr_do_ioctl(minor
, cmd
, buffer
, 0x16, 1, SCSI_DATA_READ
, NULL
);
206 if (buffer
[14] != 0 && buffer
[14] != 0xb0) {
207 printk(KERN_INFO
"sr%d: Hmm, seems the cdrom "
208 "doesn't support multisession CD's\n", minor
);
212 min
= BCD_TO_BIN(buffer
[15]);
213 sec
= BCD_TO_BIN(buffer
[16]);
214 frame
= BCD_TO_BIN(buffer
[17]);
215 sector
= min
* CD_SECS
* CD_FRAMES
+ sec
* CD_FRAMES
+ frame
;
219 case VENDOR_TOSHIBA
:{
220 unsigned long min
, sec
, frame
;
222 /* we request some disc information (is it a XA-CD ?,
223 * where starts the last session ?) */
224 memset(cmd
, 0, MAX_COMMAND_SIZE
);
226 cmd
[1] = (scsi_CDs
[minor
].device
->lun
<< 5) | 3;
227 rc
= sr_do_ioctl(minor
, cmd
, buffer
, 4, 1, SCSI_DATA_READ
, NULL
);
229 printk(KERN_INFO
"sr%d: Hmm, seems the drive "
230 "doesn't support multisession CD's\n", minor
);
236 min
= BCD_TO_BIN(buffer
[1]);
237 sec
= BCD_TO_BIN(buffer
[2]);
238 frame
= BCD_TO_BIN(buffer
[3]);
239 sector
= min
* CD_SECS
* CD_FRAMES
+ sec
* CD_FRAMES
+ frame
;
241 sector
-= CD_MSF_OFFSET
;
242 sr_set_blocklength(minor
, 2048);
247 memset(cmd
, 0, MAX_COMMAND_SIZE
);
249 cmd
[1] = (scsi_CDs
[minor
].device
->lun
<< 5);
252 rc
= sr_do_ioctl(minor
, cmd
, buffer
, 0x04, 1, SCSI_DATA_READ
, NULL
);
256 if ((rc
= buffer
[2]) == 0) {
258 "sr%d: No finished session\n", minor
);
261 cmd
[0] = READ_TOC
; /* Read TOC */
262 cmd
[1] = (scsi_CDs
[minor
].device
->lun
<< 5);
263 cmd
[6] = rc
& 0x7f; /* number of last session */
266 rc
= sr_do_ioctl(minor
, cmd
, buffer
, 12, 1, SCSI_DATA_READ
, NULL
);
270 sector
= buffer
[11] + (buffer
[10] << 8) +
271 (buffer
[9] << 16) + (buffer
[8] << 24);
273 #endif /* CONFIG_BLK_DEV_SR_VENDOR */
276 /* should not happen */
278 "sr%d: unknown vendor code (%i), not initialized ?\n",
284 scsi_CDs
[minor
].ms_offset
= sector
;
285 scsi_CDs
[minor
].xa_flag
= 0;
286 if (CDS_AUDIO
!= sr_disk_status(cdi
) && 1 == sr_is_xa(minor
))
287 scsi_CDs
[minor
].xa_flag
= 1;
289 if (2048 != scsi_CDs
[minor
].device
->sector_size
) {
290 sr_set_blocklength(minor
, 2048);
293 cdi
->mask
|= CDC_MULTI_SESSION
;
297 printk(KERN_DEBUG
"sr%d: multisession offset=%lu\n",
300 scsi_free(buffer
, 512);