xref: /netbsd-src/sys/dev/scsipi/cd.c (revision 811e6386f8c5e4a3521c7003da29ec8673e344fa)
1 /*
2  * Written by Julian Elischer (julian@tfs.com)
3  * for TRW Financial Systems for use under the MACH(2.5) operating system.
4  *
5  * TRW Financial Systems, in accordance with their agreement with Carnegie
6  * Mellon University, makes this software available to CMU to distribute
7  * or use in any manner that they see fit as long as this message is kept with
8  * the software. For this reason TFS also grants any other persons or
9  * organisations permission to use or modify this software.
10  *
11  * TFS supplies this software to be publicly redistributed
12  * on the understanding that TFS is not responsible for the correct
13  * functioning of this software in any circumstances.
14  *
15  */
16 
17 /*
18  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
19  *
20  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
21  * --------------------         -----   ----------------------
22  * CURRENT PATCH LEVEL:         1       00098
23  * --------------------         -----   ----------------------
24  *
25  * 16 Feb 93	Julian Elischer		ADDED for SCSI system
26  */
27 
28 #define SPLCD splbio
29 #define ESUCCESS 0
30 
31 #include "cd.h"
32 #include "sys/types.h"
33 #include "sys/param.h"
34 #include "sys/dkbad.h"
35 #include "sys/systm.h"
36 #include "sys/conf.h"
37 #include "sys/file.h"
38 #include "sys/stat.h"
39 #include "sys/ioctl.h"
40 #include "sys/buf.h"
41 #include "sys/uio.h"
42 #include "sys/malloc.h"
43 #include "sys/cdio.h"
44 
45 #include "sys/errno.h"
46 #include "sys/disklabel.h"
47 #include "scsi/scsi_all.h"
48 #include "scsi/scsi_cd.h"
49 #include "scsi/cddefs.h"
50 #include "scsi/scsi_disk.h"	/* rw_big and start_stop come from there */
51 #include "scsi/scsiconf.h"
52 
53 long int cdstrats,cdqueues;
54 
55 
56 #ifdef	DDB
57 int	Debugger();
58 #else
59 #define Debugger()
60 #endif
61 
62 
63 #define PAGESIZ 	4096
64 #define SECSIZE 2048	/* XXX */ /* default only */
65 #define	CDOUTSTANDING	2
66 #define CDQSIZE		4
67 #define	CD_RETRIES	4
68 
69 #define	UNITSHIFT	3
70 #define PARTITION(z)	(minor(z) & 0x07)
71 #define	RAW_PART	3
72 #define UNIT(z)		(  (minor(z) >> UNITSHIFT) )
73 
74 
75 extern	int hz;
76 int	cd_done();
77 int	cdstrategy();
78 int	cd_debug = 0;
79 
80 struct buf		cd_buf_queue[NCD];
81 struct	scsi_xfer	cd_scsi_xfer[NCD][CDOUTSTANDING]; /* XXX */
82 struct	scsi_xfer	*cd_free_xfer[NCD];
83 int			cd_xfer_block_wait[NCD];
84 
85 struct	cd_data *cd_data[NCD];
86 
87 #define CD_STOP		0
88 #define CD_START	1
89 #define CD_EJECT	-2
90 
91 /***********************************************************************\
92 * The routine called by the low level scsi routine when it discovers	*
93 * A device suitable for this driver					*
94 \***********************************************************************/
95 int	cdattach(int masunit, struct scsi_switch *sw, int physid, int unit)
96 {
97 	unsigned char *tbl;
98 	struct cd_data *cd;
99 	struct cd_parms *dp;
100 	int	targ, lun, i;
101 
102 	targ = physid >> 3;
103 	lun = physid & 7;
104 
105 	if(unit >= NCD)
106 		return -1;
107 	if(cd_data[unit])
108 		return -1;
109 
110 	cd = cd_data[unit] = (struct cd_data *)malloc(sizeof *cd,
111 		M_TEMP, M_NOWAIT);
112 	if(!cd)
113 		return -1;
114 	bzero(cd, sizeof *cd);
115 
116 	dp  = &(cd->params);
117 	if(scsi_debug & PRINTROUTINES) printf("cdattach: ");
118 
119 	/*******************************************************\
120 	* Store information needed to contact our base driver	*
121 	\*******************************************************/
122 	cd->sc_sw	=	sw;
123 	cd->ctlr	=	masunit;
124 	cd->targ	=	targ;
125 	cd->lu		=	lun;
126 	cd->cmdscount =	CDOUTSTANDING; /* XXX (ask the board) */
127 
128 
129 	i = cd->cmdscount;
130 	while(i-- )
131 	{
132 		cd_scsi_xfer[unit][i].next = cd_free_xfer[unit];
133 		cd_free_xfer[unit] = &cd_scsi_xfer[unit][i];
134 	}
135 	/*******************************************************\
136 	* Use the subdriver to request information regarding	*
137 	* the drive. We cannot use interrupts yet, so the	*
138 	* request must specify this.				*
139 	\*******************************************************/
140 	cd_get_parms(unit,  SCSI_NOSLEEP |  SCSI_NOMASK);
141 	printf("cd%d at %s%d targ %d lun %d: %s\n",
142 		unit, sw->name, masunit, targ, lun,
143 		dp->disksize ? "loaded" : "empty");
144 	cd->flags |= CDINIT;
145 	return 0;
146 }
147 
148 
149 /*******************************************************\
150 *	open the device. Make sure the partition info	*
151 * is a up-to-date as can be.				*
152 \*******************************************************/
153 cdopen(dev_t dev)
154 {
155 	int errcode = 0;
156 	int unit, part;
157 	struct cd_parms cd_parms;
158 	struct cd_data *cd;
159 
160 	unit = UNIT(dev);
161 	part = PARTITION(dev);
162 
163 	if(scsi_debug & (PRINTROUTINES | TRACEOPENS))
164 		printf("cd%d: open dev=0x%x partition %d)\n",
165 			unit, dev, part);
166 
167 	/*******************************************************\
168 	* Check the unit is legal				*
169 	\*******************************************************/
170 	if( unit >= NCD )
171 		return(ENXIO);
172 	cd = cd_data[unit];
173 	if(!cd)
174 		return ENXIO;
175 	if (! (cd->flags & CDINIT))
176 		return(ENXIO);
177 
178 	/*******************************************************\
179 	* If it's been invalidated, and not everybody has	*
180 	* closed it then forbid re-entry.			*
181 	* 	(may have changed media)			*
182 	\*******************************************************/
183 	if ((! (cd->flags & CDVALID))
184 	   && ( cd->openparts))
185 		return(ENXIO);
186 	/*******************************************************\
187 	* Check that it is still responding and ok.		*
188 	* if the media has been changed this will result in a	*
189 	* "unit attention" error which the error code will	*
190 	* disregard because the CDVALID flag is not yet set	*
191 	\*******************************************************/
192 	if (cd_req_sense(unit, SCSI_SILENT) != 0) {
193 		if(scsi_debug & TRACEOPENS)
194 			printf("not reponding\n");
195 		return(ENXIO);
196 	}
197 	if(scsi_debug & TRACEOPENS)
198 		printf("Device present\n");
199 	/*******************************************************\
200 	* In case it is a funny one, tell it to start		*
201 	* not needed for hard drives				*
202 	\*******************************************************/
203 	cd_start_unit(unit,part,CD_START);
204         cd_prevent_unit(unit,PR_PREVENT,SCSI_SILENT);
205 	if(scsi_debug & TRACEOPENS)
206 		printf("started ");
207 	/*******************************************************\
208 	* Load the physical device parameters 			*
209 	\*******************************************************/
210 	cd_get_parms(unit, 0);
211 	if(scsi_debug & TRACEOPENS)
212 		printf("Params loaded ");
213 	/*******************************************************\
214 	* Load the partition info if not already loaded		*
215 	\*******************************************************/
216 	cdgetdisklabel(unit);
217 	if(scsi_debug & TRACEOPENS)
218 		printf("Disklabel fabricated ");
219 	/*******************************************************\
220 	* Check the partition is legal				*
221 	\*******************************************************/
222 	if (( part >= cd->disklabel.d_npartitions )
223 		&& (part != RAW_PART))
224 	{
225 		if(scsi_debug & TRACEOPENS)
226 			printf("partition %d > %d\n",part
227 				,cd->disklabel.d_npartitions);
228         	cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
229 		return(ENXIO);
230 	}
231 	/*******************************************************\
232 	*  Check that the partition exists			*
233 	\*******************************************************/
234 	if (( cd->disklabel.d_partitions[part].p_fstype != FS_UNUSED )
235 		|| (part == RAW_PART))
236 	{
237 		cd->partflags[part] |= CDOPEN;
238 		cd->openparts |= (1 << part);
239 		if(scsi_debug & TRACEOPENS)
240 			printf("open complete\n");
241 		cd->flags |= CDVALID;
242 	}
243 	else
244 	{
245 		if(scsi_debug & TRACEOPENS)
246 			printf("part %d type UNUSED\n",part);
247         	cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
248 		return(ENXIO);
249 	}
250 	return(0);
251 }
252 
253 /*******************************************************\
254 * Get ownership of a scsi_xfer structure		*
255 * If need be, sleep on it, until it comes free		*
256 \*******************************************************/
257 struct scsi_xfer *cd_get_xs(unit,flags)
258 int	flags;
259 int	unit;
260 {
261 	struct scsi_xfer *xs;
262 	int	s;
263 
264 	if(flags & (SCSI_NOSLEEP |  SCSI_NOMASK))
265 	{
266 		if (xs = cd_free_xfer[unit])
267 		{
268 			cd_free_xfer[unit] = xs->next;
269 			xs->flags = 0;
270 		}
271 	}
272 	else
273 	{
274 		s = SPLCD();
275 		while (!(xs = cd_free_xfer[unit]))
276 		{
277 			cd_xfer_block_wait[unit]++;  /* someone waiting! */
278 			sleep((caddr_t)&cd_free_xfer[unit], PRIBIO+1);
279 			cd_xfer_block_wait[unit]--;
280 		}
281 		cd_free_xfer[unit] = xs->next;
282 		splx(s);
283 		xs->flags = 0;
284 	}
285 	return(xs);
286 }
287 
288 /*******************************************************\
289 * Free a scsi_xfer, wake processes waiting for it	*
290 \*******************************************************/
291 void
292 cd_free_xs(int unit, struct scsi_xfer *xs, int flags)
293 {
294 	int	s;
295 
296 	if(flags & SCSI_NOMASK)
297 	{
298 		if (cd_xfer_block_wait[unit])
299 		{
300 			printf("cd%d: doing a wakeup from NOMASK mode\n", unit);
301 			wakeup((caddr_t)&cd_free_xfer[unit]);
302 		}
303 		xs->next = cd_free_xfer[unit];
304 		cd_free_xfer[unit] = xs;
305 	}
306 	else
307 	{
308 		s = SPLCD();
309 		if (cd_xfer_block_wait[unit])
310 			wakeup((caddr_t)&cd_free_xfer[unit]);
311 		xs->next = cd_free_xfer[unit];
312 		cd_free_xfer[unit] = xs;
313 		splx(s);
314 	}
315 }
316 
317 /*******************************************************\
318 * trim the size of the transfer if needed,		*
319 * called by physio					*
320 * basically the smaller of our max and the scsi driver's*
321 * minphys (note we have no max ourselves)		*
322 \*******************************************************/
323 /* Trim buffer length if buffer-size is bigger than page size */
324 void	cdminphys(bp)
325 struct buf	*bp;
326 {
327 	(*(cd_data[UNIT(bp->b_dev)]->sc_sw->scsi_minphys))(bp);
328 }
329 
330 /*******************************************************\
331 * Actually translate the requested transfer into	*
332 * one the physical driver can understand		*
333 * The transfer is described by a buf and will include	*
334 * only one physical transfer.				*
335 \*******************************************************/
336 
337 int	cdstrategy(bp)
338 struct	buf	*bp;
339 {
340 	struct	buf	*dp;
341 	unsigned int opri;
342 	struct cd_data *cd ;
343 	int	unit;
344 
345 	cdstrats++;
346 	unit = UNIT((bp->b_dev));
347 	cd = cd_data[unit];
348 	if(scsi_debug & PRINTROUTINES) printf("\ncdstrategy ");
349 	if(scsi_debug & SHOWREQUESTS) printf("cd%d: %d bytes @ blk%d\n",
350 					unit,bp->b_bcount,bp->b_blkno);
351 
352 	if(!cd) {
353 		bp->b_error = EIO;
354 		goto bad;
355 	}
356 	if(!(cd->flags & CDVALID)) {
357 		bp->b_error = EIO;
358 		goto bad;
359 	}
360 
361 	cdminphys(bp);
362 	/*******************************************************\
363 	* If the device has been made invalid, error out	*
364 	* maybe the media changed				*
365 	\*******************************************************/
366 
367 	/*******************************************************\
368 	* can't ever write to a CD				*
369 	\*******************************************************/
370 	if ((bp->b_flags & B_READ) == 0) {
371 		bp->b_error = EROFS;
372 		goto bad;
373 	}
374 	/*******************************************************\
375 	* If it's a null transfer, return immediatly		*
376 	\*******************************************************/
377 	if (bp->b_bcount == 0) {
378 		goto done;
379 	}
380 
381 	/*******************************************************\
382 	* Decide which unit and partition we are talking about	*
383 	\*******************************************************/
384  	if(PARTITION(bp->b_dev) != RAW_PART)
385 	{
386 		if (!(cd->flags & CDHAVELABEL))
387 		{
388 			bp->b_error = EIO;
389 			goto bad;
390 		}
391 		/*
392 		 * do bounds checking, adjust transfer. if error, process.
393 		 * if end of partition, just return
394 		 */
395 		if (bounds_check_with_label(bp,&cd->disklabel,1) <= 0)
396 			goto done;
397 		/* otherwise, process transfer request */
398 	}
399 
400 	opri = SPLCD();
401 	dp = &cd_buf_queue[unit];
402 
403 	/*******************************************************\
404 	* Place it in the queue of disk activities for this disk*
405 	\*******************************************************/
406 	disksort(dp, bp);
407 
408 	/*******************************************************\
409 	* Tell the device to get going on the transfer if it's	*
410 	* not doing anything, otherwise just wait for completion*
411 	\*******************************************************/
412 	cdstart(unit);
413 
414 	splx(opri);
415 	return;
416 bad:
417 	bp->b_flags |= B_ERROR;
418 done:
419 
420 	/*******************************************************\
421 	* Correctly set the buf to indicate a completed xfer	*
422 	\*******************************************************/
423   	bp->b_resid = bp->b_bcount;
424 	biodone(bp);
425 	return;
426 }
427 
428 /***************************************************************\
429 * cdstart looks to see if there is a buf waiting for the device	*
430 * and that the device is not already busy. If both are true,	*
431 * It deques the buf and creates a scsi command to perform the	*
432 * transfer in the buf. The transfer request will call cd_done	*
433 * on completion, which will in turn call this routine again	*
434 * so that the next queued transfer is performed.		*
435 * The bufs are queued by the strategy routine (cdstrategy)	*
436 *								*
437 * This routine is also called after other non-queued requests	*
438 * have been made of the scsi driver, to ensure that the queue	*
439 * continues to be drained.					*
440 *								*
441 * must be called at the correct (highish) spl level		*
442 \***************************************************************/
443 /* cdstart() is called at SPLCD  from cdstrategy and cd_done*/
444 void
445 cdstart(int unit)
446 {
447 	register struct buf	*bp = 0;
448 	register struct buf	*dp;
449 	struct	scsi_xfer	*xs;
450 	struct	scsi_rw_big	cmd;
451 	int			blkno, nblk;
452 	struct cd_data *cd = cd_data[unit];
453 	struct partition *p ;
454 
455 	if(scsi_debug & PRINTROUTINES) printf("cdstart%d ",unit);
456 	/*******************************************************\
457 	* See if there is a buf to do and we are not already	*
458 	* doing one						*
459 	\*******************************************************/
460 	if(!cd_free_xfer[unit])
461 	{
462 		return;    /* none for us, unit already underway */
463 	}
464 
465 	if(cd_xfer_block_wait[unit])    /* there is one, but a special waits */
466 	{
467 		return;	/* give the special that's waiting a chance to run */
468 	}
469 
470 
471 	dp = &cd_buf_queue[unit];
472 	if ((bp = dp->b_actf) != NULL)	/* yes, an assign */
473 	{
474 		dp->b_actf = bp->av_forw;
475 	}
476 	else
477 	{
478 		return;
479 	}
480 
481 	xs=cd_get_xs(unit,0);	/* ok we can grab it */
482 	xs->flags = INUSE;    /* Now ours */
483 	/***************************************************************\
484 	* Should reject all queued entries if CDVALID is not true	*
485 	\***************************************************************/
486 	if(!(cd->flags & CDVALID))
487 	{
488 		goto bad; /* no I/O.. media changed or something */
489 	}
490 
491 	/*******************************************************\
492 	* We have a buf, now we should move the data into	*
493 	* a scsi_xfer definition and try start it		*
494 	\*******************************************************/
495 	/*******************************************************\
496 	*  First, translate the block to absolute		*
497 	* and put it in terms of the logical blocksize of the	*
498 	* device..						*
499 	\*******************************************************/
500 	p = cd->disklabel.d_partitions + PARTITION(bp->b_dev);
501 	blkno = ((bp->b_blkno / (cd->params.blksize/512)) + p->p_offset);
502 	nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize);
503 
504 	/*******************************************************\
505 	*  Fill out the scsi command				*
506 	\*******************************************************/
507 	bzero(&cmd, sizeof(cmd));
508 	cmd.op_code	=	READ_BIG;
509 	cmd.addr_3	=	(blkno & 0xff000000) >> 24;
510 	cmd.addr_2	=	(blkno & 0xff0000) >> 16;
511 	cmd.addr_1	=	(blkno & 0xff00) >> 8;
512 	cmd.addr_0	=	blkno & 0xff;
513 	cmd.length2	=	(nblk & 0xff00) >> 8;
514 	cmd.length1	=	(nblk & 0xff);
515 	/*******************************************************\
516 	* Fill out the scsi_xfer structure			*
517 	*	Note: we cannot sleep as we may be an interrupt	*
518 	\*******************************************************/
519 	xs->flags	|=	SCSI_NOSLEEP;
520 	xs->adapter	=	cd->ctlr;
521 	xs->targ	=	cd->targ;
522 	xs->lu		=	cd->lu;
523 	xs->retries	=	CD_RETRIES;
524 	xs->timeout	=	10000;/* 10000 millisecs for a disk !*/
525 	xs->cmd		=	(struct	scsi_generic *)&cmd;
526 	xs->cmdlen	=	sizeof(cmd);
527 	xs->resid	=	bp->b_bcount;
528 	xs->when_done	=	cd_done;
529 	xs->done_arg	=	unit;
530 	xs->done_arg2	=	(int)xs;
531 	xs->error	=	XS_NOERROR;
532 	xs->bp		=	bp;
533 	xs->data	=	(u_char *)bp->b_un.b_addr;
534 	xs->datalen	=	bp->b_bcount;
535 
536 	/*******************************************************\
537 	* Pass all this info to the scsi driver.		*
538 	\*******************************************************/
539 	if ( (*(cd->sc_sw->scsi_cmd))(xs) != SUCCESSFULLY_QUEUED)
540 	{
541 		printf("cd%d: oops not queued",unit);
542 		goto bad;
543 	}
544 	cdqueues++;
545 	return;
546 bad:	xs->error = XS_DRIVER_STUFFUP;
547 	cd_done(unit,xs);
548 }
549 
550 /*******************************************************\
551 * This routine is called by the scsi interrupt when	*
552 * the transfer is complete. (or failed)			*
553 \*******************************************************/
554 int	cd_done(unit,xs)
555 int	unit;
556 struct	scsi_xfer	*xs;
557 {
558 	struct	buf		*bp;
559 	int	retval;
560 
561 	if(scsi_debug & PRINTROUTINES) printf("cd_done%d ",unit);
562 	if (! (xs->flags & INUSE)) 	/* paranoia always pays off */
563 		panic("scsi_xfer not in use!");
564 	if(bp = xs->bp)
565 	{
566 		switch(xs->error)
567 		{
568 		case	XS_NOERROR:
569 			bp->b_error = 0;
570 			bp->b_resid = 0;
571 			break;
572 
573 		case	XS_SENSE:
574 			retval = (cd_interpret_sense(unit,xs));
575 			if(retval)
576 			{
577 				bp->b_flags |= B_ERROR;
578 				bp->b_error = retval;
579 			}
580 			break;
581 
582 		case	XS_TIMEOUT:
583 			printf("cd%d: timeout\n",unit);
584 
585 		case	XS_BUSY:
586 			/***********************************\
587 			* Just resubmit it straight back to *
588 			* the SCSI driver to try it again   *
589 			\***********************************/
590 			if(xs->retries--)
591 			{
592 				xs->error = XS_NOERROR;
593 				xs->flags &= ~ITSDONE;
594 				if ( (*(cd_data[unit]->sc_sw->scsi_cmd))(xs)
595 					== SUCCESSFULLY_QUEUED)
596 				{	/* shhh! don't wake the job, ok? */
597 					/* don't tell cdstart either, */
598 					return;
599 				}
600 				/* xs->error is set by the scsi driver */
601 			} /* Fall through */
602 
603 		case	XS_DRIVER_STUFFUP:
604 			bp->b_flags |= B_ERROR;
605 			bp->b_error = EIO;
606 			break;
607 		default:
608 			printf("cd%d: unknown error category from scsi driver\n"
609 				,unit);
610 		}
611 		biodone(bp);
612 		cd_free_xs(unit,xs,0);
613 		cdstart(unit);	/* If there's anything waiting.. do it */
614 	}
615 	else /* special has finished */
616 	{
617 		wakeup(xs);
618 	}
619 }
620 /*******************************************************\
621 * Perform special action on behalf of the user		*
622 * Knows about the internals of this device		*
623 \*******************************************************/
624 cdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
625 {
626 	int error = 0;
627 	unsigned int opri;
628 	unsigned char unit, part;
629 	register struct cd_data *cd;
630 
631 
632 	/*******************************************************\
633 	* Find the device that the user is talking about	*
634 	\*******************************************************/
635 	unit = UNIT(dev);
636 	part = PARTITION(dev);
637 	cd = cd_data[unit];
638 	if(scsi_debug & PRINTROUTINES) printf("cdioctl%d ",unit);
639 
640 	/*******************************************************\
641 	* If the device is not valid.. abandon ship		*
642 	\*******************************************************/
643 	if(!cd)
644 		return ENXIO;
645 	if (!(cd_data[unit]->flags & CDVALID))
646 		return ENXIO;
647 
648 	switch(cmd)
649 	{
650 
651 	case DIOCSBAD:
652                         error = EINVAL;
653 		break;
654 
655 	case DIOCGDINFO:
656 		*(struct disklabel *)addr = cd->disklabel;
657 		break;
658 
659         case DIOCGPART:
660                 ((struct partinfo *)addr)->disklab = &cd->disklabel;
661                 ((struct partinfo *)addr)->part =
662                     &cd->disklabel.d_partitions[PARTITION(dev)];
663                 break;
664 
665         case DIOCWDINFO:
666         case DIOCSDINFO:
667                 if ((flag & FWRITE) == 0)
668                         error = EBADF;
669                 else
670                         error = setdisklabel(&cd->disklabel,
671 					(struct disklabel *)addr,
672                          /*(cd->flags & DKFL_BSDLABEL) ? cd->openparts : */0,
673 				0);
674                 if (error == 0) {
675 			cd->flags |= CDHAVELABEL;
676 		}
677                 break;
678 
679         case DIOCWLABEL:
680                 error = EBADF;
681                 break;
682 
683 	case CDIOCPLAYTRACKS:
684 		{
685 			struct	ioc_play_track *args
686 					= (struct  ioc_play_track *)addr;
687 			struct	cd_mode_data data;
688 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
689 				break;
690 			data.page.audio.sotc = 0;
691 			data.page.audio.immed = 1;
692 			if(error = cd_set_mode(unit,&data))
693 				break;
694 			return(cd_play_tracks(unit
695 						,args->start_track
696 						,args->start_index
697 						,args->end_track
698 						,args->end_index
699 						));
700 		}
701 		break;
702 	case CDIOCPLAYBLOCKS:
703 		{
704 			struct	ioc_play_blocks *args
705 					= (struct  ioc_play_blocks *)addr;
706 			struct	cd_mode_data data;
707 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
708 				break;
709 			data.page.audio.sotc = 0;
710 			data.page.audio.immed = 1;
711 			if(error = cd_set_mode(unit,&data))
712 				break;
713 			return(cd_play(unit,args->blk,args->len));
714 
715 
716 		}
717 		break;
718 	case CDIOCREADSUBCHANNEL:
719 		{
720 			struct ioc_read_subchannel *args
721 					= (struct ioc_read_subchannel *)addr;
722 			struct cd_sub_channel_info data;
723 			int len=args->data_len;
724 			if(len>sizeof(data)||
725 			   len<sizeof(struct cd_sub_channel_header)) {
726 				error=EINVAL;
727 				break;
728 			}
729 			if(error = cd_read_subchannel(unit,args->address_format,
730 					args->data_format,args->track,&data,len)) {
731 				break;
732 			}
733 			len=MIN(len,((data.header.data_len[0]<<8)+data.header.data_len[1]+
734 					sizeof(struct cd_sub_channel_header)));
735 			if(copyout(&data,args->data,len)!=0) {
736 				error=EFAULT;
737 			}
738 		}
739 		break;
740 	case CDIOREADTOCHEADER:
741 		{
742 			struct ioc_toc_header th;
743 			if( error = cd_read_toc(unit, 0, 0,
744 			    (struct cd_toc_entry *)&th,sizeof(th)))
745 				break;
746 			th.len=(th.len&0xff)<<8+((th.len>>8)&0xff);
747 			bcopy(&th,addr,sizeof(th));
748 		}
749 		break;
750 	case CDIOREADTOCENTRYS:
751 		{
752 			struct ioc_read_toc_entry *te=
753 					(struct ioc_read_toc_entry *)addr;
754 			struct cd_toc_entry data[65];
755 			struct ioc_toc_header *th;
756 			int len=te->data_len;
757 			th=(struct ioc_toc_header *)data;
758 
759                         if(len>sizeof(data) || len<sizeof(struct cd_toc_entry)) {
760                                 error=EINVAL;
761                                 break;
762                         }
763 			if(error = cd_read_toc(unit,te->address_format,
764 						    te->starting_track,
765 						    (struct cd_toc_entry *)data,
766 						    len))
767 				break;
768 			len=MIN(len,((((th->len&0xff)<<8)+((th->len>>8)))+
769 								sizeof(*th)));
770 			if(copyout(th,te->data,len)!=0) {
771 				error=EFAULT;
772 			}
773 
774 		}
775 		break;
776 	case CDIOCSETPATCH:
777 		{
778 			struct ioc_patch *arg = (struct ioc_patch *)addr;
779 			struct	cd_mode_data data;
780 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
781 				break;
782 			data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
783 			data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
784 			data.page.audio.port[2].channels = arg->patch[2];
785 			data.page.audio.port[3].channels = arg->patch[3];
786 			if(error = cd_set_mode(unit,&data))
787 				break;
788 		}
789 		break;
790 	case CDIOCGETVOL:
791 		{
792 			struct ioc_vol *arg = (struct ioc_vol *)addr;
793 			struct	cd_mode_data data;
794 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
795 				break;
796 			arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
797 			arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
798 			arg->vol[2] = data.page.audio.port[2].volume;
799 			arg->vol[3] = data.page.audio.port[3].volume;
800 		}
801 		break;
802 	case CDIOCSETVOL:
803 		{
804 			struct ioc_vol *arg = (struct ioc_vol *)addr;
805 			struct	cd_mode_data data;
806 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
807 				break;
808 			data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
809 			data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
810 			data.page.audio.port[2].volume = arg->vol[2];
811 			data.page.audio.port[3].volume = arg->vol[3];
812 			if(error = cd_set_mode(unit,&data))
813 				break;
814 		}
815 		break;
816 	case CDIOCSETMONO:
817 		{
818 			struct ioc_vol *arg = (struct ioc_vol *)addr;
819 			struct	cd_mode_data data;
820 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
821 				break;
822 			data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL|4|8;
823 			data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL|RIGHT_CHANNEL;
824 			data.page.audio.port[2].channels = 0;
825 			data.page.audio.port[3].channels = 0;
826 			if(error = cd_set_mode(unit,&data))
827 				break;
828 		}
829 		break;
830 	case CDIOCSETSTERIO:
831 		{
832 			struct ioc_vol *arg = (struct ioc_vol *)addr;
833 			struct	cd_mode_data data;
834 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
835 				break;
836 			data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
837 			data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
838 			data.page.audio.port[2].channels = 0;
839 			data.page.audio.port[3].channels = 0;
840 			if(error = cd_set_mode(unit,&data))
841 				break;
842 		}
843 		break;
844 	case CDIOCSETMUTE:
845 		{
846 			struct ioc_vol *arg = (struct ioc_vol *)addr;
847 			struct	cd_mode_data data;
848 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
849 				break;
850 			data.page.audio.port[LEFT_PORT].channels = 0;
851 			data.page.audio.port[RIGHT_PORT].channels = 0;
852 			data.page.audio.port[2].channels = 0;
853 			data.page.audio.port[3].channels = 0;
854 			if(error = cd_set_mode(unit,&data))
855 				break;
856 		}
857 		break;
858 	case CDIOCSETLEFT:
859 		{
860 			struct ioc_vol *arg = (struct ioc_vol *)addr;
861 			struct	cd_mode_data data;
862 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
863 				break;
864 			data.page.audio.port[LEFT_PORT].channels = 15;
865 			data.page.audio.port[RIGHT_PORT].channels = 15;
866 			data.page.audio.port[2].channels = 15;
867 			data.page.audio.port[3].channels = 15;
868 			if(error = cd_set_mode(unit,&data))
869 				break;
870 		}
871 		break;
872 	case CDIOCSETRIGHT:
873 		{
874 			struct ioc_vol *arg = (struct ioc_vol *)addr;
875 			struct	cd_mode_data data;
876 			if(error = cd_get_mode(unit,&data,AUDIO_PAGE))
877 				break;
878 			data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
879 			data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
880 			data.page.audio.port[2].channels = 0;
881 			data.page.audio.port[3].channels = 0;
882 			if(error = cd_set_mode(unit,&data))
883 				break;
884 		}
885 		break;
886 	case CDIOCRESUME:
887 		error = cd_pause(unit,1);
888 		break;
889 	case CDIOCPAUSE:
890 		error = cd_pause(unit,0);
891 		break;
892 	case CDIOCSTART:
893 		error = cd_start_unit(unit,part,CD_START);
894 		break;
895 	case CDIOCSTOP:
896 		error = cd_start_unit(unit,part,CD_STOP);
897 		break;
898 	case CDIOCEJECT:
899 		error = cd_start_unit(unit,part,CD_EJECT);
900 		break;
901 	case CDIOCSETDEBUG:
902 		scsi_debug = 0xfff; cd_debug = 0xfff;
903 		break;
904 	case CDIOCCLRDEBUG:
905 		scsi_debug = 0; cd_debug = 0;
906 		break;
907 	case CDIOCRESET:
908 		return(cd_reset(unit));
909 		break;
910 	default:
911 		error = ENOTTY;
912 		break;
913 	}
914 	return (error);
915 }
916 
917 
918 /*******************************************************\
919 * Load the label information on the named device	*
920 * 							*
921 * EVENTUALLY take information about different		*
922 * data tracks from the TOC and put it in the disklabel	*
923 \*******************************************************/
924 int cdgetdisklabel(unit)
925 unsigned char	unit;
926 {
927 	/*unsigned int n, m;*/
928 	char *errstring;
929 	struct dos_partition *dos_partition_p;
930 	struct cd_data *cd = cd_data[unit];
931 
932 	/*******************************************************\
933 	* If the inflo is already loaded, use it		*
934 	\*******************************************************/
935 	if(cd->flags & CDHAVELABEL) return;
936 
937 	bzero(&cd->disklabel,sizeof(struct disklabel));
938 	/*******************************************************\
939 	* make partition 3 the whole disk in case of failure	*
940   	*   then get pdinfo 					*
941 	\*******************************************************/
942 	strncpy(cd->disklabel.d_typename,"scsi cd_rom",16);
943 	strncpy(cd->disklabel.d_packname,"ficticious",16);
944 	cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */
945 	cd->disklabel.d_nsectors = 100;
946 	cd->disklabel.d_ntracks = 1;
947 	cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1;
948 	cd->disklabel.d_secpercyl = 100;
949 	cd->disklabel.d_secperunit = cd->params.disksize;
950 	cd->disklabel.d_rpm = 300;
951 	cd->disklabel.d_interleave = 1;
952 	cd->disklabel.d_flags = D_REMOVABLE;
953 
954 	cd->disklabel.d_npartitions = 1;
955 	 cd->disklabel.d_partitions[0].p_offset = 0;
956 	 cd->disklabel.d_partitions[0].p_size = cd->params.disksize;
957 	 cd->disklabel.d_partitions[0].p_fstype = 9;
958 
959 	cd->disklabel.d_magic = DISKMAGIC;
960 	cd->disklabel.d_magic2 = DISKMAGIC;
961 	cd->disklabel.d_checksum = dkcksum(&(cd->disklabel));
962 
963 	/*******************************************************\
964 	* Signal to other users and routines that we now have a *
965 	* disklabel that represents the media (maybe)		*
966 	\*******************************************************/
967 	cd->flags |= CDHAVELABEL;
968 	return(ESUCCESS);
969 }
970 
971 /*******************************************************\
972 * Find out form the device what it's capacity is	*
973 \*******************************************************/
974 cd_size(unit, flags)
975 {
976 	struct	scsi_read_cd_cap_data	rdcap;
977 	struct	scsi_read_cd_capacity	scsi_cmd;
978 	int size;
979 	int	blksize;
980 
981 	/*******************************************************\
982 	* make up a scsi command and ask the scsi driver to do	*
983 	* it for you.						*
984 	\*******************************************************/
985 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
986 	scsi_cmd.op_code = READ_CD_CAPACITY;
987 
988 	/*******************************************************\
989 	* If the command works, interpret the result as a 4 byte*
990 	* number of blocks					*
991 	\*******************************************************/
992 	if (cd_scsi_cmd(unit,
993 			(struct scsi_generic *)&scsi_cmd,
994 			sizeof(scsi_cmd),
995 			(u_char *)&rdcap,
996 			sizeof(rdcap),
997 			2000,
998 			flags) != 0)
999 	{
1000 		printf("cd%d: could not get size\n", unit);
1001 		return(0);
1002 	} else {
1003 		size = rdcap.addr_0 + 1 ;
1004 		size += rdcap.addr_1 << 8;
1005 		size += rdcap.addr_2 << 16;
1006 		size += rdcap.addr_3 << 24;
1007 		blksize  = rdcap.length_0 ;
1008 		blksize += rdcap.length_1 << 8;
1009 		blksize += rdcap.length_2 << 16;
1010 		blksize += rdcap.length_3 << 24;
1011 	}
1012 	if(cd_debug)printf("cd%d: %d %d byte blocks\n",unit,size,blksize);
1013 	cd_data[unit]->params.disksize = size;
1014 	cd_data[unit]->params.blksize = blksize;
1015 	return(size);
1016 }
1017 
1018 /*******************************************************\
1019 * Check with the device that it is ok, (via scsi driver)*
1020 \*******************************************************/
1021 cd_req_sense(unit, flags)
1022 {
1023 	struct	scsi_sense_data sense_data;
1024 	struct	scsi_sense scsi_cmd;
1025 
1026 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1027 	scsi_cmd.op_code = REQUEST_SENSE;
1028 	scsi_cmd.length = sizeof(sense_data);
1029 
1030 	if (cd_scsi_cmd(unit,
1031 			(struct scsi_generic *)&scsi_cmd,
1032 			sizeof(scsi_cmd),
1033 			(u_char *)&sense_data,
1034 			sizeof(sense_data),
1035 			2000,
1036 			flags) != 0)
1037 	{
1038 		return(ENXIO);
1039 	}
1040 	else
1041 		return(0);
1042 }
1043 
1044 /*******************************************************\
1045 * Get the requested page into the buffer given		*
1046 \*******************************************************/
1047 cd_get_mode(unit,data,page)
1048 int	unit;
1049 struct	cd_mode_data *data;
1050 int	page;
1051 {
1052 	struct scsi_mode_sense scsi_cmd;
1053 	int	retval;
1054 
1055 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1056 	bzero(data,sizeof(*data));
1057 	scsi_cmd.op_code = MODE_SENSE;
1058 	scsi_cmd.page_code = page;
1059 	scsi_cmd.length = sizeof(*data) & 0xff;
1060 	retval = cd_scsi_cmd(unit,
1061 			(struct scsi_generic *)&scsi_cmd,
1062 			sizeof(scsi_cmd),
1063 			(u_char *)data,
1064 			sizeof(*data),
1065 			20000,	/* should be immed */
1066 			0);
1067 	return (retval);
1068 }
1069 /*******************************************************\
1070 * Get the requested page into the buffer given		*
1071 \*******************************************************/
1072 cd_set_mode(unit,data)
1073 int	unit;
1074 struct	cd_mode_data *data;
1075 {
1076 	struct scsi_mode_select scsi_cmd;
1077 
1078 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1079 	scsi_cmd.op_code = MODE_SELECT;
1080 	scsi_cmd.pf = 1;
1081 	scsi_cmd.length = sizeof(*data) & 0xff;
1082 	data->header.data_length = 0;
1083 	/*show_mem(data,sizeof(*data));/**/
1084 	return (cd_scsi_cmd(unit,
1085 			(struct scsi_generic *)&scsi_cmd,
1086 			sizeof(scsi_cmd),
1087 			(u_char *)data,
1088 			sizeof(*data),
1089 			20000,	/* should be immed */
1090 			0)
1091 	);
1092 }
1093 /*******************************************************\
1094 * Get scsi driver to send a "start playing" command	*
1095 \*******************************************************/
1096 cd_play(unit,blk,len)
1097 int	unit,blk,len;
1098 {
1099 	struct scsi_play scsi_cmd;
1100 	int	retval;
1101 
1102 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1103 	scsi_cmd.op_code = PLAY;
1104 	scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
1105 	scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
1106 	scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
1107 	scsi_cmd.blk_addr[3] = blk & 0xff;
1108 	scsi_cmd.xfer_len[0] = (len >> 8) & 0xff;
1109 	scsi_cmd.xfer_len[1] = len & 0xff;
1110 	retval = cd_scsi_cmd(unit,
1111 			(struct scsi_generic *)&scsi_cmd,
1112 			sizeof(scsi_cmd),
1113 			0,
1114 			0,
1115 			200000,	/* should be immed */
1116 			0);
1117 	return(retval);
1118 }
1119 /*******************************************************\
1120 * Get scsi driver to send a "start playing" command	*
1121 \*******************************************************/
1122 cd_play_big(unit,blk,len)
1123 int	unit,blk,len;
1124 {
1125 	struct scsi_play_big scsi_cmd;
1126 	int	retval;
1127 
1128 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1129 	scsi_cmd.op_code = PLAY_BIG;
1130 	scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
1131 	scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
1132 	scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
1133 	scsi_cmd.blk_addr[3] = blk & 0xff;
1134 	scsi_cmd.xfer_len[0] = (len >> 24) & 0xff;
1135 	scsi_cmd.xfer_len[1] = (len >> 16) & 0xff;
1136 	scsi_cmd.xfer_len[2] = (len >> 8) & 0xff;
1137 	scsi_cmd.xfer_len[3] = len & 0xff;
1138 	retval = cd_scsi_cmd(unit,
1139 			(struct scsi_generic *)&scsi_cmd,
1140 			sizeof(scsi_cmd),
1141 			0,
1142 			0,
1143 			20000,	/* should be immed */
1144 			0);
1145 	return(retval);
1146 }
1147 /*******************************************************\
1148 * Get scsi driver to send a "start playing" command	*
1149 \*******************************************************/
1150 cd_play_tracks(unit,strack,sindex,etrack,eindex)
1151 int	unit,strack,sindex,etrack,eindex;
1152 {
1153 	struct scsi_play_track scsi_cmd;
1154 	int	retval;
1155 
1156 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1157 	scsi_cmd.op_code = PLAY_TRACK;
1158 	scsi_cmd.start_track = strack;
1159 	scsi_cmd.start_index = sindex;
1160 	scsi_cmd.end_track = etrack;
1161 	scsi_cmd.end_index = eindex;
1162 	retval = cd_scsi_cmd(unit,
1163 			(struct scsi_generic *)&scsi_cmd,
1164 			sizeof(scsi_cmd),
1165 			0,
1166 			0,
1167 			20000,	/* should be immed */
1168 			0);
1169 	return(retval);
1170 }
1171 /*******************************************************\
1172 * Get scsi driver to send a "start up" command		*
1173 \*******************************************************/
1174 cd_pause(unit,go)
1175 int	unit,go;
1176 {
1177 	struct scsi_pause scsi_cmd;
1178 
1179 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1180 	scsi_cmd.op_code = PAUSE;
1181 	scsi_cmd.resume = go;
1182 
1183 	return (cd_scsi_cmd(unit,
1184 			(struct scsi_generic *)&scsi_cmd,
1185 			sizeof(scsi_cmd),
1186 			0,
1187 			0,
1188 			2000,
1189 			0));
1190 }
1191 /*******************************************************\
1192 * Get scsi driver to send a "start up" command		*
1193 \*******************************************************/
1194 cd_reset(unit)
1195 int	unit;
1196 {
1197 	return(cd_scsi_cmd(unit,0,0,0,0,2000,SCSI_RESET));
1198 }
1199 /*******************************************************\
1200 * Get scsi driver to send a "start up" command		*
1201 \*******************************************************/
1202 cd_start_unit(unit,part,type)
1203 {
1204 	struct scsi_start_stop scsi_cmd;
1205 
1206         if(type==CD_EJECT && (cd_data[unit]->openparts&~(1<<part)) == 0 ) {
1207 		cd_prevent_unit(unit,CD_EJECT,0);
1208 	}
1209 
1210 	bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1211 	scsi_cmd.op_code = START_STOP;
1212 	scsi_cmd.start = type==CD_START?1:0;
1213 	scsi_cmd.loej  = type==CD_EJECT?1:0;
1214 
1215 	if (cd_scsi_cmd(unit,
1216 			(struct scsi_generic *)&scsi_cmd,
1217 			sizeof(scsi_cmd),
1218 			0,
1219 			0,
1220 			2000,
1221 			0) != 0) {
1222 		return(ENXIO);
1223 	} else
1224 		return(0);
1225 }
1226 /*******************************************************\
1227 * Prevent or allow the user to remove the disk          *
1228 \*******************************************************/
1229 cd_prevent_unit(unit,type,flags)
1230 int     unit,type,flags;
1231 {
1232         struct  scsi_prevent    scsi_cmd;
1233 
1234         if(type==CD_EJECT || type==PR_PREVENT || cd_data[unit]->openparts == 0 ) {
1235                 bzero((struct scsi_generic *)&scsi_cmd, sizeof(scsi_cmd));
1236                 scsi_cmd.op_code = PREVENT_ALLOW;
1237                 scsi_cmd.prevent=type==CD_EJECT?PR_ALLOW:type;
1238                 if (cd_scsi_cmd(unit,
1239                         (struct scsi_generic *)&scsi_cmd,
1240                         sizeof(struct   scsi_prevent),
1241                         0,
1242                         0,
1243                         5000,
1244                         0) != 0)
1245                 {
1246                  if(!(flags & SCSI_SILENT))
1247                          printf("cannot prevent/allow on cd%d\n", unit);
1248                  return(0);
1249                 }
1250         }
1251         return(1);
1252 }
1253 
1254 /******************************************************\
1255 * Read Subchannel				       *
1256 \******************************************************/
1257 
1258 cd_read_subchannel(unit,mode,format,track,data,len)
1259 int unit,mode,format,len;
1260 struct cd_sub_channel_info *data;
1261 {
1262 	struct scsi_read_subchannel scsi_cmd;
1263 	int error;
1264 
1265 	bzero((struct scsi_generic *)&scsi_cmd,sizeof(scsi_cmd));
1266 
1267 	scsi_cmd.op_code=READ_SUBCHANNEL;
1268         if(mode==CD_MSF_FORMAT)
1269 		scsi_cmd.msf=1;
1270 	scsi_cmd.subQ=1;
1271 	scsi_cmd.subchan_format=format;
1272 	scsi_cmd.track=track;
1273 	scsi_cmd.data_len[0]=(len)>>8;
1274 	scsi_cmd.data_len[1]=(len)&0xff;
1275 	return cd_scsi_cmd(unit,
1276 		(struct scsi_generic *)&scsi_cmd,
1277 		sizeof(struct   scsi_read_subchannel),
1278 		(u_char *)data,
1279 		len,
1280 		5000,
1281 		0);
1282 }
1283 
1284 /*******************************************************\
1285 * Read Table of contents                                *
1286 \*******************************************************/
1287 cd_read_toc(unit,mode,start,data,len)
1288 int unit,mode,start,len;
1289 struct cd_toc_entry *data;
1290 {
1291 	struct scsi_read_toc scsi_cmd;
1292 	int error;
1293 	int ntoc;
1294 
1295 	bzero((struct scsi_generic *)&scsi_cmd,sizeof(scsi_cmd));
1296 	/*if(len!=sizeof(struct ioc_toc_header))
1297 	   ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
1298 	  else*/
1299 	   ntoc=len;
1300 
1301 	scsi_cmd.op_code=READ_TOC;
1302         if(mode==CD_MSF_FORMAT)
1303                 scsi_cmd.msf=1;
1304 	scsi_cmd.from_track=start;
1305 	scsi_cmd.data_len[0]=(ntoc)>>8;
1306 	scsi_cmd.data_len[1]=(ntoc)&0xff;
1307         return cd_scsi_cmd(unit,
1308                 (struct scsi_generic *)&scsi_cmd,
1309                 sizeof(struct   scsi_read_toc),
1310                 (u_char *)data,
1311                 len,
1312                 5000,
1313                 0);
1314 }
1315 
1316 
1317 #define b2tol(a)	(((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
1318 
1319 /*******************************************************\
1320 * Get the scsi driver to send a full inquiry to the	*
1321 * device and use the results to fill out the disk 	*
1322 * parameter structure.					*
1323 \*******************************************************/
1324 
1325 int	cd_get_parms(unit, flags)
1326 {
1327 	struct cd_data *cd = cd_data[unit];
1328 
1329 
1330 	if(!cd)
1331 		return 0;
1332 	if(cd->flags & CDVALID)
1333 		return 0;
1334 
1335 	/*******************************************************\
1336 	* give a number of sectors so that sec * trks * cyls	*
1337 	* is <= disk_size 					*
1338 	\*******************************************************/
1339 	if(cd_size(unit, flags))
1340 	{
1341 		cd->flags |= CDVALID;
1342 		return(0);
1343 	}
1344 	else
1345 	{
1346 		return(ENXIO);
1347 	}
1348 }
1349 
1350 /*******************************************************\
1351 * close the device.. only called if we are the LAST	*
1352 * occurence of an open device				*
1353 \*******************************************************/
1354 int
1355 cdclose(dev_t dev)
1356 {
1357 	unsigned char unit, part;
1358 	unsigned int old_priority;
1359 
1360 	unit = UNIT(dev);
1361 	part = PARTITION(dev);
1362 	if(scsi_debug & TRACEOPENS)
1363 		printf("closing cd%d part %d\n",unit,part);
1364 	cd_data[unit]->partflags[part] &= ~CDOPEN;
1365 	cd_data[unit]->openparts &= ~(1 << part);
1366        	cd_prevent_unit(unit,PR_ALLOW,SCSI_SILENT);
1367 	return(0);
1368 }
1369 
1370 /*******************************************************\
1371 * ask the scsi driver to perform a command for us.	*
1372 * Call it through the switch table, and tell it which	*
1373 * sub-unit we want, and what target and lu we wish to	*
1374 * talk to. Also tell it where to find the command	*
1375 * how long int is.					*
1376 * Also tell it where to read/write the data, and how	*
1377 * long the data is supposed to be			*
1378 \*******************************************************/
1379 int	cd_scsi_cmd(unit,scsi_cmd,cmdlen,data_addr,datalen,timeout,flags)
1380 
1381 int	unit,flags;
1382 struct	scsi_generic *scsi_cmd;
1383 int	cmdlen;
1384 int	timeout;
1385 u_char	*data_addr;
1386 int	datalen;
1387 {
1388 	struct	scsi_xfer *xs;
1389 	int	retval;
1390 	int	s;
1391 	struct cd_data *cd = cd_data[unit];
1392 
1393 	if(scsi_debug & PRINTROUTINES) printf("\ncd_scsi_cmd%d ",unit);
1394 	if(cd->sc_sw)	/* If we have a scsi driver */
1395 	{
1396 		xs = cd_get_xs(unit,flags); /* should wait unless booting */
1397 		if(!xs)
1398 		{
1399 			printf("cd%d: cd_scsi_cmd: controller busy"
1400  					" (this should never happen)\n",unit);
1401 				return(EBUSY);
1402 		}
1403 		xs->flags |= INUSE;
1404 		/*******************************************************\
1405 		* Fill out the scsi_xfer structure			*
1406 		\*******************************************************/
1407 		xs->flags	|=	flags;
1408 		xs->adapter	=	cd->ctlr;
1409 		xs->targ	=	cd->targ;
1410 		xs->lu		=	cd->lu;
1411 		xs->retries	=	CD_RETRIES;
1412 		xs->timeout	=	timeout;
1413 		xs->cmd		=	scsi_cmd;
1414 		xs->cmdlen	=	cmdlen;
1415 		xs->data	=	data_addr;
1416 		xs->datalen	=	datalen;
1417 		xs->resid	=	datalen;
1418 		xs->when_done	=	(flags & SCSI_NOMASK)
1419 					?(int (*)())0
1420 					:cd_done;
1421 		xs->done_arg	=	unit;
1422 		xs->done_arg2	=	(int)xs;
1423 retry:		xs->error	=	XS_NOERROR;
1424 		xs->bp		=	0;
1425 		retval = (*(cd->sc_sw->scsi_cmd))(xs);
1426 		switch(retval)
1427 		{
1428 		case	SUCCESSFULLY_QUEUED:
1429 			s = splbio();
1430 			while(!(xs->flags & ITSDONE))
1431 				sleep(xs,PRIBIO+1);
1432 			splx(s);
1433 
1434 		case	HAD_ERROR:
1435 			/*printf("err = %d ",xs->error);*/
1436 			switch(xs->error)
1437 			{
1438 			case	XS_NOERROR:
1439 				retval = ESUCCESS;
1440 				break;
1441 			case	XS_SENSE:
1442 				retval = (cd_interpret_sense(unit,xs));
1443 				break;
1444 			case	XS_DRIVER_STUFFUP:
1445 				retval = EIO;
1446 				break;
1447 
1448 
1449 			case	XS_BUSY:
1450 			case	XS_TIMEOUT:
1451 				if(xs->retries-- )
1452 				{
1453 					xs->flags &= ~ITSDONE;
1454 					goto retry;
1455 				}
1456 				retval = EIO;
1457 				break;
1458 			default:
1459 				retval = EIO;
1460 				printf("cd%d: unknown error category from scsi driver\n"
1461 					,unit);
1462 			}
1463 			break;
1464 		case	COMPLETE:
1465 			retval = ESUCCESS;
1466 			break;
1467 		case 	TRY_AGAIN_LATER:
1468 			if(xs->retries-- )
1469 			{
1470 				if(tsleep( 0,PRIBIO + 2,"retry",hz * 2))
1471 				{
1472 					xs->flags &= ~ITSDONE;
1473 					goto retry;
1474 				}
1475 			}
1476 			retval = EIO;
1477 			break;
1478 		default:
1479 			retval = EIO;
1480 		}
1481 		cd_free_xs(unit,xs,flags);
1482 		cdstart(unit);		/* check if anything is waiting fr the xs */
1483 	}
1484 	else
1485 	{
1486 		printf("cd%d: not set up\n",unit);
1487 		return(EINVAL);
1488 	}
1489 	return(retval);
1490 }
1491 /***************************************************************\
1492 * Look at the returned sense and act on the error and detirmine	*
1493 * The unix error number to pass back... (0 = report no error)	*
1494 \***************************************************************/
1495 
1496 int	cd_interpret_sense(unit,xs)
1497 int	unit;
1498 struct	scsi_xfer *xs;
1499 {
1500 	struct	scsi_sense_data *sense;
1501 	int	key;
1502 	int	silent;
1503 
1504 	/***************************************************************\
1505 	* If the flags say errs are ok, then always return ok.		*
1506 	\***************************************************************/
1507 	if (xs->flags & SCSI_ERR_OK) return(ESUCCESS);
1508 	silent = (xs->flags & SCSI_SILENT);
1509 
1510 	sense = &(xs->sense);
1511 	switch(sense->error_class)
1512 	{
1513 	case 7:
1514 		{
1515 		key=sense->ext.extended.sense_key;
1516 		switch(key)
1517 		{
1518 		case	0x0:
1519 			return(ESUCCESS);
1520 		case	0x1:
1521 			if(!silent)
1522 			{
1523 				printf("cd%d: soft error(corrected) ", unit);
1524 				if(sense->valid)
1525 				{
1526 			  		printf("block no. %d (decimal)",
1527 			  		(sense->ext.extended.info[0] <<24),
1528 			  		(sense->ext.extended.info[1] <<16),
1529 			  		(sense->ext.extended.info[2] <<8),
1530 			  		(sense->ext.extended.info[3] ));
1531 				}
1532 				printf("\n");
1533 			}
1534 			return(ESUCCESS);
1535 		case	0x2:
1536 			if(!silent)printf("cd%d: not ready\n",
1537 				unit);
1538 			return(ENODEV);
1539 		case	0x3:
1540 			if(!silent)
1541 			{
1542 				printf("cd%d: medium error ", unit);
1543 				if(sense->valid)
1544 				{
1545 			  		printf("block no. %d (decimal)",
1546 			  		(sense->ext.extended.info[0] <<24),
1547 			  		(sense->ext.extended.info[1] <<16),
1548 			  		(sense->ext.extended.info[2] <<8),
1549 			  		(sense->ext.extended.info[3] ));
1550 				}
1551 				printf("\n");
1552 			}
1553 			return(EIO);
1554 		case	0x4:
1555 			if(!silent)printf("cd%d: non-media hardware failure\n",
1556 				unit);
1557 			return(EIO);
1558 		case	0x5:
1559 			if(!silent)printf("cd%d: illegal request\n",
1560 				unit);
1561 			return(EINVAL);
1562 		case	0x6:
1563 			if(!silent)printf("cd%d: media change\n", unit);
1564 			if (cd_data[unit]->openparts)
1565 			cd_data[unit]->flags &= ~(CDVALID | CDHAVELABEL);
1566 			{
1567 				return(EIO);
1568 			}
1569 			return(ESUCCESS);
1570 		case	0x7:
1571 			if(!silent)
1572 			{
1573 				printf("cd%d: attempted protection violation ",
1574 						unit);
1575 				if(sense->valid)
1576 			  	{
1577 					printf("block no. %d (decimal)\n",
1578 			  		(sense->ext.extended.info[0] <<24),
1579 			  		(sense->ext.extended.info[1] <<16),
1580 			  		(sense->ext.extended.info[2] <<8),
1581 			  		(sense->ext.extended.info[3] ));
1582 				}
1583 				printf("\n");
1584 			}
1585 			return(EACCES);
1586 		case	0x8:
1587 			if(!silent)
1588 			{
1589 				printf("cd%d: block wrong state (worm)\n",
1590 				unit);
1591 				if(sense->valid)
1592 				{
1593 			  		printf("block no. %d (decimal)\n",
1594 			  		(sense->ext.extended.info[0] <<24),
1595 			  		(sense->ext.extended.info[1] <<16),
1596 			  		(sense->ext.extended.info[2] <<8),
1597 			  		(sense->ext.extended.info[3] ));
1598 				}
1599 				printf("\n");
1600 			}
1601 			return(EIO);
1602 		case	0x9:
1603 			if(!silent)printf("cd%d: vendor unique\n",
1604 				unit);
1605 			return(EIO);
1606 		case	0xa:
1607 			if(!silent)printf("cd%d: copy aborted\n",
1608 				unit);
1609 			return(EIO);
1610 		case	0xb:
1611 			if(!silent)printf("cd%d: command aborted\n",
1612 				unit);
1613 			return(EIO);
1614 		case	0xc:
1615 			if(!silent)
1616 			{
1617 				printf("cd%d: search returned\n",
1618 					unit);
1619 				if(sense->valid)
1620 				{
1621 			  		printf("block no. %d (decimal)\n",
1622 			  		(sense->ext.extended.info[0] <<24),
1623 			  		(sense->ext.extended.info[1] <<16),
1624 			  		(sense->ext.extended.info[2] <<8),
1625 			  		(sense->ext.extended.info[3] ));
1626 				}
1627 				printf("\n");
1628 			}
1629 			return(ESUCCESS);
1630 		case	0xd:
1631 			if(!silent)printf("cd%d: volume overflow\n",
1632 				unit);
1633 			return(ENOSPC);
1634 		case	0xe:
1635 			if(!silent)
1636 			{
1637 				printf("cd%d: verify miscompare\n",
1638 				unit);
1639 				if(sense->valid)
1640 				{
1641 			  		printf("block no. %d (decimal)\n",
1642 			  		(sense->ext.extended.info[0] <<24),
1643 			  		(sense->ext.extended.info[1] <<16),
1644 			  		(sense->ext.extended.info[2] <<8),
1645 			  		(sense->ext.extended.info[3] ));
1646 				}
1647 				printf("\n");
1648 			}
1649 			return(EIO);
1650 		case	0xf:
1651 			if(!silent)printf("cd%d: unknown error key\n",
1652 				unit);
1653 			return(EIO);
1654 		}
1655 		break;
1656 	}
1657 	case 0:
1658 	case 1:
1659 	case 2:
1660 	case 3:
1661 	case 4:
1662 	case 5:
1663 	case 6:
1664 		{
1665 			if(!silent)printf("cd%d: error class %d code %d\n",
1666 				unit,
1667 				sense->error_class,
1668 				sense->error_code);
1669 		if(sense->valid)
1670 			if(!silent)printf("block no. %d (decimal)\n",
1671 			(sense->ext.unextended.blockhi <<16),
1672 			+ (sense->ext.unextended.blockmed <<8),
1673 			+ (sense->ext.unextended.blocklow ));
1674 		}
1675 		return(EIO);
1676 	}
1677 }
1678 
1679 
1680 
1681 
1682 int
1683 cdsize(dev_t dev)
1684 {
1685 	return (-1);
1686 }
1687 
1688 show_mem(address,num)
1689 unsigned char   *address;
1690 int     num;
1691 {
1692 	int x,y;
1693 	printf("------------------------------");
1694 	for (y = 0; y<num; y += 1)
1695 	{
1696 		if(!(y % 16))
1697 			printf("\n%03d: ",y);
1698 		printf("%02x ",*address++);
1699 	}
1700 	printf("\n------------------------------\n");
1701 }
1702 
1703