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