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