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