xref: /freebsd/sys/cam/scsi/scsi_cd.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
1 /*
2  * Copyright (c) 1997 Justin T. Gibbs.
3  * Copyright (c) 1997, 1998 Kenneth D. Merry.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer,
11  *    without modification, immediately at the beginning of the file.
12  * 2. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *      $Id$
28  */
29 /*
30  * Portions of this driver taken from the original FreeBSD cd driver.
31  * Written by Julian Elischer (julian@tfs.com)
32  * for TRW Financial Systems for use under the MACH(2.5) operating system.
33  *
34  * TRW Financial Systems, in accordance with their agreement with Carnegie
35  * Mellon University, makes this software available to CMU to distribute
36  * or use in any manner that they see fit as long as this message is kept with
37  * the software. For this reason TFS also grants any other persons or
38  * organisations permission to use or modify this software.
39  *
40  * TFS supplies this software to be publicly redistributed
41  * on the understanding that TFS is not responsible for the correct
42  * functioning of this software in any circumstances.
43  *
44  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
45  *
46  *      from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $
47  */
48 
49 
50 #include <sys/param.h>
51 #include <sys/queue.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
54 #include <sys/types.h>
55 #include <sys/buf.h>
56 #include <sys/dkbad.h>
57 #include <sys/disklabel.h>
58 #include <sys/diskslice.h>
59 #include <sys/malloc.h>
60 #include <sys/fcntl.h>
61 #include <sys/stat.h>
62 #include <sys/conf.h>
63 #include <sys/buf.h>
64 #include <sys/cdio.h>
65 #include <sys/errno.h>
66 #include <sys/devicestat.h>
67 #include <sys/sysctl.h>
68 
69 #include <cam/cam.h>
70 #include <cam/cam_ccb.h>
71 #include <cam/cam_extend.h>
72 #include <cam/cam_periph.h>
73 #include <cam/cam_xpt_periph.h>
74 #include <cam/cam_queue.h>
75 #include <cam/cam_debug.h>
76 
77 #include <cam/scsi/scsi_all.h>
78 #include <cam/scsi/scsi_message.h>
79 #include <cam/scsi/scsi_da.h>
80 #include <cam/scsi/scsi_cd.h>
81 #include "opt_cd.h"
82 
83 #define ESUCCESS 0
84 
85 #define CDUNIT(DEV)	((minor(DEV)&0xF8) >> 3)    /* 5 bit unit */
86 #define CDSETUNIT(DEV, U) makedev(major(DEV), ((U) << 3))
87 #define PARTITION(z)	(minor(z) & 0x07)
88 #define RAW_PART	2
89 #define LEADOUT         0xaa            /* leadout toc entry */
90 
91 struct cd_params {
92 	u_int32_t blksize;
93 	u_long    disksize;
94 };
95 
96 typedef enum {
97 	CD_Q_NONE	= 0x00,
98 	CD_Q_NO_TOUCH	= 0x01,
99 	CD_Q_BCD_TRACKS	= 0x02,
100 	CD_Q_NO_CHANGER	= 0x04,
101 	CD_Q_CHANGER	= 0x08
102 } cd_quirks;
103 
104 typedef enum {
105 	CD_FLAG_INVALID		= 0x001,
106 	CD_FLAG_NEW_DISC	= 0x002,
107 	CD_FLAG_DISC_LOCKED	= 0x004,
108 	CD_FLAG_DISC_REMOVABLE	= 0x008,
109 	CD_FLAG_TAGGED_QUEUING	= 0x010,
110 	CD_FLAG_OPEN		= 0x020,
111 	CD_FLAG_CHANGER		= 0x040,
112 	CD_FLAG_ACTIVE		= 0x080,
113 	CD_FLAG_SCHED_ON_COMP	= 0x100,
114 	CD_FLAG_RETRY_UA	= 0x200
115 } cd_flags;
116 
117 typedef enum {
118 	CD_CCB_PROBE		= 0x01,
119 	CD_CCB_BUFFER_IO	= 0x02,
120 	CD_CCB_WAITING		= 0x03,
121 	CD_CCB_TYPE_MASK	= 0x0F,
122 	CD_CCB_RETRY_UA		= 0x10
123 } cd_ccb_state;
124 
125 typedef enum {
126 	CHANGER_TIMEOUT_SCHED		= 0x01,
127 	CHANGER_SHORT_TMOUT_SCHED	= 0x02,
128 	CHANGER_MANUAL_CALL		= 0x04,
129 	CHANGER_NEED_TIMEOUT		= 0x08
130 } cd_changer_flags;
131 
132 #define ccb_state ppriv_field0
133 #define ccb_bp ppriv_ptr1
134 
135 typedef enum {
136 	CD_STATE_PROBE,
137 	CD_STATE_NORMAL
138 } cd_state;
139 
140 struct cd_softc {
141 	cam_pinfo		pinfo;
142 	cd_state		state;
143 	cd_flags		flags;
144 	struct buf_queue_head	buf_queue;
145 	LIST_HEAD(, ccb_hdr)	pending_ccbs;
146 	struct cd_params	params;
147 	struct disklabel	disklabel;
148 	struct diskslices 	*cd_slices;
149 	union ccb		saved_ccb;
150 	cd_quirks		quirks;
151 	struct devstat		device_stats;
152 	STAILQ_ENTRY(cd_softc)	changer_links;
153 	struct cdchanger	*changer;
154 	int			bufs_left;
155 	struct cam_periph	*periph;
156 #ifdef  DEVFS
157 	void	  *ra_devfs_token;
158 	void	  *rc_devfs_token;
159 	void	  *a_devfs_token;
160 	void	  *c_devfs_token;
161 	void	  *ctl_devfs_token;
162 #endif
163 };
164 
165 struct cd_quirk_entry {
166 	struct scsi_inquiry_pattern inq_pat;
167 	cd_quirks quirks;
168 };
169 
170 /*
171  * These quirk entries aren't strictly necessary.  Basically, what they do
172  * is tell cdregister() up front that a device is a changer.  Otherwise, it
173  * will figure that fact out once it sees a LUN on the device that is
174  * greater than 0.  If it is known up front that a device is a changer, all
175  * I/O to the device will go through the changer scheduling routines, as
176  * opposed to the "normal" CD code.
177  */
178 static struct cd_quirk_entry cd_quirk_table[] =
179 {
180 	{
181 		{ T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"},
182 		 /*quirks*/ CD_Q_CHANGER
183 	},
184 	{
185 		{ T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM-604X",
186 		  "*"}, /* quirks */ CD_Q_CHANGER
187 	}
188 };
189 
190 #ifndef MIN
191 #define MIN(x,y) ((x<y) ? x : y)
192 #endif
193 
194 #define CD_CDEV_MAJOR 15
195 #define CD_BDEV_MAJOR 6
196 
197 static	d_open_t	cdopen;
198 static	d_read_t	cdread;
199 static	d_close_t	cdclose;
200 static	d_ioctl_t	cdioctl;
201 static	d_strategy_t	cdstrategy;
202 
203 static	periph_init_t	cdinit;
204 static	periph_ctor_t	cdregister;
205 static	periph_dtor_t	cdcleanup;
206 static	periph_start_t	cdstart;
207 static	void		cdasync(void *callback_arg, u_int32_t code,
208 				struct cam_path *path, void *arg);
209 static	void		cdshorttimeout(void *arg);
210 static	void		cdschedule(struct cam_periph *periph, int priority);
211 static	void		cdrunchangerqueue(void *arg);
212 static	void		cdchangerschedule(struct cd_softc *softc);
213 static	int		cdrunccb(union ccb *ccb,
214 				 int (*error_routine)(union ccb *ccb,
215 						      u_int32_t cam_flags,
216 						      u_int32_t sense_flags),
217 				 u_int32_t cam_flags, u_int32_t sense_flags);
218 union	ccb 		*cdgetccb(struct cam_periph *periph,
219 				  u_int32_t priority);
220 static	void		cddone(struct cam_periph *periph,
221 			       union ccb *start_ccb);
222 static	int		cderror(union ccb *ccb, u_int32_t cam_flags,
223 				u_int32_t sense_flags);
224 static	void		cdprevent(struct cam_periph *periph, int action);
225 static	int		cdsize(dev_t dev, u_int32_t *size);
226 static	int		cdgetdisklabel (dev_t dev);
227 static	int		cdreadtoc(struct cam_periph *periph, u_int32_t mode,
228 				  u_int32_t start, struct cd_toc_entry *data,
229 				  u_int32_t len);
230 static	int		cdgetmode(struct cam_periph *periph,
231 				  struct cd_mode_data *data, u_int32_t page);
232 static	int		cdsetmode(struct cam_periph *periph,
233 				  struct cd_mode_data *data);
234 static	int		cdplay(struct cam_periph *periph, u_int32_t blk,
235 			       u_int32_t len);
236 static	int		cdreadsubchannel(struct cam_periph *periph,
237 					 u_int32_t mode, u_int32_t format,
238 					 int track,
239 					 struct cd_sub_channel_info *data,
240 					 u_int32_t len);
241 static	int		cdplaymsf(struct cam_periph *periph, u_int32_t startm,
242 				  u_int32_t starts, u_int32_t startf,
243 				  u_int32_t endm, u_int32_t ends,
244 				  u_int32_t endf);
245 static	int		cdplaytracks(struct cam_periph *periph,
246 				     u_int32_t strack, u_int32_t sindex,
247 				     u_int32_t etrack, u_int32_t eindex);
248 static	int		cdpause(struct cam_periph *periph, u_int32_t go);
249 static	int		cdstopunit(struct cam_periph *periph, u_int32_t eject);
250 static	int		cdstartunit(struct cam_periph *periph);
251 
252 static struct periph_driver cddriver =
253 {
254 	cdinit, "cd",
255 	TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0
256 };
257 
258 DATA_SET(periphdriver_set, cddriver);
259 
260 /* For 2.2-stable support */
261 #ifndef D_DISK
262 #define D_DISK 0
263 #endif
264 static struct cdevsw cd_cdevsw =
265 {
266 	/*d_open*/	cdopen,
267 	/*d_close*/	cdclose,
268 	/*d_read*/	cdread,
269 	/*d_write*/	nowrite,
270 	/*d_ioctl*/	cdioctl,
271 	/*d_stop*/	nostop,
272 	/*d_reset*/	noreset,
273 	/*d_devtotty*/	nodevtotty,
274 	/*d_poll*/	seltrue,
275 	/*d_mmap*/	nommap,
276 	/*d_strategy*/	cdstrategy,
277 	/*d_name*/	"cd",
278 	/*d_spare*/	NULL,
279 	/*d_maj*/	-1,
280 	/*d_dump*/	nodump,
281 	/*d_psize*/	nopsize,
282 	/*d_flags*/	D_DISK,
283 	/*d_maxio*/	0,
284 	/*b_maj*/	-1
285 };
286 
287 static struct extend_array *cdperiphs;
288 static int num_changers;
289 
290 #ifndef CHANGER_MIN_BUSY_SECONDS
291 #define CHANGER_MIN_BUSY_SECONDS	2
292 #endif
293 #ifndef CHANGER_MAX_BUSY_SECONDS
294 #define CHANGER_MAX_BUSY_SECONDS	10
295 #endif
296 
297 static int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS;
298 static int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS;
299 
300 /*
301  * XXX KDM this CAM node should be moved if we ever get more CAM sysctl
302  * variables.
303  */
304 SYSCTL_NODE(_kern, OID_AUTO, cam, CTLFLAG_RD, 0, "CAM Subsystem");
305 SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver");
306 SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer");
307 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW,
308 	   &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum");
309 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW,
310 	   &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum");
311 
312 struct cdchanger {
313 	path_id_t			 path_id;
314 	target_id_t			 target_id;
315 	int				 num_devices;
316 	struct camq			 devq;
317 	struct timeval			 start_time;
318 	struct cd_softc			 *cur_device;
319 	struct callout_handle		 short_handle;
320 	struct callout_handle		 long_handle;
321 	cd_changer_flags		 flags;
322 	STAILQ_ENTRY(cdchanger)		 changer_links;
323 	STAILQ_HEAD(chdevlist, cd_softc) chluns;
324 };
325 
326 STAILQ_HEAD(changerlist, cdchanger) changerq;
327 
328 void
329 cdinit(void)
330 {
331 	cam_status status;
332 	struct cam_path *path;
333 
334 	/*
335 	 * Create our extend array for storing the devices we attach to.
336 	 */
337 	cdperiphs = cam_extend_new();
338 	if (cdperiphs == NULL) {
339 		printf("cd: Failed to alloc extend array!\n");
340 		return;
341 	}
342 
343 	/*
344 	 * Install a global async callback.  This callback will
345 	 * receive async callbacks like "new device found".
346 	 */
347 	status = xpt_create_path(&path, /*periph*/NULL, CAM_XPT_PATH_ID,
348 				 CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD);
349 
350 	if (status == CAM_REQ_CMP) {
351 		struct ccb_setasync csa;
352 
353                 xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
354                 csa.ccb_h.func_code = XPT_SASYNC_CB;
355                 csa.event_enable = AC_FOUND_DEVICE;
356                 csa.callback = cdasync;
357                 csa.callback_arg = NULL;
358                 xpt_action((union ccb *)&csa);
359 		status = csa.ccb_h.status;
360                 xpt_free_path(path);
361         }
362 
363 	if (status != CAM_REQ_CMP) {
364 		printf("cd: Failed to attach master async callback "
365 		       "due to status 0x%x!\n", status);
366 	} else {
367 		/* If we were successfull, register our devsw */
368 		cdevsw_add_generic(CD_BDEV_MAJOR, CD_CDEV_MAJOR, &cd_cdevsw);
369 	}
370 }
371 
372 static void
373 cdcleanup(struct cam_periph *periph)
374 {
375 	struct cd_softc *softc;
376 
377 	softc = (struct cd_softc *)periph->softc;
378 
379 	xpt_print_path(periph->path);
380 	printf("removing device entry\n");
381 	/*
382 	 * In the queued, non-active case, the device in question
383 	 * has already been removed from the changer run queue.  Since this
384 	 * device is active, we need to de-activate it, and schedule
385 	 * another device to run.  (if there is another one to run)
386 	 */
387 	if ((softc->flags & CD_FLAG_CHANGER)
388 	 && (softc->flags & CD_FLAG_ACTIVE)) {
389 
390 		/*
391 		 * The purpose of the short timeout is soley to determine
392 		 * whether the current device has finished or not.  Well,
393 		 * since we're removing the active device, we know that it
394 		 * is finished.  So, get rid of the short timeout.
395 		 * Otherwise, if we're in the time period before the short
396 		 * timeout fires, and there are no other devices in the
397 		 * queue to run, there won't be any other device put in the
398 		 * active slot.  i.e., when we call cdrunchangerqueue()
399 		 * below, it won't do anything.  Then, when the short
400 		 * timeout fires, it'll look at the "current device", which
401 		 * we are free below, and possibly panic the kernel on a
402 		 * bogus pointer reference.
403 		 *
404 		 * The long timeout doesn't really matter, since we
405 		 * decrement the qfrozen_cnt to indicate that there is
406 		 * nothing in the active slot now.  Therefore, there won't
407 		 * be any bogus pointer references there.
408 		 */
409 		if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
410 			untimeout(cdshorttimeout, softc->changer,
411 				  softc->changer->short_handle);
412 			softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
413 		}
414 		softc->changer->devq.qfrozen_cnt--;
415 		softc->changer->flags |= CHANGER_MANUAL_CALL;
416 		cdrunchangerqueue(softc->changer);
417 	}
418 
419 	/*
420 	 * If we're removing the last device on the changer, go ahead and
421 	 * remove the changer device structure.
422 	 */
423 	if ((softc->flags & CD_FLAG_CHANGER)
424 	 && (--softc->changer->num_devices == 0)) {
425 
426 		/*
427 		 * Theoretically, there shouldn't be any timeouts left, but
428 		 * I'm not completely sure that that will be the case.  So,
429 		 * it won't hurt to check and see if there are any left.
430 		 */
431 		if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) {
432 			untimeout(cdrunchangerqueue, softc->changer,
433 				  softc->changer->long_handle);
434 			softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED;
435 		}
436 
437 		if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
438 			untimeout(cdshorttimeout, softc->changer,
439 				  softc->changer->short_handle);
440 			softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
441 		}
442 
443 		STAILQ_REMOVE(&changerq, softc->changer, cdchanger,
444 			      changer_links);
445 		xpt_print_path(periph->path);
446 		printf("removing changer entry\n");
447 		free(softc->changer, M_DEVBUF);
448 		num_changers--;
449 	}
450 	cam_extend_release(cdperiphs, periph->unit_number);
451 	free(periph->softc, M_DEVBUF);
452 }
453 
454 static void
455 cdasync(void *callback_arg, u_int32_t code,
456 	struct cam_path *path, void *arg)
457 {
458 	struct cam_periph *periph;
459 
460 	periph = (struct cam_periph *)callback_arg;
461 	switch (code) {
462 	case AC_FOUND_DEVICE:
463 	{
464 		struct ccb_getdev *cgd;
465 		cam_status status;
466 
467 		cgd = (struct ccb_getdev *)arg;
468 
469 		if ((cgd->pd_type != T_CDROM) && (cgd->pd_type != T_WORM))
470 			break;
471 
472 		/*
473 		 * Allocate a peripheral instance for
474 		 * this device and start the probe
475 		 * process.
476 		 */
477 		status = cam_periph_alloc(cdregister, cdcleanup, cdstart,
478 					  "cd", CAM_PERIPH_BIO, cgd->ccb_h.path,
479 					  cdasync, AC_FOUND_DEVICE, cgd);
480 
481 		if (status != CAM_REQ_CMP
482 		 && status != CAM_REQ_INPROG)
483 			printf("cdasync: Unable to attach new device "
484 			       "due to status 0x%x\n", status);
485 
486 		break;
487 	}
488 	case AC_LOST_DEVICE:
489 	{
490 		int s;
491 		struct cd_softc *softc;
492 		struct buf *q_bp;
493 		struct ccb_setasync csa;
494 
495 		softc = (struct cd_softc *)periph->softc;
496 
497 		/*
498 		 * Insure that no other async callbacks that
499 		 * might affect this peripheral can come through.
500 		 */
501 		s = splcam();
502 
503 		/*
504 		 * De-register any async callbacks.
505 		 */
506 		xpt_setup_ccb(&csa.ccb_h, periph->path,
507 			      /* priority */ 5);
508 		csa.ccb_h.func_code = XPT_SASYNC_CB;
509 		csa.event_enable = 0;
510 		csa.callback = cdasync;
511 		csa.callback_arg = periph;
512 		xpt_action((union ccb *)&csa);
513 
514 		softc->flags |= CD_FLAG_INVALID;
515 
516 		/*
517 		 * Return all queued I/O with ENXIO.
518 		 * XXX Handle any transactions queued to the card
519 		 *     with XPT_ABORT_CCB.
520 		 */
521 		while ((q_bp = bufq_first(&softc->buf_queue)) != NULL){
522 			bufq_remove(&softc->buf_queue, q_bp);
523 			q_bp->b_resid = q_bp->b_bcount;
524 			q_bp->b_error = ENXIO;
525 			q_bp->b_flags |= B_ERROR;
526 			biodone(q_bp);
527 		}
528 
529 		/*
530 		 * If this device is part of a changer, and it was scheduled
531 		 * to run, remove it from the run queue since we just nuked
532 		 * all of its scheduled I/O.
533 		 */
534 		if ((softc->flags & CD_FLAG_CHANGER)
535 		 && (softc->pinfo.index != CAM_UNQUEUED_INDEX))
536 			camq_remove(&softc->changer->devq, softc->pinfo.index);
537 
538 		devstat_remove_entry(&softc->device_stats);
539 
540 		xpt_print_path(periph->path);
541 		printf("lost device\n");
542 
543 		splx(s);
544 
545 		cam_periph_invalidate(periph);
546 		break;
547 	}
548 	case AC_SENT_BDR:
549 	case AC_BUS_RESET:
550 	{
551 		struct cd_softc *softc;
552 		struct ccb_hdr *ccbh;
553 		int s;
554 
555 		softc = (struct cd_softc *)periph->softc;
556 		s = splsoftcam();
557 		/*
558 		 * Don't fail on the expected unit attention
559 		 * that will occur.
560 		 */
561 		softc->flags |= CD_FLAG_RETRY_UA;
562 		for (ccbh = LIST_FIRST(&softc->pending_ccbs);
563 		     ccbh != NULL; ccbh = LIST_NEXT(ccbh, periph_links.le))
564 			ccbh->ccb_state |= CD_CCB_RETRY_UA;
565 		splx(s);
566 		break;
567 	}
568 	case AC_TRANSFER_NEG:
569 	case AC_SCSI_AEN:
570 	case AC_UNSOL_RESEL:
571 	default:
572 		break;
573 	}
574 }
575 
576 static cam_status
577 cdregister(struct cam_periph *periph, void *arg)
578 {
579 	int s;
580 	struct cd_softc *softc;
581 	struct ccb_setasync csa;
582 	struct ccb_getdev *cgd;
583 	caddr_t match;
584 
585 	cgd = (struct ccb_getdev *)arg;
586 	if (periph == NULL) {
587 		printf("cdregister: periph was NULL!!\n");
588 		return(CAM_REQ_CMP_ERR);
589 	}
590 	if (cgd == NULL) {
591 		printf("cdregister: no getdev CCB, can't register device\n");
592 		return(CAM_REQ_CMP_ERR);
593 	}
594 
595 	softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
596 
597 	if (softc == NULL) {
598 		printf("cdregister: Unable to probe new device. "
599 		       "Unable to allocate softc\n");
600 		return(CAM_REQ_CMP_ERR);
601 	}
602 
603 	bzero(softc, sizeof(*softc));
604 	LIST_INIT(&softc->pending_ccbs);
605 	softc->state = CD_STATE_PROBE;
606 	bufq_init(&softc->buf_queue);
607 	if (SID_IS_REMOVABLE(&cgd->inq_data))
608 		softc->flags |= CD_FLAG_DISC_REMOVABLE;
609 	if ((cgd->inq_data.flags & SID_CmdQue) != 0)
610 		softc->flags |= CD_FLAG_TAGGED_QUEUING;
611 
612 	periph->softc = softc;
613 	softc->periph = periph;
614 
615 	cam_extend_set(cdperiphs, periph->unit_number, periph);
616 
617 	/*
618 	 * See if this device has any quirks.
619 	 */
620 	match = cam_quirkmatch((caddr_t)&cgd->inq_data,
621 			       (caddr_t)cd_quirk_table,
622 			       sizeof(cd_quirk_table)/sizeof(*cd_quirk_table),
623 			       sizeof(*cd_quirk_table), scsi_inquiry_match);
624 
625 	if (match != NULL)
626 		softc->quirks = ((struct cd_quirk_entry *)match)->quirks;
627 	else
628 		softc->quirks = CD_Q_NONE;
629 
630 	/*
631 	 * We need to register the statistics structure for this device,
632 	 * but we don't have the blocksize yet for it.  So, we register
633 	 * the structure and indicate that we don't have the blocksize
634 	 * yet.  Unlike other SCSI peripheral drivers, we explicitly set
635 	 * the device type here to be CDROM, rather than just ORing in
636 	 * cgd->pd_type.  This is because this driver can attach to either
637 	 * CDROM or WORM devices, and we want this peripheral driver to
638 	 * show up in the devstat list as a CD peripheral driver, not a
639 	 * WORM peripheral driver.  WORM drives will also have the WORM
640 	 * driver attached to them.
641 	 */
642 	devstat_add_entry(&softc->device_stats, "cd",
643 			  periph->unit_number, 0,
644 	  		  DEVSTAT_BS_UNAVAILABLE,
645 			  DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI);
646 
647 	/*
648 	 * Add an async callback so that we get
649 	 * notified if this device goes away.
650 	 */
651 	xpt_setup_ccb(&csa.ccb_h, periph->path,
652 		      /* priority */ 5);
653 	csa.ccb_h.func_code = XPT_SASYNC_CB;
654 	csa.event_enable = AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE;
655 	csa.callback = cdasync;
656 	csa.callback_arg = periph;
657 	xpt_action((union ccb *)&csa);
658 
659 	/*
660 	 * If the target lun is greater than 0, we most likely have a CD
661 	 * changer device.  Check the quirk entries as well, though, just
662 	 * in case someone has a CD tower with one lun per drive or
663 	 * something like that.  Also, if we know up front that a
664 	 * particular device is a changer, we can mark it as such starting
665 	 * with lun 0, instead of lun 1.  It shouldn't be necessary to have
666 	 * a quirk entry to define something as a changer, however.
667 	 */
668 	if (((cgd->ccb_h.target_lun > 0)
669 	  && ((softc->quirks & CD_Q_NO_CHANGER) == 0))
670 	 || ((softc->quirks & CD_Q_CHANGER) != 0)) {
671 		struct cdchanger *nchanger;
672 		struct cam_periph *nperiph;
673 		struct cam_path *path;
674 		cam_status status;
675 		int found;
676 
677 		/* Set the changer flag in the current device's softc */
678 		softc->flags |= CD_FLAG_CHANGER;
679 
680 		if (num_changers == 0)
681 			STAILQ_INIT(&changerq);
682 
683 		/*
684 		 * Now, look around for an existing changer device with the
685 		 * same path and target ID as the current device.
686 		 */
687 		for (found = 0,
688 		     nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq);
689 		     nchanger != NULL;
690 		     nchanger = STAILQ_NEXT(nchanger, changer_links)){
691 			if ((nchanger->path_id == cgd->ccb_h.path_id)
692 			 && (nchanger->target_id == cgd->ccb_h.target_id)) {
693 				found = 1;
694 				break;
695 			}
696 		}
697 
698 		/*
699 		 * If we found a matching entry, just add this device to
700 		 * the list of devices on this changer.
701 		 */
702 		if (found == 1) {
703 			struct chdevlist *chlunhead;
704 
705 			chlunhead = &nchanger->chluns;
706 
707 			/*
708 			 * XXX KDM look at consolidating this code with the
709 			 * code below in a separate function.
710 			 */
711 
712 			/*
713 			 * Create a path with lun id 0, and see if we can
714 			 * find a matching device
715 			 */
716 			status = xpt_create_path(&path, /*periph*/ periph,
717 						 cgd->ccb_h.path_id,
718 						 cgd->ccb_h.target_id, 0);
719 
720 			if ((status == CAM_REQ_CMP)
721 			 && ((nperiph = cam_periph_find(path, "cd")) != NULL)){
722 				struct cd_softc *nsoftc;
723 
724 				nsoftc = (struct cd_softc *)nperiph->softc;
725 
726 				if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){
727 					nsoftc->flags |= CD_FLAG_CHANGER;
728 					nchanger->num_devices++;
729 					if (camq_resize(&nchanger->devq,
730 					   nchanger->num_devices)!=CAM_REQ_CMP){
731 						printf("cdregister: "
732 						       "camq_resize "
733 						       "failed, changer "
734 						       "support may "
735 						       "be messed up\n");
736 					}
737 					nsoftc->changer = nchanger;
738 					nsoftc->pinfo.index =CAM_UNQUEUED_INDEX;
739 
740 					STAILQ_INSERT_TAIL(&nchanger->chluns,
741 							  nsoftc,changer_links);
742 				}
743 			} else if (status == CAM_REQ_CMP)
744 				xpt_free_path(path);
745 			else {
746 				printf("cdregister: unable to allocate path\n"
747 				       "cdregister: changer support may be "
748 				       "broken\n");
749 			}
750 
751 			nchanger->num_devices++;
752 
753 			softc->changer = nchanger;
754 			softc->pinfo.index = CAM_UNQUEUED_INDEX;
755 
756 			if (camq_resize(&nchanger->devq,
757 			    nchanger->num_devices) != CAM_REQ_CMP) {
758 				printf("cdregister: camq_resize "
759 				       "failed, changer support may "
760 				       "be messed up\n");
761 			}
762 
763 			STAILQ_INSERT_TAIL(chlunhead, softc, changer_links);
764 		}
765 		/*
766 		 * In this case, we don't already have an entry for this
767 		 * particular changer, so we need to create one, add it to
768 		 * the queue, and queue this device on the list for this
769 		 * changer.  Before we queue this device, however, we need
770 		 * to search for lun id 0 on this target, and add it to the
771 		 * queue first, if it exists.  (and if it hasn't already
772 		 * been marked as part of the changer.)
773 		 */
774 		else {
775 			nchanger = malloc(sizeof(struct cdchanger),
776 				M_DEVBUF, M_NOWAIT);
777 
778 			if (nchanger == NULL) {
779 				softc->flags &= ~CD_FLAG_CHANGER;
780 				printf("cdregister: unable to malloc "
781 				       "changer structure\ncdregister: "
782 				       "changer support disabled\n");
783 
784 				/*
785 				 * Yes, gotos can be gross but in this case
786 				 * I think it's justified..
787 				 */
788 				goto cdregisterexit;
789 			}
790 
791 			/* zero the structure */
792 			bzero(nchanger, sizeof(struct cdchanger));
793 
794 			if (camq_init(&nchanger->devq, 1) != 0) {
795 				softc->flags &= ~CD_FLAG_CHANGER;
796 				printf("cdregister: changer support "
797 				       "disabled\n");
798 				goto cdregisterexit;
799 			}
800 
801 			num_changers++;
802 
803 			nchanger->path_id = cgd->ccb_h.path_id;
804 			nchanger->target_id = cgd->ccb_h.target_id;
805 
806 			/* this is superfluous, but it makes things clearer */
807 			nchanger->num_devices = 0;
808 
809 			STAILQ_INIT(&nchanger->chluns);
810 
811 			STAILQ_INSERT_TAIL(&changerq, nchanger,
812 					   changer_links);
813 
814 			/*
815 			 * Create a path with lun id 0, and see if we can
816 			 * find a matching device
817 			 */
818 			status = xpt_create_path(&path, /*periph*/ periph,
819 						 cgd->ccb_h.path_id,
820 						 cgd->ccb_h.target_id, 0);
821 
822 			/*
823 			 * If we were able to allocate the path, and if we
824 			 * find a matching device and it isn't already
825 			 * marked as part of a changer, then we add it to
826 			 * the current changer.
827 			 */
828 			if ((status == CAM_REQ_CMP)
829 			 && ((nperiph = cam_periph_find(path, "cd")) != NULL)
830 			 && ((((struct cd_softc *)periph->softc)->flags &
831 			       CD_FLAG_CHANGER) == 0)) {
832 				struct cd_softc *nsoftc;
833 
834 				nsoftc = (struct cd_softc *)nperiph->softc;
835 
836 				nsoftc->flags |= CD_FLAG_CHANGER;
837 				nchanger->num_devices++;
838 				if (camq_resize(&nchanger->devq,
839 				    nchanger->num_devices) != CAM_REQ_CMP) {
840 					printf("cdregister: camq_resize "
841 					       "failed, changer support may "
842 					       "be messed up\n");
843 				}
844 				nsoftc->changer = nchanger;
845 				nsoftc->pinfo.index = CAM_UNQUEUED_INDEX;
846 
847 				STAILQ_INSERT_TAIL(&nchanger->chluns,
848 						   nsoftc, changer_links);
849 			} else if (status == CAM_REQ_CMP)
850 				xpt_free_path(path);
851 			else {
852 				printf("cdregister: unable to allocate path\n"
853 				       "cdregister: changer support may be "
854 				       "broken\n");
855 			}
856 
857 			softc->changer = nchanger;
858 			softc->pinfo.index = CAM_UNQUEUED_INDEX;
859 			nchanger->num_devices++;
860 			if (camq_resize(&nchanger->devq,
861 			    nchanger->num_devices) != CAM_REQ_CMP) {
862 				printf("cdregister: camq_resize "
863 				       "failed, changer support may "
864 				       "be messed up\n");
865 			}
866 			STAILQ_INSERT_TAIL(&nchanger->chluns, softc,
867 					   changer_links);
868 		}
869 	}
870 
871 cdregisterexit:
872 
873 	/* Lock this peripheral until we are setup */
874 	/* Can't block */
875 	cam_periph_lock(periph, PRIBIO);
876 
877 	if ((softc->flags & CD_FLAG_CHANGER) == 0)
878 		xpt_schedule(periph, /*priority*/5);
879 	else
880 		cdschedule(periph, /*priority*/ 5);
881 
882 	return(CAM_REQ_CMP);
883 }
884 
885 static int
886 cdopen(dev_t dev, int flags, int fmt, struct proc *p)
887 {
888 	struct cam_periph *periph;
889 	struct cd_softc *softc;
890 	u_int32_t size;
891 	int unit, error;
892 
893 	error = 0; /* default to no error */
894 
895 	unit = dkunit(dev);
896 	periph = cam_extend_get(cdperiphs, unit);
897 
898 	if (periph == NULL)
899 		return (ENXIO);
900 
901 	softc = (struct cd_softc *)periph->softc;
902 
903 	if (softc->flags & CD_FLAG_INVALID)
904 		return(ENXIO);
905 
906 	if ((error = cam_periph_lock(periph, PRIBIO | PCATCH)) != 0)
907 		return (error);
908 
909 	if ((softc->flags & CD_FLAG_OPEN) == 0) {
910 		if (cam_periph_acquire(periph) != CAM_REQ_CMP)
911 			return(ENXIO);
912 		softc->flags |= CD_FLAG_OPEN;
913 	}
914 
915 	/* lock the cd */
916 	cdprevent(periph, PR_PREVENT);
917 
918 	/* find out the size */
919 	if ((error = cdsize(dev, &size)) != 0) {
920 		cdprevent(periph, PR_ALLOW);
921 		softc->flags &= ~CD_FLAG_OPEN;
922 		cam_periph_unlock(periph);
923 		cam_periph_release(periph);
924 		return(error);
925 	}
926 
927 	/* get a disklabel */
928 	if ((error = cdgetdisklabel(dev)) != 0) {
929 		printf("error getting disklabel\n");
930 		cdprevent(periph, PR_ALLOW);
931 		softc->flags &= ~CD_FLAG_OPEN;
932 		cam_periph_unlock(periph);
933 		cam_periph_release(periph);
934 		return(error);
935 	}
936 
937 	if (error == 0) {
938 		/* Initialize slice tables. */
939 		error = dsopen("cd", dev, fmt, DSO_NOLABELS | DSO_ONESLICE,
940 			       &softc->cd_slices, &softc->disklabel,
941 			       cdstrategy, (ds_setgeom_t *)NULL, &cd_cdevsw);
942 
943 		/*
944 		 * We unconditionally (re)set the blocksize each time the
945 		 * CD device is opened.  This is because the CD can change,
946 		 * and therefore the blocksize might change.
947 		 */
948 		if ((softc->device_stats.flags & DEVSTAT_BS_UNAVAILABLE) != 0)
949 			softc->device_stats.flags &= ~DEVSTAT_BS_UNAVAILABLE;
950 		softc->device_stats.block_size = softc->params.blksize;
951 	} else {
952 		if ((dsisopen(softc->cd_slices) == 0)
953 		 && ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0))
954 			cdprevent(periph, PR_ALLOW);
955 	}
956 
957 	cam_periph_unlock(periph);
958 
959 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
960 
961 	return (error);
962 }
963 
964 static int
965 cdclose(dev_t dev, int flag, int fmt, struct proc *p)
966 {
967 	struct 	cam_periph *periph;
968 	struct	cd_softc *softc;
969 	int	unit, error;
970 
971 	unit = dkunit(dev);
972 	periph = cam_extend_get(cdperiphs, unit);
973 	if (periph == NULL)
974 		return (ENXIO);
975 
976 	softc = (struct cd_softc *)periph->softc;
977 
978 	if ((error = cam_periph_lock(periph, PRIBIO)) != 0)
979 		return (error);
980 
981 	dsclose(dev, fmt, softc->cd_slices);
982 
983 	if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)
984 		cdprevent(periph, PR_ALLOW);
985 
986 	/*
987 	 * Since we're closing this CD, mark the blocksize as unavailable.
988 	 * It will be marked as available whence the CD is opened again.
989 	 */
990 	softc->device_stats.flags |= DEVSTAT_BS_UNAVAILABLE;
991 
992 	softc->flags &= ~CD_FLAG_OPEN;
993 	cam_periph_unlock(periph);
994 	cam_periph_release(periph);
995 
996 	return (0);
997 }
998 
999 static int
1000 cdread(dev_t dev, struct uio *uio, int ioflag)
1001 {
1002 	return(physio(cdstrategy, NULL, dev, 1, minphys, uio));
1003 }
1004 
1005 static void
1006 cdshorttimeout(void *arg)
1007 {
1008 	struct cdchanger *changer;
1009 	int s;
1010 
1011 	s = splsoftcam();
1012 
1013 	changer = (struct cdchanger *)arg;
1014 
1015 	/* Always clear the short timeout flag, since that's what we're in */
1016 	changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
1017 
1018 	/*
1019 	 * Check to see if there is any more pending or outstanding I/O for
1020 	 * this device.  If not, move it out of the active slot.
1021 	 */
1022 	if ((bufq_first(&changer->cur_device->buf_queue) == NULL)
1023 	 && (changer->cur_device->device_stats.busy_count == 0)) {
1024 		changer->flags |= CHANGER_MANUAL_CALL;
1025 		cdrunchangerqueue(changer);
1026 	}
1027 
1028 	splx(s);
1029 }
1030 
1031 /*
1032  * This is a wrapper for xpt_schedule.  It only applies to changers.
1033  */
1034 static void
1035 cdschedule(struct cam_periph *periph, int priority)
1036 {
1037 	struct cd_softc *softc;
1038 	int s;
1039 
1040 	s = splsoftcam();
1041 
1042 	softc = (struct cd_softc *)periph->softc;
1043 
1044 	/*
1045 	 * If this device isn't currently queued, and if it isn't
1046 	 * the active device, then we queue this device and run the
1047 	 * changer queue if there is no timeout scheduled to do it.
1048 	 * If this device is the active device, just schedule it
1049 	 * to run again.  If this device is queued, there should be
1050 	 * a timeout in place already that will make sure it runs.
1051 	 */
1052 	if ((softc->pinfo.index == CAM_UNQUEUED_INDEX)
1053 	 && ((softc->flags & CD_FLAG_ACTIVE) == 0)) {
1054 		/*
1055 		 * We don't do anything with the priority here.
1056 		 * This is strictly a fifo queue.
1057 		 */
1058 		softc->pinfo.priority = 1;
1059 		if (softc->changer->devq.generation++ == 0)
1060 			camq_regen(&softc->changer->devq);
1061 		softc->pinfo.generation =
1062 			softc->changer->devq.generation;
1063 		camq_insert(&softc->changer->devq, (cam_pinfo *)softc);
1064 
1065 		/*
1066 		 * Since we just put a device in the changer queue,
1067 		 * check and see if there is a timeout scheduled for
1068 		 * this changer.  If so, let the timeout handle
1069 		 * switching this device into the active slot.  If
1070 		 * not, manually call the timeout routine to
1071 		 * bootstrap things.
1072 		 */
1073 		if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0)
1074 		 &&((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0)){
1075 			softc->changer->flags |= CHANGER_MANUAL_CALL;
1076 			cdrunchangerqueue(softc->changer);
1077 		}
1078 	} else if ((softc->flags & CD_FLAG_ACTIVE)
1079 		&& ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0))
1080 		xpt_schedule(periph, priority);
1081 
1082 	splx(s);
1083 
1084 }
1085 
1086 static void
1087 cdrunchangerqueue(void *arg)
1088 {
1089 	struct timeval cur_time, busy_time;
1090 	struct cd_softc *softc;
1091 	struct cdchanger *changer;
1092 	int called_from_timeout;
1093 	int s;
1094 
1095 	s = splsoftcam();
1096 
1097 	changer = (struct cdchanger *)arg;
1098 
1099 	/*
1100 	 * If we have NOT been called from cdstrategy() or cddone(), and
1101 	 * instead from a timeout routine, go ahead and clear the
1102 	 * timeout flag.
1103 	 */
1104 	if ((changer->flags & CHANGER_MANUAL_CALL) == 0) {
1105 		changer->flags &= ~CHANGER_TIMEOUT_SCHED;
1106 		called_from_timeout = 1;
1107 	} else
1108 		called_from_timeout = 0;
1109 
1110 	/* Always clear the manual call flag */
1111 	changer->flags &= ~CHANGER_MANUAL_CALL;
1112 
1113 	/* nothing to do if the queue is empty */
1114 	if (changer->devq.entries <= 0) {
1115 		splx(s);
1116 		return;
1117 	}
1118 
1119 	/*
1120 	 * If the changer queue is frozen, that means we have an active
1121 	 * device.
1122 	 */
1123 	if (changer->devq.qfrozen_cnt > 0) {
1124 
1125 		if (changer->cur_device->device_stats.busy_count > 0) {
1126 			changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP;
1127 			changer->cur_device->bufs_left =
1128 				changer->cur_device->device_stats.busy_count;
1129 			if (called_from_timeout) {
1130 				changer->long_handle =
1131 					timeout(cdrunchangerqueue, changer,
1132 				        changer_max_busy_seconds * hz);
1133 				changer->flags |= CHANGER_TIMEOUT_SCHED;
1134 			}
1135 			splx(s);
1136 			return;
1137 		}
1138 
1139 		/*
1140 		 * We always need to reset the frozen count and clear the
1141 		 * active flag.
1142 		 */
1143 		changer->devq.qfrozen_cnt--;
1144 		changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
1145 		changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
1146 
1147 		/*
1148 		 * Check to see whether the current device has any I/O left
1149 		 * to do.  If so, requeue it at the end of the queue.  If
1150 		 * not, there is no need to requeue it.
1151 		 */
1152 		if (bufq_first(&changer->cur_device->buf_queue) != NULL) {
1153 
1154 			if (changer->devq.generation++ == 0)
1155 				camq_regen(&changer->devq);
1156 
1157 			changer->cur_device->pinfo.generation =
1158 				changer->devq.generation;
1159 			camq_insert(&changer->devq,
1160 				(cam_pinfo *)changer->cur_device);
1161 		}
1162 	}
1163 
1164 	softc = (struct cd_softc *)camq_remove(&changer->devq, 0);
1165 
1166 	changer->cur_device = softc;
1167 
1168 	changer->devq.qfrozen_cnt++;
1169 	softc->flags |= CD_FLAG_ACTIVE;
1170 
1171 	/* Just in case this device is waiting */
1172 	wakeup(&softc->changer);
1173 	xpt_schedule(softc->periph, /*priority*/ 1);
1174 
1175 	/*
1176 	 * Get rid of any pending timeouts, and set a flag to schedule new
1177 	 * ones so this device gets its full time quantum.
1178 	 */
1179 	if (changer->flags & CHANGER_TIMEOUT_SCHED) {
1180 		untimeout(cdrunchangerqueue, changer, changer->long_handle);
1181 		changer->flags &= ~CHANGER_TIMEOUT_SCHED;
1182 	}
1183 
1184 	if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
1185 		untimeout(cdshorttimeout, changer, changer->short_handle);
1186 		changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
1187 	}
1188 
1189 	/*
1190 	 * We need to schedule timeouts, but we only do this after the
1191 	 * first transaction has completed.  This eliminates the changer
1192 	 * switch time.
1193 	 */
1194 	changer->flags |= CHANGER_NEED_TIMEOUT;
1195 
1196 	splx(s);
1197 }
1198 
1199 static void
1200 cdchangerschedule(struct cd_softc *softc)
1201 {
1202 	struct cdchanger *changer;
1203 	int s;
1204 
1205 	s = splsoftcam();
1206 
1207 	changer = softc->changer;
1208 
1209 	/*
1210 	 * If this is a changer, and this is the current device,
1211 	 * and this device has at least the minimum time quantum to
1212 	 * run, see if we can switch it out.
1213 	 */
1214 	if ((softc->flags & CD_FLAG_ACTIVE)
1215 	 && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0)
1216 	 && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) {
1217 		/*
1218 		 * We try three things here.  The first is that we
1219 		 * check to see whether the schedule on completion
1220 		 * flag is set.  If it is, we decrement the number
1221 		 * of buffers left, and if it's zero, we reschedule.
1222 		 * Next, we check to see whether the pending buffer
1223 		 * queue is empty and whether there are no
1224 		 * outstanding transactions.  If so, we reschedule.
1225 		 * Next, we see if the pending buffer queue is empty.
1226 		 * If it is, we set the number of buffers left to
1227 		 * the current active buffer count and set the
1228 		 * schedule on complete flag.
1229 		 */
1230 		if (softc->flags & CD_FLAG_SCHED_ON_COMP) {
1231 		 	if (--softc->bufs_left == 0) {
1232 				softc->changer->flags |=
1233 					CHANGER_MANUAL_CALL;
1234 				softc->flags &= ~CD_FLAG_SCHED_ON_COMP;
1235 				cdrunchangerqueue(softc->changer);
1236 			}
1237 		} else if ((bufq_first(&softc->buf_queue) == NULL)
1238 		        && (softc->device_stats.busy_count == 0)) {
1239 			softc->changer->flags |= CHANGER_MANUAL_CALL;
1240 			cdrunchangerqueue(softc->changer);
1241 		}
1242 	} else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT)
1243 		&& (softc->flags & CD_FLAG_ACTIVE)) {
1244 
1245 		/*
1246 		 * Now that the first transaction to this
1247 		 * particular device has completed, we can go ahead
1248 		 * and schedule our timeouts.
1249 		 */
1250 		if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) {
1251 			changer->long_handle =
1252 			    timeout(cdrunchangerqueue, changer,
1253 				    changer_max_busy_seconds * hz);
1254 			changer->flags |= CHANGER_TIMEOUT_SCHED;
1255 		} else
1256 			printf("cdchangerschedule: already have a long"
1257 			       " timeout!\n");
1258 
1259 		if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) {
1260 			changer->short_handle =
1261 			    timeout(cdshorttimeout, changer,
1262 				    changer_min_busy_seconds * hz);
1263 			changer->flags |= CHANGER_SHORT_TMOUT_SCHED;
1264 		} else
1265 			printf("cdchangerschedule: already have a short "
1266 			       "timeout!\n");
1267 
1268 		/*
1269 		 * We just scheduled timeouts, no need to schedule
1270 		 * more.
1271 		 */
1272 		changer->flags &= ~CHANGER_NEED_TIMEOUT;
1273 
1274 	}
1275 	splx(s);
1276 }
1277 
1278 static int
1279 cdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb,
1280 					      u_int32_t cam_flags,
1281 					      u_int32_t sense_flags),
1282 	 u_int32_t cam_flags, u_int32_t sense_flags)
1283 {
1284 	struct cd_softc *softc;
1285 	struct cam_periph *periph;
1286 	int error;
1287 
1288 	periph = xpt_path_periph(ccb->ccb_h.path);
1289 	softc = (struct cd_softc *)periph->softc;
1290 
1291 	error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags,
1292 				  &softc->device_stats);
1293 
1294 	if (softc->flags & CD_FLAG_CHANGER)
1295 		cdchangerschedule(softc);
1296 
1297 	return(error);
1298 }
1299 
1300 union ccb *
1301 cdgetccb(struct cam_periph *periph, u_int32_t priority)
1302 {
1303 	struct cd_softc *softc;
1304 	int s;
1305 
1306 	softc = (struct cd_softc *)periph->softc;
1307 
1308 	if (softc->flags & CD_FLAG_CHANGER) {
1309 
1310 		s = splsoftcam();
1311 
1312 		/*
1313 		 * This should work the first time this device is woken up,
1314 		 * but just in case it doesn't, we use a while loop.
1315 		 */
1316 		while ((((volatile cd_flags)softc->flags) & CD_FLAG_ACTIVE)==0){
1317 			/*
1318 			 * If this changer isn't already queued, queue it up.
1319 			 */
1320 			if (softc->pinfo.index == CAM_UNQUEUED_INDEX) {
1321 				softc->pinfo.priority = 1;
1322 				if (softc->changer->devq.generation++ == 0)
1323 					camq_regen(&softc->changer->devq);
1324 				softc->pinfo.generation =
1325 					softc->changer->devq.generation;
1326 				camq_insert(&softc->changer->devq,
1327 					    (cam_pinfo *)softc);
1328 			}
1329 			if (((((volatile cd_changer_flags)softc->changer->flags)
1330 				& CHANGER_TIMEOUT_SCHED)==0)
1331 			 &&((((volatile cd_changer_flags)softc->changer->flags)
1332 				& CHANGER_NEED_TIMEOUT)==0)){
1333 				softc->changer->flags |= CHANGER_MANUAL_CALL;
1334 				cdrunchangerqueue(softc->changer);
1335 			} else
1336 				tsleep(&softc->changer, PRIBIO, "cgticb", 0);
1337 		}
1338 		splx(s);
1339 	}
1340 	return(cam_periph_getccb(periph, priority));
1341 }
1342 
1343 
1344 /*
1345  * Actually translate the requested transfer into one the physical driver
1346  * can understand.  The transfer is described by a buf and will include
1347  * only one physical transfer.
1348  */
1349 static void
1350 cdstrategy(struct buf *bp)
1351 {
1352 	struct cam_periph *periph;
1353 	struct cd_softc *softc;
1354 	u_int  unit, part;
1355 	int    s;
1356 
1357 	unit = dkunit(bp->b_dev);
1358 	part = dkpart(bp->b_dev);
1359 	periph = cam_extend_get(cdperiphs, unit);
1360 	if (periph == NULL) {
1361 		bp->b_error = ENXIO;
1362 		goto bad;
1363 	}
1364 
1365 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n"));
1366 
1367 	softc = (struct cd_softc *)periph->softc;
1368 
1369 	/*
1370 	 * Do bounds checking, adjust transfer, and set b_pbklno.
1371 	 */
1372 	if (dscheck(bp, softc->cd_slices) <= 0)
1373 		goto done;
1374 
1375 	/*
1376 	 * Mask interrupts so that the pack cannot be invalidated until
1377 	 * after we are in the queue.  Otherwise, we might not properly
1378 	 * clean up one of the buffers.
1379 	 */
1380 	s = splbio();
1381 
1382 	/*
1383 	 * If the device has been made invalid, error out
1384 	 */
1385 	if ((softc->flags & CD_FLAG_INVALID)) {
1386 		splx(s);
1387 		bp->b_error = ENXIO;
1388 		goto bad;
1389 	}
1390 
1391 	/*
1392 	 * Place it in the queue of disk activities for this disk
1393 	 */
1394 	bufqdisksort(&softc->buf_queue, bp);
1395 
1396 	splx(s);
1397 
1398 	/*
1399 	 * Schedule ourselves for performing the work.  We do things
1400 	 * differently for changers.
1401 	 */
1402 	if ((softc->flags & CD_FLAG_CHANGER) == 0)
1403 		xpt_schedule(periph, /* XXX priority */1);
1404 	else
1405 		cdschedule(periph, /* priority */ 1);
1406 
1407 	return;
1408 bad:
1409 	bp->b_flags |= B_ERROR;
1410 done:
1411 	/*
1412 	 * Correctly set the buf to indicate a completed xfer
1413 	 */
1414 	bp->b_resid = bp->b_bcount;
1415 	biodone(bp);
1416 	return;
1417 }
1418 
1419 static void
1420 cdstart(struct cam_periph *periph, union ccb *start_ccb)
1421 {
1422 	struct cd_softc *softc;
1423 	struct buf *bp;
1424 	struct ccb_scsiio *csio;
1425 	struct scsi_read_capacity_data *rcap;
1426 	struct partition *p;
1427 	u_int32_t blkno, nblk;
1428 	int s;
1429 
1430 	softc = (struct cd_softc *)periph->softc;
1431 
1432 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n"));
1433 
1434 	switch (softc->state) {
1435 	case CD_STATE_NORMAL:
1436 	{
1437 		int oldspl;
1438 
1439 		s = splbio();
1440 		bp = bufq_first(&softc->buf_queue);
1441 		if (periph->immediate_priority <= periph->pinfo.priority) {
1442 			start_ccb->ccb_h.ccb_state = CD_CCB_WAITING;
1443 
1444 			SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
1445 					  periph_links.sle);
1446 			periph->immediate_priority = CAM_PRIORITY_NONE;
1447 			splx(s);
1448 			wakeup(&periph->ccb_list);
1449 		} else if (bp == NULL) {
1450 			splx(s);
1451 			xpt_release_ccb(start_ccb);
1452 		} else {
1453 			bufq_remove(&softc->buf_queue, bp);
1454 
1455 			devstat_start_transaction(&softc->device_stats);
1456 
1457 			scsi_read_write(&start_ccb->csio,
1458 					/*retries*/4,
1459 					/* cbfcnp */ cddone,
1460 					(bp->b_flags & B_ORDERED) != 0 ?
1461 					    MSG_ORDERED_Q_TAG :
1462 					    MSG_SIMPLE_Q_TAG,
1463 					/* read */bp->b_flags & B_READ,
1464 					/* byte2 */ 0,
1465 					/* minimum_cmd_size */ 10,
1466 					/* lba */ bp->b_pblkno,
1467 					bp->b_bcount / softc->params.blksize,
1468 					/* data_ptr */ bp->b_data,
1469 					/* dxfer_len */ bp->b_bcount,
1470 					/* sense_len */ SSD_FULL_SIZE,
1471 					/* timeout */ 30000);
1472 			start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO;
1473 
1474 
1475 			/*
1476 			 * Block out any asyncronous callbacks
1477 			 * while we touch the pending ccb list.
1478 			 */
1479 			oldspl = splcam();
1480 			LIST_INSERT_HEAD(&softc->pending_ccbs,
1481 					 &start_ccb->ccb_h, periph_links.le);
1482 			splx(oldspl);
1483 
1484 			/* We expect a unit attention from this device */
1485 			if ((softc->flags & CD_FLAG_RETRY_UA) != 0) {
1486 				start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA;
1487 				softc->flags &= ~CD_FLAG_RETRY_UA;
1488 			}
1489 
1490 			start_ccb->ccb_h.ccb_bp = bp;
1491 			bp = bufq_first(&softc->buf_queue);
1492 			splx(s);
1493 
1494 			xpt_action(start_ccb);
1495 		}
1496 		if (bp != NULL) {
1497 			/* Have more work to do, so ensure we stay scheduled */
1498 			xpt_schedule(periph, /* XXX priority */1);
1499 		}
1500 		break;
1501 	}
1502 	case CD_STATE_PROBE:
1503 	{
1504 
1505 		rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
1506 								M_TEMP,
1507 								M_NOWAIT);
1508 		if (rcap == NULL) {
1509 			xpt_print_path(periph->path);
1510 			printf("cdstart: Couldn't malloc read_capacity data\n");
1511 			/* cd_free_periph??? */
1512 			break;
1513 		}
1514 		csio = &start_ccb->csio;
1515 		scsi_read_capacity(csio,
1516 				   /*retries*/1,
1517 				   cddone,
1518 				   MSG_SIMPLE_Q_TAG,
1519 				   rcap,
1520 				   SSD_FULL_SIZE,
1521 				   /*timeout*/20000);
1522 		start_ccb->ccb_h.ccb_bp = NULL;
1523 		start_ccb->ccb_h.ccb_state = CD_CCB_PROBE;
1524 		xpt_action(start_ccb);
1525 		break;
1526 	}
1527 	}
1528 }
1529 
1530 static void
1531 cddone(struct cam_periph *periph, union ccb *done_ccb)
1532 {
1533 	struct cd_softc *softc;
1534 	struct ccb_scsiio *csio;
1535 
1536 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n"));
1537 
1538 	softc = (struct cd_softc *)periph->softc;
1539 	csio = &done_ccb->csio;
1540 
1541 	switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) {
1542 	case CD_CCB_BUFFER_IO:
1543 	{
1544 		struct buf	*bp;
1545 		int		error;
1546 		int		oldspl;
1547 
1548 		bp = (struct buf *)done_ccb->ccb_h.ccb_bp;
1549 		error = 0;
1550 
1551 		if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
1552 			int sf;
1553 
1554 			if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0)
1555 				sf = SF_RETRY_UA;
1556 			else
1557 				sf = 0;
1558 
1559 			if ((error = cderror(done_ccb, 0, sf)) == ERESTART) {
1560 				/*
1561 				 * A retry was scheuled, so
1562 				 * just return.
1563 				 */
1564 				return;
1565 			}
1566 		}
1567 
1568 		if (error != 0) {
1569 			int s;
1570 			struct buf *q_bp;
1571 
1572 			xpt_print_path(periph->path);
1573 			printf("cddone: got error %#x back\n", error);
1574 			s = splbio();
1575 			while ((q_bp = bufq_first(&softc->buf_queue)) != NULL) {
1576 				bufq_remove(&softc->buf_queue, q_bp);
1577 				q_bp->b_resid = q_bp->b_bcount;
1578 				q_bp->b_error = EIO;
1579 				q_bp->b_flags |= B_ERROR;
1580 				biodone(q_bp);
1581 			}
1582 			splx(s);
1583 			bp->b_resid = bp->b_bcount;
1584 			bp->b_error = error;
1585 			bp->b_flags |= B_ERROR;
1586 			cam_release_devq(done_ccb->ccb_h.path,
1587 					 /*relsim_flags*/0,
1588 					 /*reduction*/0,
1589 					 /*timeout*/0,
1590 					 /*getcount_only*/0);
1591 
1592 		} else {
1593 			bp->b_resid = csio->resid;
1594 			bp->b_error = 0;
1595 			if (bp->b_resid != 0) {
1596 				/* Short transfer ??? */
1597 				bp->b_flags |= B_ERROR;
1598 			}
1599 		}
1600 
1601 		/*
1602 		 * Block out any asyncronous callbacks
1603 		 * while we touch the pending ccb list.
1604 		 */
1605 		oldspl = splcam();
1606 		LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
1607 		splx(oldspl);
1608 
1609 		devstat_end_transaction(&softc->device_stats,
1610 					bp->b_bcount - bp->b_resid,
1611 					done_ccb->csio.tag_action & 0xf,
1612 					(bp->b_flags & B_READ) ? DEVSTAT_READ
1613 							       : DEVSTAT_WRITE);
1614 
1615 		if (softc->flags & CD_FLAG_CHANGER)
1616 			cdchangerschedule(softc);
1617 
1618 		biodone(bp);
1619 		break;
1620 	}
1621 	case CD_CCB_PROBE:
1622 	{
1623 		struct	   scsi_read_capacity_data *rdcap;
1624 		char	   announce_buf[120]; /*
1625 					       * Currently (9/30/97) the
1626 					       * longest possible announce
1627 					       * buffer is 108 bytes, for the
1628 					       * first error case below.
1629 					       * That is 39 bytes for the
1630 					       * basic string, 16 bytes for the
1631 					       * biggest sense key (hardware
1632 					       * error), 52 bytes for the
1633 					       * text of the largest sense
1634 					       * qualifier valid for a CDROM,
1635 					       * (0x72, 0x03 or 0x04,
1636 					       * 0x03), and one byte for the
1637 					       * null terminating character.
1638 					       * To allow for longer strings,
1639 					       * the announce buffer is 120
1640 					       * bytes.
1641 					       */
1642 		struct	   cd_params *cdp;
1643 
1644 		cdp = &softc->params;
1645 
1646 		rdcap = (struct scsi_read_capacity_data *)csio->data_ptr;
1647 
1648 		cdp->disksize = scsi_4btoul (rdcap->addr) + 1;
1649 		cdp->blksize = scsi_4btoul (rdcap->length);
1650 
1651 		if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
1652 
1653 			sprintf(announce_buf,
1654 				"cd present [%ld x %d byte records]",
1655 				cdp->disksize, cdp->blksize);
1656 
1657 		} else {
1658 			int	error;
1659 			/*
1660 			 * Retry any UNIT ATTENTION type errors.  They
1661 			 * are expected at boot.
1662 			 */
1663 			error = cderror(done_ccb, 0, SF_RETRY_UA|SF_NO_PRINT);
1664 			if (error == ERESTART) {
1665 				/*
1666 				 * A retry was scheuled, so
1667 				 * just return.
1668 				 */
1669 				return;
1670 			} else if (error != 0) {
1671 
1672 				struct scsi_sense_data *sense;
1673 				int asc, ascq;
1674 				int sense_key, error_code;
1675 				int have_sense;
1676 				cam_status status;
1677 				struct ccb_getdev cgd;
1678 
1679 				/* Don't wedge this device's queue */
1680 				cam_release_devq(done_ccb->ccb_h.path,
1681 						 /*relsim_flags*/0,
1682 						 /*reduction*/0,
1683 						 /*timeout*/0,
1684 						 /*getcount_only*/0);
1685 
1686 				status = done_ccb->ccb_h.status;
1687 
1688 				xpt_setup_ccb(&cgd.ccb_h,
1689 					      done_ccb->ccb_h.path,
1690 					      /* priority */ 1);
1691 				cgd.ccb_h.func_code = XPT_GDEV_TYPE;
1692 				xpt_action((union ccb *)&cgd);
1693 
1694 				if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0)
1695 				 || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0)
1696 				 || ((status & CAM_AUTOSNS_VALID) == 0))
1697 					have_sense = FALSE;
1698 				else
1699 					have_sense = TRUE;
1700 
1701 				if (have_sense) {
1702 					sense = &csio->sense_data;
1703 					scsi_extract_sense(sense, &error_code,
1704 							   &sense_key,
1705 							   &asc, &ascq);
1706 				}
1707 				/*
1708 				 * With CDROM devices, we expect 0x3a
1709 				 * (Medium not present) errors, since not
1710 				 * everyone leaves a CD in the drive.  If
1711 				 * the error is anything else, though, we
1712 				 * shouldn't attach.
1713 				 */
1714 				if ((have_sense) && (asc == 0x3a)
1715 				 && (error_code == SSD_CURRENT_ERROR))
1716 					sprintf(announce_buf,
1717 						"Attempt to query device "
1718 						"size failed: %s, %s",
1719 						scsi_sense_key_text[sense_key],
1720 						scsi_sense_desc(asc,ascq,
1721 								&cgd.inq_data));
1722 				else if (cgd.pd_type == T_CDROM) {
1723 					/*
1724 					 * We only print out an error for
1725 					 * CDROM type devices.  For WORM
1726 					 * devices, we don't print out an
1727 					 * error since a few WORM devices
1728 					 * don't support CDROM commands.
1729 					 * If we have sense information, go
1730 					 * ahead and print it out.
1731 					 * Otherwise, just say that we
1732 					 * couldn't attach.
1733 					 */
1734 					if ((have_sense) && (asc || ascq)
1735 					 && (error_code == SSD_CURRENT_ERROR))
1736 						sprintf(announce_buf,
1737 							"fatal error: %s, %s "
1738 							"-- failed to attach "
1739 							"to device",
1740 						scsi_sense_key_text[sense_key],
1741 						scsi_sense_desc(asc,ascq,
1742 								&cgd.inq_data));
1743 					else
1744 						sprintf(announce_buf,
1745 							"fatal error, failed"
1746 							" to attach to device");
1747 
1748 					/*
1749 					 * Just print out the error, not
1750 					 * the full probe message, when we
1751 					 * don't attach.
1752 					 */
1753 					printf("%s%d: %s\n",
1754 					       periph->periph_name,
1755 					       periph->unit_number,
1756 						announce_buf);
1757 					scsi_sense_print(&done_ccb->csio);
1758 
1759 					/*
1760 					 * Free up resources.
1761 					 */
1762 					cam_extend_release(cdperiphs,
1763 							   periph->unit_number);
1764 					cam_periph_invalidate(periph);
1765 					periph = NULL;
1766 				} else {
1767 					/*
1768 					 * Free up resources.
1769 					 */
1770 					cam_extend_release(cdperiphs,
1771 							   periph->unit_number);
1772 					cam_periph_invalidate(periph);
1773 					periph = NULL;
1774 				}
1775 			}
1776 		}
1777 		free(rdcap, M_TEMP);
1778 		if (periph != NULL) {
1779 			xpt_announce_periph(periph, announce_buf);
1780 			softc->state = CD_STATE_NORMAL;
1781 			cam_periph_unlock(periph);
1782 		}
1783 
1784 		if (softc->flags & CD_FLAG_CHANGER)
1785 			cdchangerschedule(softc);
1786 		break;
1787 	}
1788 	case CD_CCB_WAITING:
1789 	{
1790 		/* Caller will release the CCB */
1791 		CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1792 			  ("trying to wakeup ccbwait\n"));
1793 
1794 		wakeup(&done_ccb->ccb_h.cbfcnp);
1795 		return;
1796 	}
1797 	}
1798 	xpt_release_ccb(done_ccb);
1799 }
1800 
1801 static int
1802 cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1803 {
1804 
1805 	struct 	cam_periph *periph;
1806 	struct	cd_softc *softc;
1807 	u_int8_t unit, part;
1808 	int      error;
1809 
1810 	unit = dkunit(dev);
1811 	part = dkpart(dev);
1812 
1813 	periph = cam_extend_get(cdperiphs, unit);
1814 	if (periph == NULL)
1815 		return(ENXIO);
1816 
1817 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n"));
1818 
1819 	softc = (struct cd_softc *)periph->softc;
1820 
1821 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
1822 		  ("trying to do ioctl %#x\n", cmd));
1823 
1824 	error = 0;
1825 
1826 	switch (cmd) {
1827 
1828 	case CDIOCPLAYTRACKS:
1829 		{
1830 			struct ioc_play_track *args
1831 			    = (struct ioc_play_track *) addr;
1832 			struct cd_mode_data *data;
1833 
1834 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1835 				      M_WAITOK);
1836 
1837 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1838 				  ("trying to do CDIOCPLAYTRACKS\n"));
1839 
1840 			error = cdgetmode(periph, data, AUDIO_PAGE);
1841 			if (error) {
1842 				free(data, M_TEMP);
1843 				break;
1844 			}
1845 			data->page.audio.flags &= ~CD_PA_SOTC;
1846 			data->page.audio.flags |= CD_PA_IMMED;
1847 			error = cdsetmode(periph, data);
1848 			free(data, M_TEMP);
1849 			if (error)
1850 				break;
1851 			if (softc->quirks & CD_Q_BCD_TRACKS) {
1852 				args->start_track = bin2bcd(args->start_track);
1853 				args->end_track = bin2bcd(args->end_track);
1854 			}
1855 			error = cdplaytracks(periph,
1856 					     args->start_track,
1857 					     args->start_index,
1858 					     args->end_track,
1859 					     args->end_index);
1860 		}
1861 		break;
1862 	case CDIOCPLAYMSF:
1863 		{
1864 			struct ioc_play_msf *args
1865 				= (struct ioc_play_msf *) addr;
1866 			struct cd_mode_data *data;
1867 
1868 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1869 				      M_WAITOK);
1870 
1871 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1872 				  ("trying to do CDIOCPLAYMSF\n"));
1873 
1874 			error = cdgetmode(periph, data, AUDIO_PAGE);
1875 			if (error) {
1876 				free(data, M_TEMP);
1877 				break;
1878 			}
1879 			data->page.audio.flags &= ~CD_PA_SOTC;
1880 			data->page.audio.flags |= CD_PA_IMMED;
1881 			error = cdsetmode(periph, data);
1882 			free(data, M_TEMP);
1883 			if (error)
1884 				break;
1885 			error = cdplaymsf(periph,
1886 					  args->start_m,
1887 					  args->start_s,
1888 					  args->start_f,
1889 					  args->end_m,
1890 					  args->end_s,
1891 					  args->end_f);
1892 		}
1893 		break;
1894 	case CDIOCPLAYBLOCKS:
1895 		{
1896 			struct ioc_play_blocks *args
1897 				= (struct ioc_play_blocks *) addr;
1898 			struct cd_mode_data *data;
1899 
1900 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1901 				  ("trying to do CDIOCPLAYBLOCKS\n"));
1902 
1903 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
1904 				      M_WAITOK);
1905 
1906 			error = cdgetmode(periph, data, AUDIO_PAGE);
1907 			if (error) {
1908 				free(data, M_TEMP);
1909 				break;
1910 			}
1911 			data->page.audio.flags &= ~CD_PA_SOTC;
1912 			data->page.audio.flags |= CD_PA_IMMED;
1913 			error = cdsetmode(periph, data);
1914 			free(data, M_TEMP);
1915 			if (error)
1916 				break;
1917 			error = cdplay(periph, args->blk, args->len);
1918 		}
1919 		break;
1920 	case CDIOCREADSUBCHANNEL:
1921 		{
1922 			struct ioc_read_subchannel *args
1923 				= (struct ioc_read_subchannel *) addr;
1924 			struct cd_sub_channel_info *data;
1925 			u_int32_t len = args->data_len;
1926 
1927 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1928 				  ("trying to do CDIOCREADSUBCHANNEL\n"));
1929 
1930 			data = malloc(sizeof(struct cd_sub_channel_info),
1931 				      M_TEMP, M_WAITOK);
1932 
1933 			if ((len > sizeof(struct cd_sub_channel_info)) ||
1934 			    (len < sizeof(struct cd_sub_channel_header))) {
1935 				printf(
1936 					"scsi_cd: cdioctl: "
1937 					"cdioreadsubchannel: error, len=%d\n",
1938 					len);
1939 				error = EINVAL;
1940 				free(data, M_TEMP);
1941 				break;
1942 			}
1943 
1944 			if (softc->quirks & CD_Q_BCD_TRACKS)
1945 				args->track = bin2bcd(args->track);
1946 
1947 			error = cdreadsubchannel(periph, args->address_format,
1948 				args->data_format, args->track, data, len);
1949 
1950 			if (error) {
1951 				free(data, M_TEMP);
1952 	 			break;
1953 			}
1954 			if (softc->quirks & CD_Q_BCD_TRACKS)
1955 				data->what.track_info.track_number =
1956 				    bcd2bin(data->what.track_info.track_number);
1957 			len = min(len, ((data->header.data_len[0] << 8) +
1958 				data->header.data_len[1] +
1959 				sizeof(struct cd_sub_channel_header)));
1960 			if (copyout(data, args->data, len) != 0) {
1961 				error = EFAULT;
1962 			}
1963 			free(data, M_TEMP);
1964 		}
1965 		break;
1966 
1967 	case CDIOREADTOCHEADER:
1968 		{
1969 			struct ioc_toc_header *th;
1970 
1971 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
1972 				  ("trying to do CDIOREADTOCHEADER\n"));
1973 
1974 			th = malloc(sizeof(struct ioc_toc_header), M_TEMP,
1975 				    M_WAITOK);
1976 			error = cdreadtoc(periph, 0, 0,
1977 					  (struct cd_toc_entry *)th,
1978 				          sizeof (*th));
1979 			if (error) {
1980 				free(th, M_TEMP);
1981 				break;
1982 			}
1983 			if (softc->quirks & CD_Q_BCD_TRACKS) {
1984 				/* we are going to have to convert the BCD
1985 				 * encoding on the cd to what is expected
1986 				 */
1987 				th->starting_track =
1988 					bcd2bin(th->starting_track);
1989 				th->ending_track = bcd2bin(th->ending_track);
1990 			}
1991 			NTOHS(th->len);
1992 			bcopy(th, addr, sizeof(*th));
1993 			free(th, M_TEMP);
1994 		}
1995 		break;
1996 	case CDIOREADTOCENTRYS:
1997 		{
1998 			typedef struct {
1999 				struct ioc_toc_header header;
2000 				struct cd_toc_entry entries[100];
2001 			} data_t;
2002 			typedef struct {
2003 				struct ioc_toc_header header;
2004 				struct cd_toc_entry entry;
2005 			} lead_t;
2006 
2007 			data_t *data;
2008 			lead_t *lead;
2009 			struct ioc_read_toc_entry *te =
2010 				(struct ioc_read_toc_entry *) addr;
2011 			struct ioc_toc_header *th;
2012 			u_int32_t len, readlen, idx, num;
2013 			u_int32_t starting_track = te->starting_track;
2014 
2015 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2016 				  ("trying to do CDIOREADTOCENTRYS\n"));
2017 
2018 			data = malloc(sizeof(data_t), M_TEMP, M_WAITOK);
2019 			lead = malloc(sizeof(lead_t), M_TEMP, M_WAITOK);
2020 
2021 			if (te->data_len < sizeof(struct cd_toc_entry)
2022 			 || (te->data_len % sizeof(struct cd_toc_entry)) != 0
2023 			 || (te->address_format != CD_MSF_FORMAT
2024 			  && te->address_format != CD_LBA_FORMAT)) {
2025 				error = EINVAL;
2026 				printf("scsi_cd: error in readtocentries, "
2027 				       "returning EINVAL\n");
2028 				free(data, M_TEMP);
2029 				free(lead, M_TEMP);
2030 				break;
2031 			}
2032 
2033 			th = &data->header;
2034 			error = cdreadtoc(periph, 0, 0,
2035 					  (struct cd_toc_entry *)th,
2036 					  sizeof (*th));
2037 			if (error) {
2038 				free(data, M_TEMP);
2039 				free(lead, M_TEMP);
2040 				break;
2041 			}
2042 
2043 			if (softc->quirks & CD_Q_BCD_TRACKS) {
2044 				/* we are going to have to convert the BCD
2045 				 * encoding on the cd to what is expected
2046 				 */
2047 				th->starting_track =
2048 				    bcd2bin(th->starting_track);
2049 				th->ending_track = bcd2bin(th->ending_track);
2050 			}
2051 
2052 			if (starting_track == 0)
2053 				starting_track = th->starting_track;
2054 			else if (starting_track == LEADOUT)
2055 				starting_track = th->ending_track + 1;
2056 			else if (starting_track < th->starting_track ||
2057 				 starting_track > th->ending_track + 1) {
2058 				printf("scsi_cd: error in readtocentries, "
2059 				       "returning EINVAL\n");
2060 				free(data, M_TEMP);
2061 				free(lead, M_TEMP);
2062 				error = EINVAL;
2063 				break;
2064 			}
2065 
2066 			/* calculate reading length without leadout entry */
2067 			readlen = (th->ending_track - starting_track + 1) *
2068 				  sizeof(struct cd_toc_entry);
2069 
2070 			/* and with leadout entry */
2071 			len = readlen + sizeof(struct cd_toc_entry);
2072 			if (te->data_len < len) {
2073 				len = te->data_len;
2074 				if (readlen > len)
2075 					readlen = len;
2076 			}
2077 			if (len > sizeof(data->entries)) {
2078 				printf("scsi_cd: error in readtocentries, "
2079 				       "returning EINVAL\n");
2080 				error = EINVAL;
2081 				free(data, M_TEMP);
2082 				free(lead, M_TEMP);
2083 				break;
2084 			}
2085 			num = len / sizeof(struct cd_toc_entry);
2086 
2087 			if (readlen > 0) {
2088 				error = cdreadtoc(periph, te->address_format,
2089 						  starting_track,
2090 						  (struct cd_toc_entry *)data,
2091 						  readlen + sizeof (*th));
2092 				if (error) {
2093 					free(data, M_TEMP);
2094 					free(lead, M_TEMP);
2095 					break;
2096 				}
2097 			}
2098 
2099 			/* make leadout entry if needed */
2100 			idx = starting_track + num - 1;
2101 			if (softc->quirks & CD_Q_BCD_TRACKS)
2102 				th->ending_track = bcd2bin(th->ending_track);
2103 			if (idx == th->ending_track + 1) {
2104 				error = cdreadtoc(periph, te->address_format,
2105 						  LEADOUT,
2106 						  (struct cd_toc_entry *)lead,
2107 						  sizeof(*lead));
2108 				if (error) {
2109 					free(data, M_TEMP);
2110 					free(lead, M_TEMP);
2111 					break;
2112 				}
2113 				data->entries[idx - starting_track] =
2114 					lead->entry;
2115 			}
2116 			if (softc->quirks & CD_Q_BCD_TRACKS) {
2117 				for (idx = 0; idx < num - 1; idx++) {
2118 					data->entries[idx].track =
2119 					    bcd2bin(data->entries[idx].track);
2120 				}
2121 			}
2122 
2123 			error = copyout(data->entries, te->data, len);
2124 			free(data, M_TEMP);
2125 			free(lead, M_TEMP);
2126 		}
2127 		break;
2128 	case CDIOREADTOCENTRY:
2129 		{
2130 			/* yeah yeah, this is ugly */
2131 			typedef struct {
2132 				struct ioc_toc_header header;
2133 				struct cd_toc_entry entry;
2134 			} data_t;
2135 
2136 			data_t *data;
2137 			struct ioc_read_toc_single_entry *te =
2138 				(struct ioc_read_toc_single_entry *) addr;
2139 			struct ioc_toc_header *th;
2140 			u_int32_t track;
2141 
2142 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2143 				  ("trying to do CDIOREADTOCENTRY\n"));
2144 
2145 			data = malloc(sizeof(data_t), M_TEMP, M_WAITOK);
2146 
2147 			if (te->address_format != CD_MSF_FORMAT
2148 			    && te->address_format != CD_LBA_FORMAT) {
2149 				printf("error in readtocentry, "
2150 				       " returning EINVAL\n");
2151 				free(data, M_TEMP);
2152 				error = EINVAL;
2153 				break;
2154 			}
2155 
2156 			th = &data->header;
2157 			error = cdreadtoc(periph, 0, 0,
2158 					  (struct cd_toc_entry *)th,
2159 					  sizeof (*th));
2160 			if (error) {
2161 				free(data, M_TEMP);
2162 				break;
2163 			}
2164 
2165 			if (softc->quirks & CD_Q_BCD_TRACKS) {
2166 				/* we are going to have to convert the BCD
2167 				 * encoding on the cd to what is expected
2168 				 */
2169 				th->starting_track =
2170 				    bcd2bin(th->starting_track);
2171 				th->ending_track = bcd2bin(th->ending_track);
2172 			}
2173 			track = te->track;
2174 			if (track == 0)
2175 				track = th->starting_track;
2176 			else if (track == LEADOUT)
2177 				/* OK */;
2178 			else if (track < th->starting_track ||
2179 				 track > th->ending_track + 1) {
2180 				printf("error in readtocentry, "
2181 				       " returning EINVAL\n");
2182 				free(data, M_TEMP);
2183 				error = EINVAL;
2184 				break;
2185 			}
2186 
2187 			error = cdreadtoc(periph, te->address_format, track,
2188 					  (struct cd_toc_entry *)data,
2189 					  sizeof(data_t));
2190 			if (error) {
2191 				free(data, M_TEMP);
2192 				break;
2193 			}
2194 
2195 			if (softc->quirks & CD_Q_BCD_TRACKS)
2196 				data->entry.track = bcd2bin(data->entry.track);
2197 			bcopy(&data->entry, &te->entry,
2198 			      sizeof(struct cd_toc_entry));
2199 			free(data, M_TEMP);
2200 		}
2201 		break;
2202 	case CDIOCSETPATCH:
2203 		{
2204 			struct ioc_patch *arg = (struct ioc_patch *) addr;
2205 			struct cd_mode_data *data;
2206 
2207 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2208 				  ("trying to do CDIOCSETPATCH\n"));
2209 
2210 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2211 				      M_WAITOK);
2212 			error = cdgetmode(periph, data, AUDIO_PAGE);
2213 			if (error) {
2214 				free(data, M_TEMP);
2215 				break;
2216 			}
2217 			data->page.audio.port[LEFT_PORT].channels =
2218 				arg->patch[0];
2219 			data->page.audio.port[RIGHT_PORT].channels =
2220 				arg->patch[1];
2221 			data->page.audio.port[2].channels = arg->patch[2];
2222 			data->page.audio.port[3].channels = arg->patch[3];
2223 			error = cdsetmode(periph, data);
2224 			free(data, M_TEMP);
2225 		}
2226 		break;
2227 	case CDIOCGETVOL:
2228 		{
2229 			struct ioc_vol *arg = (struct ioc_vol *) addr;
2230 			struct cd_mode_data *data;
2231 
2232 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2233 				  ("trying to do CDIOCGETVOL\n"));
2234 
2235 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2236 				      M_WAITOK);
2237 			error = cdgetmode(periph, data, AUDIO_PAGE);
2238 			if (error) {
2239 				free(data, M_TEMP);
2240 				break;
2241 			}
2242 			arg->vol[LEFT_PORT] =
2243 				data->page.audio.port[LEFT_PORT].volume;
2244 			arg->vol[RIGHT_PORT] =
2245 				data->page.audio.port[RIGHT_PORT].volume;
2246 			arg->vol[2] = data->page.audio.port[2].volume;
2247 			arg->vol[3] = data->page.audio.port[3].volume;
2248 			free(data, M_TEMP);
2249 		}
2250 		break;
2251 	case CDIOCSETVOL:
2252 		{
2253 			struct ioc_vol *arg = (struct ioc_vol *) addr;
2254 			struct cd_mode_data *data;
2255 
2256 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2257 				  ("trying to do CDIOCSETVOL\n"));
2258 
2259 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2260 				      M_WAITOK);
2261 			error = cdgetmode(periph, data, AUDIO_PAGE);
2262 			if (error) {
2263 				free(data, M_TEMP);
2264 				break;
2265 			}
2266 			data->page.audio.port[LEFT_PORT].channels = CHANNEL_0;
2267 			data->page.audio.port[LEFT_PORT].volume =
2268 				arg->vol[LEFT_PORT];
2269 			data->page.audio.port[RIGHT_PORT].channels = CHANNEL_1;
2270 			data->page.audio.port[RIGHT_PORT].volume =
2271 				arg->vol[RIGHT_PORT];
2272 			data->page.audio.port[2].volume = arg->vol[2];
2273 			data->page.audio.port[3].volume = arg->vol[3];
2274 			error = cdsetmode(periph, data);
2275 			free(data, M_TEMP);
2276 		}
2277 		break;
2278 	case CDIOCSETMONO:
2279 		{
2280 			struct cd_mode_data *data;
2281 
2282 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2283 				  ("trying to do CDIOCSETMONO\n"));
2284 
2285 			data = malloc(sizeof(struct cd_mode_data),
2286 				      M_TEMP, M_WAITOK);
2287 			error = cdgetmode(periph, data, AUDIO_PAGE);
2288 			if (error) {
2289 				free(data, M_TEMP);
2290 				break;
2291 			}
2292 			data->page.audio.port[LEFT_PORT].channels =
2293 				LEFT_CHANNEL | RIGHT_CHANNEL;
2294 			data->page.audio.port[RIGHT_PORT].channels =
2295 				LEFT_CHANNEL | RIGHT_CHANNEL;
2296 			data->page.audio.port[2].channels = 0;
2297 			data->page.audio.port[3].channels = 0;
2298 			error = cdsetmode(periph, data);
2299 			free(data, M_TEMP);
2300 		}
2301 		break;
2302 	case CDIOCSETSTEREO:
2303 		{
2304 			struct cd_mode_data *data;
2305 
2306 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2307 				  ("trying to do CDIOCSETSTEREO\n"));
2308 
2309 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2310 				      M_WAITOK);
2311 			error = cdgetmode(periph, data, AUDIO_PAGE);
2312 			if (error) {
2313 				free(data, M_TEMP);
2314 				break;
2315 			}
2316 			data->page.audio.port[LEFT_PORT].channels =
2317 				LEFT_CHANNEL;
2318 			data->page.audio.port[RIGHT_PORT].channels =
2319 				RIGHT_CHANNEL;
2320 			data->page.audio.port[2].channels = 0;
2321 			data->page.audio.port[3].channels = 0;
2322 			error = cdsetmode(periph, data);
2323 			free(data, M_TEMP);
2324 		}
2325 		break;
2326 	case CDIOCSETMUTE:
2327 		{
2328 			struct cd_mode_data *data;
2329 
2330 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2331 				  ("trying to do CDIOCSETMUTE\n"));
2332 
2333 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2334 				      M_WAITOK);
2335 			error = cdgetmode(periph, data, AUDIO_PAGE);
2336 			if (error) {
2337 				free(data, M_TEMP);
2338 				break;
2339 			}
2340 			data->page.audio.port[LEFT_PORT].channels = 0;
2341 			data->page.audio.port[RIGHT_PORT].channels = 0;
2342 			data->page.audio.port[2].channels = 0;
2343 			data->page.audio.port[3].channels = 0;
2344 			error = cdsetmode(periph, data);
2345 			free(data, M_TEMP);
2346 		}
2347 		break;
2348 	case CDIOCSETLEFT:
2349 		{
2350 			struct cd_mode_data *data;
2351 
2352 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2353 				  ("trying to do CDIOCSETLEFT\n"));
2354 
2355 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2356 				      M_WAITOK);
2357 			error = cdgetmode(periph, data, AUDIO_PAGE);
2358 			if (error) {
2359 				free(data, M_TEMP);
2360 				break;
2361 			}
2362 			data->page.audio.port[LEFT_PORT].channels =
2363 				LEFT_CHANNEL;
2364 			data->page.audio.port[RIGHT_PORT].channels =
2365 				LEFT_CHANNEL;
2366 			data->page.audio.port[2].channels = 0;
2367 			data->page.audio.port[3].channels = 0;
2368 			error = cdsetmode(periph, data);
2369 			free(data, M_TEMP);
2370 		}
2371 		break;
2372 	case CDIOCSETRIGHT:
2373 		{
2374 			struct cd_mode_data *data;
2375 
2376 			CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE,
2377 				  ("trying to do CDIOCSETRIGHT\n"));
2378 
2379 			data = malloc(sizeof(struct cd_mode_data), M_TEMP,
2380 				      M_WAITOK);
2381 			error = cdgetmode(periph, data, AUDIO_PAGE);
2382 			if (error) {
2383 				free(data, M_TEMP);
2384 				break;
2385 			}
2386 			data->page.audio.port[LEFT_PORT].channels =
2387 				RIGHT_CHANNEL;
2388 			data->page.audio.port[RIGHT_PORT].channels =
2389 				RIGHT_CHANNEL;
2390 			data->page.audio.port[2].channels = 0;
2391 			data->page.audio.port[3].channels = 0;
2392 			error = cdsetmode(periph, data);
2393 			free(data, M_TEMP);
2394 		}
2395 		break;
2396 	case CDIOCRESUME:
2397 		error = cdpause(periph, 1);
2398 		break;
2399 	case CDIOCPAUSE:
2400 		error = cdpause(periph, 0);
2401 		break;
2402 	case CDIOCSTART:
2403 		error = cdstartunit(periph);
2404 		break;
2405 	case CDIOCSTOP:
2406 		error = cdstopunit(periph, 0);
2407 		break;
2408 	case CDIOCEJECT:
2409 		error = cdstopunit(periph, 1);
2410 		break;
2411 	case CDIOCALLOW:
2412 		cdprevent(periph, PR_ALLOW);
2413 		break;
2414 	case CDIOCPREVENT:
2415 		cdprevent(periph, PR_PREVENT);
2416 		break;
2417 	case CDIOCSETDEBUG:
2418 		/* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */
2419 		error = ENOTTY;
2420 		break;
2421 	case CDIOCCLRDEBUG:
2422 		/* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */
2423 		error = ENOTTY;
2424 		break;
2425 	case CDIOCRESET:
2426 		/* return (cd_reset(periph)); */
2427 		error = ENOTTY;
2428 		break;
2429 	default:
2430 		if (cmd == DIOCSBAD) {
2431 			error = EINVAL;	/* XXX */
2432 			break;
2433 		}
2434 
2435 		/*
2436 		 * Check to see whether we've got a disk-type ioctl.  If we
2437 		 * don't, dsioctl will pass back an error code of ENOIOCTL.
2438 		 */
2439 		error = dsioctl("cd", dev, cmd, addr, flag, &softc->cd_slices,
2440 				cdstrategy, (ds_setgeom_t *)NULL);
2441 
2442 		if (error != ENOIOCTL)
2443 			break;
2444 
2445 		error = cam_periph_ioctl(periph, cmd, addr, cderror);
2446 		break;
2447 	}
2448 
2449 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n"));
2450 
2451 	return (error);
2452 }
2453 
2454 static void
2455 cdprevent(struct cam_periph *periph, int action)
2456 {
2457 	union	ccb *ccb;
2458 	struct	cd_softc *softc;
2459 	int	error;
2460 
2461 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n"));
2462 
2463 	softc = (struct cd_softc *)periph->softc;
2464 
2465 	if (((action == PR_ALLOW)
2466 	  && (softc->flags & CD_FLAG_DISC_LOCKED) == 0)
2467 	 || ((action == PR_PREVENT)
2468 	  && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) {
2469 		return;
2470 	}
2471 
2472 	ccb = cdgetccb(periph, /* priority */ 1);
2473 
2474 	scsi_prevent(&ccb->csio,
2475 		     /*retries*/ 1,
2476 		     cddone,
2477 		     MSG_SIMPLE_Q_TAG,
2478 		     action,
2479 		     SSD_FULL_SIZE,
2480 		     /* timeout */60000);
2481 
2482 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2483 				  /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
2484 
2485 	xpt_release_ccb(ccb);
2486 
2487 	if (error == 0) {
2488 		if (action == PR_ALLOW)
2489 			softc->flags &= ~CD_FLAG_DISC_LOCKED;
2490 		else
2491 			softc->flags |= CD_FLAG_DISC_LOCKED;
2492 	}
2493 }
2494 
2495 static int
2496 cdsize(dev_t dev, u_int32_t *size)
2497 {
2498 	struct cam_periph *periph;
2499 	struct cd_softc *softc;
2500 	union ccb *ccb;
2501 	struct scsi_read_capacity_data *rcap_buf;
2502 	int error;
2503 
2504 	periph = cam_extend_get(cdperiphs, dkunit(dev));
2505 
2506 	if (periph == NULL)
2507 		return (ENXIO);
2508 
2509 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n"));
2510 
2511 	softc = (struct cd_softc *)periph->softc;
2512 
2513 	ccb = cdgetccb(periph, /* priority */ 1);
2514 
2515 	rcap_buf = malloc(sizeof(struct scsi_read_capacity_data),
2516 			  M_TEMP, M_WAITOK);
2517 
2518 	scsi_read_capacity(&ccb->csio,
2519 			   /*retries*/ 1,
2520 			   cddone,
2521 			   MSG_SIMPLE_Q_TAG,
2522 			   rcap_buf,
2523 			   SSD_FULL_SIZE,
2524 			   /* timeout */20000);
2525 
2526 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2527 				  /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
2528 
2529 	xpt_release_ccb(ccb);
2530 
2531 	softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1;
2532 	softc->params.blksize  = scsi_4btoul(rcap_buf->length);
2533 
2534 	free(rcap_buf, M_TEMP);
2535 	*size = softc->params.disksize;
2536 
2537 	return (error);
2538 
2539 }
2540 
2541 static int
2542 cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
2543 {
2544 	struct cd_softc *softc;
2545 	struct cam_periph *periph;
2546 
2547 	periph = xpt_path_periph(ccb->ccb_h.path);
2548 	softc = (struct cd_softc *)periph->softc;
2549 
2550 	return (cam_periph_error(ccb, cam_flags, sense_flags,
2551 				 &softc->saved_ccb));
2552 }
2553 
2554 static int
2555 cdgetdisklabel(dev_t dev)
2556 {
2557 	struct	cam_periph *periph;
2558 	struct	cd_softc *softc;
2559 
2560 	periph = cam_extend_get(cdperiphs, dkunit(dev));
2561 
2562 	if (periph == NULL)
2563 		return (ENXIO);
2564 
2565 	CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdgetdisklabel\n"));
2566 
2567 	softc = (struct cd_softc *)periph->softc;
2568 
2569 	bzero(&softc->disklabel, sizeof(struct disklabel));
2570 
2571 	/* XXX Use the controller's geometry for this */
2572 	softc->disklabel.d_type = DTYPE_SCSI;
2573 	sprintf(softc->disklabel.d_typename, "%s%d", periph->periph_name,
2574 		periph->unit_number);
2575         strncpy(softc->disklabel.d_packname, "ficticious", 16);
2576         softc->disklabel.d_secsize = softc->params.blksize;
2577         softc->disklabel.d_nsectors = 100;
2578         softc->disklabel.d_ntracks = 1;
2579         softc->disklabel.d_ncylinders = (softc->params.disksize / 100) + 1;
2580         softc->disklabel.d_secpercyl = 100;
2581         softc->disklabel.d_secperunit = softc->params.disksize;
2582         softc->disklabel.d_rpm = 300;
2583         softc->disklabel.d_interleave = 1;
2584         softc->disklabel.d_flags = D_REMOVABLE;
2585 
2586 	/*
2587 	 * Make partition 'a' cover the whole disk.  This is a temporary
2588 	 * compatibility hack.  The 'a' partition should not exist, so
2589 	 * the slice code won't create it.  The slice code will make
2590 	 * partition (RAW_PART + 'a') cover the whole disk and fill in
2591 	 * some more defaults.
2592 	 */
2593         softc->disklabel.d_npartitions = 1;
2594         softc->disklabel.d_partitions[0].p_offset = 0;
2595         softc->disklabel.d_partitions[0].p_size
2596             = softc->params.disksize;
2597         softc->disklabel.d_partitions[0].p_fstype = FS_OTHER;
2598 
2599         /*
2600          * Signal to other users and routines that we now have a
2601          * disklabel that represents the media (maybe)
2602          */
2603         return (0);
2604 
2605 }
2606 
2607 /*
2608  * Read table of contents
2609  */
2610 static int
2611 cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start,
2612 	    struct cd_toc_entry *data, u_int32_t len)
2613 {
2614 	struct scsi_read_toc *scsi_cmd;
2615 	u_int32_t ntoc;
2616         struct ccb_scsiio *csio;
2617 	union ccb *ccb;
2618 	int error;
2619 
2620 	ntoc = len;
2621 	error = 0;
2622 
2623 	ccb = cdgetccb(periph, /* priority */ 1);
2624 
2625 	csio = &ccb->csio;
2626 
2627 	cam_fill_csio(csio,
2628 		      /* retries */ 1,
2629 		      /* cbfcnp */ cddone,
2630 		      /* flags */ CAM_DIR_IN,
2631 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2632 		      /* data_ptr */ (u_int8_t *)data,
2633 		      /* dxfer_len */ len,
2634 		      /* sense_len */ SSD_FULL_SIZE,
2635 		      sizeof(struct scsi_read_toc),
2636  		      /* timeout */ 50000);
2637 
2638 	scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes;
2639 	bzero (scsi_cmd, sizeof(*scsi_cmd));
2640 
2641 	if (mode == CD_MSF_FORMAT)
2642 		scsi_cmd->byte2 |= CD_MSF;
2643 	scsi_cmd->from_track = start;
2644 	/* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */
2645 	scsi_cmd->data_len[0] = (ntoc) >> 8;
2646 	scsi_cmd->data_len[1] = (ntoc) & 0xff;
2647 
2648 	scsi_cmd->op_code = READ_TOC;
2649 
2650 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2651 				  /*sense_flags*/SF_RETRY_UA);
2652 
2653 	xpt_release_ccb(ccb);
2654 
2655 	return(error);
2656 }
2657 
2658 static int
2659 cdreadsubchannel(struct cam_periph *periph, u_int32_t mode,
2660 		 u_int32_t format, int track,
2661 		 struct cd_sub_channel_info *data, u_int32_t len)
2662 {
2663 	struct scsi_read_subchannel *scsi_cmd;
2664         struct ccb_scsiio *csio;
2665 	union ccb *ccb;
2666 	int error;
2667 
2668 	error = 0;
2669 
2670 	ccb = cdgetccb(periph, /* priority */ 1);
2671 
2672 	csio = &ccb->csio;
2673 
2674 	cam_fill_csio(csio,
2675 		      /* retries */ 1,
2676 		      /* cbfcnp */ cddone,
2677 		      /* flags */ CAM_DIR_IN,
2678 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2679 		      /* data_ptr */ (u_int8_t *)data,
2680 		      /* dxfer_len */ len,
2681 		      /* sense_len */ SSD_FULL_SIZE,
2682 		      sizeof(struct scsi_read_subchannel),
2683  		      /* timeout */ 50000);
2684 
2685 	scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes;
2686 	bzero (scsi_cmd, sizeof(*scsi_cmd));
2687 
2688 	scsi_cmd->op_code = READ_SUBCHANNEL;
2689 	if (mode == CD_MSF_FORMAT)
2690 		scsi_cmd->byte1 |= CD_MSF;
2691 	scsi_cmd->byte2 = SRS_SUBQ;
2692 	scsi_cmd->subchan_format = format;
2693 	scsi_cmd->track = track;
2694 	scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len);
2695 	scsi_cmd->control = 0;
2696 
2697 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2698 				  /*sense_flags*/SF_RETRY_UA);
2699 
2700 	xpt_release_ccb(ccb);
2701 
2702 	return(error);
2703 }
2704 
2705 
2706 static int
2707 cdgetmode(struct cam_periph *periph, struct cd_mode_data *data, u_int32_t page)
2708 {
2709 	struct scsi_mode_sense_6 *scsi_cmd;
2710         struct ccb_scsiio *csio;
2711 	union ccb *ccb;
2712 	int error;
2713 
2714 	ccb = cdgetccb(periph, /* priority */ 1);
2715 
2716 	csio = &ccb->csio;
2717 
2718 	bzero(data, sizeof(*data));
2719 	cam_fill_csio(csio,
2720 		      /* retries */ 1,
2721 		      /* cbfcnp */ cddone,
2722 		      /* flags */ CAM_DIR_IN,
2723 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2724 		      /* data_ptr */ (u_int8_t *)data,
2725 		      /* dxfer_len */ sizeof(*data),
2726 		      /* sense_len */ SSD_FULL_SIZE,
2727 		      sizeof(struct scsi_mode_sense_6),
2728  		      /* timeout */ 50000);
2729 
2730 	scsi_cmd = (struct scsi_mode_sense_6 *)&csio->cdb_io.cdb_bytes;
2731 	bzero (scsi_cmd, sizeof(*scsi_cmd));
2732 
2733 	scsi_cmd->page = page;
2734 	scsi_cmd->length = sizeof(*data) & 0xff;
2735 	scsi_cmd->opcode = MODE_SENSE;
2736 
2737 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2738 				  /*sense_flags*/SF_RETRY_UA);
2739 
2740 	xpt_release_ccb(ccb);
2741 
2742 	return(error);
2743 }
2744 
2745 static int
2746 cdsetmode(struct cam_periph *periph, struct cd_mode_data *data)
2747 {
2748 	struct scsi_mode_select_6 *scsi_cmd;
2749         struct ccb_scsiio *csio;
2750 	union ccb *ccb;
2751 	int error;
2752 
2753 	ccb = cdgetccb(periph, /* priority */ 1);
2754 
2755 	csio = &ccb->csio;
2756 
2757 	error = 0;
2758 
2759 	cam_fill_csio(csio,
2760 		      /* retries */ 1,
2761 		      /* cbfcnp */ cddone,
2762 		      /* flags */ CAM_DIR_IN,
2763 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2764 		      /* data_ptr */ (u_int8_t *)data,
2765 		      /* dxfer_len */ sizeof(*data),
2766 		      /* sense_len */ SSD_FULL_SIZE,
2767 		      sizeof(struct scsi_mode_select_6),
2768  		      /* timeout */ 50000);
2769 
2770 	scsi_cmd = (struct scsi_mode_select_6 *)&csio->cdb_io.cdb_bytes;
2771 
2772 	bzero(scsi_cmd, sizeof(*scsi_cmd));
2773 	scsi_cmd->opcode = MODE_SELECT;
2774 	scsi_cmd->byte2 |= SMS_PF;
2775 	scsi_cmd->length = sizeof(*data) & 0xff;
2776 	data->header.data_length = 0;
2777 	/*
2778 	 * SONY drives do not allow a mode select with a medium_type
2779 	 * value that has just been returned by a mode sense; use a
2780 	 * medium_type of 0 (Default) instead.
2781 	 */
2782 	data->header.medium_type = 0;
2783 
2784 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2785 				  /*sense_flags*/SF_RETRY_UA);
2786 
2787 	xpt_release_ccb(ccb);
2788 
2789 	return(error);
2790 }
2791 
2792 
2793 static int
2794 cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len)
2795 {
2796 	struct scsi_play *scsi_cmd;
2797         struct ccb_scsiio *csio;
2798 	union ccb *ccb;
2799 	int error;
2800 
2801 	error = 0;
2802 
2803 	ccb = cdgetccb(periph, /* priority */ 1);
2804 
2805 	csio = &ccb->csio;
2806 
2807 	cam_fill_csio(csio,
2808 		      /* retries */ 1,
2809 		      /* cbfcnp */ cddone,
2810 		      /* flags */ CAM_DIR_IN,
2811 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2812 		      /* data_ptr */ NULL,
2813 		      /* dxfer_len */ 0,
2814 		      /* sense_len */ SSD_FULL_SIZE,
2815 		      sizeof(struct scsi_play),
2816  		      /* timeout */ 50000);
2817 
2818 	scsi_cmd = (struct scsi_play *)&csio->cdb_io.cdb_bytes;
2819 	bzero (scsi_cmd, sizeof(*scsi_cmd));
2820 
2821 	scsi_cmd->op_code = PLAY;
2822 	scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
2823 	scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len);
2824 
2825 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2826 				  /*sense_flags*/SF_RETRY_UA);
2827 
2828 	xpt_release_ccb(ccb);
2829 
2830 	return(error);
2831 
2832 }
2833 
2834 static int
2835 cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts,
2836 	  u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf)
2837 {
2838 	struct scsi_play_msf *scsi_cmd;
2839         struct ccb_scsiio *csio;
2840 	union ccb *ccb;
2841 	int error;
2842 
2843 	error = 0;
2844 
2845 	ccb = cdgetccb(periph, /* priority */ 1);
2846 
2847 	csio = &ccb->csio;
2848 
2849 	cam_fill_csio(csio,
2850 		      /* retries */ 1,
2851 		      /* cbfcnp */ cddone,
2852 		      /* flags */ CAM_DIR_IN,
2853 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2854 		      /* data_ptr */ NULL,
2855 		      /* dxfer_len */ 0,
2856 		      /* sense_len */ SSD_FULL_SIZE,
2857 		      sizeof(struct scsi_play_msf),
2858  		      /* timeout */ 50000);
2859 
2860 	scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes;
2861 	bzero (scsi_cmd, sizeof(*scsi_cmd));
2862 
2863         scsi_cmd->op_code = PLAY_MSF;
2864         scsi_cmd->start_m = startm;
2865         scsi_cmd->start_s = starts;
2866         scsi_cmd->start_f = startf;
2867         scsi_cmd->end_m = endm;
2868         scsi_cmd->end_s = ends;
2869         scsi_cmd->end_f = endf;
2870 
2871 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2872 				  /*sense_flags*/SF_RETRY_UA);
2873 
2874 	xpt_release_ccb(ccb);
2875 
2876 	return(error);
2877 }
2878 
2879 
2880 static int
2881 cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex,
2882 	     u_int32_t etrack, u_int32_t eindex)
2883 {
2884 	struct scsi_play_track *scsi_cmd;
2885         struct ccb_scsiio *csio;
2886 	union ccb *ccb;
2887 	int error;
2888 
2889 	error = 0;
2890 
2891 	ccb = cdgetccb(periph, /* priority */ 1);
2892 
2893 	csio = &ccb->csio;
2894 
2895 	cam_fill_csio(csio,
2896 		      /* retries */ 1,
2897 		      /* cbfcnp */ cddone,
2898 		      /* flags */ CAM_DIR_IN,
2899 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2900 		      /* data_ptr */ NULL,
2901 		      /* dxfer_len */ 0,
2902 		      /* sense_len */ SSD_FULL_SIZE,
2903 		      sizeof(struct scsi_play_track),
2904  		      /* timeout */ 50000);
2905 
2906 	scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes;
2907 	bzero (scsi_cmd, sizeof(*scsi_cmd));
2908 
2909         scsi_cmd->op_code = PLAY_TRACK;
2910         scsi_cmd->start_track = strack;
2911         scsi_cmd->start_index = sindex;
2912         scsi_cmd->end_track = etrack;
2913         scsi_cmd->end_index = eindex;
2914 
2915 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2916 				  /*sense_flags*/SF_RETRY_UA);
2917 
2918 	xpt_release_ccb(ccb);
2919 
2920 	return(error);
2921 }
2922 
2923 static int
2924 cdpause(struct cam_periph *periph, u_int32_t go)
2925 {
2926 	struct scsi_pause *scsi_cmd;
2927         struct ccb_scsiio *csio;
2928 	union ccb *ccb;
2929 	int error;
2930 
2931 	error = 0;
2932 
2933 	ccb = cdgetccb(periph, /* priority */ 1);
2934 
2935 	csio = &ccb->csio;
2936 
2937 	cam_fill_csio(csio,
2938 		      /* retries */ 1,
2939 		      /* cbfcnp */ cddone,
2940 		      /* flags */ CAM_DIR_IN,
2941 		      /* tag_action */ MSG_SIMPLE_Q_TAG,
2942 		      /* data_ptr */ NULL,
2943 		      /* dxfer_len */ 0,
2944 		      /* sense_len */ SSD_FULL_SIZE,
2945 		      sizeof(struct scsi_pause),
2946  		      /* timeout */ 50000);
2947 
2948 	scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes;
2949 	bzero (scsi_cmd, sizeof(*scsi_cmd));
2950 
2951         scsi_cmd->op_code = PAUSE;
2952 	scsi_cmd->resume = go;
2953 
2954 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2955 				  /*sense_flags*/SF_RETRY_UA);
2956 
2957 	xpt_release_ccb(ccb);
2958 
2959 	return(error);
2960 }
2961 
2962 static int
2963 cdstartunit(struct cam_periph *periph)
2964 {
2965 	union ccb *ccb;
2966 	int error;
2967 
2968 	error = 0;
2969 
2970 	ccb = cdgetccb(periph, /* priority */ 1);
2971 
2972 	scsi_start_stop(&ccb->csio,
2973 			/* retries */ 1,
2974 			/* cbfcnp */ cddone,
2975 			/* tag_action */ MSG_SIMPLE_Q_TAG,
2976 			/* start */ TRUE,
2977 			/* load_eject */ TRUE,
2978 			/* immediate */ FALSE,
2979 			/* sense_len */ SSD_FULL_SIZE,
2980 			/* timeout */ 50000);
2981 
2982 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
2983 				  /*sense_flags*/SF_RETRY_UA);
2984 
2985 	xpt_release_ccb(ccb);
2986 
2987 	return(error);
2988 }
2989 
2990 static int
2991 cdstopunit(struct cam_periph *periph, u_int32_t eject)
2992 {
2993 	union ccb *ccb;
2994 	int error;
2995 
2996 	error = 0;
2997 
2998 	ccb = cdgetccb(periph, /* priority */ 1);
2999 
3000 	scsi_start_stop(&ccb->csio,
3001 			/* retries */ 1,
3002 			/* cbfcnp */ cddone,
3003 			/* tag_action */ MSG_SIMPLE_Q_TAG,
3004 			/* start */ FALSE,
3005 			/* load_eject */ eject,
3006 			/* immediate */ FALSE,
3007 			/* sense_len */ SSD_FULL_SIZE,
3008 			/* timeout */ 50000);
3009 
3010 	error = cdrunccb(ccb, cderror, /*cam_flags*/0,
3011 				  /*sense_flags*/SF_RETRY_UA);
3012 
3013 	xpt_release_ccb(ccb);
3014 
3015 	return(error);
3016 }
3017