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