diff -c -r -N --exclude exp --exclude compile sys/atapi.orig/acd.c sys/atapi/acd.c
*** sys/atapi.orig/acd.c	Thu Jan  1 01:00:00 1970
--- sys/atapi/acd.c	Thu Jun 13 03:19:49 1996
***************
*** 0 ****
--- 1,1294 ----
+ /*
+  * Copyright (c) 1996 Manuel Bouyer.  All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *  This product includes software developed by Manuel Bouyer.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ 
+ #include <sys/types.h>
+ #include <sys/param.h>
+ #include <sys/systm.h>
+ #include <sys/kernel.h>
+ #include <sys/conf.h>
+ #include <sys/file.h>
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <sys/buf.h>
+ #include <sys/uio.h>
+ #include <sys/malloc.h>
+ #include <sys/errno.h>
+ #include <sys/device.h>
+ #include <sys/disklabel.h>
+ #include <sys/disk.h>
+ #include <sys/cdio.h>
+ #include <sys/proc.h>  
+ 
+ #include <atapi/atapilink.h>
+ #include <atapi/atapi.h>
+ 
+ #define	CDUNIT(z)			DISKUNIT(z)
+ #define	CDPART(z)			DISKPART(z)
+ #define	MAKECDDEV(maj, unit, part)	MAKEDISKDEV(maj, unit, part)
+ 
+ struct acd_softc {
+ 	struct device sc_dev;
+ 	struct disk sc_dk;
+ 
+ 	int flags;
+ #define	CDF_LOCKED	0x01
+ #define	CDF_WANTED	0x02
+ #define	CDF_WLABEL	0x04		/* label is writable */
+ #define	CDF_LABELLING	0x08		/* writing label */
+ 	struct at_dev_link *ad_link;	/* contains our drive number, etc ... */
+ 	struct cd_parms {
+ 		int blksize;
+ 		u_long disksize;	/* total number sectors */
+ 	} params;
+ 	struct buf buf_queue;
+ };
+ 
+ int acdmatch __P((struct device *, void *, void *));
+ void acdattach __P((struct device *, struct device *, void *));
+ 
+ struct cfattach acd_ca = {
+ 	sizeof(struct acd_softc), acdmatch, acdattach
+ };
+ 
+ struct cfdriver acd_cd = {
+ 	NULL, "acd", DV_DISK
+ };
+ 
+ void acdgetdisklabel __P((struct acd_softc *));
+ int acd_get_parms __P((struct acd_softc *, int));
+ void acdstrategy __P((struct buf *));
+ void acdstart __P((struct acd_softc *));
+ int acd_pause __P((struct acd_softc *, int));
+ void    acdminphys __P((struct buf*));
+ u_long acd_size __P((struct acd_softc*, int));
+ int acddone __P((struct atapi_command_packet *));
+ int acd_reset __P((struct acd_softc *acd));
+ 
+ struct dkdriver acddkdriver = { acdstrategy };
+ 
+ int
+ acdmatch(parent, match, aux)
+ 	struct device *parent;
+ 	void *match, *aux;
+ {
+ /*	struct cfdata *cf = match;*/
+ 	struct at_dev_link *sa = aux;
+ #ifdef ATAPI_DEBUG_PROBE
+ 	printf("acdmatch: device %d\n",sa->id.config.device_type);
+ #endif
+ 	if (sa->id.config.device_type == ATAPI_DEVICE_TYPE_CD) return 1;
+ 	return 0;
+ 	
+ }
+ 
+ /*
+  * The routine called by the low level atapi routine when it discovers
+  * A device suitable for this driver
+  */
+ void
+ acdattach(parent, self, aux)
+ 	struct device *parent, *self;
+ 	void *aux;
+ {
+ 	struct acd_softc *acd = (void *)self;
+ 	struct at_dev_link *sa = aux;
+ 	struct mode_sense cmd;
+ 	struct cappage cap;
+ 
+ 	sa->device_softc = acd;
+ 	sa->start = acdstart;
+ 	sa->done = acddone;
+ 	sa->flags |= ADEV_REMOVABLE;
+ 	sa->openings = 1;
+ 	acd->ad_link = sa;
+ 
+     /*
+      * Initialize and attach the disk structure.
+      */
+     acd->sc_dk.dk_driver = &acddkdriver;
+     acd->sc_dk.dk_name = acd->sc_dev.dv_xname;
+     disk_attach(&acd->sc_dk);
+ 
+ #if !defined(i386) || defined(NEWCONFIG)
+     dk_establish(&acd->sc_dk, &acd->sc_dev);   
+ #endif
+ 
+ 	(void)atapi_test_unit_ready(sa, A_POLLED | A_SILENT); 
+ 	delay(1000);
+ 	(void)atapi_test_unit_ready(sa, A_POLLED | A_SILENT);
+ 										/* To clear media change, etc ...*/
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.operation_code = ATAPI_MODE_SENSE;
+ 	cmd.page_code = CAP_PAGE;
+ 	cmd.length[0] = sizeof (cap) >> 8;
+ 	cmd.length[1] = sizeof (cap);
+ 	if (atapi_exec_cmd(sa, &cmd , sizeof(cmd), &cap, sizeof(cap),
+ 	    B_READ, A_POLLED) != 0) {
+ 		printf("atapi_exec_cmd failed\n");
+ 		return;
+ 	}
+ 	switch (cap.medium_type) {
+ 		case MDT_UNKNOWN:   printf ("medium type unknown");
+ 							break;
+ 		case MDT_DATA_120:  printf ("120mm data disc ");
+ 							break;
+ 		case MDT_AUDIO_120: printf ("120mm audio disc ");
+ 							break;
+ 		case MDT_COMB_120:  printf ("120mm data/audio disc ");
+ 							break;
+ 		case MDT_PHOTO_120: printf ("120mm photo disc ");
+ 							break;
+ 		case MDT_DATA_80:   printf ("80mm data disc ");
+ 							break;
+ 		case MDT_AUDIO_80:  printf ("80mm audio disc ");
+ 							break;
+ 		case MDT_COMB_80:   printf ("80mm data/audio disc ");
+ 							break;
+ 		case MDT_PHOTO_80:  printf ("80mm photo disc ");
+ 							break;
+ 		case MDT_NO_DISC:   printf ("drive empty ");
+ 							break;
+ 		case MDT_DOOR_OPEN: printf ("door open");
+ 							break;
+ 		case MDT_FMT_ERROR: printf ("medium format error");
+ 							break;
+ 		default:    printf ("unknown medium type=0x%x", cap.medium_type);
+ 					break;
+ 	}
+ 	printf("\n");
+ 
+ }
+ 
+ /*
+  * Wait interruptibly for an exclusive lock.
+  *
+  * XXX
+  * Several drivers do this; it should be abstracted and made MP-safe.
+  */
+ int
+ acdlock(acd)
+ 	struct acd_softc *acd;
+ {
+ 	int error;
+ 
+ 	while ((acd->flags & CDF_LOCKED) != 0) {
+ 		acd->flags |= CDF_WANTED;
+ 		if ((error = tsleep(acd, PRIBIO | PCATCH, "acdlck", 0)) != 0)
+ 			return error;
+ 	}
+ 	acd->flags |= CDF_LOCKED;
+ 	return 0;
+ }
+ 
+ /*
+  * Unlock and wake up any waiters.
+  */
+ void
+ acdunlock(acd)
+ 	struct acd_softc *acd;
+ {
+ 
+ 	acd->flags &= ~CDF_LOCKED;
+ 	if ((acd->flags & CDF_WANTED) != 0) {
+ 		acd->flags &= ~CDF_WANTED;
+ 		wakeup(acd);
+ 	}
+ }
+ 
+ /*
+  * open the device. Make sure the partition info is a up-to-date as can be.
+  */
+ int
+ acdopen(dev, flag, fmt)
+ 	dev_t dev;
+ 	int flag, fmt;
+ {
+ 	struct acd_softc *acd;
+ 	struct at_dev_link *ad_link;
+ 	int unit, part;
+ 	int error;
+ 
+ #ifdef ACD_DEBUG
+ 	printf("acd: open\n");
+ #endif
+ 
+ 	unit = CDUNIT(dev);
+ 	if (unit >= acd_cd.cd_ndevs)
+ 		return ENXIO;
+ 	acd = acd_cd.cd_devs[unit];
+ 	if (!acd)
+ 		return ENXIO;
+ 
+ 	ad_link = acd->ad_link;
+ 
+ 	if ((error = atapi_test_unit_ready(ad_link,0)) != 0) {
+ 		if (error != UNIT_ATTENTION) return EIO;
+ 		if ((ad_link->flags & ADEV_OPEN) != 0 ) return EIO;
+ 	}
+ 
+ 	if ((error = acdlock(acd)))
+ 		return error;
+ 
+ 	if (acd->sc_dk.dk_openmask != 0) {
+ 		/*
+ 		 * If any partition is open, but the disk has been invalidated,
+ 		 * disallow further opens.
+ 		 */
+ 		if ((ad_link->flags & ADEV_MEDIA_LOADED) == 0) {
+ 			error = EIO;
+ 			goto bad3;
+ 		}
+ 	} else {
+ 		ad_link->flags |= ADEV_OPEN;
+ 
+ 		/* Lock the pack in. */
+ 		if ((error = atapi_prevent(ad_link, PR_PREVENT)))
+ 			goto bad;
+ 
+ 		if ((ad_link->flags & ADEV_MEDIA_LOADED) == 0) {
+ 			ad_link->flags |= ADEV_MEDIA_LOADED;
+ 
+ 			/* Load the physical device parameters. */
+ 			if (acd_get_parms(acd, 0) != 0) {
+ 				error = ENXIO;
+ 				goto bad2;
+ 			}
+ 
+ 			/* Fabricate a disk label. */
+ 			acdgetdisklabel(acd);
+ 		}
+ 	}
+ 
+ 	part = CDPART(dev);
+ 
+ 	/* Check that the partition exists. */
+ 	if (part != RAW_PART &&
+ 	    (part >= acd->sc_dk.dk_label->d_npartitions ||
+ 	     acd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
+ 		error = ENXIO;
+ 		goto bad;
+ 	}
+ 
+ 	/* Insure only one open at a time. */
+ 	switch (fmt) {
+ 	case S_IFCHR:
+ 		acd->sc_dk.dk_copenmask |= (1 << part);
+ 		break;
+ 	case S_IFBLK:
+ 		acd->sc_dk.dk_bopenmask |= (1 << part);
+ 		break;
+ 	}
+ 	acd->sc_dk.dk_openmask = acd->sc_dk.dk_copenmask | acd->sc_dk.dk_bopenmask;
+ #ifdef ACD_DEBUG
+ 	printf("open complete\n");
+ #endif
+ 	acdunlock(acd);
+ 	return 0;
+ 
+ bad2:
+ 	ad_link->flags &= ~ADEV_MEDIA_LOADED;
+ 
+ bad:
+ 	if (acd->sc_dk.dk_openmask == 0) {
+ 		atapi_prevent(ad_link, PR_ALLOW);
+ 		ad_link->flags &= ~ADEV_OPEN;
+ 	}
+ 
+ bad3:
+ 	acdunlock(acd);
+ 	return error;
+ }
+ 
+ /*
+  * close the device.. only called if we are the LAST
+  * occurence of an open device
+  */
+ int
+ acdclose(dev, flag, fmt)
+ 	dev_t dev;
+ 	int flag, fmt;
+ {
+ 	struct acd_softc *acd = acd_cd.cd_devs[CDUNIT(dev)];
+ 	int part = CDPART(dev);
+ 	int error;
+ 
+ 	if ((error = acdlock(acd)))
+ 		return error;
+ 
+ 	switch (fmt) {
+ 	case S_IFCHR:
+ 		acd->sc_dk.dk_copenmask &= ~(1 << part);
+ 		break;
+ 	case S_IFBLK:
+ 		acd->sc_dk.dk_bopenmask &= ~(1 << part);
+ 		break;
+ 	}
+ 	acd->sc_dk.dk_openmask = acd->sc_dk.dk_copenmask | acd->sc_dk.dk_bopenmask;
+ 
+ 	if (acd->sc_dk.dk_openmask == 0) {
+ 		/* XXXX Must wait for I/O to complete! */
+ 
+ 		atapi_prevent(acd->ad_link, PR_ALLOW);
+ 		acd->ad_link->flags &= ~ADEV_OPEN;
+ 	}
+ 
+ 	acdunlock(acd);
+ 	return 0;
+ }
+ 
+ /*
+  * Actually translate the requested transfer into one the physical driver can
+  * understand.  The transfer is described by a buf and will include only one
+  * physical transfer.
+  */
+ void
+ acdstrategy(bp)
+ 	struct buf *bp;
+ {
+ 	struct acd_softc *acd = acd_cd.cd_devs[CDUNIT(bp->b_dev)];
+ 	int opri;
+ 
+ #ifdef ACD_DEBUG
+ 	printf("acdstrategy\n");
+ #endif
+ 
+ 	/*
+ 	 * The transfer must be a whole number of blocks.
+ 	 */
+ 	if ((bp->b_bcount % acd->sc_dk.dk_label->d_secsize) != 0) {
+ 		bp->b_error = EINVAL;
+ 		goto bad;
+ 	}
+ 	if ((bp->b_flags & (B_READ|B_WRITE)) == B_WRITE) {
+ 		bp->b_error = EROFS;
+ 		goto bad;
+ 	}
+ 	/*
+ 	 * If the device has been made invalid, error out
+ 	 * maybe the media changed
+ 	 */
+ 	if ((acd->ad_link->flags & ADEV_MEDIA_LOADED) == 0) {
+ 		bp->b_error = EIO;
+ 		goto bad;
+ 	}
+ 	/*
+ 	 * If it's a null transfer, return immediately
+ 	 */
+ 	if (bp->b_bcount == 0)
+ 		goto done;
+ 
+ 	/*
+ 	 * Do bounds checking, adjust transfer. if error, process.
+ 	 * If end of partition, just return.
+ 	 */
+ 	if (CDPART(bp->b_dev) != RAW_PART &&
+ 	    bounds_check_with_label(bp, acd->sc_dk.dk_label,
+ 	    (acd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0)
+ 		goto done;
+ 
+ 	opri = splbio();
+ 
+ 	/*
+ 	 * Place it in the queue of disk activities for this disk
+ 	 */
+ 	disksort(&acd->buf_queue, bp);
+ 
+ 	/*
+ 	 * Tell the device to get going on the transfer if it's
+ 	 * not doing anything, otherwise just wait for completion
+ 	 */
+ 	acdstart(acd);
+ 
+ 	splx(opri);
+ 	return;
+ 
+ bad:
+ 	bp->b_flags |= B_ERROR;
+ done:
+ 	/*
+ 	 * Correctly set the buf to indicate a completed xfer
+ 	 */
+ 	bp->b_resid = bp->b_bcount;
+ 	biodone(bp);
+ }
+ 
+ /*
+  * acdstart looks to see if there is a buf waiting for the device
+  * and that the device is not already busy. If both are true,
+  * It deques the buf and creates a atapi command to perform the
+  * transfer in the buf. The transfer request will call atapi_done
+  * on completion, which will in turn call this routine again
+  * so that the next queued transfer is performed.
+  * The bufs are queued by the strategy routine (cdstrategy)
+  *
+  * This routine is also called after other non-queued requests
+  * have been made of the atapi driver, to ensure that the queue
+  * continues to be drained.
+  *
+  * must be called at the correct (highish) spl level
+  * cdstart() is called at splbio from cdstrategy and atapi_done
+  */
+ void
+ acdstart(acd)
+ 	struct acd_softc *acd;
+ {
+ 	struct at_dev_link *ad_link;
+ 	struct buf *bp = 0;
+ 	struct buf *dp;
+ 	struct read cmd;
+ 	u_int32_t blkno, nblks;
+ 	struct partition *p;
+ 
+ #ifdef ACD_DEBUG
+ 	printf("acd: acdstart\n");
+ 	if (acd == NULL) {
+ 		printf("acdstart: null acd\n");
+ 		return;
+ 	}
+ #endif
+ 		
+ 	ad_link = acd->ad_link;
+ #ifdef ACD_DEBUG
+ 	if (ad_link == NULL) {
+ 		printf("acdstart: null ad_link\n");
+ 		return;
+ 	}
+ #endif
+ 	/*
+ 	 * Check if the device has room for another command
+ 	 */
+ 	while (ad_link->openings >0 ) {
+ 		/*
+ 		 * there is excess capacity, but a special waits
+ 		 * It'll need the adapter as soon as we clear out of the
+ 		 * way and let it run (user level wait).
+ 		 */
+ 		if (ad_link->flags & ADEV_WAITING) {
+ #ifdef ATAPI_DEBUG
+ 			printf("acdstart: waking up\n");
+ #endif
+ 			ad_link->flags &= ~ADEV_WAITING;
+ 			wakeup((caddr_t)ad_link);
+ 			return;
+ 		}
+ 		
+ 		/*
+ 		 * See if there is a buf with work for us to do..
+ 		 */
+ 		dp = &acd->buf_queue;
+ #ifdef ACD_DEBUG
+ 		if (dp == NULL) {
+ 			printf("acdstart: null dp\n");
+ 			return;
+ 		}
+ #endif
+ 		if ((bp = dp->b_actf) == NULL)	/* yes, an assign */
+ 			return;
+ #ifdef ACD_DEBUG
+ 		printf("acdstart: a buf\n");
+ #endif
+ 		dp->b_actf = bp->b_actf;
+ 
+ 		/*
+ 		 * If the device has become invalid, abort all the
+ 		 * reads and writes until all files have been closed and
+ 		 * re-opened
+ 		 */
+ 		if ((ad_link->flags & ADEV_MEDIA_LOADED) == 0) {
+ 			bp->b_error = EIO;
+ 			bp->b_flags |= B_ERROR;
+ 			biodone(bp);
+ 			continue;
+ 		}
+ 
+ 		/*
+ 		 *
+ 		 * First, translate the block to absolute and put it in terms
+ 		 * of the logical blocksize of the device.
+ 		 */
+ 		blkno =
+ 		    bp->b_blkno / (acd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
+ 		if (CDPART(bp->b_dev) != RAW_PART) {
+ 			p = &acd->sc_dk.dk_label->d_partitions[CDPART(bp->b_dev)];
+ 			blkno += p->p_offset;
+ 		}
+ 		nblks = howmany(bp->b_bcount, acd->sc_dk.dk_label->d_secsize);
+ #ifdef ACD_DEBUG
+ 		printf("acdstart: blkno %d nblk %d\n",blkno, nblks);
+ #endif
+ 
+ 		/*
+ 		 *  Fill out the atapi command
+ 		 */
+ 		bzero(&cmd, sizeof(cmd));
+ 		cmd.operation_code = ATAPI_READ;
+ 		cmd.lba[0] = (blkno >> 24) & 0xff;
+ 		cmd.lba[1] = (blkno >> 16) & 0xff;
+ 		cmd.lba[2] = (blkno >> 8) & 0xff;
+ 		cmd.lba[3] = blkno & 0xff;
+ 		cmd.length[0] = (nblks >> 8) & 0xff;
+ 		cmd.length[1] = nblks & 0xff;
+ 
+ 		/* Instrumentation. */
+ 		disk_busy(&acd->sc_dk);
+ 
+ 		/*
+ 		 * Call the routine that chats with the adapter.
+ 		 * Note: we cannot sleep as we may be an interrupt
+ 		 */
+ 
+ 		 if (atapi_exec_io(ad_link, &cmd, sizeof(cmd), bp, A_NOSLEEP))
+ 			printf("%s: not queued", acd->sc_dev.dv_xname);
+ 	}
+ }
+ 
+ int
+ acdread(dev, uio)
+ 	dev_t dev;
+ 	struct uio *uio;
+ {
+ 
+ 	return (physio(acdstrategy, NULL, dev, B_READ,
+ 		       acdminphys, uio));
+ }
+ 
+ int
+ acdwrite(dev, uio)
+ 	dev_t dev;
+ 	struct uio *uio;
+ {
+ 
+ 	return (physio(acdstrategy, NULL, dev, B_WRITE,
+ 		       acdminphys, uio));
+ }
+ 
+ /*
+  * Perform special action on behalf of the user.
+  * Knows about the internals of this device
+  */
+ int
+ acdioctl(dev, cmd, addr, flag, p)
+ 	dev_t dev;
+ 	u_long cmd;
+ 	caddr_t addr;
+ 	int flag;
+ 	struct proc *p;
+ {
+ 	struct acd_softc *acd = acd_cd.cd_devs[CDUNIT(dev)];
+ 	int error;
+ 
+ 	/*
+ 	 * If the device is not valid.. abandon ship
+ 	 */
+ 	if ((acd->ad_link->flags & ADEV_MEDIA_LOADED) == 0)
+ 		return EIO;
+ 
+ 	switch (cmd) {
+ 	case DIOCGDINFO:
+ 		*(struct disklabel *)addr = *acd->sc_dk.dk_label;
+ 		return 0;
+ 
+ 	case DIOCGPART:
+ 		((struct partinfo *)addr)->disklab = acd->sc_dk.dk_label;
+ 		((struct partinfo *)addr)->part =
+ 		    &acd->sc_dk.dk_label->d_partitions[CDPART(dev)];
+ 		return 0;
+ 
+ 	case DIOCWDINFO:
+ 	case DIOCSDINFO:
+ 		if ((flag & FWRITE) == 0)
+ 			return EBADF;
+ 
+ 		if ((error = acdlock(acd)))
+ 			return error;
+ 		acd->flags |= CDF_LABELLING;
+ 
+ 		error = setdisklabel(acd->sc_dk.dk_label,
+ 		    (struct disklabel *)addr, /*acd->sc_dk.dk_openmask : */0,
+ 		    acd->sc_dk.dk_cpulabel);
+ 		if (error == 0) {
+ 		}
+ 
+ 		acd->flags &= ~CDF_LABELLING;
+ 		acdunlock(acd);
+ 		return error;
+ 
+ 	case DIOCWLABEL:
+ 		return EBADF;
+ 
+ 	case CDIOCPLAYTRACKS:
+ #ifdef notyet
+ 		{
+ 		struct ioc_play_track *args = (struct ioc_play_track *)addr;
+ 		struct acd_mode_data data;
+ 		if (error = acd_get_mode(acd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.flags &= ~CD_PA_SOTC;
+ 		data.page.audio.flags |= CD_PA_IMMED;
+ 		if (error = acd_set_mode(acd, &data))
+ 			return error;
+ 		return acd_play_tracks(acd, args->start_track, args->start_index,
+ 		    args->end_track, args->end_index);
+ 	}
+ #else
+ 	return ENOTTY;
+ #endif
+ 	case CDIOCPLAYMSF:
+ #ifdef notyet
+ 		{
+ 		struct ioc_play_msf *args
+ 		= (struct ioc_play_msf *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.flags &= ~CD_PA_SOTC;
+ 		data.page.audio.flags |= CD_PA_IMMED;
+ 		if (error = cd_set_mode(cd, &data))
+ 			return error;
+ 		return cd_play_msf(cd, args->start_m, args->start_s,
+ 		    args->start_f, args->end_m, args->end_s, args->end_f);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCPLAYBLOCKS:
+ #ifdef notyet
+ 	{
+ 		struct ioc_play_blocks *args
+ 		= (struct ioc_play_blocks *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.flags &= ~CD_PA_SOTC;
+ 		data.page.audio.flags |= CD_PA_IMMED;
+ 		if (error = cd_set_mode(cd, &data))
+ 			return error;
+ 		return cd_play(cd, args->blk, args->len);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCREADSUBCHANNEL:
+ #ifdef notyet 
+ 	{
+ 		struct ioc_read_subchannel *args
+ 		= (struct ioc_read_subchannel *)addr;
+ 		struct cd_sub_channel_info data;
+ 		int len = args->data_len;
+ 		if (len > sizeof(data) ||
+ 		    len < sizeof(struct cd_sub_channel_header))
+ 			return EINVAL;
+ 		if (error = cd_read_subchannel(cd, args->address_format,
+ 		    args->data_format, args->track, &data, len))
+ 			return error;
+ 		len = min(len, ((data.header.data_len[0] << 8) +
+ 		    data.header.data_len[1] +
+ 		    sizeof(struct cd_sub_channel_header)));
+ 		return copyout(&data, args->data, len);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOREADTOCHEADER:
+ #ifdef notyet
+ 	{
+ 		struct ioc_toc_header th;
+ 		if (error = cd_read_toc(cd, 0, 0, &th, sizeof(th)))
+ 			return error;
+ 		th.len = ntohs(th.len);
+ 		bcopy(&th, addr, sizeof(th));
+ 		return 0;
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOREADTOCENTRYS:
+ #ifdef notyet
+ 	{
+ 		struct cd_toc {
+ 			struct ioc_toc_header header;
+ 			struct cd_toc_entry entries[65];
+ 		} data;
+ 		struct ioc_read_toc_entry *te =
+ 		(struct ioc_read_toc_entry *)addr;
+ 		struct ioc_toc_header *th;
+ 		int len = te->data_len;
+ 		th = &data.header;
+ 
+ 		if (len > sizeof(data.entries) ||
+ 		    len < sizeof(struct cd_toc_entry))
+ 			return EINVAL;
+ 		if (error = cd_read_toc(cd, te->address_format,
+ 		    te->starting_track, (struct cd_toc_entry *)&data,
+ 		    len + sizeof(struct ioc_toc_header)))
+ 			return error;
+ 		len = min(len, ntohs(th->len) - (sizeof(th->starting_track) +
+ 		    sizeof(th->ending_track)));
+ 		return copyout(data.entries, te->data, len);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCSETPATCH:
+ #ifdef notyet
+ {
+ 		struct ioc_patch *arg = (struct ioc_patch *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
+ 		data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
+ 		data.page.audio.port[2].channels = arg->patch[2];
+ 		data.page.audio.port[3].channels = arg->patch[3];
+ 		return cd_set_mode(cd, &data);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCGETVOL:
+ #ifdef notyet
+ 	{
+ 		struct ioc_vol *arg = (struct ioc_vol *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
+ 		arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
+ 		arg->vol[2] = data.page.audio.port[2].volume;
+ 		arg->vol[3] = data.page.audio.port[3].volume;
+ 		return 0;
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCSETVOL:
+ #ifdef notyet
+ {
+ 		struct ioc_vol *arg = (struct ioc_vol *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.port[LEFT_PORT].channels = CHANNEL_0;
+ 		data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
+ 		data.page.audio.port[RIGHT_PORT].channels = CHANNEL_1;
+ 		data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
+ 		data.page.audio.port[2].volume = arg->vol[2];
+ 		data.page.audio.port[3].volume = arg->vol[3];
+ 		return cd_set_mode(cd, &data);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCSETMONO:
+ #ifdef notyet
+ 	{
+ 		struct ioc_vol *arg = (struct ioc_vol *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.port[LEFT_PORT].channels =
+ 		    LEFT_CHANNEL | RIGHT_CHANNEL | 4 | 8;
+ 		data.page.audio.port[RIGHT_PORT].channels =
+ 		    LEFT_CHANNEL | RIGHT_CHANNEL;
+ 		data.page.audio.port[2].channels = 0;
+ 		data.page.audio.port[3].channels = 0;
+ 		return cd_set_mode(cd, &data);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCSETSTEREO:
+ #ifdef notyet
+ 	{
+ 		struct ioc_vol *arg = (struct ioc_vol *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
+ 		data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
+ 		data.page.audio.port[2].channels = 0;
+ 		data.page.audio.port[3].channels = 0;
+ 		return cd_set_mode(cd, &data);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCSETMUTE:
+ #ifdef notyet
+ {
+ 		struct ioc_vol *arg = (struct ioc_vol *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.port[LEFT_PORT].channels = 0;
+ 		data.page.audio.port[RIGHT_PORT].channels = 0;
+ 		data.page.audio.port[2].channels = 0;
+ 		data.page.audio.port[3].channels = 0;
+ 		return cd_set_mode(cd, &data);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCSETLEFT:
+ #ifdef notyet
+ {
+ 		struct ioc_vol *arg = (struct ioc_vol *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
+ 		data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
+ 		data.page.audio.port[2].channels = 0;
+ 		data.page.audio.port[3].channels = 0;
+ 		return cd_set_mode(cd, &data);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCSETRIGHT:
+ #ifdef notyet
+ {
+ 		struct ioc_vol *arg = (struct ioc_vol *)addr;
+ 		struct cd_mode_data data;
+ 		if (error = cd_get_mode(cd, &data, AUDIO_PAGE))
+ 			return error;
+ 		data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
+ 		data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
+ 		data.page.audio.port[2].channels = 0;
+ 		data.page.audio.port[3].channels = 0;
+ 		return cd_set_mode(cd, &data);
+ 	}
+ #else
+     return ENOTTY; 
+ #endif
+ 	case CDIOCRESUME:
+ 		return acd_pause(acd, 1);
+ 	case CDIOCPAUSE:
+ 		return acd_pause(acd, 0);
+ 	case CDIOCSTART:
+ 		return atapi_start_stop(acd->ad_link, SSS_START, 0);
+ 	case CDIOCSTOP:
+ 		return atapi_start_stop(acd->ad_link, SSS_STOP, 0);
+ 	case CDIOCEJECT: /* FALLTHROUGH */
+ 	case DIOCEJECT:
+ 		return atapi_start_stop(acd->ad_link, SSS_STOP|SSS_LOEJ, 0);
+ 	case CDIOCALLOW:
+ 		return atapi_prevent(acd->ad_link, PR_ALLOW);
+ 	case CDIOCPREVENT:
+ 		return atapi_prevent(acd->ad_link, PR_PREVENT);
+ 	case DIOCLOCK:
+ 		return atapi_prevent(acd->ad_link,
+ 			(*(int *)addr) ? PR_PREVENT : PR_ALLOW);
+ 	case CDIOCRESET:
+ 		return acd_reset(acd);
+ 	default:
+ 		return ENOTTY;
+ 	}
+ 
+ #ifdef DIAGNOSTIC
+ 	panic("cdioctl: impossible");
+ #endif
+ }
+ 
+ /*
+  * Load the label information on the named device
+  * Actually fabricate a disklabel
+  *
+  * EVENTUALLY take information about different
+  * data tracks from the TOC and put it in the disklabel
+  */
+ void
+ acdgetdisklabel(acd)
+ 	struct acd_softc *acd;
+ {
+ 	struct disklabel *lp = acd->sc_dk.dk_label;
+ 
+ 	bzero(lp, sizeof(struct disklabel));
+ 	bzero(acd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel));
+ 
+ /*	lp->d_secsize = acd->params.blksize;*/ /* XXX */
+ 	lp->d_secsize = 2048;
+ 	lp->d_ntracks = 1;
+ 	lp->d_nsectors = 100;
+ 	lp->d_ncylinders = (acd->params.disksize / 100) + 1;
+ 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
+ 
+ 	strncpy(lp->d_typename, "ATAPI CD-ROM", 16);
+ 	lp->d_type = DTYPE_SCSI; /* XXX */
+ 	strncpy(lp->d_packname, "fictitious", 16);
+ 	lp->d_secperunit = acd->params.disksize;
+ 	lp->d_rpm = 300;
+ 	lp->d_interleave = 1;
+ 	lp->d_flags = D_REMOVABLE;
+ 
+ 	lp->d_partitions[0].p_offset = 0;
+ 	lp->d_partitions[0].p_size =
+ 	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
+ 	lp->d_partitions[0].p_fstype = FS_ISO9660;
+ 	lp->d_partitions[RAW_PART].p_offset = 0;
+ 	lp->d_partitions[RAW_PART].p_size =
+ 	    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
+ 	lp->d_partitions[RAW_PART].p_fstype = FS_ISO9660;
+ 	lp->d_npartitions = RAW_PART + 1;
+ 
+ 	lp->d_magic = DISKMAGIC;
+ 	lp->d_magic2 = DISKMAGIC;
+ 	lp->d_checksum = dkcksum(lp);
+ }
+ 
+ /*
+  * Find out from the device what it's capacity is
+  */
+ u_long
+ acd_size(cd, flags)
+ 	struct acd_softc *cd;
+ 	int flags;
+ {
+ 	struct read_cd_capacity_data rdcap;
+ 	struct read_cd_capacity cmd;
+ 	u_long blksize;
+ 	u_long size=0;
+ 
+ 	/*
+ 	 * make up a atapi command and ask the atapi driver to do
+ 	 * it for you.
+ 	 */
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.operation_code = ATAPI_READ_CD_CAPACITY;
+ 	cmd.len = sizeof(rdcap);
+ 
+ 	/*
+ 	 * If the command works, interpret the result as a 4 byte
+ 	 * number of blocks and a blocksize
+ 	 */
+ 	if (atapi_exec_cmd(cd->ad_link, &cmd , sizeof(cmd),
+ 		&rdcap, sizeof(rdcap), B_READ, 0) != 0) {
+ #ifdef ATAPI_DEBUG
+ 		printf("ATAPI_READ_CD_CAPACITY failed\n");
+ #endif
+ 		return 0;
+ 	}
+ 
+ 	blksize = ntohl(rdcap.blksize);
+ 	if (blksize < 512)
+ 		blksize = 2048;	/* some drives lie ! */
+ 	cd->params.blksize = blksize;
+ 
+ 	size = ntohl(rdcap.size);
+ 	if (size < 100)
+ 		size = 400000;	/* ditto */
+ 	cd->params.disksize = size;
+ #ifdef ATAPI_DEBUG
+ 	printf("acd_size: %ld %ld\n",blksize,size);
+ #endif
+ 
+ 	return size;
+ }
+ 
+ #ifdef notyet
+ /*
+  * Get the requested page into the buffer given
+  */
+ int
+ cd_get_mode(cd, data, page)
+ 	struct acd_softc *cd;
+ 	struct cd_mode_data *data;
+ 	int page;
+ {
+ 	struct scsi_mode_sense scsi_cmd;
+ 	int error;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	bzero(data, sizeof(*data));
+ 	scsi_cmd.opcode = MODE_SENSE;
+ 	scsi_cmd.page = page;
+ 	scsi_cmd.length = sizeof(*data) & 0xff;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(scsi_cmd), (u_char *)data, sizeof(*data), CDRETRIES, 20000,
+ 	    NULL, SCSI_DATA_IN);
+ }
+ 
+ /*
+  * Get the requested page into the buffer given
+  */
+ int
+ cd_set_mode(cd, data)
+ 	struct acd_softc *cd;
+ 	struct cd_mode_data *data;
+ {
+ 	struct scsi_mode_select scsi_cmd;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.opcode = MODE_SELECT;
+ 	scsi_cmd.byte2 |= SMS_PF;
+ 	scsi_cmd.length = sizeof(*data) & 0xff;
+ 	data->header.data_length = 0;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(scsi_cmd), (u_char *)data, sizeof(*data), CDRETRIES, 20000,
+ 	    NULL, SCSI_DATA_OUT);
+ }
+ 
+ /*
+  * Get scsi driver to send a "start playing" command
+  */
+ int
+ cd_play(cd, blkno, nblks)
+ 	struct acd_softc *cd;
+ 	int blkno, nblks;
+ {
+ 	struct scsi_play scsi_cmd;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.opcode = PLAY;
+ 	scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff;
+ 	scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff;
+ 	scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff;
+ 	scsi_cmd.blk_addr[3] = blkno & 0xff;
+ 	scsi_cmd.xfer_len[0] = (nblks >> 8) & 0xff;
+ 	scsi_cmd.xfer_len[1] = nblks & 0xff;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 200000, NULL, 0);
+ }
+ 
+ /*
+  * Get scsi driver to send a "start playing" command
+  */
+ int
+ cd_play_big(cd, blkno, nblks)
+ 	struct acd_softc *cd;
+ 	int blkno, nblks;
+ {
+ 	struct scsi_play_big scsi_cmd;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.opcode = PLAY_BIG;
+ 	scsi_cmd.blk_addr[0] = (blkno >> 24) & 0xff;
+ 	scsi_cmd.blk_addr[1] = (blkno >> 16) & 0xff;
+ 	scsi_cmd.blk_addr[2] = (blkno >> 8) & 0xff;
+ 	scsi_cmd.blk_addr[3] = blkno & 0xff;
+ 	scsi_cmd.xfer_len[0] = (nblks >> 24) & 0xff;
+ 	scsi_cmd.xfer_len[1] = (nblks >> 16) & 0xff;
+ 	scsi_cmd.xfer_len[2] = (nblks >> 8) & 0xff;
+ 	scsi_cmd.xfer_len[3] = nblks & 0xff;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 20000, NULL, 0);
+ }
+ 
+ /*
+  * Get scsi driver to send a "start playing" command
+  */
+ int
+ cd_play_tracks(cd, strack, sindex, etrack, eindex)
+ 	struct acd_softc *cd;
+ 	int strack, sindex, etrack, eindex;
+ {
+ 	struct scsi_play_track scsi_cmd;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.opcode = PLAY_TRACK;
+ 	scsi_cmd.start_track = strack;
+ 	scsi_cmd.start_index = sindex;
+ 	scsi_cmd.end_track = etrack;
+ 	scsi_cmd.end_index = eindex;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 20000, NULL, 0);
+ }
+ 
+ /*
+  * Get scsi driver to send a "play msf" command
+  */
+ int
+ cd_play_msf(cd, startm, starts, startf, endm, ends, endf)
+ 	struct acd_softc *cd;
+ 	int startm, starts, startf, endm, ends, endf;
+ {
+ 	struct scsi_play_msf scsi_cmd;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.opcode = PLAY_MSF;
+ 	scsi_cmd.start_m = startm;
+ 	scsi_cmd.start_s = starts;
+ 	scsi_cmd.start_f = startf;
+ 	scsi_cmd.end_m = endm;
+ 	scsi_cmd.end_s = ends;
+ 	scsi_cmd.end_f = endf;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(scsi_cmd), 0, 0, CDRETRIES, 2000, NULL, 0);
+ }
+ 
+ #endif  /* notyet */
+ 
+ /*
+  * Get atapi driver to send a "start up" command
+  */
+ int
+ acd_pause(acd, go)
+ 	struct acd_softc *acd;
+ 	int go;
+ {
+ 	struct pause_resume cmd;
+ 
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.operation_code = ATAPI_PAUSE_RESUME;
+ 	cmd.resume = go;
+ 	return atapi_exec_cmd(acd->ad_link, &cmd , sizeof(cmd), 0, 0, 0, 0);
+ }
+ 
+ /*
+  * Get atapi driver to send a "RESET" command
+  */
+ int
+ acd_reset(acd)
+ 	struct acd_softc *acd;
+ {
+ #ifdef notyet	
+ 	return atapi_soft_reset(acd->ad_link);
+ #else
+  	return 0;
+ #endif
+ }
+ 
+ #ifdef notyet
+ /*
+  * Read subchannel
+  */
+ int
+ cd_read_subchannel(cd, mode, format, track, data, len)
+ 	struct acd_softc *cd;
+ 	int mode, format, len;
+ 	struct cd_sub_channel_info *data;
+ {
+ 	struct scsi_read_subchannel scsi_cmd;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	scsi_cmd.opcode = READ_SUBCHANNEL;
+ 	if (mode == CD_MSF_FORMAT)
+ 		scsi_cmd.byte2 |= CD_MSF;
+ 	scsi_cmd.byte3 = SRS_SUBQ;
+ 	scsi_cmd.subchan_format = format;
+ 	scsi_cmd.track = track;
+ 	scsi_cmd.data_len[0] = (len >> 8) & 0xff;
+ 	scsi_cmd.data_len[1] = len & 0xff;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(struct scsi_read_subchannel), (u_char *)data, len,
+ 	    CDRETRIES, 5000, NULL, SCSI_DATA_IN);
+ }
+ 
+ /*
+  * Read table of contents
+  */
+ int
+ cd_read_toc(cd, mode, start, data, len)
+ 	struct acd_softc *cd;
+ 	int mode, start, len;
+ 	struct cd_toc_entry *data;
+ {
+ 	struct scsi_read_toc scsi_cmd;
+ 	int ntoc;
+ 
+ 	bzero(&scsi_cmd, sizeof(scsi_cmd));
+ 	/*if (len!=sizeof(struct ioc_toc_header))
+ 	 * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
+ 	 * else */
+ 	ntoc = len;
+ 	scsi_cmd.opcode = READ_TOC;
+ 	if (mode == CD_MSF_FORMAT)
+ 		scsi_cmd.byte2 |= CD_MSF;
+ 	scsi_cmd.from_track = start;
+ 	scsi_cmd.data_len[0] = (ntoc >> 8) & 0xff;
+ 	scsi_cmd.data_len[1] = ntoc & 0xff;
+ 	return scsi_scsi_cmd(cd->ad_link, (struct scsi_generic *)&scsi_cmd,
+ 	    sizeof(struct scsi_read_toc), (u_char *)data, len, CDRETRIES,
+ 	    5000, NULL, SCSI_DATA_IN);
+ }
+ 
+ #endif /* notyet */
+ 
+ /*
+  * Get the atapi driver to send a full inquiry to the device and use the
+  * results to fill out the disk parameter structure.
+  */
+ int
+ acd_get_parms(acd, flags)
+ 	struct acd_softc *acd;
+ 	int flags;
+ {
+ 
+ 	/*
+ 	 * give a number of sectors so that sec * trks * cyls
+ 	 * is <= disk_size
+ 	 */
+ 	if (acd_size(acd, flags) == 0)
+ 		return ENXIO;
+ 
+ 	return 0;
+ }
+ 
+ int
+ acdsize(dev)
+ 	dev_t dev;
+ {
+ 
+ 	/* CD-ROMs are read-only. */
+ 	return -1;
+ }
+ 
+ void acdminphys(bp)
+ struct buf *bp;
+ {
+ 	minphys(bp);
+ }
+ 
+ 
+ int
+ acddump(dev, blkno, va, size)
+ 	dev_t dev;
+ 	daddr_t blkno;
+ 	caddr_t va;
+ 	size_t size;
+ {
+ 
+ 	/* Not implemented. */
+ 	return ENXIO;
+ }
+ 
+ int
+ acddone(acp)
+ struct atapi_command_packet *acp;
+ {
+ 	struct at_dev_link *ad_link = acp->ad_link;
+ 	struct acd_softc *acd = ad_link->device_softc;
+ 
+ 	if (acp->bp != NULL)
+ 		disk_unbusy(&acd->sc_dk, (acp->bp->b_bcount - acp->bp->b_resid));
+ 
+ 	return (0);     
+ }   
+ 
diff -c -r -N --exclude exp --exclude compile sys/atapi.orig/atapi.h sys/atapi/atapi.h
*** sys/atapi.orig/atapi.h	Thu Jan  1 01:00:00 1970
--- sys/atapi/atapi.h	Thu Jun 13 03:19:49 1996
***************
*** 0 ****
--- 1,244 ----
+ /*
+  * Copyright (c) 1996 Manuel Bouyer.  All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *  This product includes software developed by Manuel Bouyer.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ /* Definition of atapi commands and associated data structures */
+ /* 
+    TEST UNIT READY (mandatory)
+  */
+ 
+ #define ATAPI_TEST_UNIT_READY           0x00
+ 
+ struct test_unit_ready {
+ 	u_char  operation_code;
+ 	u_char  reserved1[15];
+ };
+ 
+ /* 
+    START/STOP UNIT (mandatory)
+    */ 
+  
+ #define ATAPI_START_STOP_UNIT           0x1b
+  
+ struct start_stop_unit {
+ 	u_char  operation_code;
+     u_char  immed       :1;
+     u_char  reserved1   :7;
+     u_char  reserved2[2]; 
+ 	u_char  how;
+ #define SSS_STOP        0x00 
+ #define SSS_START       0x01
+ #define SSS_LOEJ        0x02
+     u_char  reserved4[11];
+ };
+ 
+ /* 
+    PREVENT/ALLOW MEDIUM REMOVAL (mandatory)
+    */ 
+  
+ #define ATAPI_PREVENT_ALLOW_MEDIUM_REMOVAL  0x1e
+  
+ struct prevent_allow_medium_removal {
+ 	u_char  operation_code;
+     u_char  reserved1[3];
+     u_char  prevent     :1;
+ #define PR_PREVENT 0x01
+ #define PR_ALLOW   0x00
+     u_char  reserved2   :7;
+     u_char  reserved3[11];
+ };
+ 
+ 
+ /* 
+    READ CD CAPACITY (mandatory)
+  */
+ 	   
+ #define ATAPI_READ_CD_CAPACITY          0x25
+ 	
+ struct read_cd_capacity {
+ 	u_char  operation_code;
+ 	u_char  reserved1[7];
+ 	u_char len;
+ 	u_char reserved2[7];
+ };
+ 
+ /* 
+  * Volume size info.
+  */
+ struct read_cd_capacity_data {
+ 	u_long size;         /* Volume size in blocks */
+ 	u_long blksize;         /* Block size in bytes */
+ };
+ 
+ 
+ /*
+    READ (10) (mandatory)
+  */  
+ 	
+ #define ATAPI_READ              0x28  
+ 
+ struct read {    
+ 	u_char  operation_code;
+ 	u_char  reserved1;  
+ 	u_char  lba[4];       
+ 	u_char  reserved2;            
+ 	u_char  length[2];                    
+ 	u_char  reserved3[7];                         
+ }; 
+ 
+ /* 
+    PAUSE/RESUME (optional) 
+  */ 
+  
+ #define ATAPI_PAUSE_RESUME      0x4b
+  
+ struct pause_resume {
+ 	u_char  operation_code;
+     u_char  reserved1[7];
+     u_char  resume      :1;
+     u_char  reserved2   :7;
+     u_char  reserved3[7];
+ };
+ 
+ 
+ /*
+    MODE SENSE (mandatory)
+    */
+ 
+ #define ATAPI_MODE_SENSE        0x5a
+ 
+ struct mode_sense {
+ 	u_char  operation_code;
+     u_char  reserved1;
+     u_char  page_code   :6;
+     u_char  page_control    :2;  /* page control */
+     u_char  reserved2[4];
+     u_char  length[2];
+     u_char  reserved3[7];
+ };
+ 
+ struct cappage {
+     /* Mode data header */
+     u_short data_length;
+     u_char  medium_type;
+ #define MDT_UNKNOWN     0x00        
+ #define MDT_DATA_120    0x01
+ #define MDT_AUDIO_120   0x02
+ #define MDT_COMB_120    0x03    
+ #define MDT_PHOTO_120   0x04    
+ #define MDT_DATA_80     0x05
+ #define MDT_AUDIO_80    0x06
+ #define MDT_COMB_80     0x07 
+ #define MDT_PHOTO_80    0x08
+ #define MDT_NO_DISC     0x70
+ #define MDT_DOOR_OPEN   0x71
+ #define MDT_FMT_ERROR   0x72
+     u_char  reserved1[5];
+ 
+     /* Capabilities page */
+     u_char  page_code;
+ #define CAP_PAGE        0x2a
+     u_char  param_len;
+     u_char  reserved2[2];
+ 
+     u_char  audio_play : 1;         /* audio play supported */
+     u_char  composite : 1;          /* composite audio/video supported */
+     u_char  dport1 : 1;             /* digital audio on port 1 */
+     u_char  dport2 : 1;             /* digital audio on port 2 */
+     u_char  mode2_form1 : 1;        /* mode 2 form 1 (XA) read */
+     u_char  mode2_form2 : 1;        /* mode 2 form 2 format */
+     u_char  multisession : 1;       /* multi-session photo-CD */
+     u_char  : 1;
+     u_char  cd_da : 1;              /* audio-CD read supported */
+     u_char  cd_da_stream : 1;       /* CD-DA streaming */
+     u_char  rw : 1;                 /* combined R-W subchannels */
+     u_char  rw_corr : 1;            /* R-W subchannel data corrected */
+     u_char  c2 : 1;                 /* C2 error pointers supported */
+     u_char  isrc : 1;               /* can return the ISRC info */
+     u_char  upc : 1;                /* can return the catalog number UPC */
+     u_char  : 1;
+     u_char  lock : 1;               /* could be locked */
+     u_char  locked : 1;             /* current lock state */
+     u_char  prevent : 1;            /* prevent jumper installed */
+     u_char  eject : 1;              /* can eject */
+     u_char  : 1;
+     u_char  mech : 3;               /* loading mechanism type */
+ #define MECH_CADDY      0
+ #define MECH_TRAY       1
+ #define MECH_POPUP      2
+ #define MECH_CHANGER    4
+ #define MECH_CARTRIDGE  5
+     u_char  sep_vol : 1;            /* independent volume of channels */
+     u_char  sep_mute : 1;           /* independent mute of channels */
+     u_char  : 6;
+ 
+     u_short max_speed;              /* max raw data rate in bytes/1000 */
+     u_short max_vol_levels;         /* number of discrete volume levels */
+     u_short buf_size;               /* internal buffer size in bytes/1024 */
+     u_short cur_speed;              /* current data rate in bytes/1000  */
+     /* Digital drive output format description (optional?) */
+     u_char  reserved3;
+     u_char  bckf : 1;               /* data valid on failing edge of BCK */
+     u_char  rch : 1;                /* high LRCK indicates left channel */
+     u_char  lsbf : 1;               /* set if LSB first */
+     u_char  dlen: 2;
+ #define DLEN_32         0               /* 32 BCKs */
+ #define DLEN_16         1               /* 16 BCKs */
+ #define DLEN_24         2               /* 24 BCKs */
+ #define DLEN_24_I2S     3               /* 24 BCKs (I2S) */
+     u_char  : 3;
+     u_char  reserved4[2];
+ };
+ 
+ /* ATAPI error codes */
+ #define ATAPI_SK_NO_SENSE       0x0
+ #define ATAPI_SK_REC_ERROR      0x1  /* recovered error */
+ #define ATAPI_SK_NOT_READY      0x2
+ #define ATAPI_SK_MEDIUM_ERROR       0x3
+ #define ATAPI_SK_HARDWARE_ERROR     0x4
+ #define ATAPI_SK_ILLEGAL_REQUEST    0x5
+ #define ATAPI_SK_UNIT_ATTENTION     0x6
+ #define ATAPI_SK_DATA_PROTECT       0x7
+                          /* 0x8 reserved */
+                          /* 0x9-0xa reserved */
+ #define ATAPI_SK_ABORTED_COMMAND    0xb
+                         /* 0xc-0xd not referenced */
+ #define ATAPI_SK_MISCOMPARE     0xe
+                         /* 0xf reserved */
+ 
+ #define ATAPI_MCR           0x08 /* media change requested */
+ #define ATAPI_ABRT          0x04 /* aborted command */
+ #define ATAPI_EOM           0x02 /* end of media */
+ #define ATAPI_ILI           0x01 /* illegal length indication */
+ 
+ 
+ int atapi_exec_cmd __P((struct at_dev_link *, void*, int, void*, int, long, int));
+ int atapi_exec_io __P((struct at_dev_link *, void *, int, struct buf *, int));
+ int atapi_test_unit_ready __P((struct at_dev_link  *, int));
+ int atapi_start_stop __P((struct at_dev_link  *, int, int));
+ int atapi_prevent __P((struct at_dev_link  *, int));
diff -c -r -N --exclude exp --exclude compile sys/atapi.orig/atapiconf.c sys/atapi/atapiconf.c
*** sys/atapi.orig/atapiconf.c	Thu Jan  1 01:00:00 1970
--- sys/atapi/atapiconf.c	Thu Jun 13 03:19:49 1996
***************
*** 0 ****
--- 1,588 ----
+ /*
+  * Copyright (c) 1996 Manuel Bouyer.  All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *  This product includes software developed by Manuel Bouyer.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ #include <sys/types.h>
+ #include <sys/param.h>
+ #include <sys/systm.h>
+ #include <sys/malloc.h>
+ #include <sys/device.h>
+ #include <sys/buf.h>
+ #include <sys/proc.h>  
+ 
+ #include <atapi/atapilink.h>
+ #include <atapi/atapi.h>
+ #define SILENT_PRINTF(flags,string) if (!(flags & A_SILENT)) printf string
+ 
+ struct atapibus_softc {
+ 	struct device sc_dev;
+ 	struct bus_link *b_link;
+     struct atapi_devices *ad_link[2];
+ };
+ 
+ LIST_HEAD(pkt_free_list, atapi_command_packet) pkt_free_list;
+ 
+ void bswap __P((char*, int));
+ void btrim __P((char*, int));
+ 
+ int atapi_error __P((struct atapi_command_packet*));
+ void atapi_sense __P((struct atapi_command_packet*, u_char, u_char));
+ void at_print_addr __P((struct at_dev_link*, u_char));
+ 
+ int atapibusmatch __P((struct device *, void *, void *));
+ void atapibusattach __P((struct device *, struct device *, void *));
+ 
+ struct cfattach atapibus_ca = {
+     sizeof(struct atapibus_softc), atapibusmatch, atapibusattach,
+ };
+ 
+ struct cfdriver atapibus_cd = {
+     NULL, "atapibus", DV_DULL
+ };
+ 
+ 
+ int
+ atapibusmatch(parent, match, aux)
+         struct device *parent;
+         void *match, *aux;
+ {
+ /*	struct cfdata *cf = match;*/
+ 	struct bus_link *ab_link = aux;
+ 
+ 	if (ab_link == NULL ) return 0;
+ 	if (ab_link-> type != BUS) return 0;
+ 	return 1;
+ }
+ 
+ int
+ atapiprint(aux, bus)
+     void *aux;
+ 	char *bus;
+ {
+ 	struct at_dev_link *ad_link = aux;
+  
+ 	 if (!bus)
+ 		 printf(" drive %d: ", ad_link->drive); 
+ 	 return QUIET; 
+ }
+ 
+ 
+ void atapibusattach(parent, self, aux)
+         struct device *parent, *self;
+         void *aux;
+ {
+     struct atapibus_softc *ab = (struct atapibus_softc *)self;
+     struct bus_link *ab_link_proto = aux;
+ 	int drive;
+ 	struct atapi_identify ids;
+ 	struct atapi_identify *id = &ids;
+ 	struct at_dev_link *ad_link;
+ 
+     ab_link_proto->atapibus_softc = (caddr_t)ab;
+     ab->b_link = ab_link_proto;
+     printf("\n");
+ 	for (drive = 0; drive < 2 ; drive++) {
+ 		if (wdc_atapi_get_params(ab_link_proto, drive, id)) {
+ 			/*
+ 			 * Shuffle string byte order.
+ 			 * Mitsumi and NEC drives don't need this.
+ 			 */
+ 			if (! ((id->model[0] == 'N' && id->model[1] == 'E') ||
+ 				(id->model[0] == 'F' && id->model[1] == 'X')))
+ 				bswap(id->model, sizeof(id->model));
+ 			bswap (id->serial_number, sizeof(id->serial_number));
+ 			bswap (id->firmware_revision, sizeof(id->firmware_revision));
+ 			/* Clean up the model name, serial and revision numbers. */
+ 			btrim (id->model, sizeof(id->model));
+ 			btrim (id->serial_number, sizeof(id->serial_number));
+ 		    btrim (id->firmware_revision, sizeof(id->firmware_revision));
+ 			printf("atapibus%d drive%d: <%s, %s, %s> ",
+ 				ab->sc_dev.dv_unit, drive, id->model, id->serial_number, id->firmware_revision);
+ 			switch (id->config.device_type) {
+ 			case ATAPI_DEVICE_TYPE_DAD: printf("direct, ");
+ 									   break;
+ 			case ATAPI_DEVICE_TYPE_CD: printf("cdrom, ");
+ 									   break;
+ 			case ATAPI_DEVICE_TYPE_OMD: printf(" optical, ");
+ 									   break;
+ 			default: printf(" unknown type %d, ",id->config.device_type);
+ 			}
+ 			printf("%s.\n", id->config.removable?"removable":"fixed");
+ #ifdef ATAPI_DEBUG_PROBE
+ 			printf("cmdsz %d drqtype %d\n",id->config.packet_size, id->config.drq_type);
+ #endif
+ 			
+ 			ad_link = malloc(sizeof(*ad_link), M_DEVBUF, M_NOWAIT);
+ 			if (ad_link == NULL) {
+ 				printf("Warning: cannot allocate memory for device\n");
+ 				continue;
+ 			}
+ 			ad_link->drive = drive;
+ 			if (id->config.packet_size) ad_link->flags |= ACAP_LEN;
+ 			ad_link->flags |= id->config.drq_type << 8;
+ 			bcopy(id, &ad_link->id, sizeof(*id));
+ 			ad_link->bus=ab_link_proto;
+ 			if (config_found(self,ad_link,atapiprint) == NULL) {
+ 				printf("atapibus:config not found\n");
+ 				free(ad_link,M_DEVBUF);
+ 			}
+ 		}
+ 	}
+ }
+ 
+ void
+ bswap (buf, len)
+ char *buf;
+ int len;
+ {       
+     u_short *p = (u_short*) (buf + len);
+ 	while (--p >= (u_short*) buf)
+ 			*p = ntohs (*p);
+ }   
+ 
+ void
+ btrim (buf, len)
+ char *buf;
+ int len;
+ {
+     char *p; 
+ 	 
+ 	 /* Remove the trailing spaces. */
+ 	 for (p=buf; p<buf+len; ++p)
+ 		 if (! *p)
+ 			 *p = ' ';
+ 		 for (p=buf+len-1; p>=buf && *p==' '; --p)
+ 			 *p = 0;
+ }
+ 
+ int atapi_exec_cmd(ad_link, cmd, cmd_size, databuf, datalen, rw, flags)
+ struct at_dev_link *ad_link;
+ void *cmd;
+ int cmd_size;
+ void *databuf;
+ int datalen;
+ long rw;
+ int flags;
+ {
+ 	struct atapi_command_packet *pkt;
+ 	struct bus_link *b_link = ad_link->bus;
+ 	int status, s;
+ 
+ 	pkt = atapi_get_pkt(ad_link, flags);
+ 	if (!pkt) return -1;
+ 	bcopy(cmd, &pkt->cmd_store, cmd_size);
+ 	pkt->command = &pkt->cmd_store;
+ 	pkt->command_size = (ad_link->flags & ACAP_LEN)?16:12;
+ 	pkt->databuf = databuf;
+ 	pkt->data_size = datalen;
+ 	pkt->flags = rw|(flags & 0xff)| (ad_link->flags & 0x0300);
+ 	pkt->drive = ad_link->drive;
+ 	wdc_atapi_send_command_packet(b_link, pkt);
+ 	if ((flags & (A_POLLED|A_NOSLEEP)) == 0 ) {
+ #ifdef ATAPI_DEBUG_CMD
+ 		printf("atapi_exec_cmd: sleeping\n");
+ #endif
+ 		s=splbio();
+ 		while ((pkt->status & ITSDONE) == 0)
+ 			tsleep(pkt,PRIBIO+1,"atapicmd",0);
+ 		splx(s);
+ #ifdef ATAPI_DEBUG_CMD
+ 		printf("atapi_exec_cmd: done sleeping\n");
+ #endif
+ 		status = pkt->status & STATUS_MASK;
+ 		atapi_free_pkt(pkt);
+ 	} else {
+ 		if ((flags & A_POLLED) != 0) {
+ 			if ((pkt->status & ERROR) && (pkt->error)) {
+ 				atapi_error(pkt);
+ 				SILENT_PRINTF(flags,("\n"));
+ 			}
+ 		}
+ 		status = pkt->status & STATUS_MASK;
+ 		if ((flags & A_POLLED) != 0)
+ 			atapi_free_pkt(pkt);
+ 
+ 	}
+ 	return status;
+ }
+ 
+ int atapi_exec_io(ad_link, cmd, cmd_size, bp, flags)
+ struct at_dev_link *ad_link;
+ void *cmd;
+ int cmd_size;
+ struct buf *bp;
+ int flags;
+ {
+ 	struct atapi_command_packet *pkt;
+ 	struct bus_link *b_link = ad_link->bus;
+ 
+ 	pkt = atapi_get_pkt(ad_link, flags);
+ 	if (pkt == NULL) {
+ 		printf("atapi_exec_io: no pkt\n");
+ 		return ERROR;
+ 	}
+ 	bcopy(cmd, &pkt->cmd_store, cmd_size);
+ 	pkt->command = &pkt->cmd_store;
+ 	pkt->command_size = (ad_link->flags & ACAP_LEN)?16:12;
+ 	pkt->bp = bp;
+ 	pkt->databuf = bp->b_data;
+ 	pkt->data_size = bp->b_bcount;
+ 	pkt->flags = bp->b_flags & ((B_READ|B_WRITE)|(flags & 0xff)|
+ 			(ad_link->flags & 0x0300));
+ 	pkt->drive = ad_link->drive;
+ 	wdc_atapi_send_command_packet(b_link, pkt);
+ 	return (pkt->status & STATUS_MASK);
+ }
+ 
+ void atapi_done(acp)
+ struct atapi_command_packet *acp;
+ {
+ 	struct at_dev_link *ad_link=acp->ad_link;
+ 	struct buf *bp = acp->bp;
+ 	int error = 0;
+ 
+ #ifdef ATAPI_DEBUG_CMD
+ 	printf("atapi_done\n");
+ #endif
+ 
+ 	if ((acp->status & ERROR) && (acp->error)) {
+ 		atapi_error(acp);
+ 		if (acp->status & RETRY) {
+ 			if (acp->retries <ATAPI_NRETRIES) {
+ 				acp->retries++;
+ 				acp->status = 0;
+ 				acp->error = 0;
+         		SILENT_PRINTF(acp->flags & 0xff,(", retry #%d\n",acp->retries));
+ 				wdc_atapi_send_command_packet(ad_link->bus, acp);
+ 				return;
+ 			} else acp->status = ERROR;
+ 		}
+ 		SILENT_PRINTF(acp->flags & 0xff,("\n"));
+ 	}
+ 	acp->status |= ITSDONE;
+ 
+ 	if (ad_link->done) {
+ #ifdef ATAPI_DEBUG_CMD
+ 		printf("calling private done\n");
+ #endif
+ 		error = (*ad_link->done) (acp);
+ 		if (error == EJUSTRETURN) return;
+ 	}
+ 	if (acp->bp == NULL) {
+ #ifdef ATAPI_DEBUG_CMD
+ 		printf("atapidone: wakeup acp\n");
+ #endif
+ 		wakeup(acp);
+ 		return;
+ 	}
+ #ifdef ATAPI_DEBUG_CMD
+ 	printf("atapi_done: status %d\n", acp->status);
+ #endif
+ 	switch (acp->status&0x0f) {
+ 	case MEDIA_CHANGE:
+ 		if (ad_link->flags & ADEV_REMOVABLE) {
+ 			ad_link->flags &= ~ADEV_MEDIA_LOADED;
+ 		}
+ 		error=EIO;
+ 		break;
+ 	case NO_ERROR:
+ 		error=0;
+ 		break;
+ 	case ERROR:
+ 	case END_OF_MEDIA:
+ 	default:
+ 		error=EIO;
+ 		break;
+ 	}
+ 	switch (acp->status&0xf0) {
+ 	case NOT_READY:
+ 	case UNIT_ATTENTION:
+ 		if (ad_link->flags & ADEV_REMOVABLE) {  
+ 			ad_link->flags &= ~ADEV_MEDIA_LOADED;
+ 		}   
+ 		error=EIO;
+ 		break;
+ 	default:
+ 	}
+ 
+ 	if (error) {
+ 		bp->b_error = error;;
+ 		bp->b_flags |= B_ERROR;
+ 		bp->b_resid = bp->b_bcount;
+ 	} else {
+ 		bp->b_error = 0;
+ 		bp->b_resid = acp->data_size;
+ 	}
+ 	biodone(bp);
+ 	atapi_free_pkt(acp);
+ }
+ 
+ struct atapi_command_packet *
+ atapi_get_pkt(ad_link, flags)
+ struct at_dev_link *ad_link;
+ int flags;
+ {
+ 	struct atapi_command_packet *pkt;
+ 	int s;
+ 
+ 	s = splbio();
+ 	while (ad_link->openings <= 0) {
+ 		if (flags & A_NOSLEEP) {
+ 			splx(s);
+ 			return 0;
+ 		}
+ #ifdef ATAPI_DEBUG_CMD
+ 		printf("atapi_get_pkt: sleeping\n");
+ #endif
+ 		ad_link->flags |= ADEV_WAITING;
+ 		(void) tsleep(ad_link, PRIBIO, "getpkt", 0);
+ 	}
+ 	ad_link->openings--;
+ 	if ((pkt = pkt_free_list.lh_first) != 0) {
+ 		LIST_REMOVE(pkt, free_list);
+ 		splx(s);
+ 	} else {
+ 		splx(s);
+ 		pkt = malloc(sizeof(struct atapi_command_packet), M_DEVBUF,
+ 			((flags & A_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK));
+ 		if (!pkt) {
+ 			printf("atapi_get_pkt: cannot allocate pkt\n");
+ 			ad_link->openings++;
+ 			return 0;
+ 		}
+ 	}
+ 	bzero(pkt, sizeof(struct atapi_command_packet));
+ 	pkt->ad_link = ad_link;
+ 	return pkt;
+ }
+ 
+ void
+ atapi_free_pkt(pkt)
+ struct atapi_command_packet *pkt;
+ {
+ 	struct at_dev_link *ad_link = pkt->ad_link;
+ 	int s;
+ 
+ 	s = splbio();
+ 	LIST_INSERT_HEAD(&pkt_free_list, pkt, free_list);
+ 
+ 	ad_link->openings++;
+ 	if ((ad_link->flags & ADEV_WAITING) != 0) {
+ 		ad_link->flags &= ~ADEV_WAITING;
+ 		wakeup(ad_link);
+ 	} else {
+ 		if (ad_link->start) {
+ #ifdef ATAPI_DEBUG_CMD
+ 			printf("atapi_free_pkt: calling private start\n");
+ #endif
+ 			(*(ad_link->start)) ((void*)ad_link->device_softc);
+ 		}
+ 	}
+ 	splx(s);
+ }
+ 
+ int
+ atapi_test_unit_ready(ad_link, flags)
+ struct at_dev_link  *ad_link;
+ int flags;
+ {	
+ 	int ret;
+ 	struct test_unit_ready cmd;
+ #ifdef ATAPI_DEBUG_FCTN
+ 	printf("atapi_test_unit_ready: ");
+ #endif
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.operation_code = ATAPI_TEST_UNIT_READY;
+ 	ret = atapi_exec_cmd(ad_link, &cmd, sizeof(cmd), 0,0,0,flags);
+ #ifdef ATAPI_DEBUG_FCTN
+     printf("atapi_test_unit_ready: ret %d\n", ret);
+ #endif
+ 	return ret;
+ }
+ 
+ int
+ atapi_start_stop(ad_link, how, flags)
+ struct at_dev_link  *ad_link;
+ int how;
+ int flags;
+ {
+ 	struct start_stop_unit cmd;
+ 	int ret;
+ 		
+ #ifdef ATAPI_DEBUG_FCTN
+ 	printf("atapi_start_stop: ");
+ #endif
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.operation_code = ATAPI_START_STOP_UNIT;
+ 	cmd.how = how;
+ 	ret = atapi_exec_cmd(ad_link, &cmd, sizeof(cmd), 0,0,0,flags);
+ #ifdef ATAPI_DEBUG_FCTN
+     printf("ret %d\n", ret);
+ #endif
+ 	return ret;
+ }
+ 
+ int
+ atapi_prevent(ad_link, how)
+ struct at_dev_link  *ad_link;
+ int how;
+ {
+ 	struct prevent_allow_medium_removal cmd;
+ 	int ret;
+ 
+ #ifdef ATAPI_DEBUG_FCTN
+ 	printf("atapi_prevent: ");
+ #endif
+ 	bzero(&cmd, sizeof(cmd));
+ 	cmd.operation_code = ATAPI_PREVENT_ALLOW_MEDIUM_REMOVAL;
+ 	cmd.prevent = how;
+ 	ret = atapi_exec_cmd(ad_link, &cmd, sizeof(cmd), 0,0,0,0);
+ #ifdef ATAPI_DEBUG_FCTN
+     printf("ret %d\n", ret);
+ #endif
+ 	return ret;
+ }
+ 
+ int 
+ atapi_error(acp)
+ struct atapi_command_packet* acp;
+ {
+     int flags, error, ret = -1;
+ 	struct at_dev_link *ad_link = acp->ad_link;
+ 	flags = acp->flags & 0xff;
+     error = acp->error;
+ 	at_print_addr(ad_link, acp->flags & 0xff);
+     if (error & ATAPI_MCR) {
+         SILENT_PRINTF(flags,("media change requested"));
+         acp->status = MEDIA_CHANGE;
+     }
+     if (error & ATAPI_ABRT) {      
+         SILENT_PRINTF(flags,("command aborted"));
+         acp->status = ERROR; 
+     }
+     if (error & ATAPI_EOM) {
+         SILENT_PRINTF(flags,("end of media"));
+         acp->status = END_OF_MEDIA;
+     }
+     if (error & ATAPI_ILI) {
+         SILENT_PRINTF(flags,("illegal length indication"));
+         acp->status = ERROR;
+     }
+     if ((error & 0x0f) == 0) {
+         ret=0;
+     }
+     atapi_sense (acp, error >> 4, flags);
+ 	if (!(flags & A_SILENT) && (acp->status != NO_ERROR)) {
+ 		int i;
+ 		printf(", command:");
+ 		for (i=0; i< acp->command_size; i++)
+ 			printf(" %2x", ((u_char*)acp->command)[i]);
+ 	}
+     return ret;
+ }
+ 
+ void
+ atapi_sense(acp, sense_key, flags)
+ struct atapi_command_packet *acp;
+ u_char sense_key;
+ u_char flags;
+ {
+ 	struct at_dev_link *ad_link = acp->ad_link;
+ 
+     switch (sense_key)
+     {
+     case ATAPI_SK_NO_SENSE:
+     break;
+ 
+     case ATAPI_SK_REC_ERROR:
+     SILENT_PRINTF(flags,("recovered error"));
+     acp->status = 0;
+     break;
+ 
+     case ATAPI_SK_NOT_READY:
+     SILENT_PRINTF(flags,("not ready"));
+     acp->status = NOT_READY;
+     break;
+ 
+     case ATAPI_SK_MEDIUM_ERROR:
+     SILENT_PRINTF(flags,("medium error"));
+     acp->status = ERROR;
+     break;
+ 
+     case ATAPI_SK_HARDWARE_ERROR:
+     SILENT_PRINTF(flags,("hardware error"));
+     acp->status = ERROR;
+     break;
+ 
+     case ATAPI_SK_ILLEGAL_REQUEST:
+     SILENT_PRINTF(flags,("illegal request"));
+     acp->status = ERROR;
+     break;
+ 
+     case ATAPI_SK_UNIT_ATTENTION:
+     SILENT_PRINTF(flags,("unit attention"));
+     acp->status = UNIT_ATTENTION;
+ 	if (ad_link->flags & ADEV_REMOVABLE) {  
+ 		ad_link->flags &= ~ADEV_MEDIA_LOADED;
+ 	}   
+     break;
+ 
+     case ATAPI_SK_DATA_PROTECT:
+     SILENT_PRINTF(flags,("data protect"));
+     acp->status = ERROR;
+     break;
+ 
+     case ATAPI_SK_ABORTED_COMMAND:
+     SILENT_PRINTF(flags,("aborted command"));
+     acp->status = RETRY;
+     break;
+ 
+     case ATAPI_SK_MISCOMPARE:
+     SILENT_PRINTF(flags,("miscompare"));
+     acp->status = ERROR;
+     break;
+ 
+     default:
+     SILENT_PRINTF(flags,("unexpected sense key %02x", sense_key));
+     acp->status = ERROR;
+     break;
+     }
+ }
+ 
+ void
+ at_print_addr(ad_link, flags)
+     struct at_dev_link *ad_link; 
+ 	u_char flags;
+ {
+ 	if (flags & A_SILENT) return;
+     printf("%s(%s:%d): ",
+         ad_link->device_softc ?
+         ((struct device *)ad_link->device_softc)->dv_xname : "probe",
+         ((struct device *)ad_link->bus->wdc_softc)->dv_xname,
+         ad_link->drive);
+ }       
diff -c -r -N --exclude exp --exclude compile sys/atapi.orig/atapilink.h sys/atapi/atapilink.h
*** sys/atapi.orig/atapilink.h	Thu Jan  1 01:00:00 1970
--- sys/atapi/atapilink.h	Thu Jun 13 03:19:49 1996
***************
*** 0 ****
--- 1,186 ----
+ /*
+  * Copyright (c) 1996 Manuel Bouyer.  All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  * 3. All advertising materials mentioning features or use of this software
+  *    must display the following acknowledgement:
+  *  This product includes software developed by Manuel Bouyer.
+  * 4. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  */
+ 
+ #undef ATAPI_DEBUG
+ #undef ATAPI_DEBUG_PROBE
+ 
+ struct bus_link {
+     u_int8_t type;  
+ #define DRIVE 0
+ #define BUS 1
+ 	caddr_t wdc_softc;
+ 	caddr_t atapibus_softc;
+ 	struct wdc_link *ctlr_link;
+ 	u_int8_t ctrl;
+ };
+ 
+ struct atapi_identify {
+ 	struct config_s {
+     u_int8_t  packet_size :2;
+ #define ATAPI_PACKET_SIZE_12        0x0
+ #define ATAPI_PACKET_SIZE_16        0x1
+                          /* 1xb reserved */
+     u_int8_t  reserved1   :3;
+     u_int8_t  drq_type    :2;
+ #define ATAPI_MICROPROCESSOR_DRQ    0x0
+ #define ATAPI_INTERRUPT_DRQ     0x1
+ #define ATAPI_ACCELERATED_DRQ       0x2
+                          /* 0x3 reserved */
+     u_int8_t  removable   :1;
+     u_int8_t  device_type :5;
+ #define ATAPI_DEVICE_TYPE_DAD       0x0  /* direct access device, eg magnetic di
+ sk */
+                          /* 0x1-0x4 reserved */
+ #define ATAPI_DEVICE_TYPE_CD        0x5
+                          /* 0x6 reserved */
+ #define ATAPI_DEVICE_TYPE_OMD       0x7  /* optical memory device */
+                          /* 0x8-0x1e reserved */
+ #define ATAPI_DEVICE_TYPE_UNKNOWN   0x1f
+     u_int8_t  reserved2   :1;
+     u_int8_t  protocol_type   :2;
+                          /* 0x0, 0x1 are ATA */
+ #define ATAPI_GC_PROTO_TYPE_ATAPI   0x2
+ #define ATAPI_GC_PROTO_TYPE_RESERVED    0x3
+     } config;                /* general configuration */
+     u_int16_t cylinders;
+     u_int16_t reserved1;
+     u_int16_t heads;
+     u_int16_t unf_bytes_per_track;
+     u_int16_t unf_bytes_per_sector;
+     u_int16_t sectors_per_track;
+     u_int16_t reserved2[3];
+     char    serial_number[20];
+     u_int16_t buffer_type;
+     u_int16_t buffer_size;
+     u_int16_t ECC_bytes_available;
+     char    firmware_revision[8];
+     char    model[40];
+     u_int16_t sector_count;
+     u_int16_t double_word;             /* ==0 for CD-ROMs */
+     struct capabilities_s {
+       u_int8_t    vendor;
+       u_int8_t    dma     :1;      /* DMA supported */
+       u_int8_t    lba     :1;      /* LBA supported */
+       u_int8_t    iordy_disable   :1;      /* IORDY can be disabled */
+       u_int8_t    iordy       :1;      /* IORDY supported */
+       u_int8_t    reserved1   :4;
+     } capabilities;
+     u_int16_t reserved3;
+     u_int16_t PIO_cycle_timing;
+     u_int16_t DMA_cycle_timing;
+     u_int16_t validity;            /* of words 54-58, 64-70 in this table */
+ 
+ #define ATAPI_VALID_FIRST       0x0  /* == 1 => words 54-58 are valid */
+ #define ATAPI_VALID_SECOND      0x1  /* == 1 => words 64-70 are valid */
+ 
+     u_int16_t current_chs[3];          /* cylinder/head/sector */
+     u_int16_t current_capacity[2];
+     u_int16_t reserved4;
+     u_int16_t user_addressable_sectors[2];
+     u_int16_t singleword_DMA_mode;
+ 
+ #define ATAPI_SW_DMA_MODE_AVAIL     0x00ff /* bit 0 set => Mode 0 is supported */
+ #define ATAPI_SW_DMA_MODE_ACTIVE    0xff00 /* which mode is active */
+ 
+     u_int16_t multiword_DMA_mode;
+ 
+ #define ATAPI_MW_DMA_MODE_AVAIL     0x00ff /* bit 0 set => Mode 0 is supported */
+ #define ATAPI_MW_DMA_MODE_ACTIVE    0xff00 /* which mode is active */
+ 
+ 	u_int16_t enhanced_PIO_mode;
+ 
+ #define ATAPI_ENHANCED_PIO_AVAIL    0x0001 /* bit 0 set => PIO Mode 3 is support
+ ed */
+ 
+     u_int16_t blind_PIO_minimum_cycles;
+     u_int16_t mw_dma_tct;          /* multi-word DMA transfer cycle time */
+     u_int16_t min_PIO_tct_no_flow_control;
+     u_int16_t min_PIO_tct_with_flow_control;
+     u_int16_t reserved5[2];
+     u_int16_t reserved6[57];
+     u_int16_t vendor[32];          /* vendor unique */
+     u_int16_t reserved7[96];
+ };
+ 
+ struct at_dev_link {
+ 	void *device_softc;
+ 	u_int8_t drive;
+ 	u_int8_t openings;
+ 	struct atapi_identify id;  
+ 	struct bus_link *bus;
+ 	u_int16_t flags;
+ #define ADEV_REMOVABLE      0x001    /* media is removable */
+ #define ADEV_MEDIA_LOADED   0x002    /* device figures are still valid */  
+ #define ADEV_WAITING        0x004    /* a process is waiting for this */
+ #define ADEV_OPEN           0x008    /* at least 1 open session */
+ #define ACAP_DRQ_MPROC		0x000   /* microprocessor DRQ */
+ #define ACAP_DRQ_INTR		0x100	/* interrupt DRQ */
+ #define ACAP_DRQ_ACCEL		0x200	/* accelerated DRQ */
+ #define ACAP_LEN 			0x400   /* 16 bit commands */
+ 	void (*start)();
+ 	int (*done)();
+ };
+ 
+ struct atapi_command_packet {
+ 	void *ad_link;
+     void *command;
+ 	char cmd_store[16];
+ 	int command_size;
+ 	struct buf* bp; 
+ 	void *databuf;
+ 	int data_size;
+ 	long flags;   /* handle B_READ/B_WRITE mask 0x00f00000 */
+ 				  /* controller flags maks 0x0000000f */
+ 				  /* ATAPI flags mask 0x000000f0 */
+ 				  /* Capabilities flags 0x00000f00 */
+ 	u_int8_t drive;
+ 	u_int16_t status;
+ #define STATUS_MASK 0xff
+ #define NO_ERROR 0x00
+ #define ERROR 0x01
+ #define MEDIA_CHANGE 0x02
+ #define END_OF_MEDIA 0x03
+ #define NOT_READY 0x10
+ #define UNIT_ATTENTION 0x20
+ #define RETRY 0x40
+ #define ITSDONE 0x100
+ 	u_int8_t error;
+ 	u_int8_t retries;
+ #define ATAPI_NRETRIES 5
+ 	LIST_ENTRY(atapi_command_packet) free_list;
+ };
+ 
+ int wdc_atapi_get_params  __P((struct bus_link *,u_int8_t, struct atapi_identify *)); 
+ void wdc_atapi_send_command_packet __P((struct bus_link*, struct atapi_command_packet*));
+ #define A_POLLED 0x10
+ #define A_NOSLEEP 0x20
+ #define A_SILENT 0x40
+ void atapi_done __P((struct atapi_command_packet *));
+ struct atapi_command_packet *atapi_get_pkt __P((struct at_dev_link *, int));
+ void atapi_free_pkt __P((struct atapi_command_packet *));
diff -c -r -N --exclude exp --exclude compile sys/atapi.orig/files.atapi sys/atapi/files.atapi
*** sys/atapi.orig/files.atapi	Thu Jan  1 01:00:00 1970
--- sys/atapi/files.atapi	Thu Jun 13 03:19:50 1996
***************
*** 0 ****
--- 1,14 ----
+ #
+ # Config.new file and device description for machine-independent ATAPI code.
+ # Included by ports that need it.  Ports that usee it must provide
+ # their own "major" declarations for the appropriate devices.
+ 
+ define	atapi {}
+ file	atapi/atapiconf.c			atapi
+ 
+ device	atapibus {drive = -1}
+ attach	atapibus at atapi
+ 
+ device  acd: disk
+ attach  acd at atapibus
+ file    atapi/acd.c           acd needs-flag
