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