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