Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0
2 : /* -*-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 and
7 : * the like) are too new to be included into the SCSI-II standard (to
8 : * 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 does
11 : * multisession using the READ TOC command (like SONY).
12 : *
13 : * Rearranged stuff here: SCSI-3 is included allways, support
14 : * 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's
21 : *
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 to
31 : * 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 0
54 : #define DEBUG
55 : #endif
56 :
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 2
62 : #define VENDOR_TOSHIBA 3
63 : #define VENDOR_WRITER 4 /* pre-scsi3 writers */
64 : #define VENDOR_CYGNAL_85ED 5 /* CD-on-a-chip */
65 :
66 : #define VENDOR_TIMEOUT 30*HZ
67 :
68 0 : void sr_vendor_init(Scsi_CD *cd)
69 : {
70 0 : const char *vendor = cd->device->vendor;
71 0 : const char *model = cd->device->model;
72 :
73 : /* default */
74 0 : cd->vendor = VENDOR_SCSI3;
75 0 : if (cd->readcd_known)
76 : /* this is true for scsi3/mmc drives - no more checks */
77 : return;
78 :
79 0 : if (cd->device->type == TYPE_WORM) {
80 0 : cd->vendor = VENDOR_WRITER;
81 :
82 0 : } else if (!strncmp(vendor, "NEC", 3)) {
83 0 : cd->vendor = VENDOR_NEC;
84 0 : if (!strncmp(model, "CD-ROM DRIVE:25", 15) ||
85 0 : !strncmp(model, "CD-ROM DRIVE:36", 15) ||
86 0 : !strncmp(model, "CD-ROM DRIVE:83", 15) ||
87 0 : !strncmp(model, "CD-ROM DRIVE:84 ", 16)
88 : #if 0
89 : /* my NEC 3x returns the read-raw data if a read-raw
90 : is followed by a read for the same sector - aeb */
91 : || !strncmp(model, "CD-ROM DRIVE:500", 16)
92 : #endif
93 : )
94 : /* these can't handle multisession, may hang */
95 0 : cd->cdi.mask |= CDC_MULTI_SESSION;
96 :
97 0 : } else if (!strncmp(vendor, "TOSHIBA", 7)) {
98 0 : cd->vendor = VENDOR_TOSHIBA;
99 :
100 0 : } else if (!strncmp(vendor, "Beurer", 6) &&
101 0 : !strncmp(model, "Gluco Memory", 12)) {
102 : /* The Beurer GL50 evo uses a Cygnal-manufactured CD-on-a-chip
103 : that only accepts a subset of SCSI commands. Most of the
104 : not-implemented commands are fine to fail, but a few,
105 : particularly around the MMC or Audio commands, will put the
106 : device into an unrecoverable state, so they need to be
107 : avoided at all costs.
108 : */
109 0 : cd->vendor = VENDOR_CYGNAL_85ED;
110 0 : cd->cdi.mask |= (
111 : CDC_MULTI_SESSION |
112 : CDC_CLOSE_TRAY | CDC_OPEN_TRAY |
113 : CDC_LOCK |
114 : CDC_GENERIC_PACKET |
115 : CDC_PLAY_AUDIO
116 : );
117 : }
118 : }
119 :
120 :
121 : /* small handy function for switching block length using MODE SELECT,
122 : * used by sr_read_sector() */
123 :
124 0 : int sr_set_blocklength(Scsi_CD *cd, int blocklength)
125 : {
126 0 : unsigned char *buffer; /* the buffer for the ioctl */
127 0 : struct packet_command cgc;
128 0 : struct ccs_modesel_head *modesel;
129 0 : int rc, density = 0;
130 :
131 0 : if (cd->vendor == VENDOR_TOSHIBA)
132 0 : density = (blocklength > 2048) ? 0x81 : 0x83;
133 :
134 0 : buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
135 0 : if (!buffer)
136 : return -ENOMEM;
137 :
138 : #ifdef DEBUG
139 : sr_printk(KERN_INFO, cd, "MODE SELECT 0x%x/%d\n", density, blocklength);
140 : #endif
141 0 : memset(&cgc, 0, sizeof(struct packet_command));
142 0 : cgc.cmd[0] = MODE_SELECT;
143 0 : cgc.cmd[1] = (1 << 4);
144 0 : cgc.cmd[4] = 12;
145 0 : modesel = (struct ccs_modesel_head *) buffer;
146 0 : memset(modesel, 0, sizeof(*modesel));
147 0 : modesel->block_desc_length = 0x08;
148 0 : modesel->density = density;
149 0 : modesel->block_length_med = (blocklength >> 8) & 0xff;
150 0 : modesel->block_length_lo = blocklength & 0xff;
151 0 : cgc.buffer = buffer;
152 0 : cgc.buflen = sizeof(*modesel);
153 0 : cgc.data_direction = DMA_TO_DEVICE;
154 0 : cgc.timeout = VENDOR_TIMEOUT;
155 0 : if (0 == (rc = sr_do_ioctl(cd, &cgc))) {
156 0 : cd->device->sector_size = blocklength;
157 : }
158 : #ifdef DEBUG
159 : else
160 : sr_printk(KERN_INFO, cd,
161 : "switching blocklength to %d bytes failed\n",
162 : blocklength);
163 : #endif
164 0 : kfree(buffer);
165 0 : return rc;
166 : }
167 :
168 : /* This function gets called after a media change. Checks if the CD is
169 : multisession, asks for offset etc. */
170 :
171 0 : int sr_cd_check(struct cdrom_device_info *cdi)
172 : {
173 0 : Scsi_CD *cd = cdi->handle;
174 0 : unsigned long sector;
175 0 : unsigned char *buffer; /* the buffer for the ioctl */
176 0 : struct packet_command cgc;
177 0 : int rc, no_multi;
178 :
179 0 : if (cd->cdi.mask & CDC_MULTI_SESSION)
180 : return 0;
181 :
182 0 : buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
183 0 : if (!buffer)
184 : return -ENOMEM;
185 :
186 0 : sector = 0; /* the multisession sector offset goes here */
187 0 : no_multi = 0; /* flag: the drive can't handle multisession */
188 0 : rc = 0;
189 :
190 0 : memset(&cgc, 0, sizeof(struct packet_command));
191 :
192 0 : switch (cd->vendor) {
193 :
194 0 : case VENDOR_SCSI3:
195 0 : cgc.cmd[0] = READ_TOC;
196 0 : cgc.cmd[8] = 12;
197 0 : cgc.cmd[9] = 0x40;
198 0 : cgc.buffer = buffer;
199 0 : cgc.buflen = 12;
200 0 : cgc.quiet = 1;
201 0 : cgc.data_direction = DMA_FROM_DEVICE;
202 0 : cgc.timeout = VENDOR_TIMEOUT;
203 0 : rc = sr_do_ioctl(cd, &cgc);
204 0 : if (rc != 0)
205 : break;
206 0 : if ((buffer[0] << 8) + buffer[1] < 0x0a) {
207 0 : sr_printk(KERN_INFO, cd, "Hmm, seems the drive "
208 : "doesn't support multisession CD's\n");
209 0 : no_multi = 1;
210 0 : break;
211 : }
212 0 : sector = buffer[11] + (buffer[10] << 8) +
213 0 : (buffer[9] << 16) + (buffer[8] << 24);
214 0 : if (buffer[6] <= 1) {
215 : /* ignore sector offsets from first track */
216 0 : sector = 0;
217 : }
218 : break;
219 :
220 0 : case VENDOR_NEC:{
221 0 : unsigned long min, sec, frame;
222 0 : cgc.cmd[0] = 0xde;
223 0 : cgc.cmd[1] = 0x03;
224 0 : cgc.cmd[2] = 0xb0;
225 0 : cgc.buffer = buffer;
226 0 : cgc.buflen = 0x16;
227 0 : cgc.quiet = 1;
228 0 : cgc.data_direction = DMA_FROM_DEVICE;
229 0 : cgc.timeout = VENDOR_TIMEOUT;
230 0 : rc = sr_do_ioctl(cd, &cgc);
231 0 : if (rc != 0)
232 : break;
233 0 : if (buffer[14] != 0 && buffer[14] != 0xb0) {
234 0 : sr_printk(KERN_INFO, cd, "Hmm, seems the cdrom "
235 : "doesn't support multisession CD's\n");
236 :
237 0 : no_multi = 1;
238 0 : break;
239 : }
240 0 : min = bcd2bin(buffer[15]);
241 0 : sec = bcd2bin(buffer[16]);
242 0 : frame = bcd2bin(buffer[17]);
243 0 : sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
244 0 : break;
245 : }
246 :
247 0 : case VENDOR_TOSHIBA:{
248 0 : unsigned long min, sec, frame;
249 :
250 : /* we request some disc information (is it a XA-CD ?,
251 : * where starts the last session ?) */
252 0 : cgc.cmd[0] = 0xc7;
253 0 : cgc.cmd[1] = 0x03;
254 0 : cgc.buffer = buffer;
255 0 : cgc.buflen = 4;
256 0 : cgc.quiet = 1;
257 0 : cgc.data_direction = DMA_FROM_DEVICE;
258 0 : cgc.timeout = VENDOR_TIMEOUT;
259 0 : rc = sr_do_ioctl(cd, &cgc);
260 0 : if (rc == -EINVAL) {
261 0 : sr_printk(KERN_INFO, cd, "Hmm, seems the drive "
262 : "doesn't support multisession CD's\n");
263 0 : no_multi = 1;
264 0 : break;
265 : }
266 0 : if (rc != 0)
267 : break;
268 0 : min = bcd2bin(buffer[1]);
269 0 : sec = bcd2bin(buffer[2]);
270 0 : frame = bcd2bin(buffer[3]);
271 0 : sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
272 0 : if (sector)
273 0 : sector -= CD_MSF_OFFSET;
274 0 : sr_set_blocklength(cd, 2048);
275 0 : break;
276 : }
277 :
278 0 : case VENDOR_WRITER:
279 0 : cgc.cmd[0] = READ_TOC;
280 0 : cgc.cmd[8] = 0x04;
281 0 : cgc.cmd[9] = 0x40;
282 0 : cgc.buffer = buffer;
283 0 : cgc.buflen = 0x04;
284 0 : cgc.quiet = 1;
285 0 : cgc.data_direction = DMA_FROM_DEVICE;
286 0 : cgc.timeout = VENDOR_TIMEOUT;
287 0 : rc = sr_do_ioctl(cd, &cgc);
288 0 : if (rc != 0) {
289 : break;
290 : }
291 0 : if ((rc = buffer[2]) == 0) {
292 0 : sr_printk(KERN_WARNING, cd,
293 : "No finished session\n");
294 0 : break;
295 : }
296 0 : cgc.cmd[0] = READ_TOC; /* Read TOC */
297 0 : cgc.cmd[6] = rc & 0x7f; /* number of last session */
298 0 : cgc.cmd[8] = 0x0c;
299 0 : cgc.cmd[9] = 0x40;
300 0 : cgc.buffer = buffer;
301 0 : cgc.buflen = 12;
302 0 : cgc.quiet = 1;
303 0 : cgc.data_direction = DMA_FROM_DEVICE;
304 0 : cgc.timeout = VENDOR_TIMEOUT;
305 0 : rc = sr_do_ioctl(cd, &cgc);
306 0 : if (rc != 0) {
307 : break;
308 : }
309 0 : sector = buffer[11] + (buffer[10] << 8) +
310 0 : (buffer[9] << 16) + (buffer[8] << 24);
311 0 : break;
312 :
313 0 : default:
314 : /* should not happen */
315 0 : sr_printk(KERN_WARNING, cd,
316 : "unknown vendor code (%i), not initialized ?\n",
317 : cd->vendor);
318 0 : sector = 0;
319 0 : no_multi = 1;
320 0 : break;
321 : }
322 0 : cd->ms_offset = sector;
323 0 : cd->xa_flag = 0;
324 0 : if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(cd))
325 0 : cd->xa_flag = 1;
326 :
327 0 : if (2048 != cd->device->sector_size) {
328 0 : sr_set_blocklength(cd, 2048);
329 : }
330 0 : if (no_multi)
331 0 : cdi->mask |= CDC_MULTI_SESSION;
332 :
333 : #ifdef DEBUG
334 : if (sector)
335 : sr_printk(KERN_DEBUG, cd, "multisession offset=%lu\n",
336 : sector);
337 : #endif
338 0 : kfree(buffer);
339 0 : return rc;
340 : }
|