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