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