Home | History | Annotate | Line # | Download | only in scsipi
cd.c revision 1.18.2.2
      1       1.1      cgd /*
      2       1.1      cgd  * Written by Julian Elischer (julian (at) tfs.com)
      3       1.1      cgd  * for TRW Financial Systems for use under the MACH(2.5) operating system.
      4       1.1      cgd  *
      5       1.1      cgd  * TRW Financial Systems, in accordance with their agreement with Carnegie
      6       1.1      cgd  * Mellon University, makes this software available to CMU to distribute
      7       1.1      cgd  * or use in any manner that they see fit as long as this message is kept with
      8       1.1      cgd  * the software. For this reason TFS also grants any other persons or
      9       1.1      cgd  * organisations permission to use or modify this software.
     10       1.1      cgd  *
     11       1.1      cgd  * TFS supplies this software to be publicly redistributed
     12       1.1      cgd  * on the understanding that TFS is not responsible for the correct
     13       1.1      cgd  * functioning of this software in any circumstances.
     14       1.1      cgd  *
     15  1.18.2.2  mycroft  * Ported to run under 386BSD by Julian Elischer (julian (at) tfs.com) Sept 1992
     16  1.18.2.2  mycroft  *
     17  1.18.2.2  mycroft  *      $Id: cd.c,v 1.18.2.2 1993/11/24 05:02:56 mycroft Exp $
     18       1.1      cgd  */
     19       1.1      cgd 
     20       1.1      cgd #define SPLCD splbio
     21       1.1      cgd #define ESUCCESS 0
     22  1.18.2.2  mycroft #include <cd.h>
     23  1.18.2.2  mycroft #include <sys/types.h>
     24  1.18.2.2  mycroft #include <sys/param.h>
     25  1.18.2.2  mycroft #include <sys/dkbad.h>
     26  1.18.2.2  mycroft #include <sys/systm.h>
     27  1.18.2.2  mycroft #include <sys/conf.h>
     28  1.18.2.2  mycroft #include <sys/file.h>
     29  1.18.2.2  mycroft #include <sys/stat.h>
     30  1.18.2.2  mycroft #include <sys/ioctl.h>
     31  1.18.2.2  mycroft #include <sys/buf.h>
     32  1.18.2.2  mycroft #include <sys/uio.h>
     33  1.18.2.2  mycroft #include <sys/malloc.h>
     34  1.18.2.2  mycroft #include <sys/cdio.h>
     35  1.18.2.2  mycroft 
     36  1.18.2.2  mycroft #include <sys/errno.h>
     37  1.18.2.2  mycroft #include <sys/disklabel.h>
     38  1.18.2.2  mycroft #include <scsi/scsi_all.h>
     39  1.18.2.2  mycroft #include <scsi/scsi_cd.h>
     40  1.18.2.2  mycroft #include <scsi/scsi_disk.h>	/* rw_big and start_stop come from there */
     41  1.18.2.2  mycroft #include <scsi/scsiconf.h>
     42  1.18.2.2  mycroft 
     43  1.18.2.2  mycroft int32   cdstrats, cdqueues;
     44  1.18.2.2  mycroft 
     45  1.18.2.2  mycroft #include <ddb.h>
     46  1.18.2.2  mycroft #if	NDDB > 0
     47  1.18.2.2  mycroft int     Debugger();
     48  1.18.2.2  mycroft #else	/* NDDB > 0 */
     49       1.1      cgd #define Debugger()
     50  1.18.2.2  mycroft #endif	/* NDDB > 0 */
     51       1.1      cgd 
     52       1.1      cgd #define PAGESIZ 	4096
     53  1.18.2.2  mycroft #define SECSIZE 2048	/* XXX */	/* default only */
     54       1.1      cgd #define	CDOUTSTANDING	2
     55  1.18.2.2  mycroft #define	CDRETRIES	1
     56       1.1      cgd 
     57       1.1      cgd #define	UNITSHIFT	3
     58       1.1      cgd #define PARTITION(z)	(minor(z) & 0x07)
     59       1.1      cgd #define	RAW_PART	3
     60       1.1      cgd #define UNIT(z)		(  (minor(z) >> UNITSHIFT) )
     61       1.1      cgd 
     62  1.18.2.2  mycroft extern int hz;
     63  1.18.2.2  mycroft errval  cdstrategy();
     64       1.1      cgd 
     65  1.18.2.2  mycroft void    cdstart();
     66  1.18.2.2  mycroft struct scsi_device cd_switch =
     67  1.18.2.2  mycroft {
     68  1.18.2.2  mycroft     NULL,			/* use default error handler */
     69  1.18.2.2  mycroft     cdstart,			/* we have a queue, which is started by this */
     70  1.18.2.2  mycroft     NULL,			/* we do not have an async handler */
     71  1.18.2.2  mycroft     NULL,			/* use default 'done' routine */
     72  1.18.2.2  mycroft     "cd",			/* we are to be refered to by this name */
     73  1.18.2.2  mycroft     0,				/* no device specific flags */
     74  1.18.2.2  mycroft     0, 0			/* spares not used */
     75  1.18.2.2  mycroft };
     76  1.18.2.2  mycroft 
     77  1.18.2.2  mycroft struct cd_data {
     78  1.18.2.2  mycroft 	u_int32 flags;
     79  1.18.2.2  mycroft #define	CDINIT		0x04	/* device has been init'd */
     80  1.18.2.2  mycroft 	struct scsi_link *sc_link;	/* address of scsi low level switch */
     81  1.18.2.2  mycroft 	u_int32 cmdscount;	/* cmds allowed outstanding by board */
     82  1.18.2.2  mycroft 	struct cd_parms {
     83  1.18.2.2  mycroft 		u_int32 blksize;
     84  1.18.2.2  mycroft 		u_long  disksize;	/* total number sectors */
     85  1.18.2.2  mycroft 	} params;
     86  1.18.2.2  mycroft 	struct disklabel disklabel;
     87  1.18.2.2  mycroft 	u_int32 partflags[MAXPARTITIONS];	/* per partition flags */
     88  1.18.2.2  mycroft #define CDOPEN	0x01
     89  1.18.2.2  mycroft 	u_int32 openparts;	/* one bit for each open partition */
     90  1.18.2.2  mycroft 	u_int32 xfer_block_wait;
     91  1.18.2.2  mycroft 	struct buf buf_queue;
     92  1.18.2.2  mycroft };
     93       1.1      cgd 
     94       1.1      cgd #define CD_STOP		0
     95       1.1      cgd #define CD_START	1
     96       1.1      cgd #define CD_EJECT	-2
     97       1.1      cgd 
     98  1.18.2.2  mycroft struct cd_driver {
     99  1.18.2.2  mycroft 	u_int32 size;
    100  1.18.2.2  mycroft 	struct cd_data **cd_data;
    101  1.18.2.2  mycroft } cd_driver;
    102  1.18.2.2  mycroft 
    103  1.18.2.2  mycroft static u_int32 next_cd_unit = 0;
    104  1.18.2.2  mycroft 
    105       1.6  deraadt /*
    106       1.6  deraadt  * The routine called by the low level scsi routine when it discovers
    107       1.6  deraadt  * A device suitable for this driver
    108       1.6  deraadt  */
    109  1.18.2.2  mycroft int
    110  1.18.2.2  mycroft cdattach(sc_link)
    111  1.18.2.2  mycroft 	struct scsi_link *sc_link;
    112       1.1      cgd {
    113  1.18.2.2  mycroft 	u_int32 unit, i;
    114       1.1      cgd 	unsigned char *tbl;
    115  1.18.2.2  mycroft 	struct cd_data *cd, **cdrealloc;
    116       1.1      cgd 	struct cd_parms *dp;
    117       1.1      cgd 
    118  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB2, ("cdattach "));
    119       1.3  deraadt 
    120  1.18.2.2  mycroft 	/*
    121  1.18.2.2  mycroft 	 * Fill out any more info in the
    122  1.18.2.2  mycroft 	 * Link structure that we can
    123  1.18.2.2  mycroft 	 */
    124  1.18.2.2  mycroft 	unit = next_cd_unit++;
    125  1.18.2.2  mycroft 	sc_link->device = &cd_switch;
    126  1.18.2.2  mycroft 	sc_link->dev_unit = unit;
    127  1.18.2.2  mycroft 	/*
    128  1.18.2.2  mycroft 	 * allocate the resources for another drive
    129  1.18.2.2  mycroft 	 * if we have already allocate a cd_data pointer we must
    130  1.18.2.2  mycroft 	 * copy the old pointers into a new region that is
    131  1.18.2.2  mycroft 	 * larger and release the old region, aka realloc
    132  1.18.2.2  mycroft 	 */
    133  1.18.2.2  mycroft 	/* XXX
    134  1.18.2.2  mycroft 	 * This if will always be true for now, but future code may
    135  1.18.2.2  mycroft 	 * preallocate more units to reduce overhead.  This would be
    136  1.18.2.2  mycroft 	 * done by changing the malloc to be (next_cd_unit * x) and
    137  1.18.2.2  mycroft 	 * the cd_driver.size++ to be +x
    138  1.18.2.2  mycroft 	 */
    139  1.18.2.2  mycroft 	if (unit >= cd_driver.size) {
    140  1.18.2.2  mycroft 		cdrealloc =
    141  1.18.2.2  mycroft 		    malloc(sizeof(cd_driver.cd_data) * next_cd_unit,
    142  1.18.2.2  mycroft 		    M_DEVBUF, M_NOWAIT);
    143  1.18.2.2  mycroft 		if (!cdrealloc) {
    144  1.18.2.2  mycroft 			printf("cd%d: malloc failed for cdrealloc\n", unit);
    145  1.18.2.2  mycroft 			return (0);
    146  1.18.2.2  mycroft 		}
    147  1.18.2.2  mycroft 		/* Make sure we have something to copy before we copy it */
    148  1.18.2.2  mycroft 		bzero(cdrealloc, sizeof(cd_driver.cd_data) * next_cd_unit);
    149  1.18.2.2  mycroft 		if (cd_driver.size) {
    150  1.18.2.2  mycroft 			bcopy(cd_driver.cd_data, cdrealloc,
    151  1.18.2.2  mycroft 			    sizeof(cd_driver.cd_data) * cd_driver.size);
    152  1.18.2.2  mycroft 			free(cd_driver.cd_data, M_DEVBUF);
    153  1.18.2.2  mycroft 		}
    154  1.18.2.2  mycroft 		cd_driver.cd_data = cdrealloc;
    155  1.18.2.2  mycroft 		cd_driver.cd_data[unit] = NULL;
    156  1.18.2.2  mycroft 		cd_driver.size++;
    157  1.18.2.2  mycroft 	}
    158  1.18.2.2  mycroft 	if (cd_driver.cd_data[unit]) {
    159  1.18.2.2  mycroft 		printf("cd%d: Already has storage!\n", unit);
    160  1.18.2.2  mycroft 		return (0);
    161  1.18.2.2  mycroft 	}
    162  1.18.2.2  mycroft 	/*
    163  1.18.2.2  mycroft 	 * allocate the per drive data area
    164  1.18.2.2  mycroft 	 */
    165  1.18.2.2  mycroft 	cd = cd_driver.cd_data[unit] =
    166  1.18.2.2  mycroft 	    malloc(sizeof(struct cd_data), M_DEVBUF, M_NOWAIT);
    167  1.18.2.2  mycroft 	if (!cd) {
    168  1.18.2.2  mycroft 		printf("cd%d: malloc failed for cd_data\n", unit);
    169  1.18.2.2  mycroft 		return (0);
    170  1.18.2.2  mycroft 	}
    171  1.18.2.2  mycroft 	bzero(cd, sizeof(struct cd_data));
    172  1.18.2.2  mycroft 	dp = &(cd->params);
    173  1.18.2.2  mycroft 	/*
    174  1.18.2.2  mycroft 	 * Store information needed to contact our base driver
    175  1.18.2.2  mycroft 	 */
    176  1.18.2.2  mycroft 	cd->sc_link = sc_link;
    177  1.18.2.2  mycroft 	/* only allow 1 outstanding command on tapes */
    178  1.18.2.2  mycroft 	sc_link->opennings = cd->cmdscount = CDOUTSTANDING;
    179  1.18.2.2  mycroft 
    180  1.18.2.2  mycroft 	/*
    181  1.18.2.2  mycroft 	 * Use the subdriver to request information regarding
    182  1.18.2.2  mycroft 	 * the drive. We cannot use interrupts yet, so the
    183  1.18.2.2  mycroft 	 * request must specify this.
    184  1.18.2.2  mycroft 	 */
    185  1.18.2.2  mycroft 	cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
    186  1.18.2.2  mycroft 	if (dp->disksize) {
    187  1.18.2.2  mycroft 		printf("cd%d: cd present.[%d x %d byte records]\n",
    188  1.18.2.2  mycroft 		    unit,
    189  1.18.2.2  mycroft 		    cd->params.disksize,
    190  1.18.2.2  mycroft 		    cd->params.blksize);
    191  1.18.2.2  mycroft 	} else {
    192  1.18.2.2  mycroft 		printf("cd%d: drive empty\n", unit);
    193  1.18.2.2  mycroft 	}
    194       1.1      cgd 	cd->flags |= CDINIT;
    195  1.18.2.2  mycroft 	return (1);
    196       1.1      cgd }
    197       1.1      cgd 
    198  1.18.2.2  mycroft /*
    199  1.18.2.2  mycroft  * open the device. Make sure the partition info is a up-to-date as can be.
    200  1.18.2.2  mycroft  */
    201  1.18.2.2  mycroft errval
    202  1.18.2.2  mycroft cdopen(dev)
    203       1.1      cgd {
    204  1.18.2.2  mycroft 	errval  errcode = 0;
    205  1.18.2.2  mycroft 	u_int32 unit, part;
    206       1.1      cgd 	struct cd_parms cd_parms;
    207       1.4  deraadt 	struct cd_data *cd;
    208  1.18.2.2  mycroft 	struct scsi_link *sc_link;
    209  1.18.2.2  mycroft 	u_int32 heldflags;
    210       1.1      cgd 
    211       1.1      cgd 	unit = UNIT(dev);
    212       1.1      cgd 	part = PARTITION(dev);
    213       1.3  deraadt 
    214  1.18.2.2  mycroft 	/*
    215  1.18.2.2  mycroft 	 * Check the unit is legal
    216  1.18.2.2  mycroft 	 */
    217  1.18.2.2  mycroft 	if (unit >= cd_driver.size) {
    218  1.18.2.2  mycroft 		return (ENXIO);
    219  1.18.2.2  mycroft 	}
    220  1.18.2.2  mycroft 	cd = cd_driver.cd_data[unit];
    221  1.18.2.2  mycroft 	/*
    222  1.18.2.2  mycroft 	 * Make sure the device has been initialised
    223  1.18.2.2  mycroft 	 */
    224  1.18.2.2  mycroft 	if ((cd == NULL) || (!(cd->flags & CDINIT)))
    225  1.18.2.2  mycroft 		return (ENXIO);
    226  1.18.2.2  mycroft 
    227  1.18.2.2  mycroft 	sc_link = cd->sc_link;
    228  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB1,
    229  1.18.2.2  mycroft 	    ("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n",
    230  1.18.2.2  mycroft 		dev, unit, cd_driver.size, part));
    231  1.18.2.2  mycroft 	/*
    232  1.18.2.2  mycroft 	 * If it's been invalidated, and not everybody has closed it then
    233  1.18.2.2  mycroft 	 * forbid re-entry.  (may have changed media)
    234  1.18.2.2  mycroft 	 */
    235  1.18.2.2  mycroft 	if ((!(sc_link->flags & SDEV_MEDIA_LOADED))
    236  1.18.2.2  mycroft 	    && (cd->openparts))
    237  1.18.2.2  mycroft 		return (ENXIO);
    238  1.18.2.2  mycroft 
    239  1.18.2.2  mycroft 	/*
    240  1.18.2.2  mycroft 	 * Check that it is still responding and ok.
    241  1.18.2.2  mycroft 	 * if the media has been changed this will result in a
    242  1.18.2.2  mycroft 	 * "unit attention" error which the error code will
    243  1.18.2.2  mycroft 	 * disregard because the SDEV_MEDIA_LOADED flag is not yet set
    244  1.18.2.2  mycroft 	 */
    245  1.18.2.2  mycroft 	scsi_test_unit_ready(sc_link, SCSI_SILENT);
    246  1.18.2.2  mycroft 
    247  1.18.2.2  mycroft 	/*
    248  1.18.2.2  mycroft 	 * Next time actually take notice of error returns
    249  1.18.2.2  mycroft 	 */
    250  1.18.2.2  mycroft 	sc_link->flags |= SDEV_OPEN;	/* unit attn errors are now errors */
    251  1.18.2.2  mycroft 	if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) {
    252  1.18.2.2  mycroft 		SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n"));
    253  1.18.2.2  mycroft 		errcode = ENXIO;
    254  1.18.2.2  mycroft 		goto bad;
    255  1.18.2.2  mycroft 	}
    256  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB3, ("Device present\n"));
    257  1.18.2.2  mycroft 	/*
    258  1.18.2.2  mycroft 	 * In case it is a funny one, tell it to start
    259  1.18.2.2  mycroft 	 * not needed for some drives
    260  1.18.2.2  mycroft 	 */
    261  1.18.2.2  mycroft 	scsi_start_unit(sc_link, CD_START);
    262  1.18.2.2  mycroft 	scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT);
    263  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB3, ("started "));
    264  1.18.2.2  mycroft 	/*
    265  1.18.2.2  mycroft 	 * Load the physical device parameters
    266  1.18.2.2  mycroft 	 */
    267  1.18.2.2  mycroft 	if (cd_get_parms(unit, 0)) {
    268  1.18.2.2  mycroft 		errcode = ENXIO;
    269  1.18.2.2  mycroft 		goto bad;
    270  1.18.2.2  mycroft 	}
    271  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded "));
    272  1.18.2.2  mycroft 	/*
    273  1.18.2.2  mycroft 	 * Make up some partition information
    274  1.18.2.2  mycroft 	 */
    275       1.1      cgd 	cdgetdisklabel(unit);
    276  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel fabricated "));
    277  1.18.2.2  mycroft 	/*
    278  1.18.2.2  mycroft 	 * Check the partition is legal
    279  1.18.2.2  mycroft 	 */
    280  1.18.2.2  mycroft 	if ((part >= cd->disklabel.d_npartitions)
    281  1.18.2.2  mycroft 	    && (part != RAW_PART)) {
    282  1.18.2.2  mycroft 		SC_DEBUG(sc_link, SDEV_DB3, ("partition %d > %d\n", part
    283  1.18.2.2  mycroft 			,cd->disklabel.d_npartitions));
    284  1.18.2.2  mycroft 		errcode = ENXIO;
    285  1.18.2.2  mycroft 		goto bad;
    286       1.1      cgd 	}
    287  1.18.2.2  mycroft 	/*
    288  1.18.2.2  mycroft 	 *  Check that the partition exists
    289  1.18.2.2  mycroft 	 */
    290  1.18.2.2  mycroft 	if ((cd->disklabel.d_partitions[part].p_fstype == FS_UNUSED)
    291  1.18.2.2  mycroft 	    && (part != RAW_PART)) {
    292  1.18.2.2  mycroft 		SC_DEBUG(sc_link, SDEV_DB3, ("part %d type UNUSED\n", part));
    293  1.18.2.2  mycroft 		errcode = ENXIO;
    294  1.18.2.2  mycroft 		goto bad;
    295       1.1      cgd 	}
    296  1.18.2.2  mycroft 	cd->partflags[part] |= CDOPEN;
    297  1.18.2.2  mycroft 	cd->openparts |= (1 << part);
    298  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n"));
    299  1.18.2.2  mycroft 	sc_link->flags |= SDEV_MEDIA_LOADED;
    300  1.18.2.2  mycroft 	return (0);
    301  1.18.2.2  mycroft       bad:
    302  1.18.2.2  mycroft 
    303  1.18.2.2  mycroft 	/*
    304  1.18.2.2  mycroft 	 *  if we would have been the only open
    305  1.18.2.2  mycroft 	 * then leave things back as they were
    306  1.18.2.2  mycroft 	 */
    307  1.18.2.2  mycroft 	if (!(cd->openparts)) {
    308  1.18.2.2  mycroft 		sc_link->flags &= ~SDEV_OPEN;
    309  1.18.2.2  mycroft 		scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
    310       1.1      cgd 	}
    311  1.18.2.2  mycroft 	return (errcode);
    312       1.1      cgd }
    313       1.1      cgd 
    314  1.18.2.2  mycroft /*
    315  1.18.2.2  mycroft  * close the device.. only called if we are the LAST
    316  1.18.2.2  mycroft  * occurence of an open device
    317  1.18.2.2  mycroft  */
    318  1.18.2.2  mycroft errval
    319  1.18.2.2  mycroft cdclose(dev)
    320  1.18.2.2  mycroft 	dev_t   dev;
    321  1.18.2.2  mycroft {
    322  1.18.2.2  mycroft 	u_int8  unit, part;
    323  1.18.2.2  mycroft 	u_int32 old_priority;
    324  1.18.2.2  mycroft 	struct cd_data *cd;
    325  1.18.2.2  mycroft 	struct scsi_link *sc_link;
    326       1.4  deraadt 
    327  1.18.2.2  mycroft 	unit = UNIT(dev);
    328  1.18.2.2  mycroft 	part = PARTITION(dev);
    329  1.18.2.2  mycroft 	cd = cd_driver.cd_data[unit];
    330  1.18.2.2  mycroft 	sc_link = cd->sc_link;
    331  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB2, ("cd%d: closing part %d\n", unit, part));
    332  1.18.2.2  mycroft 	cd->partflags[part] &= ~CDOPEN;
    333  1.18.2.2  mycroft 	cd->openparts &= ~(1 << part);
    334  1.18.2.2  mycroft 
    335  1.18.2.2  mycroft 	/*
    336  1.18.2.2  mycroft 	 * If we were the last open of the entire device, release it.
    337  1.18.2.2  mycroft 	 */
    338  1.18.2.2  mycroft 	if (!(cd->openparts)) {
    339  1.18.2.2  mycroft 		scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
    340  1.18.2.2  mycroft 		cd->sc_link->flags &= ~SDEV_OPEN;
    341       1.4  deraadt 	}
    342  1.18.2.2  mycroft 	return (0);
    343  1.18.2.2  mycroft }
    344  1.18.2.2  mycroft 
    345  1.18.2.2  mycroft /*
    346  1.18.2.2  mycroft  * trim the size of the transfer if needed,
    347  1.18.2.2  mycroft  * called by physio
    348  1.18.2.2  mycroft  * basically the smaller of our max and the scsi driver's
    349  1.18.2.2  mycroft  * minphys (note we have no max ourselves)
    350  1.18.2.2  mycroft  *
    351  1.18.2.2  mycroft  * Trim buffer length if buffer-size is bigger than page size
    352  1.18.2.2  mycroft  */
    353  1.18.2.2  mycroft void
    354  1.18.2.2  mycroft cdminphys(bp)
    355  1.18.2.2  mycroft 	struct buf *bp;
    356  1.18.2.2  mycroft {
    357  1.18.2.2  mycroft 	(*(cd_driver.cd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
    358  1.18.2.2  mycroft }
    359  1.18.2.2  mycroft 
    360  1.18.2.2  mycroft /*
    361  1.18.2.2  mycroft  * Actually translate the requested transfer into one the physical driver can
    362  1.18.2.2  mycroft  * understand.  The transfer is described by a buf and will include only one
    363  1.18.2.2  mycroft  * physical transfer.
    364  1.18.2.2  mycroft  */
    365  1.18.2.2  mycroft errval
    366  1.18.2.2  mycroft cdstrategy(bp)
    367  1.18.2.2  mycroft 	struct buf *bp;
    368  1.18.2.2  mycroft {
    369  1.18.2.2  mycroft 	struct buf *dp;
    370  1.18.2.2  mycroft 	u_int32 opri;
    371  1.18.2.2  mycroft 	u_int32 unit = UNIT((bp->b_dev));
    372  1.18.2.2  mycroft 	struct cd_data *cd = cd_driver.cd_data[unit];
    373  1.18.2.2  mycroft 
    374  1.18.2.2  mycroft 	cdstrats++;
    375  1.18.2.2  mycroft 	SC_DEBUG(cd->sc_link, SDEV_DB2, ("\ncdstrategy "));
    376  1.18.2.2  mycroft 	SC_DEBUG(cd->sc_link, SDEV_DB1, ("cd%d: %d bytes @ blk%d\n",
    377  1.18.2.2  mycroft 		unit, bp->b_bcount, bp->b_blkno));
    378  1.18.2.2  mycroft 	cdminphys(bp);
    379  1.18.2.2  mycroft 	/*
    380  1.18.2.2  mycroft 	 * If the device has been made invalid, error out
    381  1.18.2.2  mycroft 	 * maybe the media changed
    382  1.18.2.2  mycroft 	 */
    383  1.18.2.2  mycroft 	if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED)) {
    384       1.4  deraadt 		bp->b_error = EIO;
    385       1.4  deraadt 		goto bad;
    386       1.4  deraadt 	}
    387  1.18.2.2  mycroft 	/*
    388  1.18.2.2  mycroft 	 * can't ever write to a CD
    389  1.18.2.2  mycroft 	 */
    390       1.1      cgd 	if ((bp->b_flags & B_READ) == 0) {
    391       1.1      cgd 		bp->b_error = EROFS;
    392       1.1      cgd 		goto bad;
    393       1.1      cgd 	}
    394  1.18.2.2  mycroft 	/*
    395  1.18.2.2  mycroft 	 * If it's a null transfer, return immediatly
    396  1.18.2.2  mycroft 	 */
    397       1.1      cgd 	if (bp->b_bcount == 0) {
    398       1.1      cgd 		goto done;
    399       1.1      cgd 	}
    400  1.18.2.2  mycroft 	/*
    401  1.18.2.2  mycroft 	 * Decide which unit and partition we are talking about
    402  1.18.2.2  mycroft 	 */
    403  1.18.2.2  mycroft 	if (PARTITION(bp->b_dev) != RAW_PART) {
    404       1.1      cgd 		/*
    405       1.1      cgd 		 * do bounds checking, adjust transfer. if error, process.
    406       1.1      cgd 		 * if end of partition, just return
    407       1.1      cgd 		 */
    408  1.18.2.2  mycroft 		if (bounds_check_with_label(bp, &cd->disklabel, 1) <= 0)
    409       1.1      cgd 			goto done;
    410       1.1      cgd 		/* otherwise, process transfer request */
    411       1.1      cgd 	}
    412       1.1      cgd 	opri = SPLCD();
    413  1.18.2.2  mycroft 	dp = &cd->buf_queue;
    414       1.1      cgd 
    415  1.18.2.2  mycroft 	/*
    416  1.18.2.2  mycroft 	 * Place it in the queue of disk activities for this disk
    417  1.18.2.2  mycroft 	 */
    418       1.1      cgd 	disksort(dp, bp);
    419       1.1      cgd 
    420  1.18.2.2  mycroft 	/*
    421  1.18.2.2  mycroft 	 * Tell the device to get going on the transfer if it's
    422  1.18.2.2  mycroft 	 * not doing anything, otherwise just wait for completion
    423  1.18.2.2  mycroft 	 */
    424       1.1      cgd 	cdstart(unit);
    425       1.1      cgd 
    426       1.1      cgd 	splx(opri);
    427       1.1      cgd 	return;
    428  1.18.2.2  mycroft       bad:
    429       1.1      cgd 	bp->b_flags |= B_ERROR;
    430  1.18.2.2  mycroft       done:
    431       1.1      cgd 
    432  1.18.2.2  mycroft 	/*
    433  1.18.2.2  mycroft 	 * Correctly set the buf to indicate a completed xfer
    434  1.18.2.2  mycroft 	 */
    435  1.18.2.2  mycroft 	bp->b_resid = bp->b_bcount;
    436       1.1      cgd 	biodone(bp);
    437  1.18.2.2  mycroft 	return (0);
    438       1.1      cgd }
    439       1.1      cgd 
    440  1.18.2.2  mycroft /*
    441  1.18.2.2  mycroft  * cdstart looks to see if there is a buf waiting for the device
    442  1.18.2.2  mycroft  * and that the device is not already busy. If both are true,
    443  1.18.2.2  mycroft  * It deques the buf and creates a scsi command to perform the
    444  1.18.2.2  mycroft  * transfer in the buf. The transfer request will call scsi_done
    445  1.18.2.2  mycroft  * on completion, which will in turn call this routine again
    446  1.18.2.2  mycroft  * so that the next queued transfer is performed.
    447  1.18.2.2  mycroft  * The bufs are queued by the strategy routine (cdstrategy)
    448  1.18.2.2  mycroft  *
    449  1.18.2.2  mycroft  * This routine is also called after other non-queued requests
    450  1.18.2.2  mycroft  * have been made of the scsi driver, to ensure that the queue
    451  1.18.2.2  mycroft  * continues to be drained.
    452  1.18.2.2  mycroft  *
    453  1.18.2.2  mycroft  * must be called at the correct (highish) spl level
    454  1.18.2.2  mycroft  * cdstart() is called at SPLCD  from cdstrategy and scsi_done
    455  1.18.2.2  mycroft  */
    456  1.18.2.2  mycroft void
    457  1.18.2.2  mycroft cdstart(unit)
    458  1.18.2.2  mycroft 	u_int32 unit;
    459  1.18.2.2  mycroft {
    460  1.18.2.2  mycroft 	register struct buf *bp = 0;
    461  1.18.2.2  mycroft 	register struct buf *dp;
    462  1.18.2.2  mycroft 	struct scsi_rw_big cmd;
    463  1.18.2.2  mycroft 	u_int32 blkno, nblk;
    464  1.18.2.2  mycroft 	struct partition *p;
    465  1.18.2.2  mycroft 	struct cd_data *cd = cd_driver.cd_data[unit];
    466  1.18.2.2  mycroft 	struct scsi_link *sc_link = cd->sc_link;
    467  1.18.2.2  mycroft 
    468  1.18.2.2  mycroft 	SC_DEBUG(sc_link, SDEV_DB2, ("cdstart%d ", unit));
    469  1.18.2.2  mycroft 	/*
    470  1.18.2.2  mycroft 	 * See if there is a buf to do and we are not already
    471  1.18.2.2  mycroft 	 * doing one
    472  1.18.2.2  mycroft 	 */
    473  1.18.2.2  mycroft 	if (!sc_link->opennings) {
    474  1.18.2.2  mycroft 		return;		/* no room for us, unit already underway */
    475       1.1      cgd 	}
    476  1.18.2.2  mycroft 	if (sc_link->flags & SDEV_WAITING) {	/* is room, but a special waits */
    477  1.18.2.2  mycroft 		return;		/* give the special that's waiting a chance to run */
    478       1.1      cgd 	}
    479  1.18.2.2  mycroft 	dp = &cd->buf_queue;
    480  1.18.2.2  mycroft 	if ((bp = dp->b_actf) != NULL) {	/* yes, an assign */
    481  1.18.2.2  mycroft 		dp->b_actf = bp->av_forw;
    482  1.18.2.2  mycroft 	} else {
    483       1.1      cgd 		return;
    484       1.1      cgd 	}
    485  1.18.2.2  mycroft 	/*
    486  1.18.2.2  mycroft 	 * Should reject all queued entries if SDEV_MEDIA_LOADED is not true.
    487  1.18.2.2  mycroft 	 */
    488  1.18.2.2  mycroft 	if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
    489  1.18.2.2  mycroft 		goto bad;	/* no I/O.. media changed or something */
    490  1.18.2.2  mycroft 	}
    491  1.18.2.2  mycroft 	/*
    492  1.18.2.2  mycroft 	 * We have a buf, now we should make a command
    493  1.18.2.2  mycroft 	 *
    494  1.18.2.2  mycroft 	 * First, translate the block to absolute and put it in terms of the
    495  1.18.2.2  mycroft 	 * logical blocksize of the device.  Really a bit silly until we have
    496  1.18.2.2  mycroft 	 * real partitions, but.
    497  1.18.2.2  mycroft 	 */
    498  1.18.2.2  mycroft 	blkno = bp->b_blkno / (cd->params.blksize / 512);
    499  1.18.2.2  mycroft 	if (PARTITION(bp->b_dev) != RAW_PART) {
    500  1.18.2.2  mycroft 		p = cd->disklabel.d_partitions + PARTITION(bp->b_dev);
    501  1.18.2.2  mycroft 		blkno += p->p_offset;
    502  1.18.2.2  mycroft 	}
    503       1.1      cgd 	nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize);
    504  1.18.2.2  mycroft 	/* what if something asks for 512 bytes not on a 2k boundary? *//*XXX */
    505       1.1      cgd 
    506  1.18.2.2  mycroft 	/*
    507  1.18.2.2  mycroft 	 *  Fill out the scsi command
    508  1.18.2.2  mycroft 	 */
    509       1.1      cgd 	bzero(&cmd, sizeof(cmd));
    510  1.18.2.2  mycroft 	cmd.op_code = READ_BIG;
    511  1.18.2.2  mycroft 	cmd.addr_3 = (blkno & 0xff000000) >> 24;
    512  1.18.2.2  mycroft 	cmd.addr_2 = (blkno & 0xff0000) >> 16;
    513  1.18.2.2  mycroft 	cmd.addr_1 = (blkno & 0xff00) >> 8;
    514  1.18.2.2  mycroft 	cmd.addr_0 = blkno & 0xff;
    515  1.18.2.2  mycroft 	cmd.length2 = (nblk & 0xff00) >> 8;
    516  1.18.2.2  mycroft 	cmd.length1 = (nblk & 0xff);
    517  1.18.2.2  mycroft 
    518  1.18.2.2  mycroft 	/*
    519  1.18.2.2  mycroft 	 * Call the routine that chats with the adapter.
    520  1.18.2.2  mycroft 	 * Note: we cannot sleep as we may be an interrupt
    521  1.18.2.2  mycroft 	 */
    522  1.18.2.2  mycroft 	if (scsi_scsi_cmd(sc_link,
    523  1.18.2.2  mycroft 		(struct scsi_generic *) &cmd,
    524  1.18.2.2  mycroft 		sizeof(cmd),
    525  1.18.2.2  mycroft 		(u_char *) bp->b_un.b_addr,
    526  1.18.2.2  mycroft 		bp->b_bcount,
    527  1.18.2.2  mycroft 		CDRETRIES,
    528  1.18.2.2  mycroft 		30000,
    529  1.18.2.2  mycroft 		bp,
    530  1.18.2.2  mycroft 		SCSI_NOSLEEP | ((bp->b_flags & B_READ) ?
    531  1.18.2.2  mycroft 		    SCSI_DATA_IN : SCSI_DATA_OUT))
    532  1.18.2.2  mycroft 	    != SUCCESSFULLY_QUEUED) {
    533  1.18.2.2  mycroft 	      bad:
    534  1.18.2.2  mycroft 		printf("cd%d: oops not queued", unit);
    535  1.18.2.2  mycroft 		bp->b_error = EIO;
    536  1.18.2.2  mycroft 		bp->b_flags |= B_ERROR;
    537       1.1      cgd 		biodone(bp);
    538  1.18.2.2  mycroft 		return;
    539       1.1      cgd 	}
    540  1.18.2.2  mycroft 	cdqueues++;
    541       1.1      cgd }
    542  1.18.2.2  mycroft 
    543  1.18.2.2  mycroft /*
    544  1.18.2.2  mycroft  * Perform special action on behalf of the user.
    545  1.18.2.2  mycroft  * Knows about the internals of this device
    546  1.18.2.2  mycroft  */
    547  1.18.2.2  mycroft errval
    548       1.1      cgd cdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
    549       1.1      cgd {
    550  1.18.2.2  mycroft 	errval  error = 0;
    551  1.18.2.2  mycroft 	u_int32 opri;
    552  1.18.2.2  mycroft 	u_int8  unit, part;
    553       1.1      cgd 	register struct cd_data *cd;
    554       1.1      cgd 
    555  1.18.2.2  mycroft 	/*
    556  1.18.2.2  mycroft 	 * Find the device that the user is talking about
    557  1.18.2.2  mycroft 	 */
    558       1.1      cgd 	unit = UNIT(dev);
    559       1.1      cgd 	part = PARTITION(dev);
    560  1.18.2.2  mycroft 	cd = cd_driver.cd_data[unit];
    561  1.18.2.2  mycroft 	SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%x ", cmd));
    562       1.1      cgd 
    563  1.18.2.2  mycroft 	/*
    564  1.18.2.2  mycroft 	 * If the device is not valid.. abandon ship
    565  1.18.2.2  mycroft 	 */
    566  1.18.2.2  mycroft 	if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED))
    567  1.18.2.2  mycroft 		return (EIO);
    568  1.18.2.2  mycroft 	switch (cmd) {
    569       1.1      cgd 
    570       1.1      cgd 	case DIOCSBAD:
    571  1.18.2.2  mycroft 		error = EINVAL;
    572       1.1      cgd 		break;
    573       1.1      cgd 
    574       1.1      cgd 	case DIOCGDINFO:
    575  1.18.2.2  mycroft 		*(struct disklabel *) addr = cd->disklabel;
    576       1.1      cgd 		break;
    577       1.1      cgd 
    578  1.18.2.2  mycroft 	case DIOCGPART:
    579  1.18.2.2  mycroft 		((struct partinfo *) addr)->disklab = &cd->disklabel;
    580  1.18.2.2  mycroft 		((struct partinfo *) addr)->part =
    581  1.18.2.2  mycroft 		    &cd->disklabel.d_partitions[PARTITION(dev)];
    582  1.18.2.2  mycroft 		break;
    583  1.18.2.2  mycroft 
    584  1.18.2.2  mycroft 		/*
    585  1.18.2.2  mycroft 		 * a bit silly, but someone might want to test something on a
    586  1.18.2.2  mycroft 		 * section of cdrom.
    587  1.18.2.2  mycroft 		 */
    588  1.18.2.2  mycroft 	case DIOCWDINFO:
    589  1.18.2.2  mycroft 	case DIOCSDINFO:
    590  1.18.2.2  mycroft 		if ((flag & FWRITE) == 0)
    591  1.18.2.2  mycroft 			error = EBADF;
    592  1.18.2.2  mycroft 		else
    593  1.18.2.2  mycroft 			error = setdisklabel(&cd->disklabel,
    594  1.18.2.2  mycroft 			    (struct disklabel *) addr,
    595  1.18.2.2  mycroft 			    0,
    596  1.18.2.2  mycroft 			    0);
    597  1.18.2.2  mycroft 		if (error == 0)
    598  1.18.2.2  mycroft 			break;
    599       1.1      cgd 
    600  1.18.2.2  mycroft 	case DIOCWLABEL:
    601  1.18.2.2  mycroft 		error = EBADF;
    602  1.18.2.2  mycroft 		break;
    603       1.1      cgd 
    604       1.1      cgd 	case CDIOCPLAYTRACKS:
    605       1.1      cgd 		{
    606  1.18.2.2  mycroft 			struct ioc_play_track *args
    607  1.18.2.2  mycroft 			= (struct ioc_play_track *) addr;
    608  1.18.2.2  mycroft 			struct cd_mode_data data;
    609  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    610  1.18.2.2  mycroft 				break;
    611  1.18.2.2  mycroft 			data.page.audio.flags &= ~CD_PA_SOTC;
    612  1.18.2.2  mycroft 			data.page.audio.flags |= CD_PA_IMMED;
    613  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    614  1.18.2.2  mycroft 				break;
    615  1.18.2.2  mycroft 			return (cd_play_tracks(unit
    616  1.18.2.2  mycroft 				,args->start_track
    617  1.18.2.2  mycroft 				,args->start_index
    618  1.18.2.2  mycroft 				,args->end_track
    619  1.18.2.2  mycroft 				,args->end_index
    620  1.18.2.2  mycroft 			    ));
    621       1.1      cgd 		}
    622       1.1      cgd 		break;
    623      1.17   brezak 	case CDIOCPLAYMSF:
    624      1.17   brezak 		{
    625  1.18.2.2  mycroft 			struct ioc_play_msf *args
    626  1.18.2.2  mycroft 			= (struct ioc_play_msf *) addr;
    627  1.18.2.2  mycroft 			struct cd_mode_data data;
    628  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    629  1.18.2.2  mycroft 				break;
    630  1.18.2.2  mycroft 			data.page.audio.flags &= ~CD_PA_SOTC;
    631  1.18.2.2  mycroft 			data.page.audio.flags |= CD_PA_IMMED;
    632  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    633  1.18.2.2  mycroft 				break;
    634  1.18.2.2  mycroft 			return (cd_play_msf(unit
    635  1.18.2.2  mycroft 				,args->start_m
    636  1.18.2.2  mycroft 				,args->start_s
    637  1.18.2.2  mycroft 				,args->start_f
    638  1.18.2.2  mycroft 				,args->end_m
    639  1.18.2.2  mycroft 				,args->end_s
    640  1.18.2.2  mycroft 				,args->end_f
    641  1.18.2.2  mycroft 			    ));
    642      1.17   brezak 		}
    643      1.17   brezak 		break;
    644       1.1      cgd 	case CDIOCPLAYBLOCKS:
    645       1.1      cgd 		{
    646  1.18.2.2  mycroft 			struct ioc_play_blocks *args
    647  1.18.2.2  mycroft 			= (struct ioc_play_blocks *) addr;
    648  1.18.2.2  mycroft 			struct cd_mode_data data;
    649  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    650  1.18.2.2  mycroft 				break;
    651  1.18.2.2  mycroft 			data.page.audio.flags &= ~CD_PA_SOTC;
    652  1.18.2.2  mycroft 			data.page.audio.flags |= CD_PA_IMMED;
    653  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    654       1.1      cgd 				break;
    655  1.18.2.2  mycroft 			return (cd_play(unit, args->blk, args->len));
    656       1.1      cgd 
    657       1.1      cgd 		}
    658       1.1      cgd 		break;
    659       1.1      cgd 	case CDIOCREADSUBCHANNEL:
    660       1.1      cgd 		{
    661       1.1      cgd 			struct ioc_read_subchannel *args
    662  1.18.2.2  mycroft 			= (struct ioc_read_subchannel *) addr;
    663       1.1      cgd 			struct cd_sub_channel_info data;
    664  1.18.2.2  mycroft 			u_int32 len = args->data_len;
    665  1.18.2.2  mycroft 			if (len > sizeof(data) ||
    666  1.18.2.2  mycroft 			    len < sizeof(struct cd_sub_channel_header)) {
    667  1.18.2.2  mycroft 				error = EINVAL;
    668       1.1      cgd 				break;
    669       1.1      cgd 			}
    670  1.18.2.2  mycroft 			if (error = cd_read_subchannel(unit, args->address_format,
    671  1.18.2.2  mycroft 				args->data_format, args->track, &data, len)) {
    672       1.1      cgd 				break;
    673       1.1      cgd 			}
    674  1.18.2.2  mycroft 			len = MIN(len, ((data.header.data_len[0] << 8) + data.header.data_len[1] +
    675  1.18.2.2  mycroft 				sizeof(struct cd_sub_channel_header)));
    676  1.18.2.2  mycroft 			if (copyout(&data, args->data, len) != 0) {
    677  1.18.2.2  mycroft 				error = EFAULT;
    678       1.1      cgd 			}
    679       1.1      cgd 		}
    680       1.1      cgd 		break;
    681       1.1      cgd 	case CDIOREADTOCHEADER:
    682       1.1      cgd 		{
    683       1.1      cgd 			struct ioc_toc_header th;
    684  1.18.2.2  mycroft 			if (error = cd_read_toc(unit, 0, 0, &th, sizeof(th)))
    685       1.1      cgd 				break;
    686  1.18.2.2  mycroft 			th.len = (th.len & 0xff) << 8 + ((th.len >> 8) & 0xff);
    687  1.18.2.2  mycroft 			bcopy(&th, addr, sizeof(th));
    688       1.1      cgd 		}
    689       1.1      cgd 		break;
    690       1.1      cgd 	case CDIOREADTOCENTRYS:
    691       1.1      cgd 		{
    692  1.18.2.2  mycroft 			struct ioc_read_toc_entry *te =
    693  1.18.2.2  mycroft 			(struct ioc_read_toc_entry *) addr;
    694       1.1      cgd 			struct cd_toc_entry data[65];
    695       1.1      cgd 			struct ioc_toc_header *th;
    696  1.18.2.2  mycroft 			u_int32 len = te->data_len;
    697  1.18.2.2  mycroft 			th = (struct ioc_toc_header *) data;
    698       1.1      cgd 
    699  1.18.2.2  mycroft 			if (len > sizeof(data) || len < sizeof(struct cd_toc_entry)) {
    700  1.18.2.2  mycroft 				error = EINVAL;
    701  1.18.2.2  mycroft 				break;
    702  1.18.2.2  mycroft 			}
    703  1.18.2.2  mycroft 			if (error = cd_read_toc(unit, te->address_format,
    704  1.18.2.2  mycroft 				te->starting_track,
    705  1.18.2.2  mycroft 				data,
    706  1.18.2.2  mycroft 				len))
    707  1.18.2.2  mycroft 				break;
    708  1.18.2.2  mycroft 			len = MIN(len, ((((th->len & 0xff) << 8) + ((th->len >> 8))) +
    709  1.18.2.2  mycroft 				sizeof(*th)));
    710  1.18.2.2  mycroft 			if (copyout(th, te->data, len) != 0) {
    711  1.18.2.2  mycroft 				error = EFAULT;
    712       1.1      cgd 			}
    713       1.1      cgd 		}
    714       1.1      cgd 		break;
    715       1.1      cgd 	case CDIOCSETPATCH:
    716       1.1      cgd 		{
    717  1.18.2.2  mycroft 			struct ioc_patch *arg = (struct ioc_patch *) addr;
    718  1.18.2.2  mycroft 			struct cd_mode_data data;
    719  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    720       1.1      cgd 				break;
    721       1.1      cgd 			data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
    722       1.1      cgd 			data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
    723       1.1      cgd 			data.page.audio.port[2].channels = arg->patch[2];
    724       1.1      cgd 			data.page.audio.port[3].channels = arg->patch[3];
    725  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    726  1.18.2.2  mycroft 				break; /* eh? */
    727       1.1      cgd 		}
    728       1.1      cgd 		break;
    729       1.1      cgd 	case CDIOCGETVOL:
    730       1.1      cgd 		{
    731  1.18.2.2  mycroft 			struct ioc_vol *arg = (struct ioc_vol *) addr;
    732  1.18.2.2  mycroft 			struct cd_mode_data data;
    733  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    734       1.1      cgd 				break;
    735       1.1      cgd 			arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
    736       1.1      cgd 			arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
    737       1.1      cgd 			arg->vol[2] = data.page.audio.port[2].volume;
    738       1.1      cgd 			arg->vol[3] = data.page.audio.port[3].volume;
    739       1.1      cgd 		}
    740       1.1      cgd 		break;
    741       1.1      cgd 	case CDIOCSETVOL:
    742       1.1      cgd 		{
    743  1.18.2.2  mycroft 			struct ioc_vol *arg = (struct ioc_vol *) addr;
    744  1.18.2.2  mycroft 			struct cd_mode_data data;
    745  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    746       1.1      cgd 				break;
    747       1.1      cgd 			data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
    748       1.1      cgd 			data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
    749       1.1      cgd 			data.page.audio.port[2].volume = arg->vol[2];
    750       1.1      cgd 			data.page.audio.port[3].volume = arg->vol[3];
    751  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    752       1.1      cgd 				break;
    753       1.1      cgd 		}
    754       1.1      cgd 		break;
    755       1.1      cgd 	case CDIOCSETMONO:
    756       1.1      cgd 		{
    757  1.18.2.2  mycroft 			struct ioc_vol *arg = (struct ioc_vol *) addr;
    758  1.18.2.2  mycroft 			struct cd_mode_data data;
    759  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    760       1.1      cgd 				break;
    761  1.18.2.2  mycroft 			data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL | 4 | 8;
    762  1.18.2.2  mycroft 			data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL;
    763       1.1      cgd 			data.page.audio.port[2].channels = 0;
    764       1.1      cgd 			data.page.audio.port[3].channels = 0;
    765  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    766       1.1      cgd 				break;
    767       1.1      cgd 		}
    768       1.1      cgd 		break;
    769       1.1      cgd 	case CDIOCSETSTERIO:
    770       1.1      cgd 		{
    771  1.18.2.2  mycroft 			struct ioc_vol *arg = (struct ioc_vol *) addr;
    772  1.18.2.2  mycroft 			struct cd_mode_data data;
    773  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    774       1.1      cgd 				break;
    775       1.1      cgd 			data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
    776       1.1      cgd 			data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
    777       1.1      cgd 			data.page.audio.port[2].channels = 0;
    778       1.1      cgd 			data.page.audio.port[3].channels = 0;
    779  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    780       1.1      cgd 				break;
    781       1.1      cgd 		}
    782       1.1      cgd 		break;
    783       1.1      cgd 	case CDIOCSETMUTE:
    784       1.1      cgd 		{
    785  1.18.2.2  mycroft 			struct ioc_vol *arg = (struct ioc_vol *) addr;
    786  1.18.2.2  mycroft 			struct cd_mode_data data;
    787  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    788       1.1      cgd 				break;
    789       1.1      cgd 			data.page.audio.port[LEFT_PORT].channels = 0;
    790       1.1      cgd 			data.page.audio.port[RIGHT_PORT].channels = 0;
    791       1.1      cgd 			data.page.audio.port[2].channels = 0;
    792       1.1      cgd 			data.page.audio.port[3].channels = 0;
    793  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    794       1.1      cgd 				break;
    795       1.1      cgd 		}
    796       1.1      cgd 		break;
    797       1.1      cgd 	case CDIOCSETLEFT:
    798       1.1      cgd 		{
    799  1.18.2.2  mycroft 			struct ioc_vol *arg = (struct ioc_vol *) addr;
    800  1.18.2.2  mycroft 			struct cd_mode_data data;
    801  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    802  1.18.2.2  mycroft 				break;
    803  1.18.2.2  mycroft 			data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
    804  1.18.2.2  mycroft 			data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
    805  1.18.2.2  mycroft 			data.page.audio.port[2].channels = 0;
    806  1.18.2.2  mycroft 			data.page.audio.port[3].channels = 0;
    807  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    808       1.1      cgd 				break;
    809       1.1      cgd 		}
    810       1.1      cgd 		break;
    811       1.1      cgd 	case CDIOCSETRIGHT:
    812       1.1      cgd 		{
    813  1.18.2.2  mycroft 			struct ioc_vol *arg = (struct ioc_vol *) addr;
    814  1.18.2.2  mycroft 			struct cd_mode_data data;
    815  1.18.2.2  mycroft 			if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
    816       1.1      cgd 				break;
    817       1.1      cgd 			data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
    818       1.1      cgd 			data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
    819       1.1      cgd 			data.page.audio.port[2].channels = 0;
    820       1.1      cgd 			data.page.audio.port[3].channels = 0;
    821  1.18.2.2  mycroft 			if (error = cd_set_mode(unit, &data))
    822       1.1      cgd 				break;
    823       1.1      cgd 		}
    824       1.1      cgd 		break;
    825       1.1      cgd 	case CDIOCRESUME:
    826  1.18.2.2  mycroft 		error = cd_pause(unit, 1);
    827       1.1      cgd 		break;
    828       1.1      cgd 	case CDIOCPAUSE:
    829  1.18.2.2  mycroft 		error = cd_pause(unit, 0);
    830       1.1      cgd 		break;
    831       1.1      cgd 	case CDIOCSTART:
    832  1.18.2.2  mycroft 		error = scsi_start_unit(cd->sc_link, 0);
    833       1.1      cgd 		break;
    834       1.1      cgd 	case CDIOCSTOP:
    835  1.18.2.2  mycroft 		error = scsi_start_unit(cd->sc_link, 0);
    836       1.1      cgd 		break;
    837       1.1      cgd 	case CDIOCEJECT:
    838  1.18.2.2  mycroft 		error = scsi_start_unit(cd->sc_link, 0);
    839       1.1      cgd 		break;
    840       1.1      cgd 	case CDIOCSETDEBUG:
    841  1.18.2.2  mycroft 		cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2);
    842       1.1      cgd 		break;
    843       1.1      cgd 	case CDIOCCLRDEBUG:
    844  1.18.2.2  mycroft 		cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2);
    845       1.1      cgd 		break;
    846       1.1      cgd 	case CDIOCRESET:
    847  1.18.2.2  mycroft 		return (cd_reset(unit));
    848       1.1      cgd 		break;
    849       1.1      cgd 	default:
    850  1.18.2.2  mycroft 		if(part == RAW_PART)
    851  1.18.2.2  mycroft 			error = scsi_do_ioctl(cd->sc_link,cmd,addr,flag);
    852  1.18.2.2  mycroft 		else
    853  1.18.2.2  mycroft 			error = ENOTTY;
    854       1.1      cgd 		break;
    855       1.1      cgd 	}
    856       1.1      cgd 	return (error);
    857       1.1      cgd }
    858       1.1      cgd 
    859  1.18.2.2  mycroft /*
    860  1.18.2.2  mycroft  * Load the label information on the named device
    861  1.18.2.2  mycroft  * Actually fabricate a disklabel
    862  1.18.2.2  mycroft  *
    863  1.18.2.2  mycroft  * EVENTUALLY take information about different
    864  1.18.2.2  mycroft  * data tracks from the TOC and put it in the disklabel
    865  1.18.2.2  mycroft  */
    866  1.18.2.2  mycroft errval
    867  1.18.2.2  mycroft cdgetdisklabel(unit)
    868  1.18.2.2  mycroft 	u_int8  unit;
    869  1.18.2.2  mycroft {
    870  1.18.2.2  mycroft 	/*unsigned int n, m; */
    871  1.18.2.2  mycroft 	char   *errstring;
    872  1.18.2.2  mycroft 	struct cd_data *cd;
    873  1.18.2.2  mycroft 
    874  1.18.2.2  mycroft 	cd = cd_driver.cd_data[unit];
    875       1.1      cgd 
    876  1.18.2.2  mycroft 	bzero(&cd->disklabel, sizeof(struct disklabel));
    877  1.18.2.2  mycroft 	/*
    878  1.18.2.2  mycroft 	 * make partition 0 the whole disk
    879  1.18.2.2  mycroft 	 */
    880  1.18.2.2  mycroft 	strncpy(cd->disklabel.d_typename, "scsi cd_rom", 16);
    881  1.18.2.2  mycroft 	strncpy(cd->disklabel.d_packname, "ficticious", 16);
    882  1.18.2.2  mycroft 	cd->disklabel.d_secsize = cd->params.blksize;	/* as long as it's not 0 */
    883       1.1      cgd 	cd->disklabel.d_nsectors = 100;
    884       1.1      cgd 	cd->disklabel.d_ntracks = 1;
    885       1.1      cgd 	cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1;
    886       1.1      cgd 	cd->disklabel.d_secpercyl = 100;
    887       1.1      cgd 	cd->disklabel.d_secperunit = cd->params.disksize;
    888       1.1      cgd 	cd->disklabel.d_rpm = 300;
    889       1.1      cgd 	cd->disklabel.d_interleave = 1;
    890       1.1      cgd 	cd->disklabel.d_flags = D_REMOVABLE;
    891       1.1      cgd 
    892  1.18.2.2  mycroft 	/*
    893  1.18.2.2  mycroft 	 * remember that comparisons with the partition are done
    894  1.18.2.2  mycroft 	 * assuming the blocks are 512 bytes so fudge it.
    895  1.18.2.2  mycroft 	 */
    896       1.1      cgd 	cd->disklabel.d_npartitions = 1;
    897  1.18.2.2  mycroft 	cd->disklabel.d_partitions[0].p_offset = 0;
    898  1.18.2.2  mycroft 	cd->disklabel.d_partitions[0].p_size
    899  1.18.2.2  mycroft 	    = cd->params.disksize * (cd->params.blksize / 512);
    900  1.18.2.2  mycroft 	cd->disklabel.d_partitions[0].p_fstype = 9;
    901       1.1      cgd 
    902       1.1      cgd 	cd->disklabel.d_magic = DISKMAGIC;
    903       1.1      cgd 	cd->disklabel.d_magic2 = DISKMAGIC;
    904       1.1      cgd 	cd->disklabel.d_checksum = dkcksum(&(cd->disklabel));
    905       1.1      cgd 
    906  1.18.2.2  mycroft 	/*
    907  1.18.2.2  mycroft 	 * Signal to other users and routines that we now have a
    908  1.18.2.2  mycroft 	 * disklabel that represents the media (maybe)
    909  1.18.2.2  mycroft 	 */
    910  1.18.2.2  mycroft 	return (ESUCCESS);
    911       1.1      cgd }
    912       1.1      cgd 
    913  1.18.2.2  mycroft /*
    914  1.18.2.2  mycroft  * Find out from the device what it's capacity is
    915  1.18.2.2  mycroft  */
    916  1.18.2.2  mycroft u_int32
    917       1.1      cgd cd_size(unit, flags)
    918       1.1      cgd {
    919  1.18.2.2  mycroft 	struct scsi_read_cd_cap_data rdcap;
    920  1.18.2.2  mycroft 	struct scsi_read_cd_capacity scsi_cmd;
    921  1.18.2.2  mycroft 	u_int32 size;
    922  1.18.2.2  mycroft 	u_int32 blksize;
    923  1.18.2.2  mycroft 	struct cd_data *cd = cd_driver.cd_data[unit];
    924  1.18.2.2  mycroft 
    925  1.18.2.2  mycroft 	/*
    926  1.18.2.2  mycroft 	 * make up a scsi command and ask the scsi driver to do
    927  1.18.2.2  mycroft 	 * it for you.
    928  1.18.2.2  mycroft 	 */
    929  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
    930       1.1      cgd 	scsi_cmd.op_code = READ_CD_CAPACITY;
    931       1.1      cgd 
    932  1.18.2.2  mycroft 	/*
    933  1.18.2.2  mycroft 	 * If the command works, interpret the result as a 4 byte
    934  1.18.2.2  mycroft 	 * number of blocks and a blocksize
    935  1.18.2.2  mycroft 	 */
    936  1.18.2.2  mycroft 	if (scsi_scsi_cmd(cd->sc_link,
    937  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
    938  1.18.2.2  mycroft 		sizeof(scsi_cmd),
    939  1.18.2.2  mycroft 		(u_char *) & rdcap,
    940  1.18.2.2  mycroft 		sizeof(rdcap),
    941  1.18.2.2  mycroft 		CDRETRIES,
    942  1.18.2.2  mycroft 		20000,		/* might be a disk-changer */
    943  1.18.2.2  mycroft 		NULL,
    944  1.18.2.2  mycroft 		SCSI_DATA_IN | flags) != 0) {
    945  1.18.2.2  mycroft 		printf("cd%d: could not get size\n", unit);
    946  1.18.2.2  mycroft 		return (0);
    947       1.1      cgd 	} else {
    948  1.18.2.2  mycroft 		size = rdcap.addr_0 + 1;
    949       1.1      cgd 		size += rdcap.addr_1 << 8;
    950       1.1      cgd 		size += rdcap.addr_2 << 16;
    951       1.1      cgd 		size += rdcap.addr_3 << 24;
    952  1.18.2.2  mycroft 		blksize = rdcap.length_0;
    953       1.1      cgd 		blksize += rdcap.length_1 << 8;
    954       1.1      cgd 		blksize += rdcap.length_2 << 16;
    955       1.1      cgd 		blksize += rdcap.length_3 << 24;
    956       1.1      cgd 	}
    957  1.18.2.2  mycroft 	if (blksize < 512)
    958  1.18.2.2  mycroft 		blksize = 2048;	/* some drives lie ! */
    959  1.18.2.2  mycroft 	if (size < 100)
    960  1.18.2.2  mycroft 		size = 400000;	/* ditto */
    961  1.18.2.2  mycroft 	SC_DEBUG(cd->sc_link, SDEV_DB3, ("cd%d: %d %d byte blocks\n"
    962  1.18.2.2  mycroft 		,unit, size, blksize));
    963  1.18.2.2  mycroft 	cd->params.disksize = size;
    964  1.18.2.2  mycroft 	cd->params.blksize = blksize;
    965  1.18.2.2  mycroft 	return (size);
    966  1.18.2.2  mycroft }
    967  1.18.2.2  mycroft 
    968  1.18.2.2  mycroft /*
    969  1.18.2.2  mycroft  * Get the requested page into the buffer given
    970  1.18.2.2  mycroft  */
    971  1.18.2.2  mycroft errval
    972  1.18.2.2  mycroft cd_get_mode(unit, data, page)
    973  1.18.2.2  mycroft 	u_int32 unit;
    974  1.18.2.2  mycroft 	struct cd_mode_data *data;
    975  1.18.2.2  mycroft 	u_int32 page;
    976       1.1      cgd {
    977       1.1      cgd 	struct scsi_mode_sense scsi_cmd;
    978  1.18.2.2  mycroft 	errval  retval;
    979       1.1      cgd 
    980  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
    981  1.18.2.2  mycroft 	bzero(data, sizeof(*data));
    982       1.1      cgd 	scsi_cmd.op_code = MODE_SENSE;
    983  1.18.2.2  mycroft 	scsi_cmd.page = page;
    984       1.1      cgd 	scsi_cmd.length = sizeof(*data) & 0xff;
    985  1.18.2.2  mycroft 	retval = scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
    986  1.18.2.2  mycroft 	    (struct scsi_generic *) &scsi_cmd,
    987  1.18.2.2  mycroft 	    sizeof(scsi_cmd),
    988  1.18.2.2  mycroft 	    (u_char *) data,
    989  1.18.2.2  mycroft 	    sizeof(*data),
    990  1.18.2.2  mycroft 	    CDRETRIES,
    991  1.18.2.2  mycroft 	    20000,		/* should be immed */
    992  1.18.2.2  mycroft 	    NULL,
    993  1.18.2.2  mycroft 	    SCSI_DATA_IN);
    994       1.1      cgd 	return (retval);
    995       1.1      cgd }
    996  1.18.2.2  mycroft 
    997  1.18.2.2  mycroft /*
    998  1.18.2.2  mycroft  * Get the requested page into the buffer given
    999  1.18.2.2  mycroft  */
   1000  1.18.2.2  mycroft errval
   1001  1.18.2.2  mycroft cd_set_mode(unit, data)
   1002  1.18.2.2  mycroft 	u_int32 unit;
   1003  1.18.2.2  mycroft 	struct cd_mode_data *data;
   1004       1.1      cgd {
   1005       1.1      cgd 	struct scsi_mode_select scsi_cmd;
   1006       1.1      cgd 
   1007  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1008       1.1      cgd 	scsi_cmd.op_code = MODE_SELECT;
   1009  1.18.2.2  mycroft 	scsi_cmd.byte2 |= SMS_PF;
   1010       1.1      cgd 	scsi_cmd.length = sizeof(*data) & 0xff;
   1011       1.1      cgd 	data->header.data_length = 0;
   1012  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1013  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1014  1.18.2.2  mycroft 		sizeof(scsi_cmd),
   1015  1.18.2.2  mycroft 		(u_char *) data,
   1016  1.18.2.2  mycroft 		sizeof(*data),
   1017  1.18.2.2  mycroft 		CDRETRIES,
   1018  1.18.2.2  mycroft 		20000,		/* should be immed */
   1019  1.18.2.2  mycroft 		NULL,
   1020  1.18.2.2  mycroft 		SCSI_DATA_OUT));
   1021  1.18.2.2  mycroft }
   1022  1.18.2.2  mycroft 
   1023  1.18.2.2  mycroft /*
   1024  1.18.2.2  mycroft  * Get scsi driver to send a "start playing" command
   1025  1.18.2.2  mycroft  */
   1026  1.18.2.2  mycroft errval
   1027  1.18.2.2  mycroft cd_play(unit, blk, len)
   1028  1.18.2.2  mycroft 	u_int32 unit, blk, len;
   1029       1.1      cgd {
   1030       1.1      cgd 	struct scsi_play scsi_cmd;
   1031  1.18.2.2  mycroft 	errval  retval;
   1032       1.1      cgd 
   1033  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1034       1.1      cgd 	scsi_cmd.op_code = PLAY;
   1035       1.1      cgd 	scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
   1036       1.1      cgd 	scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
   1037       1.1      cgd 	scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
   1038       1.1      cgd 	scsi_cmd.blk_addr[3] = blk & 0xff;
   1039       1.1      cgd 	scsi_cmd.xfer_len[0] = (len >> 8) & 0xff;
   1040       1.1      cgd 	scsi_cmd.xfer_len[1] = len & 0xff;
   1041  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1042  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1043  1.18.2.2  mycroft 		sizeof(scsi_cmd),
   1044  1.18.2.2  mycroft 		0,
   1045  1.18.2.2  mycroft 		0,
   1046  1.18.2.2  mycroft 		CDRETRIES,
   1047  1.18.2.2  mycroft 		200000,		/* should be immed */
   1048  1.18.2.2  mycroft 		NULL,
   1049  1.18.2.2  mycroft 		0));
   1050  1.18.2.2  mycroft }
   1051  1.18.2.2  mycroft 
   1052  1.18.2.2  mycroft /*
   1053  1.18.2.2  mycroft  * Get scsi driver to send a "start playing" command
   1054  1.18.2.2  mycroft  */
   1055  1.18.2.2  mycroft errval
   1056  1.18.2.2  mycroft cd_play_big(unit, blk, len)
   1057  1.18.2.2  mycroft 	u_int32 unit, blk, len;
   1058       1.1      cgd {
   1059       1.1      cgd 	struct scsi_play_big scsi_cmd;
   1060  1.18.2.2  mycroft 	errval  retval;
   1061       1.1      cgd 
   1062  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1063       1.1      cgd 	scsi_cmd.op_code = PLAY_BIG;
   1064       1.1      cgd 	scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
   1065       1.1      cgd 	scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
   1066       1.1      cgd 	scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
   1067       1.1      cgd 	scsi_cmd.blk_addr[3] = blk & 0xff;
   1068       1.1      cgd 	scsi_cmd.xfer_len[0] = (len >> 24) & 0xff;
   1069       1.1      cgd 	scsi_cmd.xfer_len[1] = (len >> 16) & 0xff;
   1070       1.1      cgd 	scsi_cmd.xfer_len[2] = (len >> 8) & 0xff;
   1071       1.1      cgd 	scsi_cmd.xfer_len[3] = len & 0xff;
   1072  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1073  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1074  1.18.2.2  mycroft 		sizeof(scsi_cmd),
   1075  1.18.2.2  mycroft 		0,
   1076  1.18.2.2  mycroft 		0,
   1077  1.18.2.2  mycroft 		CDRETRIES,
   1078  1.18.2.2  mycroft 		20000,		/* should be immed */
   1079  1.18.2.2  mycroft 		NULL,
   1080  1.18.2.2  mycroft 		0));
   1081  1.18.2.2  mycroft }
   1082  1.18.2.2  mycroft 
   1083  1.18.2.2  mycroft /*
   1084  1.18.2.2  mycroft  * Get scsi driver to send a "start playing" command
   1085  1.18.2.2  mycroft  */
   1086  1.18.2.2  mycroft errval
   1087  1.18.2.2  mycroft cd_play_tracks(unit, strack, sindex, etrack, eindex)
   1088  1.18.2.2  mycroft 	u_int32 unit, strack, sindex, etrack, eindex;
   1089       1.1      cgd {
   1090       1.1      cgd 	struct scsi_play_track scsi_cmd;
   1091  1.18.2.2  mycroft 	errval  retval;
   1092       1.1      cgd 
   1093  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1094       1.1      cgd 	scsi_cmd.op_code = PLAY_TRACK;
   1095       1.1      cgd 	scsi_cmd.start_track = strack;
   1096       1.1      cgd 	scsi_cmd.start_index = sindex;
   1097       1.1      cgd 	scsi_cmd.end_track = etrack;
   1098       1.1      cgd 	scsi_cmd.end_index = eindex;
   1099  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1100  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1101  1.18.2.2  mycroft 		sizeof(scsi_cmd),
   1102  1.18.2.2  mycroft 		0,
   1103  1.18.2.2  mycroft 		0,
   1104  1.18.2.2  mycroft 		CDRETRIES,
   1105  1.18.2.2  mycroft 		20000,		/* should be immed */
   1106  1.18.2.2  mycroft 		NULL,
   1107  1.18.2.2  mycroft 		0));
   1108  1.18.2.2  mycroft }
   1109  1.18.2.2  mycroft 
   1110  1.18.2.2  mycroft /*
   1111  1.18.2.2  mycroft  * Get scsi driver to send a "play msf" command
   1112  1.18.2.2  mycroft  */
   1113  1.18.2.2  mycroft errval
   1114  1.18.2.2  mycroft cd_play_msf(unit, startm, starts, startf, endm, ends, endf)
   1115  1.18.2.2  mycroft 	u_int32 unit, startm, starts, startf, endm, ends, endf;
   1116      1.17   brezak {
   1117      1.17   brezak 	struct scsi_play_msf scsi_cmd;
   1118      1.17   brezak 
   1119  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1120      1.17   brezak 	scsi_cmd.op_code = PLAY_MSF;
   1121  1.18.2.2  mycroft 	scsi_cmd.start_m = startm;
   1122  1.18.2.2  mycroft 	scsi_cmd.start_s = starts;
   1123  1.18.2.2  mycroft 	scsi_cmd.start_f = startf;
   1124  1.18.2.2  mycroft 	scsi_cmd.end_m = endm;
   1125  1.18.2.2  mycroft 	scsi_cmd.end_s = ends;
   1126  1.18.2.2  mycroft 	scsi_cmd.end_f = endf;
   1127  1.18.2.2  mycroft 
   1128  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1129  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1130  1.18.2.2  mycroft 		sizeof(scsi_cmd),
   1131  1.18.2.2  mycroft 		0,
   1132  1.18.2.2  mycroft 		0,
   1133  1.18.2.2  mycroft 		CDRETRIES,
   1134  1.18.2.2  mycroft 		2000,
   1135  1.18.2.2  mycroft 		NULL,
   1136  1.18.2.2  mycroft 		0));
   1137  1.18.2.2  mycroft }
   1138  1.18.2.2  mycroft 
   1139  1.18.2.2  mycroft /*
   1140  1.18.2.2  mycroft  * Get scsi driver to send a "start up" command
   1141  1.18.2.2  mycroft  */
   1142  1.18.2.2  mycroft errval
   1143  1.18.2.2  mycroft cd_pause(unit, go)
   1144  1.18.2.2  mycroft 	u_int32 unit, go;
   1145       1.1      cgd {
   1146       1.1      cgd 	struct scsi_pause scsi_cmd;
   1147       1.1      cgd 
   1148  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1149       1.1      cgd 	scsi_cmd.op_code = PAUSE;
   1150       1.1      cgd 	scsi_cmd.resume = go;
   1151       1.1      cgd 
   1152  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1153  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1154  1.18.2.2  mycroft 		sizeof(scsi_cmd),
   1155  1.18.2.2  mycroft 		0,
   1156  1.18.2.2  mycroft 		0,
   1157  1.18.2.2  mycroft 		CDRETRIES,
   1158  1.18.2.2  mycroft 		2000,
   1159  1.18.2.2  mycroft 		NULL,
   1160  1.18.2.2  mycroft 		0));
   1161  1.18.2.2  mycroft }
   1162  1.18.2.2  mycroft 
   1163  1.18.2.2  mycroft /*
   1164  1.18.2.2  mycroft  * Get scsi driver to send a "RESET" command
   1165  1.18.2.2  mycroft  */
   1166  1.18.2.2  mycroft errval
   1167       1.1      cgd cd_reset(unit)
   1168  1.18.2.2  mycroft 	u_int32 unit;
   1169       1.1      cgd {
   1170  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1171  1.18.2.2  mycroft 		0,
   1172  1.18.2.2  mycroft 		0,
   1173  1.18.2.2  mycroft 		0,
   1174  1.18.2.2  mycroft 		0,
   1175  1.18.2.2  mycroft 		CDRETRIES,
   1176  1.18.2.2  mycroft 		2000,
   1177  1.18.2.2  mycroft 		NULL,
   1178  1.18.2.2  mycroft 		SCSI_RESET));
   1179       1.1      cgd }
   1180  1.18.2.2  mycroft 
   1181  1.18.2.2  mycroft /*
   1182  1.18.2.2  mycroft  * Read subchannel
   1183  1.18.2.2  mycroft  */
   1184  1.18.2.2  mycroft errval
   1185  1.18.2.2  mycroft cd_read_subchannel(unit, mode, format, track, data, len)
   1186  1.18.2.2  mycroft 	u_int32 unit, mode, format, len;
   1187  1.18.2.2  mycroft 	struct cd_sub_channel_info *data;
   1188       1.1      cgd {
   1189       1.1      cgd 	struct scsi_read_subchannel scsi_cmd;
   1190  1.18.2.2  mycroft 	errval  error;
   1191       1.1      cgd 
   1192  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1193       1.1      cgd 
   1194  1.18.2.2  mycroft 	scsi_cmd.op_code = READ_SUBCHANNEL;
   1195  1.18.2.2  mycroft 	if (mode == CD_MSF_FORMAT)
   1196  1.18.2.2  mycroft 		scsi_cmd.byte2 |= CD_MSF;
   1197  1.18.2.2  mycroft 	scsi_cmd.byte3 = SRS_SUBQ;
   1198  1.18.2.2  mycroft 	scsi_cmd.subchan_format = format;
   1199  1.18.2.2  mycroft 	scsi_cmd.track = track;
   1200  1.18.2.2  mycroft 	scsi_cmd.data_len[0] = (len) >> 8;
   1201  1.18.2.2  mycroft 	scsi_cmd.data_len[1] = (len) & 0xff;
   1202  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1203  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1204  1.18.2.2  mycroft 		sizeof(struct scsi_read_subchannel),
   1205  1.18.2.2  mycroft 		        (u_char *) data,
   1206       1.1      cgd 		len,
   1207  1.18.2.2  mycroft 		CDRETRIES,
   1208       1.1      cgd 		5000,
   1209  1.18.2.2  mycroft 		NULL,
   1210  1.18.2.2  mycroft 		SCSI_DATA_IN));
   1211       1.1      cgd }
   1212       1.1      cgd 
   1213  1.18.2.2  mycroft /*
   1214  1.18.2.2  mycroft  * Read table of contents
   1215  1.18.2.2  mycroft  */
   1216  1.18.2.2  mycroft errval
   1217  1.18.2.2  mycroft cd_read_toc(unit, mode, start, data, len)
   1218  1.18.2.2  mycroft 	u_int32 unit, mode, start, len;
   1219  1.18.2.2  mycroft 	struct cd_toc_entry *data;
   1220       1.1      cgd {
   1221       1.1      cgd 	struct scsi_read_toc scsi_cmd;
   1222  1.18.2.2  mycroft 	errval  error;
   1223  1.18.2.2  mycroft 	u_int32 ntoc;
   1224  1.18.2.2  mycroft 
   1225  1.18.2.2  mycroft 	bzero(&scsi_cmd, sizeof(scsi_cmd));
   1226       1.1      cgd 	/*if(len!=sizeof(struct ioc_toc_header))
   1227  1.18.2.2  mycroft 	 * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
   1228  1.18.2.2  mycroft 	 * else */
   1229  1.18.2.2  mycroft 	ntoc = len;
   1230  1.18.2.2  mycroft 
   1231  1.18.2.2  mycroft 	scsi_cmd.op_code = READ_TOC;
   1232  1.18.2.2  mycroft 	if (mode == CD_MSF_FORMAT)
   1233  1.18.2.2  mycroft 		scsi_cmd.byte2 |= CD_MSF;
   1234  1.18.2.2  mycroft 	scsi_cmd.from_track = start;
   1235  1.18.2.2  mycroft 	scsi_cmd.data_len[0] = (ntoc) >> 8;
   1236  1.18.2.2  mycroft 	scsi_cmd.data_len[1] = (ntoc) & 0xff;
   1237  1.18.2.2  mycroft 	return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
   1238  1.18.2.2  mycroft 		(struct scsi_generic *) &scsi_cmd,
   1239  1.18.2.2  mycroft 		sizeof(struct scsi_read_toc),
   1240  1.18.2.2  mycroft 		        (u_char *) data,
   1241  1.18.2.2  mycroft 		len,
   1242  1.18.2.2  mycroft 		CDRETRIES,
   1243  1.18.2.2  mycroft 		5000,
   1244  1.18.2.2  mycroft 		NULL,
   1245  1.18.2.2  mycroft 		SCSI_DATA_IN));
   1246       1.1      cgd }
   1247       1.1      cgd 
   1248       1.1      cgd #define b2tol(a)	(((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
   1249       1.1      cgd 
   1250  1.18.2.2  mycroft /*
   1251  1.18.2.2  mycroft  * Get the scsi driver to send a full inquiry to the device and use the
   1252  1.18.2.2  mycroft  * results to fill out the disk parameter structure.
   1253  1.18.2.2  mycroft  */
   1254  1.18.2.2  mycroft errval
   1255  1.18.2.2  mycroft cd_get_parms(unit, flags)
   1256       1.1      cgd {
   1257  1.18.2.2  mycroft 	struct cd_data *cd = cd_driver.cd_data[unit];
   1258       1.1      cgd 
   1259  1.18.2.2  mycroft 	/*
   1260  1.18.2.2  mycroft 	 * First check if we have it all loaded
   1261  1.18.2.2  mycroft 	 */
   1262  1.18.2.2  mycroft 	if (cd->sc_link->flags & SDEV_MEDIA_LOADED)
   1263  1.18.2.2  mycroft 		return (0);
   1264  1.18.2.2  mycroft 	/*
   1265  1.18.2.2  mycroft 	 * give a number of sectors so that sec * trks * cyls
   1266  1.18.2.2  mycroft 	 * is <= disk_size
   1267  1.18.2.2  mycroft 	 */
   1268  1.18.2.2  mycroft 	if (cd_size(unit, flags)) {
   1269  1.18.2.2  mycroft 		cd->sc_link->flags |= SDEV_MEDIA_LOADED;
   1270  1.18.2.2  mycroft 		return (0);
   1271  1.18.2.2  mycroft 	} else {
   1272  1.18.2.2  mycroft 		return (ENXIO);
   1273       1.1      cgd 	}
   1274       1.1      cgd }
   1275       1.1      cgd 
   1276       1.1      cgd int
   1277       1.1      cgd cdsize(dev_t dev)
   1278       1.1      cgd {
   1279       1.1      cgd 	return (-1);
   1280       1.1      cgd }
   1281