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