Home | History | Annotate | Line # | Download | only in scsipi
cd.c revision 1.10
      1 /*
      2  * Written by Julian Elischer (julian (at) tfs.com)
      3  * for TRW Financial Systems for use under the MACH(2.5) operating system.
      4  * Hacked by Theo de Raadt <deraadt (at) 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