cd.c revision 1.76
1/*	$NetBSD: cd.c,v 1.76 1995/10/10 02:52:56 mycroft Exp $	*/
2
3/*
4 * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by Charles M. Hannum.
17 * 4. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Originally written by Julian Elischer (julian@tfs.com)
34 * for TRW Financial Systems for use under the MACH(2.5) operating system.
35 *
36 * TRW Financial Systems, in accordance with their agreement with Carnegie
37 * Mellon University, makes this software available to CMU to distribute
38 * or use in any manner that they see fit as long as this message is kept with
39 * the software. For this reason TFS also grants any other persons or
40 * organisations permission to use or modify this software.
41 *
42 * TFS supplies this software to be publicly redistributed
43 * on the understanding that TFS is not responsible for the correct
44 * functioning of this software in any circumstances.
45 *
46 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
47 */
48
49#include <sys/types.h>
50#include <sys/param.h>
51#include <sys/systm.h>
52#include <sys/kernel.h>
53#include <sys/conf.h>
54#include <sys/file.h>
55#include <sys/stat.h>
56#include <sys/ioctl.h>
57#include <sys/buf.h>
58#include <sys/uio.h>
59#include <sys/malloc.h>
60#include <sys/errno.h>
61#include <sys/device.h>
62#include <sys/disklabel.h>
63#include <sys/disk.h>
64#include <sys/cdio.h>
65
66#include <scsi/scsi_all.h>
67#include <scsi/scsi_cd.h>
68#include <scsi/scsi_disk.h>	/* rw_big and start_stop come from there */
69#include <scsi/scsiconf.h>
70
71#define	CDOUTSTANDING	2
72#define	CDRETRIES	1
73
74#define	CDUNIT(z)			DISKUNIT(z)
75#define	CDPART(z)			DISKPART(z)
76#define	MAKECDDEV(maj, unit, part)	MAKEDISKDEV(maj, unit, part)
77
78struct cd_softc {
79	struct device sc_dev;
80	struct dkdevice sc_dk;
81
82	int flags;
83#define	CDF_LOCKED	0x01
84#define	CDF_WANTED	0x02
85#define	CDF_WLABEL	0x04		/* label is writable */
86#define	CDF_LABELLING	0x08		/* writing label */
87	struct scsi_link *sc_link;	/* contains our targ, lun, etc. */
88	struct cd_parms {
89		int blksize;
90		u_long disksize;	/* total number sectors */
91	} params;
92	struct buf buf_queue;
93};
94
95int cdmatch __P((struct device *, void *, void *));
96void cdattach __P((struct device *, struct device *, void *));
97
98struct cfdriver cdcd = {
99	NULL, "cd", cdmatch, cdattach, DV_DISK, sizeof(struct cd_softc)
100};
101
102void cdgetdisklabel __P((struct cd_softc *));
103int cd_get_parms __P((struct cd_softc *, int));
104void cdstrategy __P((struct buf *));
105void cdstart __P((struct cd_softc *));
106
107struct dkdriver cddkdriver = { cdstrategy };
108
109struct scsi_device cd_switch = {
110	NULL,			/* use default error handler */
111	cdstart,		/* we have a queue, which is started by this */
112	NULL,			/* we do not have an async handler */
113	NULL,			/* use default 'done' routine */
114};
115
116struct scsi_inquiry_pattern cd_patterns[] = {
117	{T_CDROM, T_REMOV,
118	 "",         "",                 ""},
119#if 0
120	{T_CDROM, T_REMOV, /* more luns */
121	 "PIONEER ", "CD-ROM DRM-600  ", ""},
122#endif
123};
124
125int
126cdmatch(parent, match, aux)
127	struct device *parent;
128	void *match, *aux;
129{
130	struct cfdata *cf = match;
131	struct scsibus_attach_args *sa = aux;
132	int priority;
133
134	(void)scsi_inqmatch(sa->sa_inqbuf,
135	    (caddr_t)cd_patterns, sizeof(cd_patterns)/sizeof(cd_patterns[0]),
136	    sizeof(cd_patterns[0]), &priority);
137	return (priority);
138}
139
140/*
141 * The routine called by the low level scsi routine when it discovers
142 * A device suitable for this driver
143 */
144void
145cdattach(parent, self, aux)
146	struct device *parent, *self;
147	void *aux;
148{
149	struct cd_softc *cd = (void *)self;
150	struct cd_parms *dp = &cd->params;
151	struct scsibus_attach_args *sa = aux;
152	struct scsi_link *sc_link = sa->sa_sc_link;
153
154	SC_DEBUG(sc_link, SDEV_DB2, ("cdattach: "));
155
156	/*
157	 * Store information needed to contact our base driver
158	 */
159	cd->sc_link = sc_link;
160	sc_link->device = &cd_switch;
161	sc_link->device_softc = cd;
162	if (sc_link->openings > CDOUTSTANDING)
163		sc_link->openings = CDOUTSTANDING;
164
165	cd->sc_dk.dk_driver = &cddkdriver;
166#if !defined(i386) || defined(NEWCONFIG)
167	dk_establish(&cd->sc_dk, &cd->sc_dev);
168#endif
169
170	/*
171	 * Use the subdriver to request information regarding
172	 * the drive. We cannot use interrupts yet, so the
173	 * request must specify this.
174	 */
175	if (scsi_start(cd->sc_link, SSS_START,
176	    SCSI_AUTOCONF | SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE | SCSI_SILENT) ||
177	    cd_get_parms(cd, SCSI_AUTOCONF) != 0)
178		printf(": drive empty\n");
179	else
180		printf(": cd present, %d x %d byte records\n",
181		    cd->params.disksize, cd->params.blksize);
182}
183
184/*
185 * Wait interruptibly for an exclusive lock.
186 *
187 * XXX
188 * Several drivers do this; it should be abstracted and made MP-safe.
189 */
190int
191cdlock(cd)
192	struct cd_softc *cd;
193{
194	int error;
195
196	while ((cd->flags & CDF_LOCKED) != 0) {
197		cd->flags |= CDF_WANTED;
198		if ((error = tsleep(cd, PRIBIO | PCATCH, "cdlck", 0)) != 0)
199			return error;
200	}
201	cd->flags |= CDF_LOCKED;
202	return 0;
203}
204
205/*
206 * Unlock and wake up any waiters.
207 */
208void
209cdunlock(cd)
210	struct cd_softc *cd;
211{
212
213	cd->flags &= ~CDF_LOCKED;
214	if ((cd->flags & CDF_WANTED) != 0) {
215		cd->flags &= ~CDF_WANTED;
216		wakeup(cd);
217	}
218}
219
220/*
221 * open the device. Make sure the partition info is a up-to-date as can be.
222 */
223int
224cdopen(dev, flag, fmt)
225	dev_t dev;
226	int flag, fmt;
227{
228	struct cd_softc *cd;
229	struct scsi_link *sc_link;
230	int unit, part;
231	int error;
232
233	unit = CDUNIT(dev);
234	if (unit >= cdcd.cd_ndevs)
235		return ENXIO;
236	cd = cdcd.cd_devs[unit];
237	if (!cd)
238		return ENXIO;
239
240	sc_link = cd->sc_link;
241
242	SC_DEBUG(sc_link, SDEV_DB1,
243	    ("cdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
244	    cdcd.cd_ndevs, part));
245
246	if (error = cdlock(cd))
247		return error;
248
249	if (cd->sc_dk.dk_openmask != 0) {
250		/*
251		 * If any partition is open, but the disk has been invalidated,
252		 * disallow further opens.
253		 */
254		if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
255			error = EIO;
256			goto bad3;
257		}
258	} else {
259		/* Check that it is still responding and ok. */
260		if (error = scsi_test_unit_ready(sc_link,
261		    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE | SCSI_IGNORE_NOT_READY))
262			goto bad3;
263
264		/* Start the pack spinning if necessary. */
265		if (error = scsi_start(sc_link, SSS_START,
266		    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE | SCSI_SILENT))
267			goto bad3;
268
269		sc_link->flags |= SDEV_OPEN;
270
271		/* Lock the pack in. */
272		if (error = scsi_prevent(sc_link, PR_PREVENT,
273		    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE))
274			goto bad;
275
276		if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
277			sc_link->flags |= SDEV_MEDIA_LOADED;
278
279			/* Load the physical device parameters. */
280			if (cd_get_parms(cd, 0) != 0) {
281				error = ENXIO;
282				goto bad2;
283			}
284			SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded "));
285
286			/* Fabricate a disk label. */
287			cdgetdisklabel(cd);
288			SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel fabricated "));
289		}
290	}
291
292	part = CDPART(dev);
293
294	/* Check that the partition exists. */
295	if (part != RAW_PART &&
296	    (part >= cd->sc_dk.dk_label.d_npartitions ||
297	     cd->sc_dk.dk_label.d_partitions[part].p_fstype == FS_UNUSED)) {
298		error = ENXIO;
299		goto bad;
300	}
301
302	/* Insure only one open at a time. */
303	switch (fmt) {
304	case S_IFCHR:
305		cd->sc_dk.dk_copenmask |= (1 << part);
306		break;
307	case S_IFBLK:
308		cd->sc_dk.dk_bopenmask |= (1 << part);
309		break;
310	}
311	cd->sc_dk.dk_openmask = cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
312
313	SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n"));
314	cdunlock(cd);
315	return 0;
316
317bad2:
318	sc_link->flags &= ~SDEV_MEDIA_LOADED;
319
320bad:
321	if (cd->sc_dk.dk_openmask == 0) {
322		scsi_prevent(sc_link, PR_ALLOW,
323		    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
324		sc_link->flags &= ~SDEV_OPEN;
325	}
326
327bad3:
328	cdunlock(cd);
329	return error;
330}
331
332/*
333 * close the device.. only called if we are the LAST
334 * occurence of an open device
335 */
336int
337cdclose(dev, flag, fmt)
338	dev_t dev;
339	int flag, fmt;
340{
341	struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)];
342	int part = CDPART(dev);
343	int error;
344
345	if (error = cdlock(cd))
346		return error;
347
348	switch (fmt) {
349	case S_IFCHR:
350		cd->sc_dk.dk_copenmask &= ~(1 << part);
351		break;
352	case S_IFBLK:
353		cd->sc_dk.dk_bopenmask &= ~(1 << part);
354		break;
355	}
356	cd->sc_dk.dk_openmask = cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
357
358	if (cd->sc_dk.dk_openmask == 0) {
359		/* XXXX Must wait for I/O to complete! */
360
361		scsi_prevent(cd->sc_link, PR_ALLOW,
362		    SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_NOT_READY);
363		cd->sc_link->flags &= ~SDEV_OPEN;
364	}
365
366	cdunlock(cd);
367	return 0;
368}
369
370/*
371 * Actually translate the requested transfer into one the physical driver can
372 * understand.  The transfer is described by a buf and will include only one
373 * physical transfer.
374 */
375void
376cdstrategy(bp)
377	struct buf *bp;
378{
379	struct cd_softc *cd = cdcd.cd_devs[CDUNIT(bp->b_dev)];
380	int opri;
381
382	SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdstrategy "));
383	SC_DEBUG(cd->sc_link, SDEV_DB1,
384	    ("%d bytes @ blk %d\n", bp->b_bcount, bp->b_blkno));
385	/*
386	 * The transfer must be a whole number of blocks.
387	 */
388	if ((bp->b_bcount % cd->sc_dk.dk_label.d_secsize) != 0) {
389		bp->b_error = EINVAL;
390		goto bad;
391	}
392	/*
393	 * If the device has been made invalid, error out
394	 * maybe the media changed
395	 */
396	if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
397		bp->b_error = EIO;
398		goto bad;
399	}
400	/*
401	 * If it's a null transfer, return immediately
402	 */
403	if (bp->b_bcount == 0)
404		goto done;
405
406	/*
407	 * Do bounds checking, adjust transfer. if error, process.
408	 * If end of partition, just return.
409	 */
410	if (CDPART(bp->b_dev) != RAW_PART &&
411	    bounds_check_with_label(bp, &cd->sc_dk.dk_label,
412	    (cd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0)
413		goto done;
414
415	opri = splbio();
416
417	/*
418	 * Place it in the queue of disk activities for this disk
419	 */
420	disksort(&cd->buf_queue, bp);
421
422	/*
423	 * Tell the device to get going on the transfer if it's
424	 * not doing anything, otherwise just wait for completion
425	 */
426	cdstart(cd);
427
428	splx(opri);
429	return;
430
431bad:
432	bp->b_flags |= B_ERROR;
433done:
434	/*
435	 * Correctly set the buf to indicate a completed xfer
436	 */
437	bp->b_resid = bp->b_bcount;
438	biodone(bp);
439}
440
441/*
442 * cdstart looks to see if there is a buf waiting for the device
443 * and that the device is not already busy. If both are true,
444 * It deques the buf and creates a scsi command to perform the
445 * transfer in the buf. The transfer request will call scsi_done
446 * on completion, which will in turn call this routine again
447 * so that the next queued transfer is performed.
448 * The bufs are queued by the strategy routine (cdstrategy)
449 *
450 * This routine is also called after other non-queued requests
451 * have been made of the scsi driver, to ensure that the queue
452 * continues to be drained.
453 *
454 * must be called at the correct (highish) spl level
455 * cdstart() is called at splbio from cdstrategy and scsi_done
456 */
457void
458cdstart(cd)
459	register struct cd_softc *cd;
460{
461	register struct scsi_link *sc_link = cd->sc_link;
462	struct buf *bp = 0;
463	struct buf *dp;
464	struct scsi_rw_big cmd;
465	int blkno, nblks;
466	struct partition *p;
467
468	SC_DEBUG(sc_link, SDEV_DB2, ("cdstart "));
469	/*
470	 * Check if the device has room for another command
471	 */
472	while (sc_link->openings > 0) {
473		/*
474		 * there is excess capacity, but a special waits
475		 * It'll need the adapter as soon as we clear out of the
476		 * way and let it run (user level wait).
477		 */
478		if (sc_link->flags & SDEV_WAITING) {
479			sc_link->flags &= ~SDEV_WAITING;
480			wakeup((caddr_t)sc_link);
481			return;
482		}
483
484		/*
485		 * See if there is a buf with work for us to do..
486		 */
487		dp = &cd->buf_queue;
488		if ((bp = dp->b_actf) == NULL)	/* yes, an assign */
489			return;
490		dp->b_actf = bp->b_actf;
491
492		/*
493		 * If the deivce has become invalid, abort all the
494		 * reads and writes until all files have been closed and
495		 * re-opened
496		 */
497		if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) {
498			bp->b_error = EIO;
499			bp->b_flags |= B_ERROR;
500			biodone(bp);
501			continue;
502		}
503
504		/*
505		 * We have a buf, now we should make a command
506		 *
507		 * First, translate the block to absolute and put it in terms
508		 * of the logical blocksize of the device.
509		 */
510		blkno =
511		    bp->b_blkno / (cd->sc_dk.dk_label.d_secsize / DEV_BSIZE);
512		if (CDPART(bp->b_dev) != RAW_PART) {
513			p = &cd->sc_dk.dk_label.d_partitions[CDPART(bp->b_dev)];
514			blkno += p->p_offset;
515		}
516		nblks = howmany(bp->b_bcount, cd->sc_dk.dk_label.d_secsize);
517
518		/*
519		 *  Fill out the scsi command
520		 */
521		bzero(&cmd, sizeof(cmd));
522		cmd.opcode = (bp->b_flags & B_READ) ? READ_BIG : WRITE_BIG;
523		cmd.addr_3 = (blkno >> 24) & 0xff;
524		cmd.addr_2 = (blkno >> 16) & 0xff;
525		cmd.addr_1 = (blkno >> 8) & 0xff;
526		cmd.addr_0 = blkno & 0xff;
527		cmd.length2 = (nblks >> 8) & 0xff;
528		cmd.length1 = nblks & 0xff;
529
530		/*
531		 * Call the routine that chats with the adapter.
532		 * Note: we cannot sleep as we may be an interrupt
533		 */
534		if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&cmd,
535		    sizeof(cmd), (u_char *) bp->b_data, bp->b_bcount,
536		    CDRETRIES, 30000, bp, SCSI_NOSLEEP |
537		    ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)))
538			printf("%s: not queued", cd->sc_dev.dv_xname);
539	}
540}
541
542int
543cdread(dev, uio)
544	dev_t dev;
545	struct uio *uio;
546{
547	struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)];
548
549	return (physio(cdstrategy, NULL, dev, B_READ,
550		       cd->sc_link->adapter->scsi_minphys, uio));
551}
552
553int
554cdwrite(dev, uio)
555	dev_t dev;
556	struct uio *uio;
557{
558	struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)];
559
560	return (physio(cdstrategy, NULL, dev, B_WRITE,
561		       cd->sc_link->adapter->scsi_minphys, uio));
562}
563
564/*
565 * Perform special action on behalf of the user.
566 * Knows about the internals of this device
567 */
568int
569cdioctl(dev, cmd, addr, flag, p)
570	dev_t dev;
571	u_long cmd;
572	caddr_t addr;
573	int flag;
574	struct proc *p;
575{
576	struct cd_softc *cd = cdcd.cd_devs[CDUNIT(dev)];
577	int error;
578
579	SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%lx ", cmd));
580
581	/*
582	 * If the device is not valid.. abandon ship
583	 */
584	if ((cd->sc_link->flags & SDEV_MEDIA_LOADED) == 0)
585		return EIO;
586
587	switch (cmd) {
588	case DIOCGDINFO:
589		*(struct disklabel *)addr = cd->sc_dk.dk_label;
590		return 0;
591
592	case DIOCGPART:
593		((struct partinfo *)addr)->disklab = &cd->sc_dk.dk_label;
594		((struct partinfo *)addr)->part =
595		    &cd->sc_dk.dk_label.d_partitions[CDPART(dev)];
596		return 0;
597
598	case DIOCWDINFO:
599	case DIOCSDINFO:
600		if ((flag & FWRITE) == 0)
601			return EBADF;
602
603		if (error = cdlock(cd))
604			return error;
605		cd->flags |= CDF_LABELLING;
606
607		error = setdisklabel(&cd->sc_dk.dk_label,
608		    (struct disklabel *)addr, /*cd->sc_dk.dk_openmask : */0,
609		    &cd->sc_dk.dk_cpulabel);
610		if (error == 0) {
611		}
612
613		cd->flags &= ~CDF_LABELLING;
614		cdunlock(cd);
615		return error;
616
617	case DIOCWLABEL:
618		return EBADF;
619
620	case CDIOCPLAYTRACKS: {
621		struct ioc_play_track *args = (struct ioc_play_track *)addr;
622		struct cd_mode_data data;
623		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
624			return error;
625		data.page.audio.flags &= ~CD_PA_SOTC;
626		data.page.audio.flags |= CD_PA_IMMED;
627		if (error = cd_set_mode(cd, &data))
628			return error;
629		return cd_play_tracks(cd, args->start_track, args->start_index,
630		    args->end_track, args->end_index);
631	}
632	case CDIOCPLAYMSF: {
633		struct ioc_play_msf *args
634		= (struct ioc_play_msf *)addr;
635		struct cd_mode_data data;
636		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
637			return error;
638		data.page.audio.flags &= ~CD_PA_SOTC;
639		data.page.audio.flags |= CD_PA_IMMED;
640		if (error = cd_set_mode(cd, &data))
641			return error;
642		return cd_play_msf(cd, args->start_m, args->start_s,
643		    args->start_f, args->end_m, args->end_s, args->end_f);
644	}
645	case CDIOCPLAYBLOCKS: {
646		struct ioc_play_blocks *args
647		= (struct ioc_play_blocks *)addr;
648		struct cd_mode_data data;
649		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
650			return error;
651		data.page.audio.flags &= ~CD_PA_SOTC;
652		data.page.audio.flags |= CD_PA_IMMED;
653		if (error = cd_set_mode(cd, &data))
654			return error;
655		return cd_play(cd, args->blk, args->len);
656	}
657	case CDIOCREADSUBCHANNEL: {
658		struct ioc_read_subchannel *args
659		= (struct ioc_read_subchannel *)addr;
660		struct cd_sub_channel_info data;
661		int len = args->data_len;
662		if (len > sizeof(data) ||
663		    len < sizeof(struct cd_sub_channel_header))
664			return EINVAL;
665		if (error = cd_read_subchannel(cd, args->address_format,
666		    args->data_format, args->track, &data, len))
667			return error;
668		len = min(len, ((data.header.data_len[0] << 8) +
669		    data.header.data_len[1] +
670		    sizeof(struct cd_sub_channel_header)));
671		return copyout(&data, args->data, len);
672	}
673	case CDIOREADTOCHEADER: {
674		struct ioc_toc_header th;
675		if (error = cd_read_toc(cd, 0, 0, &th, sizeof(th)))
676			return error;
677		th.len = ntohs(th.len);
678		bcopy(&th, addr, sizeof(th));
679		return 0;
680	}
681	case CDIOREADTOCENTRYS: {
682		struct cd_toc {
683			struct ioc_toc_header header;
684			struct cd_toc_entry entries[65];
685		} data;
686		struct ioc_read_toc_entry *te =
687		(struct ioc_read_toc_entry *)addr;
688		struct ioc_toc_header *th;
689		int len = te->data_len;
690		th = &data.header;
691
692		if (len > sizeof(data.entries) ||
693		    len < sizeof(struct cd_toc_entry))
694			return EINVAL;
695		if (error = cd_read_toc(cd, te->address_format,
696		    te->starting_track, (struct cd_toc_entry *)&data,
697		    len + sizeof(struct ioc_toc_header)))
698			return error;
699		len = min(len, ntohs(th->len) - (sizeof(th->starting_track) +
700		    sizeof(th->ending_track)));
701		return copyout(data.entries, te->data, len);
702	}
703	case CDIOCSETPATCH: {
704		struct ioc_patch *arg = (struct ioc_patch *)addr;
705		struct cd_mode_data data;
706		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
707			return error;
708		data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
709		data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
710		data.page.audio.port[2].channels = arg->patch[2];
711		data.page.audio.port[3].channels = arg->patch[3];
712		return cd_set_mode(cd, &data);
713	}
714	case CDIOCGETVOL: {
715		struct ioc_vol *arg = (struct ioc_vol *)addr;
716		struct cd_mode_data data;
717		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
718			return error;
719		arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
720		arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
721		arg->vol[2] = data.page.audio.port[2].volume;
722		arg->vol[3] = data.page.audio.port[3].volume;
723		return 0;
724	}
725	case CDIOCSETVOL: {
726		struct ioc_vol *arg = (struct ioc_vol *)addr;
727		struct cd_mode_data data;
728		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
729			return error;
730		data.page.audio.port[LEFT_PORT].channels = CHANNEL_0;
731		data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
732		data.page.audio.port[RIGHT_PORT].channels = CHANNEL_1;
733		data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
734		data.page.audio.port[2].volume = arg->vol[2];
735		data.page.audio.port[3].volume = arg->vol[3];
736		return cd_set_mode(cd, &data);
737	}
738	case CDIOCSETMONO: {
739		struct ioc_vol *arg = (struct ioc_vol *)addr;
740		struct cd_mode_data data;
741		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
742			return error;
743		data.page.audio.port[LEFT_PORT].channels =
744		    LEFT_CHANNEL | RIGHT_CHANNEL | 4 | 8;
745		data.page.audio.port[RIGHT_PORT].channels =
746		    LEFT_CHANNEL | RIGHT_CHANNEL;
747		data.page.audio.port[2].channels = 0;
748		data.page.audio.port[3].channels = 0;
749		return cd_set_mode(cd, &data);
750	}
751	case CDIOCSETSTEREO: {
752		struct ioc_vol *arg = (struct ioc_vol *)addr;
753		struct cd_mode_data data;
754		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
755			return error;
756		data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
757		data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
758		data.page.audio.port[2].channels = 0;
759		data.page.audio.port[3].channels = 0;
760		return cd_set_mode(cd, &data);
761	}
762	case CDIOCSETMUTE: {
763		struct ioc_vol *arg = (struct ioc_vol *)addr;
764		struct cd_mode_data data;
765		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
766			return error;
767		data.page.audio.port[LEFT_PORT].channels = 0;
768		data.page.audio.port[RIGHT_PORT].channels = 0;
769		data.page.audio.port[2].channels = 0;
770		data.page.audio.port[3].channels = 0;
771		return cd_set_mode(cd, &data);
772	}
773	case CDIOCSETLEFT: {
774		struct ioc_vol *arg = (struct ioc_vol *)addr;
775		struct cd_mode_data data;
776		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
777			return error;
778		data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
779		data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
780		data.page.audio.port[2].channels = 0;
781		data.page.audio.port[3].channels = 0;
782		return cd_set_mode(cd, &data);
783	}
784	case CDIOCSETRIGHT: {
785		struct ioc_vol *arg = (struct ioc_vol *)addr;
786		struct cd_mode_data data;
787		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
788			return error;
789		data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
790		data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
791		data.page.audio.port[2].channels = 0;
792		data.page.audio.port[3].channels = 0;
793		return cd_set_mode(cd, &data);
794	}
795	case CDIOCRESUME:
796		return cd_pause(cd, 1);
797	case CDIOCPAUSE:
798		return cd_pause(cd, 0);
799	case CDIOCSTART:
800		return scsi_start(cd->sc_link, SSS_START, 0);
801	case CDIOCSTOP:
802		return scsi_start(cd->sc_link, SSS_STOP, 0);
803	case CDIOCEJECT:
804		return scsi_start(cd->sc_link, SSS_STOP|SSS_LOEJ, 0);
805	case CDIOCALLOW:
806		return scsi_prevent(cd->sc_link, PR_ALLOW, 0);
807	case CDIOCPREVENT:
808		return scsi_prevent(cd->sc_link, PR_PREVENT, 0);
809	case CDIOCSETDEBUG:
810		cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2);
811		return 0;
812	case CDIOCCLRDEBUG:
813		cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2);
814		return 0;
815	case CDIOCRESET:
816		return cd_reset(cd);
817
818	default:
819		if (CDPART(dev) != RAW_PART)
820			return ENOTTY;
821		return scsi_do_ioctl(cd->sc_link, dev, cmd, addr, flag, p);
822	}
823
824#ifdef DIAGNOSTIC
825	panic("cdioctl: impossible");
826#endif
827}
828
829/*
830 * Load the label information on the named device
831 * Actually fabricate a disklabel
832 *
833 * EVENTUALLY take information about different
834 * data tracks from the TOC and put it in the disklabel
835 */
836void
837cdgetdisklabel(cd)
838	struct cd_softc *cd;
839{
840	struct disklabel *lp = &cd->sc_dk.dk_label;
841
842	bzero(lp, sizeof(struct disklabel));
843	bzero(&cd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
844
845	lp->d_secsize = cd->params.blksize;
846	lp->d_ntracks = 1;
847	lp->d_nsectors = 100;
848	lp->d_ncylinders = (cd->params.disksize / 100) + 1;
849	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
850
851	strncpy(lp->d_typename, "SCSI CD-ROM", 16);
852	lp->d_type = DTYPE_SCSI;
853	strncpy(lp->d_packname, "fictitious", 16);
854	lp->d_secperunit = cd->params.disksize;
855	lp->d_rpm = 300;
856	lp->d_interleave = 1;
857	lp->d_flags = D_REMOVABLE;
858
859	lp->d_partitions[0].p_offset = 0;
860	lp->d_partitions[0].p_size =
861	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
862	lp->d_partitions[0].p_fstype = FS_ISO9660;
863	lp->d_partitions[RAW_PART].p_offset = 0;
864	lp->d_partitions[RAW_PART].p_size =
865	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
866	lp->d_partitions[RAW_PART].p_fstype = FS_ISO9660;
867	lp->d_npartitions = RAW_PART + 1;
868
869	lp->d_magic = DISKMAGIC;
870	lp->d_magic2 = DISKMAGIC;
871	lp->d_checksum = dkcksum(lp);
872}
873
874/*
875 * Find out from the device what it's capacity is
876 */
877u_long
878cd_size(cd, flags)
879	struct cd_softc *cd;
880	int flags;
881{
882	struct scsi_read_cd_cap_data rdcap;
883	struct scsi_read_cd_capacity scsi_cmd;
884	int blksize;
885	u_long size;
886
887	/*
888	 * make up a scsi command and ask the scsi driver to do
889	 * it for you.
890	 */
891	bzero(&scsi_cmd, sizeof(scsi_cmd));
892	scsi_cmd.opcode = READ_CD_CAPACITY;
893
894	/*
895	 * If the command works, interpret the result as a 4 byte
896	 * number of blocks and a blocksize
897	 */
898	if (scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
899	    sizeof(scsi_cmd), (u_char *)&rdcap, sizeof(rdcap), CDRETRIES,
900	    2000, NULL, flags | SCSI_DATA_IN) != 0)
901		return 0;
902
903	blksize = (rdcap.length_3 << 24) + (rdcap.length_2 << 16) +
904	    (rdcap.length_1 << 8) + rdcap.length_0;
905	if (blksize < 512)
906		blksize = 2048;	/* some drives lie ! */
907	cd->params.blksize = blksize;
908
909	size = (rdcap.addr_3 << 24) + (rdcap.addr_2 << 16) +
910	    (rdcap.addr_1 << 8) + rdcap.addr_0 + 1;
911	if (size < 100)
912		size = 400000;	/* ditto */
913	cd->params.disksize = size;
914
915	return size;
916}
917
918/*
919 * Get the requested page into the buffer given
920 */
921int
922cd_get_mode(cd, data, page)
923	struct cd_softc *cd;
924	struct cd_mode_data *data;
925	int page;
926{
927	struct scsi_mode_sense scsi_cmd;
928	int error;
929
930	bzero(&scsi_cmd, sizeof(scsi_cmd));
931	bzero(data, sizeof(*data));
932	scsi_cmd.opcode = MODE_SENSE;
933	scsi_cmd.page = page;
934	scsi_cmd.length = sizeof(*data) & 0xff;
935	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
936	    sizeof(scsi_cmd), (u_char *)data, sizeof(*data), CDRETRIES, 20000,
937	    NULL, SCSI_DATA_IN);
938}
939
940/*
941 * Get the requested page into the buffer given
942 */
943int
944cd_set_mode(cd, data)
945	struct cd_softc *cd;
946	struct cd_mode_data *data;
947{
948	struct scsi_mode_select scsi_cmd;
949
950	bzero(&scsi_cmd, sizeof(scsi_cmd));
951	scsi_cmd.opcode = MODE_SELECT;
952	scsi_cmd.byte2 |= SMS_PF;
953	scsi_cmd.length = sizeof(*data) & 0xff;
954	data->header.data_length = 0;
955	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
956	    sizeof(scsi_cmd), (u_char *)data, sizeof(*data), CDRETRIES, 20000,
957	    NULL, SCSI_DATA_OUT);
958}
959
960/*
961 * Get scsi driver to send a "start playing" command
962 */
963int
964cd_play(cd, blkno, nblks)
965	struct cd_softc *cd;
966	int blkno, nblks;
967{
968	struct scsi_play scsi_cmd;
969
970	bzero(&scsi_cmd, sizeof(scsi_cmd));
971	scsi_cmd.opcode = PLAY;
972	scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff;
973	scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff;
974	scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff;
975	scsi_cmd.blk_addr[3] = blkno & 0xff;
976	scsi_cmd.xfer_len[0] = (nblks >> 8) & 0xff;
977	scsi_cmd.xfer_len[1] = nblks & 0xff;
978	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
979	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 200000, NULL, 0);
980}
981
982/*
983 * Get scsi driver to send a "start playing" command
984 */
985int
986cd_play_big(cd, blkno, nblks)
987	struct cd_softc *cd;
988	int blkno, nblks;
989{
990	struct scsi_play_big scsi_cmd;
991
992	bzero(&scsi_cmd, sizeof(scsi_cmd));
993	scsi_cmd.opcode = PLAY_BIG;
994	scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff;
995	scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff;
996	scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff;
997	scsi_cmd.blk_addr[3] = blkno & 0xff;
998	scsi_cmd.xfer_len[0] = (nblks >> 24) & 0xff;
999	scsi_cmd.xfer_len[1] = (nblks >> 16) & 0xff;
1000	scsi_cmd.xfer_len[2] = (nblks >> 8) & 0xff;
1001	scsi_cmd.xfer_len[3] = nblks & 0xff;
1002	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
1003	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 20000, NULL, 0);
1004}
1005
1006/*
1007 * Get scsi driver to send a "start playing" command
1008 */
1009int
1010cd_play_tracks(cd, strack, sindex, etrack, eindex)
1011	struct cd_softc *cd;
1012	int strack, sindex, etrack, eindex;
1013{
1014	struct scsi_play_track scsi_cmd;
1015
1016	bzero(&scsi_cmd, sizeof(scsi_cmd));
1017	scsi_cmd.opcode = PLAY_TRACK;
1018	scsi_cmd.start_track = strack;
1019	scsi_cmd.start_index = sindex;
1020	scsi_cmd.end_track = etrack;
1021	scsi_cmd.end_index = eindex;
1022	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
1023	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 20000, NULL, 0);
1024}
1025
1026/*
1027 * Get scsi driver to send a "play msf" command
1028 */
1029int
1030cd_play_msf(cd, startm, starts, startf, endm, ends, endf)
1031	struct cd_softc *cd;
1032	int startm, starts, startf, endm, ends, endf;
1033{
1034	struct scsi_play_msf scsi_cmd;
1035
1036	bzero(&scsi_cmd, sizeof(scsi_cmd));
1037	scsi_cmd.opcode = PLAY_MSF;
1038	scsi_cmd.start_m = startm;
1039	scsi_cmd.start_s = starts;
1040	scsi_cmd.start_f = startf;
1041	scsi_cmd.end_m = endm;
1042	scsi_cmd.end_s = ends;
1043	scsi_cmd.end_f = endf;
1044	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
1045	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 2000, NULL, 0);
1046}
1047
1048/*
1049 * Get scsi driver to send a "start up" command
1050 */
1051int
1052cd_pause(cd, go)
1053	struct cd_softc *cd;
1054	int go;
1055{
1056	struct scsi_pause scsi_cmd;
1057
1058	bzero(&scsi_cmd, sizeof(scsi_cmd));
1059	scsi_cmd.opcode = PAUSE;
1060	scsi_cmd.resume = go;
1061	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
1062	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 2000, NULL, 0);
1063}
1064
1065/*
1066 * Get scsi driver to send a "RESET" command
1067 */
1068int
1069cd_reset(cd)
1070	struct cd_softc *cd;
1071{
1072
1073	return scsi_scsi_cmd(cd->sc_link, 0, 0, 0, 0, CDRETRIES, 2000, NULL,
1074	    SCSI_RESET);
1075}
1076
1077/*
1078 * Read subchannel
1079 */
1080int
1081cd_read_subchannel(cd, mode, format, track, data, len)
1082	struct cd_softc *cd;
1083	int mode, format, len;
1084	struct cd_sub_channel_info *data;
1085{
1086	struct scsi_read_subchannel scsi_cmd;
1087
1088	bzero(&scsi_cmd, sizeof(scsi_cmd));
1089	scsi_cmd.opcode = READ_SUBCHANNEL;
1090	if (mode == CD_MSF_FORMAT)
1091		scsi_cmd.byte2 |= CD_MSF;
1092	scsi_cmd.byte3 = SRS_SUBQ;
1093	scsi_cmd.subchan_format = format;
1094	scsi_cmd.track = track;
1095	scsi_cmd.data_len[0] = (len >> 8) & 0xff;
1096	scsi_cmd.data_len[1] = len & 0xff;
1097	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
1098	    sizeof(struct scsi_read_subchannel), (u_char *)data, len,
1099	    CDRETRIES, 5000, NULL, SCSI_DATA_IN);
1100}
1101
1102/*
1103 * Read table of contents
1104 */
1105int
1106cd_read_toc(cd, mode, start, data, len)
1107	struct cd_softc *cd;
1108	int mode, start, len;
1109	struct cd_toc_entry *data;
1110{
1111	struct scsi_read_toc scsi_cmd;
1112	int ntoc;
1113
1114	bzero(&scsi_cmd, sizeof(scsi_cmd));
1115	/*if (len!=sizeof(struct ioc_toc_header))
1116	 * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
1117	 * else */
1118	ntoc = len;
1119	scsi_cmd.opcode = READ_TOC;
1120	if (mode == CD_MSF_FORMAT)
1121		scsi_cmd.byte2 |= CD_MSF;
1122	scsi_cmd.from_track = start;
1123	scsi_cmd.data_len[0] = (ntoc >> 8) & 0xff;
1124	scsi_cmd.data_len[1] = ntoc & 0xff;
1125	return scsi_scsi_cmd(cd->sc_link, (struct scsi_generic *)&scsi_cmd,
1126	    sizeof(struct scsi_read_toc), (u_char *)data, len, CDRETRIES,
1127	    5000, NULL, SCSI_DATA_IN);
1128}
1129
1130/*
1131 * Get the scsi driver to send a full inquiry to the device and use the
1132 * results to fill out the disk parameter structure.
1133 */
1134int
1135cd_get_parms(cd, flags)
1136	struct cd_softc *cd;
1137	int flags;
1138{
1139
1140	/*
1141	 * give a number of sectors so that sec * trks * cyls
1142	 * is <= disk_size
1143	 */
1144	if (cd_size(cd, flags) == 0)
1145		return ENXIO;
1146
1147	return 0;
1148}
1149
1150int
1151cdsize(dev)
1152	dev_t dev;
1153{
1154
1155	/* CD-ROMs are read-only. */
1156	return -1;
1157}
1158
1159int
1160cddump(dev, blkno, va, size)
1161	dev_t dev;
1162	daddr_t blkno;
1163	caddr_t va;
1164	size_t size;
1165{
1166
1167	/* Not implemented. */
1168	return ENXIO;
1169}
1170