cd.c revision 1.312
1/*	$NetBSD: cd.c,v 1.312 2013/07/02 15:05:53 reinoud Exp $	*/
2
3/*-
4 * Copyright (c) 1998, 2001, 2003, 2004, 2005, 2008 The NetBSD Foundation,
5 * Inc.  All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum.
9 *
10 * MMC framework implemented and contributed to the NetBSD Foundation by
11 * Reinoud Zandijk.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35/*
36 * Originally written by Julian Elischer (julian@tfs.com)
37 * for TRW Financial Systems for use under the MACH(2.5) operating system.
38 *
39 * TRW Financial Systems, in accordance with their agreement with Carnegie
40 * Mellon University, makes this software available to CMU to distribute
41 * or use in any manner that they see fit as long as this message is kept with
42 * the software. For this reason TFS also grants any other persons or
43 * organisations permission to use or modify this software.
44 *
45 * TFS supplies this software to be publicly redistributed
46 * on the understanding that TFS is not responsible for the correct
47 * functioning of this software in any circumstances.
48 *
49 * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
50 */
51
52#include <sys/cdefs.h>
53__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.312 2013/07/02 15:05:53 reinoud Exp $");
54
55#include <sys/param.h>
56#include <sys/systm.h>
57#include <sys/kernel.h>
58#include <sys/file.h>
59#include <sys/stat.h>
60#include <sys/ioctl.h>
61#include <sys/buf.h>
62#include <sys/bufq.h>
63#include <sys/uio.h>
64#include <sys/malloc.h>
65#include <sys/errno.h>
66#include <sys/device.h>
67#include <sys/disklabel.h>
68#include <sys/disk.h>
69#include <sys/cdio.h>
70#include <sys/dvdio.h>
71#include <sys/scsiio.h>
72#include <sys/proc.h>
73#include <sys/conf.h>
74#include <sys/vnode.h>
75#include <sys/rnd.h>
76
77#include <dev/scsipi/scsi_spc.h>
78#include <dev/scsipi/scsipi_all.h>
79#include <dev/scsipi/scsipi_cd.h>
80#include <dev/scsipi/scsipi_disk.h>	/* rw_big and start_stop come */
81#include <dev/scsipi/scsi_all.h>
82					/* from there */
83#include <dev/scsipi/scsi_disk.h>	/* rw comes from there */
84#include <dev/scsipi/scsipiconf.h>
85#include <dev/scsipi/scsipi_base.h>
86#include <dev/scsipi/cdvar.h>
87
88#include <prop/proplib.h>
89
90#define	CDUNIT(z)			DISKUNIT(z)
91#define	CDPART(z)			DISKPART(z)
92#define	CDMINOR(unit, part)		DISKMINOR(unit, part)
93#define	MAKECDDEV(maj, unit, part)	MAKEDISKDEV(maj, unit, part)
94
95#define MAXTRACK	99
96#define CD_BLOCK_OFFSET	150
97#define CD_FRAMES	75
98#define CD_SECS		60
99
100#define CD_TOC_FORM	0	/* formatted TOC, exposed to userland     */
101#define CD_TOC_MSINFO	1	/* multi-session info			  */
102#define CD_TOC_RAW	2	/* raw TOC as on disc, unprocessed	  */
103#define CD_TOC_PMA	3	/* PMA, used as intermediate (rare use)   */
104#define CD_TOC_ATIP	4	/* pressed space of recordable		  */
105#define CD_TOC_CDTEXT	5	/* special CD-TEXT, rarely used		  */
106
107#define P5LEN	0x32
108#define MS5LEN	(P5LEN + 8 + 2)
109
110struct cd_formatted_toc {
111	struct ioc_toc_header header;
112	struct cd_toc_entry entries[MAXTRACK+1]; /* One extra for the */
113						 /* leadout */
114};
115
116struct cdbounce {
117	struct buf     *obp;			/* original buf */
118	int		doff;			/* byte offset in orig. buf */
119	int		soff;			/* byte offset in bounce buf */
120	int		resid;			/* residual i/o in orig. buf */
121	int		bcount;			/* actual obp bytes in bounce */
122};
123
124static void	cdstart(struct scsipi_periph *);
125static void	cdrestart(void *);
126static void	cdminphys(struct buf *);
127static void	cdgetdefaultlabel(struct cd_softc *, struct cd_formatted_toc *,
128		    struct disklabel *);
129static void	cdgetdisklabel(struct cd_softc *);
130static void	cddone(struct scsipi_xfer *, int);
131static void	cdbounce(struct buf *);
132static int	cd_interpret_sense(struct scsipi_xfer *);
133static u_long	cd_size(struct cd_softc *, int);
134static int	cd_play(struct cd_softc *, int, int);
135static int	cd_play_tracks(struct cd_softc *, struct cd_formatted_toc *,
136		    int, int, int, int);
137static int	cd_play_msf(struct cd_softc *, int, int, int, int, int, int);
138static int	cd_pause(struct cd_softc *, int);
139static int	cd_reset(struct cd_softc *);
140static int	cd_read_subchannel(struct cd_softc *, int, int, int,
141		    struct cd_sub_channel_info *, int, int);
142static int	cd_read_toc(struct cd_softc *, int, int, int,
143		    struct cd_formatted_toc *, int, int, int);
144static int	cd_get_parms(struct cd_softc *, int);
145static int	cd_load_toc(struct cd_softc *, int, struct cd_formatted_toc *, int);
146static int	cdreadmsaddr(struct cd_softc *, struct cd_formatted_toc *,int *);
147static int	cdcachesync(struct scsipi_periph *periph, int flags);
148
149static int	dvd_auth(struct cd_softc *, dvd_authinfo *);
150static int	dvd_read_physical(struct cd_softc *, dvd_struct *);
151static int	dvd_read_copyright(struct cd_softc *, dvd_struct *);
152static int	dvd_read_disckey(struct cd_softc *, dvd_struct *);
153static int	dvd_read_bca(struct cd_softc *, dvd_struct *);
154static int	dvd_read_manufact(struct cd_softc *, dvd_struct *);
155static int	dvd_read_struct(struct cd_softc *, dvd_struct *);
156
157static int	cd_mode_sense(struct cd_softc *, u_int8_t, void *, size_t, int,
158		    int, int *);
159static int	cd_mode_select(struct cd_softc *, u_int8_t, void *, size_t,
160		    int, int);
161static int	cd_setchan(struct cd_softc *, int, int, int, int, int);
162static int	cd_getvol(struct cd_softc *, struct ioc_vol *, int);
163static int	cd_setvol(struct cd_softc *, const struct ioc_vol *, int);
164static int	cd_set_pa_immed(struct cd_softc *, int);
165static int	cd_load_unload(struct cd_softc *, struct ioc_load_unload *);
166static int	cd_setblksize(struct cd_softc *);
167
168static int	cdmatch(device_t, cfdata_t, void *);
169static void	cdattach(device_t, device_t, void *);
170static int	cddetach(device_t, int);
171
172static int	mmc_getdiscinfo(struct scsipi_periph *, struct mmc_discinfo *);
173static int	mmc_gettrackinfo(struct scsipi_periph *, struct mmc_trackinfo *);
174static int	mmc_do_op(struct scsipi_periph *, struct mmc_op *);
175static int	mmc_setup_writeparams(struct scsipi_periph *, struct mmc_writeparams *);
176
177static void	cd_set_geometry(struct cd_softc *);
178
179CFATTACH_DECL3_NEW(cd, sizeof(struct cd_softc), cdmatch, cdattach, cddetach,
180    NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
181
182extern struct cfdriver cd_cd;
183
184static const struct scsipi_inquiry_pattern cd_patterns[] = {
185	{T_CDROM, T_REMOV,
186	 "",         "",                 ""},
187	{T_WORM, T_REMOV,
188	 "",         "",                 ""},
189#if 0
190	{T_CDROM, T_REMOV, /* more luns */
191	 "PIONEER ", "CD-ROM DRM-600  ", ""},
192#endif
193	{T_DIRECT, T_REMOV,
194	 "NEC                 CD-ROM DRIVE:260", "", ""},
195};
196
197static dev_type_open(cdopen);
198static dev_type_close(cdclose);
199static dev_type_read(cdread);
200static dev_type_write(cdwrite);
201static dev_type_ioctl(cdioctl);
202static dev_type_strategy(cdstrategy);
203static dev_type_dump(cddump);
204static dev_type_size(cdsize);
205
206const struct bdevsw cd_bdevsw = {
207	cdopen, cdclose, cdstrategy, cdioctl, cddump, cdsize, D_DISK
208};
209
210const struct cdevsw cd_cdevsw = {
211	cdopen, cdclose, cdread, cdwrite, cdioctl,
212	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
213};
214
215static struct dkdriver cddkdriver = { cdstrategy, NULL };
216
217static const struct scsipi_periphsw cd_switch = {
218	cd_interpret_sense,	/* use our error handler first */
219	cdstart,		/* we have a queue, which is started by this */
220	NULL,			/* we do not have an async handler */
221	cddone,			/* deal with stats at interrupt time */
222};
223
224/*
225 * The routine called by the low level scsi routine when it discovers
226 * A device suitable for this driver
227 */
228static int
229cdmatch(device_t parent, cfdata_t match, void *aux)
230{
231	struct scsipibus_attach_args *sa = aux;
232	int priority;
233
234	(void)scsipi_inqmatch(&sa->sa_inqbuf,
235	    cd_patterns, sizeof(cd_patterns) / sizeof(cd_patterns[0]),
236	    sizeof(cd_patterns[0]), &priority);
237
238	return (priority);
239}
240
241static void
242cdattach(device_t parent, device_t self, void *aux)
243{
244	struct cd_softc *cd = device_private(self);
245	struct scsipibus_attach_args *sa = aux;
246	struct scsipi_periph *periph = sa->sa_periph;
247
248	SC_DEBUG(periph, SCSIPI_DB2, ("cdattach: "));
249
250	cd->sc_dev = self;
251
252	mutex_init(&cd->sc_lock, MUTEX_DEFAULT, IPL_NONE);
253
254	if (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph)) ==
255	    SCSIPI_BUSTYPE_SCSI && periph->periph_version == 0)
256		cd->flags |= CDF_ANCIENT;
257
258	bufq_alloc(&cd->buf_queue, "disksort", BUFQ_SORT_RAWBLOCK);
259
260	callout_init(&cd->sc_callout, 0);
261
262	/*
263	 * Store information needed to contact our base driver
264	 */
265	cd->sc_periph = periph;
266
267	periph->periph_dev = cd->sc_dev;
268	periph->periph_switch = &cd_switch;
269
270	/*
271	 * Increase our openings to the maximum-per-periph
272	 * supported by the adapter.  This will either be
273	 * clamped down or grown by the adapter if necessary.
274	 */
275	periph->periph_openings =
276	    SCSIPI_CHAN_MAX_PERIPH(periph->periph_channel);
277	periph->periph_flags |= PERIPH_GROW_OPENINGS;
278
279	/*
280	 * Initialize and attach the disk structure.
281	 */
282	disk_init(&cd->sc_dk, device_xname(cd->sc_dev), &cddkdriver);
283	disk_attach(&cd->sc_dk);
284
285	aprint_normal("\n");
286	aprint_naive("\n");
287
288	rnd_attach_source(&cd->rnd_source, device_xname(cd->sc_dev),
289			  RND_TYPE_DISK, 0);
290
291	if (!pmf_device_register(self, NULL, NULL))
292		aprint_error_dev(self, "couldn't establish power handler\n");
293}
294
295static int
296cddetach(device_t self, int flags)
297{
298	struct cd_softc *cd = device_private(self);
299	int s, bmaj, cmaj, i, mn;
300
301	/* locate the major number */
302	bmaj = bdevsw_lookup_major(&cd_bdevsw);
303	cmaj = cdevsw_lookup_major(&cd_cdevsw);
304	/* Nuke the vnodes for any open instances */
305	for (i = 0; i < MAXPARTITIONS; i++) {
306		mn = CDMINOR(device_unit(self), i);
307		vdevgone(bmaj, mn, mn, VBLK);
308		vdevgone(cmaj, mn, mn, VCHR);
309	}
310
311	/* kill any pending restart */
312	callout_stop(&cd->sc_callout);
313
314	s = splbio();
315
316	/* Kill off any queued buffers. */
317	bufq_drain(cd->buf_queue);
318
319	bufq_free(cd->buf_queue);
320
321	/* Kill off any pending commands. */
322	scsipi_kill_pending(cd->sc_periph);
323
324	splx(s);
325
326	mutex_destroy(&cd->sc_lock);
327
328	/* Detach from the disk list. */
329	disk_detach(&cd->sc_dk);
330	disk_destroy(&cd->sc_dk);
331
332	/* Unhook the entropy source. */
333	rnd_detach_source(&cd->rnd_source);
334
335	return (0);
336}
337
338/*
339 * open the device. Make sure the partition info is a up-to-date as can be.
340 */
341static int
342cdopen(dev_t dev, int flag, int fmt, struct lwp *l)
343{
344	struct cd_softc *cd;
345	struct scsipi_periph *periph;
346	struct scsipi_adapter *adapt;
347	int part;
348	int error;
349	int rawpart;
350
351	cd = device_lookup_private(&cd_cd, CDUNIT(dev));
352	if (cd == NULL)
353		return (ENXIO);
354
355	periph = cd->sc_periph;
356	adapt = periph->periph_channel->chan_adapter;
357	part = CDPART(dev);
358
359	SC_DEBUG(periph, SCSIPI_DB1,
360	    ("cdopen: dev=0x%"PRIu64" (unit %"PRIu32" (of %d), partition %"PRId32")\n",dev,
361	    CDUNIT(dev), cd_cd.cd_ndevs, CDPART(dev)));
362
363	/*
364	 * If this is the first open of this device, add a reference
365	 * to the adapter.
366	 */
367	if (cd->sc_dk.dk_openmask == 0 &&
368	    (error = scsipi_adapter_addref(adapt)) != 0)
369		return (error);
370
371	mutex_enter(&cd->sc_lock);
372
373	rawpart = (part == RAW_PART && fmt == S_IFCHR);
374	if ((periph->periph_flags & PERIPH_OPEN) != 0) {
375		/*
376		 * If any partition is open, but the disk has been invalidated,
377		 * disallow further opens.
378		 */
379		if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 &&
380			!rawpart) {
381			error = EIO;
382			goto bad3;
383		}
384	} else {
385		/* Check that it is still responding and ok. */
386		error = scsipi_test_unit_ready(periph,
387		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
388		    XS_CTL_SILENT);
389
390		/*
391		 * Start the pack spinning if necessary. Always allow the
392		 * raw parition to be opened, for raw IOCTLs. Data transfers
393		 * will check for SDEV_MEDIA_LOADED.
394		 */
395		if (error == EIO) {
396			int error2;
397			int silent;
398
399			if (rawpart)
400				silent = XS_CTL_SILENT;
401			else
402				silent = 0;
403
404			error2 = scsipi_start(periph, SSS_START, silent);
405			switch (error2) {
406			case 0:
407				error = 0;
408				break;
409			case EIO:
410			case EINVAL:
411				break;
412			default:
413				error = error2;
414				break;
415			}
416		}
417		if (error) {
418			if (rawpart)
419				goto out;
420			goto bad3;
421		}
422
423		periph->periph_flags |= PERIPH_OPEN;
424
425		/* Lock the pack in. */
426		error = scsipi_prevent(periph, SPAMR_PREVENT_DT,
427		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE);
428		SC_DEBUG(periph, SCSIPI_DB1,
429		    ("cdopen: scsipi_prevent, error=%d\n", error));
430		if (error) {
431			if (rawpart)
432				goto out;
433			goto bad;
434		}
435
436		if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
437			/* Load the physical device parameters. */
438			if (cd_get_parms(cd, 0) != 0) {
439				if (rawpart)
440					goto out;
441				error = ENXIO;
442				goto bad;
443			}
444			periph->periph_flags |= PERIPH_MEDIA_LOADED;
445			SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded "));
446
447			/* Fabricate a disk label. */
448			cdgetdisklabel(cd);
449			SC_DEBUG(periph, SCSIPI_DB3, ("Disklabel fabricated "));
450
451			cd_set_geometry(cd);
452		}
453	}
454
455	/* Check that the partition exists. */
456	if (part != RAW_PART &&
457	    (part >= cd->sc_dk.dk_label->d_npartitions ||
458	    cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
459		error = ENXIO;
460		goto bad;
461	}
462
463out:	/* Insure only one open at a time. */
464	switch (fmt) {
465	case S_IFCHR:
466		cd->sc_dk.dk_copenmask |= (1 << part);
467		break;
468	case S_IFBLK:
469		cd->sc_dk.dk_bopenmask |= (1 << part);
470		break;
471	}
472	cd->sc_dk.dk_openmask =
473	    cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
474
475	SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n"));
476	mutex_exit(&cd->sc_lock);
477	return (0);
478
479bad:
480	if (cd->sc_dk.dk_openmask == 0) {
481		scsipi_prevent(periph, SPAMR_ALLOW,
482		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE);
483		periph->periph_flags &= ~PERIPH_OPEN;
484	}
485
486bad3:
487	mutex_exit(&cd->sc_lock);
488	if (cd->sc_dk.dk_openmask == 0)
489		scsipi_adapter_delref(adapt);
490	return (error);
491}
492
493/*
494 * close the device.. only called if we are the LAST
495 * occurence of an open device
496 */
497static int
498cdclose(dev_t dev, int flag, int fmt, struct lwp *l)
499{
500	struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(dev));
501	struct scsipi_periph *periph = cd->sc_periph;
502	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
503	int part = CDPART(dev);
504	int silent = 0;
505
506	if (part == RAW_PART && ((cd->sc_dk.dk_label->d_npartitions == 0) ||
507	    (part < cd->sc_dk.dk_label->d_npartitions &&
508	    cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)))
509		silent = XS_CTL_SILENT;
510
511	mutex_enter(&cd->sc_lock);
512
513	switch (fmt) {
514	case S_IFCHR:
515		cd->sc_dk.dk_copenmask &= ~(1 << part);
516		break;
517	case S_IFBLK:
518		cd->sc_dk.dk_bopenmask &= ~(1 << part);
519		break;
520	}
521	cd->sc_dk.dk_openmask =
522	    cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
523
524	if (cd->sc_dk.dk_openmask == 0) {
525		/* synchronise caches on last close */
526		cdcachesync(periph, silent);
527
528		/* drain outstanding calls */
529		scsipi_wait_drain(periph);
530
531		scsipi_prevent(periph, SPAMR_ALLOW,
532		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
533		    XS_CTL_IGNORE_NOT_READY | silent);
534		periph->periph_flags &= ~PERIPH_OPEN;
535
536		scsipi_wait_drain(periph);
537
538		scsipi_adapter_delref(adapt);
539	}
540
541	mutex_exit(&cd->sc_lock);
542	return (0);
543}
544
545/*
546 * Actually translate the requested transfer into one the physical driver can
547 * understand.  The transfer is described by a buf and will include only one
548 * physical transfer.
549 */
550static void
551cdstrategy(struct buf *bp)
552{
553	struct cd_softc *cd = device_lookup_private(&cd_cd,CDUNIT(bp->b_dev));
554	struct disklabel *lp;
555	struct scsipi_periph *periph = cd->sc_periph;
556	daddr_t blkno;
557	int s;
558
559	SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdstrategy "));
560	SC_DEBUG(cd->sc_periph, SCSIPI_DB1,
561	    ("%d bytes @ blk %" PRId64 "\n", bp->b_bcount, bp->b_blkno));
562	/*
563	 * If the device has been made invalid, error out
564	 * maybe the media changed
565	 */
566	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
567		if (periph->periph_flags & PERIPH_OPEN)
568			bp->b_error = EIO;
569		else
570			bp->b_error = ENODEV;
571		goto done;
572	}
573
574	lp = cd->sc_dk.dk_label;
575
576	/*
577	 * The transfer must be a whole number of blocks, offset must not
578	 * be negative.
579	 */
580	if ((bp->b_bcount % lp->d_secsize) != 0 ||
581	    bp->b_blkno < 0 ) {
582		bp->b_error = EINVAL;
583		goto done;
584	}
585	/*
586	 * If it's a null transfer, return immediately
587	 */
588	if (bp->b_bcount == 0)
589		goto done;
590
591	/*
592	 * Do bounds checking, adjust transfer. if error, process.
593	 * If end of partition, just return.
594	 */
595	if (CDPART(bp->b_dev) == RAW_PART) {
596		if (bounds_check_with_mediasize(bp, DEV_BSIZE,
597		    cd->params.disksize512) <= 0)
598			goto done;
599	} else {
600		if (bounds_check_with_label(&cd->sc_dk, bp,
601		    (cd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0)
602			goto done;
603	}
604
605	/*
606	 * Now convert the block number to absolute and put it in
607	 * terms of the device's logical block size.
608	 */
609	blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
610	if (CDPART(bp->b_dev) != RAW_PART)
611		blkno += lp->d_partitions[CDPART(bp->b_dev)].p_offset;
612
613	bp->b_rawblkno = blkno;
614
615	/*
616	 * If the disklabel sector size does not match the device
617	 * sector size we may need to do some extra work.
618	 */
619	if (lp->d_secsize != cd->params.blksize) {
620
621		/*
622		 * If the xfer is not a multiple of the device block size
623		 * or it is not block aligned, we need to bounce it.
624		 */
625		if ((bp->b_bcount % cd->params.blksize) != 0 ||
626			((blkno * lp->d_secsize) % cd->params.blksize) != 0) {
627			struct cdbounce *bounce;
628			struct buf *nbp;
629			long count;
630
631			if ((bp->b_flags & B_READ) == 0) {
632
633				/* XXXX We don't support bouncing writes. */
634				bp->b_error = EACCES;
635				goto done;
636			}
637
638			bounce = malloc(sizeof(*bounce), M_DEVBUF, M_NOWAIT);
639			if (!bounce) {
640				/* No memory -- fail the iop. */
641				bp->b_error = ENOMEM;
642				goto done;
643			}
644
645			bounce->obp = bp;
646			bounce->resid = bp->b_bcount;
647			bounce->doff = 0;
648			count = ((blkno * lp->d_secsize) % cd->params.blksize);
649			bounce->soff = count;
650			count += bp->b_bcount;
651			count = roundup(count, cd->params.blksize);
652			bounce->bcount = bounce->resid;
653			if (count > MAXPHYS) {
654				bounce->bcount = MAXPHYS - bounce->soff;
655				count = MAXPHYS;
656			}
657
658			blkno = ((blkno * lp->d_secsize) / cd->params.blksize);
659			nbp = getiobuf(NULL, false);
660			if (!nbp) {
661				/* No memory -- fail the iop. */
662				free(bounce, M_DEVBUF);
663				bp->b_error = ENOMEM;
664				goto done;
665			}
666			nbp->b_data = malloc(count, M_DEVBUF, M_NOWAIT);
667			if (!nbp->b_data) {
668				/* No memory -- fail the iop. */
669				free(bounce, M_DEVBUF);
670				putiobuf(nbp);
671				bp->b_error = ENOMEM;
672				goto done;
673			}
674
675			/* Set up the IOP to the bounce buffer. */
676			nbp->b_error = 0;
677			nbp->b_proc = bp->b_proc;
678			nbp->b_bcount = count;
679			nbp->b_bufsize = count;
680			nbp->b_rawblkno = blkno;
681			nbp->b_flags = bp->b_flags | B_READ;
682			nbp->b_oflags = bp->b_oflags;
683			nbp->b_cflags = bp->b_cflags;
684			nbp->b_iodone = cdbounce;
685
686			/* store bounce state in b_private and use new buf */
687			nbp->b_private = bounce;
688
689			BIO_COPYPRIO(nbp, bp);
690
691			bp = nbp;
692
693		} else {
694			/* Xfer is aligned -- just adjust the start block */
695			bp->b_rawblkno = (blkno * lp->d_secsize) /
696				cd->params.blksize;
697		}
698	}
699	s = splbio();
700
701	/*
702	 * Place it in the queue of disk activities for this disk.
703	 *
704	 * XXX Only do disksort() if the current operating mode does not
705	 * XXX include tagged queueing.
706	 */
707	bufq_put(cd->buf_queue, bp);
708
709	/*
710	 * Tell the device to get going on the transfer if it's
711	 * not doing anything, otherwise just wait for completion
712	 */
713	cdstart(cd->sc_periph);
714
715	splx(s);
716	return;
717
718done:
719	/*
720	 * Correctly set the buf to indicate a completed xfer
721	 */
722	bp->b_resid = bp->b_bcount;
723	biodone(bp);
724}
725
726/*
727 * cdstart looks to see if there is a buf waiting for the device
728 * and that the device is not already busy. If both are true,
729 * It deques the buf and creates a scsi command to perform the
730 * transfer in the buf. The transfer request will call scsipi_done
731 * on completion, which will in turn call this routine again
732 * so that the next queued transfer is performed.
733 * The bufs are queued by the strategy routine (cdstrategy)
734 *
735 * This routine is also called after other non-queued requests
736 * have been made of the scsi driver, to ensure that the queue
737 * continues to be drained.
738 *
739 * must be called at the correct (highish) spl level
740 * cdstart() is called at splbio from cdstrategy, cdrestart and scsipi_done
741 */
742static void
743cdstart(struct scsipi_periph *periph)
744{
745	struct cd_softc *cd = device_private(periph->periph_dev);
746	struct buf *bp = 0;
747	struct scsipi_rw_10 cmd_big;
748	struct scsi_rw_6 cmd_small;
749	struct scsipi_generic *cmdp;
750	struct scsipi_xfer *xs;
751	int flags, nblks, cmdlen, error;
752
753	SC_DEBUG(periph, SCSIPI_DB2, ("cdstart "));
754	/*
755	 * Check if the device has room for another command
756	 */
757	while (periph->periph_active < periph->periph_openings) {
758		/*
759		 * there is excess capacity, but a special waits
760		 * It'll need the adapter as soon as we clear out of the
761		 * way and let it run (user level wait).
762		 */
763		if (periph->periph_flags & PERIPH_WAITING) {
764			periph->periph_flags &= ~PERIPH_WAITING;
765			wakeup((void *)periph);
766			return;
767		}
768
769		/*
770		 * If the device has become invalid, abort all the
771		 * reads and writes until all files have been closed and
772		 * re-opened
773		 */
774		if (__predict_false(
775		    (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
776			if ((bp = bufq_get(cd->buf_queue)) != NULL) {
777				bp->b_error = EIO;
778				bp->b_resid = bp->b_bcount;
779				biodone(bp);
780				continue;
781			} else {
782				return;
783			}
784		}
785
786		/*
787		 * See if there is a buf with work for us to do..
788		 */
789		if ((bp = bufq_peek(cd->buf_queue)) == NULL)
790			return;
791
792		/*
793		 * We have a buf, now we should make a command.
794		 */
795
796		nblks = howmany(bp->b_bcount, cd->params.blksize);
797
798		/*
799		 *  Fill out the scsi command.  If the transfer will
800		 *  fit in a "small" cdb, use it.
801		 */
802		if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) &&
803		    ((nblks & 0xff) == nblks) &&
804		    !(periph->periph_quirks & PQUIRK_ONLYBIG)) {
805			/*
806			 * We can fit in a small cdb.
807			 */
808			memset(&cmd_small, 0, sizeof(cmd_small));
809			cmd_small.opcode = (bp->b_flags & B_READ) ?
810			    SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND;
811			_lto3b(bp->b_rawblkno, cmd_small.addr);
812			cmd_small.length = nblks & 0xff;
813			cmdlen = sizeof(cmd_small);
814			cmdp = (struct scsipi_generic *)&cmd_small;
815		} else {
816			/*
817			 * Need a large cdb.
818			 */
819			memset(&cmd_big, 0, sizeof(cmd_big));
820			cmd_big.opcode = (bp->b_flags & B_READ) ?
821			    READ_10 : WRITE_10;
822			_lto4b(bp->b_rawblkno, cmd_big.addr);
823			_lto2b(nblks, cmd_big.length);
824			cmdlen = sizeof(cmd_big);
825			cmdp = (struct scsipi_generic *)&cmd_big;
826		}
827
828		/* Instrumentation. */
829		disk_busy(&cd->sc_dk);
830
831		/*
832		 * Figure out what flags to use.
833		 */
834		flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG;
835		if (bp->b_flags & B_READ)
836			flags |= XS_CTL_DATA_IN;
837		else
838			flags |= XS_CTL_DATA_OUT;
839
840		/*
841		 * Call the routine that chats with the adapter.
842		 * Note: we cannot sleep as we may be an interrupt
843		 */
844		xs = scsipi_make_xs(periph, cmdp, cmdlen,
845		    (u_char *)bp->b_data, bp->b_bcount,
846		    CDRETRIES, 30000, bp, flags);
847		if (__predict_false(xs == NULL)) {
848			/*
849			 * out of memory. Keep this buffer in the queue, and
850			 * retry later.
851			 */
852			callout_reset(&cd->sc_callout, hz / 2, cdrestart,
853			    periph);
854			return;
855		}
856		/*
857		 * need to dequeue the buffer before queuing the command,
858		 * because cdstart may be called recursively from the
859		 * HBA driver
860		 */
861#ifdef DIAGNOSTIC
862		if (bufq_get(cd->buf_queue) != bp)
863			panic("cdstart(): dequeued wrong buf");
864#else
865		bufq_get(cd->buf_queue);
866#endif
867		error = scsipi_execute_xs(xs);
868		/* with a scsipi_xfer preallocated, scsipi_command can't fail */
869		KASSERT(error == 0);
870	}
871}
872
873static void
874cdrestart(void *v)
875{
876	int s = splbio();
877	cdstart((struct scsipi_periph *)v);
878	splx(s);
879}
880
881static void
882cddone(struct scsipi_xfer *xs, int error)
883{
884	struct cd_softc *cd = device_private(xs->xs_periph->periph_dev);
885	struct buf *bp = xs->bp;
886
887	if (bp) {
888		/* note, bp->b_resid is NOT initialised */
889		bp->b_error = error;
890		bp->b_resid = xs->resid;
891		if (error) {
892			/* on a read/write error bp->b_resid is zero, so fix */
893			bp->b_resid = bp->b_bcount;
894		}
895
896		disk_unbusy(&cd->sc_dk, bp->b_bcount - bp->b_resid,
897		    (bp->b_flags & B_READ));
898		rnd_add_uint32(&cd->rnd_source, bp->b_rawblkno);
899
900		biodone(bp);
901	}
902}
903
904static void
905cdbounce(struct buf *bp)
906{
907	struct cdbounce *bounce = (struct cdbounce *)bp->b_private;
908	struct buf *obp = bounce->obp;
909	struct cd_softc *cd =
910	    device_lookup_private(&cd_cd, CDUNIT(obp->b_dev));
911	struct disklabel *lp = cd->sc_dk.dk_label;
912
913	if (bp->b_error != 0) {
914		/* EEK propagate the error and free the memory */
915		goto done;
916	}
917
918	KASSERT(obp->b_flags & B_READ);
919
920	/* copy bounce buffer to final destination */
921	memcpy((char *)obp->b_data + bounce->doff,
922	    (char *)bp->b_data + bounce->soff, bounce->bcount);
923
924	/* check if we need more I/O, i.e. bounce put us over MAXPHYS */
925	KASSERT(bounce->resid >= bounce->bcount);
926	bounce->resid -= bounce->bcount;
927	if (bounce->resid > 0) {
928		struct buf *nbp;
929		daddr_t blkno;
930		long count;
931		int s;
932
933		blkno = obp->b_rawblkno +
934		    ((obp->b_bcount - bounce->resid) / lp->d_secsize);
935		count = ((blkno * lp->d_secsize) % cd->params.blksize);
936		blkno = (blkno * lp->d_secsize) / cd->params.blksize;
937		bounce->soff = count;
938		bounce->doff += bounce->bcount;
939		count += bounce->resid;
940		count = roundup(count, cd->params.blksize);
941		bounce->bcount = bounce->resid;
942		if (count > MAXPHYS) {
943			bounce->bcount = MAXPHYS - bounce->soff;
944			count = MAXPHYS;
945		}
946
947		nbp = getiobuf(NULL, false);
948		if (!nbp) {
949			/* No memory -- fail the iop. */
950			bp->b_error = ENOMEM;
951			goto done;
952		}
953
954		/* Set up the IOP to the bounce buffer. */
955		nbp->b_error = 0;
956		nbp->b_proc = obp->b_proc;
957		nbp->b_bcount = count;
958		nbp->b_bufsize = count;
959		nbp->b_data = bp->b_data;
960		nbp->b_rawblkno = blkno;
961		nbp->b_flags = obp->b_flags | B_READ;
962		nbp->b_oflags = obp->b_oflags;
963		nbp->b_cflags = obp->b_cflags;
964		nbp->b_iodone = cdbounce;
965
966		/* store bounce state in b_private and use new buf */
967		nbp->b_private = bounce;
968
969		BIO_COPYPRIO(nbp, obp);
970
971		bp->b_data = NULL;
972		putiobuf(bp);
973
974		/* enqueue the request and return */
975		s = splbio();
976		bufq_put(cd->buf_queue, nbp);
977		cdstart(cd->sc_periph);
978		splx(s);
979
980		return;
981	}
982
983done:
984	obp->b_error = bp->b_error;
985	obp->b_resid = bp->b_resid;
986	free(bp->b_data, M_DEVBUF);
987	free(bounce, M_DEVBUF);
988	bp->b_data = NULL;
989	putiobuf(bp);
990	biodone(obp);
991}
992
993static int
994cd_interpret_sense(struct scsipi_xfer *xs)
995{
996	struct scsipi_periph *periph = xs->xs_periph;
997	struct scsi_sense_data *sense = &xs->sense.scsi_sense;
998	int retval = EJUSTRETURN;
999
1000	/*
1001	 * If it isn't a extended or extended/deferred error, let
1002	 * the generic code handle it.
1003	 */
1004	if (SSD_RCODE(sense->response_code) != SSD_RCODE_CURRENT &&
1005	    SSD_RCODE(sense->response_code) != SSD_RCODE_DEFERRED)
1006		return (retval);
1007
1008	/*
1009	 * If we got a "Unit not ready" (SKEY_NOT_READY) and "Logical Unit
1010	 * Is In The Process of Becoming Ready" (Sense code 0x04,0x01), then
1011	 * wait a bit for the drive to spin up
1012	 */
1013
1014	if ((SSD_SENSE_KEY(sense->flags) == SKEY_NOT_READY) &&
1015	    (sense->asc == 0x04) && (sense->ascq == 0x01)) {
1016		/*
1017		 * Sleep for 5 seconds to wait for the drive to spin up
1018		 */
1019
1020		SC_DEBUG(periph, SCSIPI_DB1, ("Waiting 5 sec for CD "
1021						"spinup\n"));
1022		if (!callout_pending(&periph->periph_callout))
1023			scsipi_periph_freeze(periph, 1);
1024		callout_reset(&periph->periph_callout,
1025		    5 * hz, scsipi_periph_timed_thaw, periph);
1026		retval = ERESTART;
1027	}
1028
1029	/*
1030	 * If we got a "Unit not ready" (SKEY_NOT_READY) and "Logical Unit Not
1031	 * Ready, Operation In Progress" (Sense code 0x04, 0x07),
1032	 * then wait for the specified time
1033	 */
1034
1035	if ((SSD_SENSE_KEY(sense->flags) == SKEY_NOT_READY) &&
1036	    (sense->asc == 0x04) && (sense->ascq == 0x07)) {
1037		/*
1038		 * we could listen to the delay; but it looks like the skey
1039		 * data is not always returned.
1040		 */
1041		/* cd_delay = _2btol(sense->sks.sks_bytes); */
1042
1043		/* wait for a half second and get going again */
1044		if (!callout_pending(&periph->periph_callout))
1045			scsipi_periph_freeze(periph, 1);
1046		callout_reset(&periph->periph_callout,
1047		    hz/2, scsipi_periph_timed_thaw, periph);
1048		retval = ERESTART;
1049	}
1050
1051	/*
1052	 * If we got a "Unit not ready" (SKEY_NOT_READY) and "Long write in
1053	 * progress" (Sense code 0x04, 0x08), then wait for the specified
1054	 * time
1055	 */
1056
1057	if ((SSD_SENSE_KEY(sense->flags) == SKEY_NOT_READY) &&
1058	    (sense->asc == 0x04) && (sense->ascq == 0x08)) {
1059		/*
1060		 * long write in process; we could listen to the delay; but it
1061		 * looks like the skey data is not always returned.
1062		 */
1063		/* cd_delay = _2btol(sense->sks.sks_bytes); */
1064
1065		/* wait for a half second and get going again */
1066		if (!callout_pending(&periph->periph_callout))
1067			scsipi_periph_freeze(periph, 1);
1068		callout_reset(&periph->periph_callout,
1069		    hz/2, scsipi_periph_timed_thaw, periph);
1070		retval = ERESTART;
1071	}
1072
1073	return (retval);
1074}
1075
1076static void
1077cdminphys(struct buf *bp)
1078{
1079	struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(bp->b_dev));
1080	long xmax;
1081
1082	/*
1083	 * If the device is ancient, we want to make sure that
1084	 * the transfer fits into a 6-byte cdb.
1085	 *
1086	 * XXX Note that the SCSI-I spec says that 256-block transfers
1087	 * are allowed in a 6-byte read/write, and are specified
1088	 * by settng the "length" to 0.  However, we're conservative
1089	 * here, allowing only 255-block transfers in case an
1090	 * ancient device gets confused by length == 0.  A length of 0
1091	 * in a 10-byte read/write actually means 0 blocks.
1092	 */
1093	if (cd->flags & CDF_ANCIENT) {
1094		xmax = cd->sc_dk.dk_label->d_secsize * 0xff;
1095
1096		if (bp->b_bcount > xmax)
1097			bp->b_bcount = xmax;
1098	}
1099
1100	(*cd->sc_periph->periph_channel->chan_adapter->adapt_minphys)(bp);
1101}
1102
1103static int
1104cdread(dev_t dev, struct uio *uio, int ioflag)
1105{
1106	return (physio(cdstrategy, NULL, dev, B_READ, cdminphys, uio));
1107}
1108
1109static int
1110cdwrite(dev_t dev, struct uio *uio, int ioflag)
1111{
1112	return (physio(cdstrategy, NULL, dev, B_WRITE, cdminphys, uio));
1113}
1114
1115#if 0	/* XXX Not used */
1116/*
1117 * conversion between minute-seconde-frame and logical block address
1118 * addresses format
1119 */
1120static void
1121lba2msf(u_long lba, u_char *m, u_char *s, u_char *f)
1122{
1123	u_long tmp;
1124
1125	tmp = lba + CD_BLOCK_OFFSET;	/* offset of first logical frame */
1126	tmp &= 0xffffff;		/* negative lbas use only 24 bits */
1127	*m = tmp / (CD_SECS * CD_FRAMES);
1128	tmp %= (CD_SECS * CD_FRAMES);
1129	*s = tmp / CD_FRAMES;
1130	*f = tmp % CD_FRAMES;
1131}
1132#endif /* XXX Not used */
1133
1134/*
1135 * Convert an hour:minute:second:frame address to a logical block adres. In
1136 * theory the number of secs/minute and number of frames/second could be
1137 * configured differently in the device  as could the block offset but in
1138 * practice these values are rock solid and most drives don't even allow
1139 * theses values to be changed.
1140 */
1141static uint32_t
1142hmsf2lba(uint8_t h, uint8_t m, uint8_t s, uint8_t f)
1143{
1144	return (((((uint32_t) h * 60 + m) * CD_SECS) + s) * CD_FRAMES + f)
1145		- CD_BLOCK_OFFSET;
1146}
1147
1148static int
1149cdreadmsaddr(struct cd_softc *cd, struct cd_formatted_toc *toc, int *addr)
1150{
1151	struct scsipi_periph *periph = cd->sc_periph;
1152	int error;
1153	struct cd_toc_entry *cte;
1154
1155	error = cd_read_toc(cd, CD_TOC_FORM, 0, 0, toc,
1156	    sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry),
1157	    0, 0x40 /* control word for "get MS info" */);
1158
1159	if (error)
1160		return (error);
1161
1162	cte = &toc->entries[0];
1163	if (periph->periph_quirks & PQUIRK_LITTLETOC) {
1164		cte->addr.lba = le32toh(cte->addr.lba);
1165		toc->header.len = le16toh(toc->header.len);
1166	} else {
1167		cte->addr.lba = be32toh(cte->addr.lba);
1168		toc->header.len = be16toh(toc->header.len);
1169	}
1170
1171	*addr = (toc->header.len >= 10 && cte->track > 1) ?
1172		cte->addr.lba : 0;
1173	return 0;
1174}
1175
1176/* synchronise caches code from sd.c, move to scsipi_ioctl.c ? */
1177static int
1178cdcachesync(struct scsipi_periph *periph, int flags) {
1179	struct scsi_synchronize_cache_10 cmd;
1180
1181	/*
1182	 * Issue a SYNCHRONIZE CACHE. MMC devices have to issue with address 0
1183	 * and length 0 as it can't synchronise parts of the disc per spec.
1184	 * We ignore ILLEGAL REQUEST in the event that the command is not
1185	 * supported by the device, and poll for completion so that we know
1186	 * that the cache has actually been flushed.
1187	 *
1188	 * XXX should we handle the PQUIRK_NOSYNCCACHE ?
1189	 */
1190
1191	memset(&cmd, 0, sizeof(cmd));
1192	cmd.opcode = SCSI_SYNCHRONIZE_CACHE_10;
1193
1194	return (scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
1195	    CDRETRIES, 30000, NULL, flags | XS_CTL_IGNORE_ILLEGAL_REQUEST));
1196}
1197
1198static int
1199do_cdioreadentries(struct cd_softc *cd, struct ioc_read_toc_entry *te,
1200    struct cd_formatted_toc *toc)
1201{
1202	/* READ TOC format 0 command, entries */
1203	struct ioc_toc_header *th;
1204	struct cd_toc_entry *cte;
1205	u_int len = te->data_len;
1206	int ntracks;
1207	int error;
1208
1209	th = &toc->header;
1210
1211	if (len > sizeof(toc->entries) ||
1212	    len < sizeof(toc->entries[0]))
1213		return (EINVAL);
1214	error = cd_read_toc(cd, CD_TOC_FORM, te->address_format,
1215	    te->starting_track, toc,
1216	    sizeof(toc->header) + len,
1217	    0, 0);
1218	if (error)
1219		return (error);
1220	if (te->address_format == CD_LBA_FORMAT)
1221		for (ntracks =
1222		    th->ending_track - th->starting_track + 1;
1223		    ntracks >= 0; ntracks--) {
1224			cte = &toc->entries[ntracks];
1225			cte->addr_type = CD_LBA_FORMAT;
1226			if (cd->sc_periph->periph_quirks & PQUIRK_LITTLETOC)
1227				cte->addr.lba = le32toh(cte->addr.lba);
1228			else
1229				cte->addr.lba = be32toh(cte->addr.lba);
1230		}
1231	if (cd->sc_periph->periph_quirks & PQUIRK_LITTLETOC)
1232		th->len = le16toh(th->len);
1233	else
1234		th->len = be16toh(th->len);
1235	return 0;
1236}
1237
1238/*
1239 * Perform special action on behalf of the user.
1240 * Knows about the internals of this device
1241 */
1242static int
1243cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1244{
1245	struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(dev));
1246	struct scsipi_periph *periph = cd->sc_periph;
1247	struct cd_formatted_toc toc;
1248	int part = CDPART(dev);
1249	int error = 0;
1250	int s;
1251#ifdef __HAVE_OLD_DISKLABEL
1252	struct disklabel *newlabel = NULL;
1253#endif
1254
1255	SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdioctl 0x%lx ", cmd));
1256
1257	/*
1258	 * If the device is not valid, some IOCTLs can still be
1259	 * handled on the raw partition. Check this here.
1260	 */
1261	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
1262		switch (cmd) {
1263		case DIOCWLABEL:
1264		case DIOCLOCK:
1265		case ODIOCEJECT:
1266		case DIOCEJECT:
1267		case DIOCCACHESYNC:
1268		case DIOCTUR:
1269		case SCIOCIDENTIFY:
1270		case OSCIOCIDENTIFY:
1271		case SCIOCCOMMAND:
1272		case SCIOCDEBUG:
1273		case CDIOCGETVOL:
1274		case CDIOCSETVOL:
1275		case CDIOCSETMONO:
1276		case CDIOCSETSTEREO:
1277		case CDIOCSETMUTE:
1278		case CDIOCSETLEFT:
1279		case CDIOCSETRIGHT:
1280		case CDIOCCLOSE:
1281		case CDIOCEJECT:
1282		case CDIOCALLOW:
1283		case CDIOCPREVENT:
1284		case CDIOCSETDEBUG:
1285		case CDIOCCLRDEBUG:
1286		case CDIOCRESET:
1287		case SCIOCRESET:
1288		case CDIOCLOADUNLOAD:
1289		case DVD_AUTH:
1290		case DVD_READ_STRUCT:
1291		case DIOCGSTRATEGY:
1292		case DIOCSSTRATEGY:
1293			if (part == RAW_PART)
1294				break;
1295		/* FALLTHROUGH */
1296		default:
1297			if ((periph->periph_flags & PERIPH_OPEN) == 0)
1298				return (ENODEV);
1299			else
1300				return (EIO);
1301		}
1302	}
1303
1304	error = disk_ioctl(&cd->sc_dk, cmd, addr, flag, l);
1305	if (error != EPASSTHROUGH)
1306		return (error);
1307
1308	switch (cmd) {
1309	case DIOCGDINFO:
1310		*(struct disklabel *)addr = *(cd->sc_dk.dk_label);
1311		return (0);
1312#ifdef __HAVE_OLD_DISKLABEL
1313	case ODIOCGDINFO:
1314		newlabel = malloc(sizeof (*newlabel), M_TEMP, M_WAITOK);
1315		if (newlabel == NULL)
1316			return (EIO);
1317		memcpy(newlabel, cd->sc_dk.dk_label, sizeof (*newlabel));
1318		if (newlabel->d_npartitions > OLDMAXPARTITIONS)
1319			error = ENOTTY;
1320		else
1321			memcpy(addr, newlabel, sizeof (struct olddisklabel));
1322		free(newlabel, M_TEMP);
1323		return error;
1324#endif
1325
1326	case DIOCGPART:
1327		((struct partinfo *)addr)->disklab = cd->sc_dk.dk_label;
1328		((struct partinfo *)addr)->part =
1329		    &cd->sc_dk.dk_label->d_partitions[part];
1330		return (0);
1331
1332	case DIOCWDINFO:
1333	case DIOCSDINFO:
1334#ifdef __HAVE_OLD_DISKLABEL
1335	case ODIOCWDINFO:
1336	case ODIOCSDINFO:
1337#endif
1338	{
1339		struct disklabel *lp;
1340
1341		if ((flag & FWRITE) == 0)
1342			return (EBADF);
1343
1344#ifdef __HAVE_OLD_DISKLABEL
1345		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
1346			newlabel = malloc(sizeof (*newlabel), M_TEMP,
1347			    M_WAITOK | M_ZERO);
1348			if (newlabel == NULL)
1349				return (EIO);
1350			memcpy(newlabel, addr, sizeof (struct olddisklabel));
1351			lp = newlabel;
1352		} else
1353#endif
1354		lp = addr;
1355
1356		mutex_enter(&cd->sc_lock);
1357		cd->flags |= CDF_LABELLING;
1358
1359		error = setdisklabel(cd->sc_dk.dk_label,
1360		    lp, /*cd->sc_dk.dk_openmask : */0,
1361		    cd->sc_dk.dk_cpulabel);
1362		if (error == 0) {
1363			/* XXX ? */
1364		}
1365
1366		cd->flags &= ~CDF_LABELLING;
1367		mutex_exit(&cd->sc_lock);
1368#ifdef __HAVE_OLD_DISKLABEL
1369		if (newlabel != NULL)
1370			free(newlabel, M_TEMP);
1371#endif
1372		return (error);
1373	}
1374
1375	case DIOCWLABEL:
1376		return (EBADF);
1377
1378	case DIOCGDEFLABEL:
1379		cdgetdefaultlabel(cd, &toc, addr);
1380		return (0);
1381
1382#ifdef __HAVE_OLD_DISKLABEL
1383	case ODIOCGDEFLABEL:
1384		newlabel = malloc(sizeof (*newlabel), M_TEMP, M_WAITOK);
1385		if (newlabel == NULL)
1386			return (EIO);
1387		cdgetdefaultlabel(cd, &toc, newlabel);
1388		if (newlabel->d_npartitions > OLDMAXPARTITIONS)
1389			error = ENOTTY;
1390		else
1391			memcpy(addr, newlabel, sizeof (struct olddisklabel));
1392		free(newlabel, M_TEMP);
1393		return error;
1394#endif
1395
1396	case DIOCTUR: {
1397		/* test unit ready */
1398		error = scsipi_test_unit_ready(cd->sc_periph, XS_CTL_SILENT);
1399		*((int*)addr) = (error == 0);
1400		if (error == ENODEV || error == EIO || error == 0)
1401			return 0;
1402		return error;
1403	}
1404
1405	case CDIOCPLAYTRACKS: {
1406		/* PLAY_MSF command */
1407		struct ioc_play_track *args = addr;
1408
1409		if ((error = cd_set_pa_immed(cd, 0)) != 0)
1410			return (error);
1411		return (cd_play_tracks(cd, &toc, args->start_track,
1412		    args->start_index, args->end_track, args->end_index));
1413	}
1414	case CDIOCPLAYMSF: {
1415		/* PLAY_MSF command */
1416		struct ioc_play_msf *args = addr;
1417
1418		if ((error = cd_set_pa_immed(cd, 0)) != 0)
1419			return (error);
1420		return (cd_play_msf(cd, args->start_m, args->start_s,
1421		    args->start_f, args->end_m, args->end_s, args->end_f));
1422	}
1423	case CDIOCPLAYBLOCKS: {
1424		/* PLAY command */
1425		struct ioc_play_blocks *args = addr;
1426
1427		if ((error = cd_set_pa_immed(cd, 0)) != 0)
1428			return (error);
1429		return (cd_play(cd, args->blk, args->len));
1430	}
1431	case CDIOCREADSUBCHANNEL: {
1432		/* READ_SUBCHANNEL command */
1433		struct ioc_read_subchannel *args = addr;
1434		struct cd_sub_channel_info data;
1435		u_int len = args->data_len;
1436
1437		if (len > sizeof(data) ||
1438		    len < sizeof(struct cd_sub_channel_header))
1439			return (EINVAL);
1440		error = cd_read_subchannel(cd, args->address_format,
1441		    args->data_format, args->track, &data, len, 0);
1442		if (error)
1443			return (error);
1444		len = min(len, _2btol(data.header.data_len) +
1445		    sizeof(struct cd_sub_channel_header));
1446		return (copyout(&data, args->data, len));
1447	}
1448	case CDIOCREADSUBCHANNEL_BUF: {
1449		/* As CDIOCREADSUBCHANNEL, but without a 2nd buffer area */
1450		struct ioc_read_subchannel_buf *args = addr;
1451		if (args->req.data_len != sizeof args->info)
1452			return EINVAL;
1453		return cd_read_subchannel(cd, args->req.address_format,
1454		    args->req.data_format, args->req.track, &args->info,
1455		    sizeof(args->info), 0);
1456	}
1457	case CDIOREADTOCHEADER: {
1458		/* READ TOC format 0 command, static header */
1459		if ((error = cd_read_toc(cd, CD_TOC_FORM, 0, 0,
1460		    &toc, sizeof(toc.header), 0, 0)) != 0)
1461			return (error);
1462		if (cd->sc_periph->periph_quirks & PQUIRK_LITTLETOC)
1463			toc.header.len = le16toh(toc.header.len);
1464		else
1465			toc.header.len = be16toh(toc.header.len);
1466		memcpy(addr, &toc.header, sizeof(toc.header));
1467		return (0);
1468	}
1469	case CDIOREADTOCENTRYS: {
1470		struct ioc_read_toc_entry *te = addr;
1471		error = do_cdioreadentries(cd, te, &toc);
1472		if (error != 0)
1473			return error;
1474		return copyout(toc.entries, te->data, min(te->data_len,
1475		    toc.header.len - (sizeof(toc.header.starting_track)
1476			+ sizeof(toc.header.ending_track))));
1477	}
1478	case CDIOREADTOCENTRIES_BUF: {
1479		struct ioc_read_toc_entry_buf *te = addr;
1480		error = do_cdioreadentries(cd, &te->req, &toc);
1481		if (error != 0)
1482			return error;
1483		memcpy(te->entry, toc.entries, min(te->req.data_len,
1484		    toc.header.len - (sizeof(toc.header.starting_track)
1485			+ sizeof(toc.header.ending_track))));
1486		return 0;
1487	}
1488	case CDIOREADMSADDR: {
1489		/* READ TOC format 0 command, length of first track only */
1490		int sessno = *(int*)addr;
1491
1492		if (sessno != 0)
1493			return (EINVAL);
1494
1495		return (cdreadmsaddr(cd, &toc, addr));
1496	}
1497	case CDIOCSETPATCH: {
1498		struct ioc_patch *arg = addr;
1499
1500		return (cd_setchan(cd, arg->patch[0], arg->patch[1],
1501		    arg->patch[2], arg->patch[3], 0));
1502	}
1503	case CDIOCGETVOL: {
1504		/* MODE SENSE command (AUDIO page) */
1505		struct ioc_vol *arg = addr;
1506
1507		return (cd_getvol(cd, arg, 0));
1508	}
1509	case CDIOCSETVOL: {
1510		/* MODE SENSE/MODE SELECT commands (AUDIO page) */
1511		struct ioc_vol *arg = addr;
1512
1513		return (cd_setvol(cd, arg, 0));
1514	}
1515	case CDIOCSETMONO:
1516		/* MODE SENSE/MODE SELECT commands (AUDIO page) */
1517		return (cd_setchan(cd, BOTH_CHANNEL, BOTH_CHANNEL,
1518		    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1519
1520	case CDIOCSETSTEREO:
1521		/* MODE SENSE/MODE SELECT commands (AUDIO page) */
1522		return (cd_setchan(cd, LEFT_CHANNEL, RIGHT_CHANNEL,
1523		    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1524
1525	case CDIOCSETMUTE:
1526		/* MODE SENSE/MODE SELECT commands (AUDIO page) */
1527		return (cd_setchan(cd, MUTE_CHANNEL, MUTE_CHANNEL,
1528		    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1529
1530	case CDIOCSETLEFT:
1531		/* MODE SENSE/MODE SELECT commands (AUDIO page) */
1532		return (cd_setchan(cd, LEFT_CHANNEL, LEFT_CHANNEL,
1533		    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1534
1535	case CDIOCSETRIGHT:
1536		/* MODE SENSE/MODE SELECT commands (AUDIO page) */
1537		return (cd_setchan(cd, RIGHT_CHANNEL, RIGHT_CHANNEL,
1538		    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1539
1540	case CDIOCRESUME:
1541		/* PAUSE command */
1542		return (cd_pause(cd, PA_RESUME));
1543	case CDIOCPAUSE:
1544		/* PAUSE command */
1545		return (cd_pause(cd, PA_PAUSE));
1546	case CDIOCSTART:
1547		return (scsipi_start(periph, SSS_START, 0));
1548	case CDIOCSTOP:
1549		return (scsipi_start(periph, SSS_STOP, 0));
1550	case CDIOCCLOSE:
1551		return (scsipi_start(periph, SSS_START|SSS_LOEJ,
1552		    XS_CTL_IGNORE_NOT_READY | XS_CTL_IGNORE_MEDIA_CHANGE));
1553	case DIOCEJECT:
1554		if (*(int *)addr == 0) {
1555			/*
1556			 * Don't force eject: check that we are the only
1557			 * partition open. If so, unlock it.
1558			 */
1559			if ((cd->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
1560			    cd->sc_dk.dk_bopenmask + cd->sc_dk.dk_copenmask ==
1561			    cd->sc_dk.dk_openmask) {
1562				error = scsipi_prevent(periph, SPAMR_ALLOW,
1563				    XS_CTL_IGNORE_NOT_READY);
1564				if (error)
1565					return (error);
1566			} else {
1567				return (EBUSY);
1568			}
1569		}
1570		/* FALLTHROUGH */
1571	case CDIOCEJECT: /* FALLTHROUGH */
1572	case ODIOCEJECT:
1573		error = scsipi_start(periph, SSS_STOP|SSS_LOEJ, 0);
1574		if (error == 0) {
1575			int i;
1576
1577			/*
1578			 * We have just successfully ejected the medium,
1579			 * all partitions cached are meaningless now.
1580			 * Make sure cdclose() will do silent operations
1581			 * now by marking all partitions unused.
1582			 * Before any real access, a new (default-)disk-
1583			 * label will be generated anyway.
1584			 */
1585			for (i = 0; i < cd->sc_dk.dk_label->d_npartitions;
1586			    i++)
1587				cd->sc_dk.dk_label->d_partitions[i].p_fstype =
1588					FS_UNUSED;
1589		}
1590		return error;
1591	case DIOCCACHESYNC:
1592		/* SYNCHRONISE CACHES command */
1593		return (cdcachesync(periph, 0));
1594	case CDIOCALLOW:
1595		return (scsipi_prevent(periph, SPAMR_ALLOW, 0));
1596	case CDIOCPREVENT:
1597		return (scsipi_prevent(periph, SPAMR_PREVENT_DT, 0));
1598	case DIOCLOCK:
1599		return (scsipi_prevent(periph,
1600		    (*(int *)addr) ? SPAMR_PREVENT_DT : SPAMR_ALLOW, 0));
1601	case CDIOCSETDEBUG:
1602		cd->sc_periph->periph_dbflags |= (SCSIPI_DB1 | SCSIPI_DB2);
1603		return (0);
1604	case CDIOCCLRDEBUG:
1605		cd->sc_periph->periph_dbflags &= ~(SCSIPI_DB1 | SCSIPI_DB2);
1606		return (0);
1607	case CDIOCRESET:
1608	case SCIOCRESET:
1609		return (cd_reset(cd));
1610	case CDIOCLOADUNLOAD:
1611		/* LOAD_UNLOAD command */
1612		return (cd_load_unload(cd, addr));
1613	case DVD_AUTH:
1614		/* GPCMD_REPORT_KEY or GPCMD_SEND_KEY command */
1615		return (dvd_auth(cd, addr));
1616	case DVD_READ_STRUCT:
1617		/* GPCMD_READ_DVD_STRUCTURE command */
1618		return (dvd_read_struct(cd, addr));
1619	case MMCGETDISCINFO:
1620		/*
1621		 * GET_CONFIGURATION, READ_DISCINFO, READ_TRACKINFO,
1622		 * (READ_TOCf2, READ_CD_CAPACITY and GET_CONFIGURATION) commands
1623		 */
1624		return mmc_getdiscinfo(periph, (struct mmc_discinfo *) addr);
1625	case MMCGETTRACKINFO:
1626		/* READ TOCf2, READ_CD_CAPACITY and READ_TRACKINFO commands */
1627		return mmc_gettrackinfo(periph, (struct mmc_trackinfo *) addr);
1628	case MMCOP:
1629		/*
1630		 * CLOSE TRACK/SESSION, RESERVE_TRACK, REPAIR_TRACK,
1631		 * SYNCHRONISE_CACHE commands
1632		 */
1633		return mmc_do_op(periph, (struct mmc_op *) addr);
1634	case MMCSETUPWRITEPARAMS :
1635		/* MODE SENSE page 5, MODE_SELECT page 5 commands */
1636		return mmc_setup_writeparams(periph, (struct mmc_writeparams *) addr);
1637	case DIOCGSTRATEGY:
1638	    {
1639		struct disk_strategy *dks = addr;
1640
1641		s = splbio();
1642		strlcpy(dks->dks_name, bufq_getstrategyname(cd->buf_queue),
1643		    sizeof(dks->dks_name));
1644		splx(s);
1645		dks->dks_paramlen = 0;
1646
1647		return 0;
1648	    }
1649	case DIOCSSTRATEGY:
1650	    {
1651		struct disk_strategy *dks = addr;
1652		struct bufq_state *new;
1653		struct bufq_state *old;
1654
1655		if ((flag & FWRITE) == 0) {
1656			return EBADF;
1657		}
1658		if (dks->dks_param != NULL) {
1659			return EINVAL;
1660		}
1661		dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */
1662		error = bufq_alloc(&new, dks->dks_name,
1663		    BUFQ_EXACT|BUFQ_SORT_RAWBLOCK);
1664		if (error) {
1665			return error;
1666		}
1667		s = splbio();
1668		old = cd->buf_queue;
1669		bufq_move(new, old);
1670		cd->buf_queue = new;
1671		splx(s);
1672		bufq_free(old);
1673
1674		return 0;
1675	    }
1676	default:
1677		if (part != RAW_PART)
1678			return (ENOTTY);
1679		return (scsipi_do_ioctl(periph, dev, cmd, addr, flag, l));
1680	}
1681
1682#ifdef DIAGNOSTIC
1683	panic("cdioctl: impossible");
1684#endif
1685}
1686
1687static void
1688cdgetdefaultlabel(struct cd_softc *cd, struct cd_formatted_toc *toc,
1689    struct disklabel *lp)
1690{
1691	int lastsession;
1692
1693	memset(lp, 0, sizeof(struct disklabel));
1694
1695	lp->d_secsize = cd->params.blksize;
1696	lp->d_ntracks = 1;
1697	lp->d_nsectors = 100;
1698	lp->d_ncylinders = (cd->params.disksize / 100) + 1;
1699	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1700
1701	switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(cd->sc_periph))) {
1702	case SCSIPI_BUSTYPE_SCSI:
1703		lp->d_type = DTYPE_SCSI;
1704		break;
1705	case SCSIPI_BUSTYPE_ATAPI:
1706		lp->d_type = DTYPE_ATAPI;
1707		break;
1708	}
1709	/*
1710	 * XXX
1711	 * We could probe the mode pages to figure out what kind of disc it is.
1712	 * Is this worthwhile?
1713	 */
1714	strncpy(lp->d_typename, "optical media", 16);
1715	strncpy(lp->d_packname, "fictitious", 16);
1716	lp->d_secperunit = cd->params.disksize;
1717	lp->d_rpm = 300;
1718	lp->d_interleave = 1;
1719	lp->d_flags = D_REMOVABLE | D_SCSI_MMC;
1720
1721	if (cdreadmsaddr(cd, toc, &lastsession) != 0)
1722		lastsession = 0;
1723
1724	lp->d_partitions[0].p_offset = 0;
1725	lp->d_partitions[0].p_size = lp->d_secperunit;
1726	lp->d_partitions[0].p_cdsession = lastsession;
1727	lp->d_partitions[0].p_fstype = FS_ISO9660;
1728
1729	lp->d_partitions[RAW_PART].p_offset = 0;
1730	lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
1731	lp->d_partitions[RAW_PART].p_fstype = FS_UDF;
1732
1733	lp->d_npartitions = RAW_PART + 1;
1734
1735	lp->d_magic = DISKMAGIC;
1736	lp->d_magic2 = DISKMAGIC;
1737	lp->d_checksum = dkcksum(lp);
1738}
1739
1740/*
1741 * Load the label information on the named device
1742 * Actually fabricate a disklabel
1743 *
1744 * EVENTUALLY take information about different
1745 * data tracks from the TOC and put it in the disklabel
1746 */
1747static void
1748cdgetdisklabel(struct cd_softc *cd)
1749{
1750	struct disklabel *lp = cd->sc_dk.dk_label;
1751	struct cd_formatted_toc toc;
1752	const char *errstring;
1753	int bmajor;
1754
1755	memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
1756
1757	cdgetdefaultlabel(cd, &toc, lp);
1758
1759	/*
1760	 * Call the generic disklabel extraction routine
1761	 *
1762	 * bmajor follows ata_raid code
1763	 */
1764	bmajor = devsw_name2blk(device_xname(cd->sc_dev), NULL, 0);
1765	errstring = readdisklabel(MAKECDDEV(bmajor,
1766	    device_unit(cd->sc_dev), RAW_PART),
1767	    cdstrategy, lp, cd->sc_dk.dk_cpulabel);
1768
1769	/* if all went OK, we are passed a NULL error string */
1770	if (errstring == NULL)
1771		return;
1772
1773	/* Reset to default label -- after printing error and the warning */
1774	aprint_error_dev(cd->sc_dev, "%s\n", errstring);
1775	memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
1776	cdgetdefaultlabel(cd, &toc, lp);
1777}
1778
1779/*
1780 * Reading a disc's total capacity is apparently a very difficult issue for the
1781 * SCSI standardisation group. Every disc type seems to have its own
1782 * (re)invented size request method and modifiers. The failsafe way of
1783 * determining the total (max) capacity i.e. not the recorded capacity but the
1784 * total maximum capacity is to request the info on the last track and
1785 * calculate the last lba.
1786 *
1787 * For ROM drives, we go for the CD recorded capacity. For recordable devices
1788 * we count.
1789 */
1790static int
1791read_cd_capacity(struct scsipi_periph *periph, u_int *blksize, u_long *last_lba)
1792{
1793	struct scsipi_read_cd_capacity    cap_cmd;
1794	struct scsipi_read_cd_cap_data    cap;
1795	struct scsipi_read_discinfo       di_cmd;
1796	struct scsipi_read_discinfo_data  di;
1797	struct scsipi_read_trackinfo      ti_cmd;
1798	struct scsipi_read_trackinfo_data ti;
1799	uint32_t track_start, track_size;
1800	int error, flags, msb, lsb, last_track;
1801
1802	/* if the device doesn't grok capacity, return the dummies */
1803	if (periph->periph_quirks & PQUIRK_NOCAPACITY)
1804		return 0;
1805
1806	/* first try read CD capacity for blksize and last recorded lba */
1807	/* issue the cd capacity request */
1808	flags = XS_CTL_DATA_IN;
1809	memset(&cap_cmd, 0, sizeof(cap_cmd));
1810	cap_cmd.opcode = READ_CD_CAPACITY;
1811
1812	error = scsipi_command(periph,
1813	    (void *) &cap_cmd, sizeof(cap_cmd),
1814	    (void *) &cap,     sizeof(cap),
1815	    CDRETRIES, 30000, NULL, flags);
1816	if (error)
1817		return error;
1818
1819	/* retrieve values and sanity check them */
1820	*blksize  = _4btol(cap.length);
1821	*last_lba = _4btol(cap.addr);
1822
1823	/* blksize is 2048 for CD, but some drives give gibberish */
1824	if ((*blksize < 512) || ((*blksize & 511) != 0))
1825		*blksize = 2048;	/* some drives lie ! */
1826
1827	/* recordables have READ_DISCINFO implemented */
1828	flags = XS_CTL_DATA_IN | XS_CTL_SILENT;
1829	memset(&di_cmd, 0, sizeof(di_cmd));
1830	di_cmd.opcode = READ_DISCINFO;
1831	_lto2b(READ_DISCINFO_BIGSIZE, di_cmd.data_len);
1832
1833	error = scsipi_command(periph,
1834	    (void *) &di_cmd,  sizeof(di_cmd),
1835	    (void *) &di,      READ_DISCINFO_BIGSIZE,
1836	    CDRETRIES, 30000, NULL, flags);
1837	if (error == 0) {
1838		msb = di.last_track_last_session_msb;
1839		lsb = di.last_track_last_session_lsb;
1840		last_track = (msb << 8) | lsb;
1841
1842		/* request info on last track */
1843		memset(&ti_cmd, 0, sizeof(ti_cmd));
1844		ti_cmd.opcode = READ_TRACKINFO;
1845		ti_cmd.addr_type = 1;			/* on tracknr */
1846		_lto4b(last_track, ti_cmd.address);	/* tracknr    */
1847		_lto2b(sizeof(ti), ti_cmd.data_len);
1848
1849		error = scsipi_command(periph,
1850		    (void *) &ti_cmd,  sizeof(ti_cmd),
1851		    (void *) &ti,      sizeof(ti),
1852		    CDRETRIES, 30000, NULL, flags);
1853		if (error == 0) {
1854			track_start = _4btol(ti.track_start);
1855			track_size  = _4btol(ti.track_size);
1856
1857			/* overwrite only with a sane value */
1858			if (track_start + track_size >= 100)
1859				*last_lba = (u_long) track_start + track_size -1;
1860		}
1861	}
1862
1863	/* sanity check for lba_size */
1864	if (*last_lba < 100)
1865		*last_lba = 400000-1;
1866
1867	return 0;
1868}
1869
1870/*
1871 * Find out from the device what it's capacity is
1872 */
1873static u_long
1874cd_size(struct cd_softc *cd, int flags)
1875{
1876	u_int blksize;
1877	u_long last_lba, size;
1878	int error;
1879
1880	error = read_cd_capacity(cd->sc_periph, &blksize, &last_lba);
1881	if (error)
1882		goto error;
1883
1884	if (blksize != 2048) {
1885		if (cd_setblksize(cd) == 0) {
1886			blksize = 2048;
1887			error = read_cd_capacity(cd->sc_periph,
1888			    &blksize, &last_lba);
1889			if (error)
1890				goto error;
1891		}
1892	}
1893
1894	size = last_lba + 1;
1895	cd->params.blksize     = blksize;
1896	cd->params.disksize    = size;
1897	cd->params.disksize512 = ((u_int64_t)cd->params.disksize * blksize) / DEV_BSIZE;
1898
1899	SC_DEBUG(cd->sc_periph, SCSIPI_DB2,
1900	    ("cd_size: %u %lu\n", blksize, size));
1901
1902	return size;
1903
1904error:
1905	/* something went wrong */
1906	cd->params.blksize     = 2048;
1907	cd->params.disksize    = 0;
1908	cd->params.disksize512 = 0;
1909
1910	SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cd_size: failed\n"));
1911
1912	return 0;
1913}
1914
1915/*
1916 * Get scsi driver to send a "start playing" command
1917 */
1918static int
1919cd_play(struct cd_softc *cd, int blkno, int nblks)
1920{
1921	struct scsipi_play cmd;
1922
1923	memset(&cmd, 0, sizeof(cmd));
1924	cmd.opcode = PLAY;
1925	_lto4b(blkno, cmd.blk_addr);
1926	_lto2b(nblks, cmd.xfer_len);
1927
1928	return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
1929	    CDRETRIES, 30000, NULL, 0));
1930}
1931
1932/*
1933 * Get scsi driver to send a "start playing" command
1934 */
1935static int
1936cd_play_tracks(struct cd_softc *cd, struct cd_formatted_toc *toc, int strack,
1937    int sindex, int etrack, int eindex)
1938{
1939	int error;
1940
1941	if (!etrack)
1942		return (EIO);
1943	if (strack > etrack)
1944		return (EINVAL);
1945
1946	error = cd_load_toc(cd, CD_TOC_FORM, toc, 0);
1947	if (error)
1948		return (error);
1949
1950	if (++etrack > (toc->header.ending_track+1))
1951		etrack = toc->header.ending_track+1;
1952
1953	strack -= toc->header.starting_track;
1954	etrack -= toc->header.starting_track;
1955	if (strack < 0)
1956		return (EINVAL);
1957
1958	return (cd_play_msf(cd, toc->entries[strack].addr.msf.minute,
1959	    toc->entries[strack].addr.msf.second,
1960	    toc->entries[strack].addr.msf.frame,
1961	    toc->entries[etrack].addr.msf.minute,
1962	    toc->entries[etrack].addr.msf.second,
1963	    toc->entries[etrack].addr.msf.frame));
1964}
1965
1966/*
1967 * Get scsi driver to send a "play msf" command
1968 */
1969static int
1970cd_play_msf(struct cd_softc *cd, int startm, int starts, int startf, int endm,
1971    int ends, int endf)
1972{
1973	struct scsipi_play_msf cmd;
1974
1975	memset(&cmd, 0, sizeof(cmd));
1976	cmd.opcode = PLAY_MSF;
1977	cmd.start_m = startm;
1978	cmd.start_s = starts;
1979	cmd.start_f = startf;
1980	cmd.end_m = endm;
1981	cmd.end_s = ends;
1982	cmd.end_f = endf;
1983
1984	return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
1985	    CDRETRIES, 30000, NULL, 0));
1986}
1987
1988/*
1989 * Get scsi driver to send a "start up" command
1990 */
1991static int
1992cd_pause(struct cd_softc *cd, int go)
1993{
1994	struct scsipi_pause cmd;
1995
1996	memset(&cmd, 0, sizeof(cmd));
1997	cmd.opcode = PAUSE;
1998	cmd.resume = go & 0xff;
1999
2000	return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
2001	    CDRETRIES, 30000, NULL, 0));
2002}
2003
2004/*
2005 * Get scsi driver to send a "RESET" command
2006 */
2007static int
2008cd_reset(struct cd_softc *cd)
2009{
2010
2011	return (scsipi_command(cd->sc_periph, 0, 0, 0, 0,
2012	    CDRETRIES, 30000, NULL, XS_CTL_RESET));
2013}
2014
2015/*
2016 * Read subchannel
2017 */
2018static int
2019cd_read_subchannel(struct cd_softc *cd, int mode, int format, int track,
2020    struct cd_sub_channel_info *data, int len, int flags)
2021{
2022	struct scsipi_read_subchannel cmd;
2023
2024	memset(&cmd, 0, sizeof(cmd));
2025	cmd.opcode = READ_SUBCHANNEL;
2026	if (mode == CD_MSF_FORMAT)
2027		cmd.byte2 |= CD_MSF;
2028	cmd.byte3 = SRS_SUBQ;
2029	cmd.subchan_format = format;
2030	cmd.track = track;
2031	_lto2b(len, cmd.data_len);
2032
2033	return (scsipi_command(cd->sc_periph,
2034	    (void *)&cmd, sizeof(struct scsipi_read_subchannel),
2035	    (void *)data, len,
2036	    CDRETRIES, 30000, NULL, flags | XS_CTL_DATA_IN | XS_CTL_SILENT));
2037}
2038
2039/*
2040 * Read table of contents
2041 */
2042static int
2043cd_read_toc(struct cd_softc *cd, int respf, int mode, int start,
2044    struct cd_formatted_toc *toc, int len, int flags, int control)
2045{
2046	struct scsipi_read_toc cmd;
2047	int ntoc;
2048
2049	memset(&cmd, 0, sizeof(cmd));
2050#if 0
2051	if (len != sizeof(struct ioc_toc_header))
2052		ntoc = ((len) - sizeof(struct ioc_toc_header)) /
2053		    sizeof(struct cd_toc_entry);
2054	else
2055#endif
2056	ntoc = len;
2057	cmd.opcode = READ_TOC;
2058	if (mode == CD_MSF_FORMAT)
2059		cmd.addr_mode |= CD_MSF;
2060	cmd.resp_format = respf;
2061	cmd.from_track = start;
2062	_lto2b(ntoc, cmd.data_len);
2063	cmd.control = control;
2064
2065	return (scsipi_command(cd->sc_periph,
2066	    (void *)&cmd, sizeof(cmd), (void *)toc, len, CDRETRIES,
2067	    30000, NULL, flags | XS_CTL_DATA_IN));
2068}
2069
2070static int
2071cd_load_toc(struct cd_softc *cd, int respf, struct cd_formatted_toc *toc, int flags)
2072{
2073	int ntracks, len, error;
2074
2075	if ((error = cd_read_toc(cd, respf, 0, 0, toc, sizeof(toc->header),
2076	    flags, 0)) != 0)
2077		return (error);
2078
2079	ntracks = toc->header.ending_track - toc->header.starting_track + 1;
2080	len = (ntracks + 1) * sizeof(struct cd_toc_entry) +
2081	    sizeof(toc->header);
2082	if ((error = cd_read_toc(cd, respf, CD_MSF_FORMAT, 0, toc, len,
2083	    flags, 0)) != 0)
2084		return (error);
2085	return (0);
2086}
2087
2088/*
2089 * Get the scsi driver to send a full inquiry to the device and use the
2090 * results to fill out the disk parameter structure.
2091 */
2092static int
2093cd_get_parms(struct cd_softc *cd, int flags)
2094{
2095
2096	/*
2097	 * give a number of sectors so that sec * trks * cyls
2098	 * is <= disk_size
2099	 */
2100	if (cd_size(cd, flags) == 0)
2101		return (ENXIO);
2102	disk_blocksize(&cd->sc_dk, cd->params.blksize);
2103	return (0);
2104}
2105
2106static int
2107cdsize(dev_t dev)
2108{
2109
2110	/* CD-ROMs are read-only. */
2111	return (-1);
2112}
2113
2114static int
2115cddump(dev_t dev, daddr_t blkno, void *va, size_t size)
2116{
2117
2118	/* Not implemented. */
2119	return (ENXIO);
2120}
2121
2122#define	dvd_copy_key(dst, src)		memcpy((dst), (src), sizeof(dvd_key))
2123#define	dvd_copy_challenge(dst, src)	memcpy((dst), (src), sizeof(dvd_challenge))
2124
2125static int
2126dvd_auth(struct cd_softc *cd, dvd_authinfo *a)
2127{
2128	struct scsipi_generic cmd;
2129	u_int8_t bf[20];
2130	int error;
2131
2132	memset(cmd.bytes, 0, 15);
2133	memset(bf, 0, sizeof(bf));
2134
2135	switch (a->type) {
2136	case DVD_LU_SEND_AGID:
2137		cmd.opcode = GPCMD_REPORT_KEY;
2138		cmd.bytes[8] = 8;
2139		cmd.bytes[9] = 0 | (0 << 6);
2140		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
2141		    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2142		if (error)
2143			return (error);
2144		a->lsa.agid = bf[7] >> 6;
2145		return (0);
2146
2147	case DVD_LU_SEND_CHALLENGE:
2148		cmd.opcode = GPCMD_REPORT_KEY;
2149		cmd.bytes[8] = 16;
2150		cmd.bytes[9] = 1 | (a->lsc.agid << 6);
2151		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 16,
2152		    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2153		if (error)
2154			return (error);
2155		dvd_copy_challenge(a->lsc.chal, &bf[4]);
2156		return (0);
2157
2158	case DVD_LU_SEND_KEY1:
2159		cmd.opcode = GPCMD_REPORT_KEY;
2160		cmd.bytes[8] = 12;
2161		cmd.bytes[9] = 2 | (a->lsk.agid << 6);
2162		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 12,
2163		    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2164		if (error)
2165			return (error);
2166		dvd_copy_key(a->lsk.key, &bf[4]);
2167		return (0);
2168
2169	case DVD_LU_SEND_TITLE_KEY:
2170		cmd.opcode = GPCMD_REPORT_KEY;
2171		_lto4b(a->lstk.lba, &cmd.bytes[1]);
2172		cmd.bytes[8] = 12;
2173		cmd.bytes[9] = 4 | (a->lstk.agid << 6);
2174		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 12,
2175		    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2176		if (error)
2177			return (error);
2178		a->lstk.cpm = (bf[4] >> 7) & 1;
2179		a->lstk.cp_sec = (bf[4] >> 6) & 1;
2180		a->lstk.cgms = (bf[4] >> 4) & 3;
2181		dvd_copy_key(a->lstk.title_key, &bf[5]);
2182		return (0);
2183
2184	case DVD_LU_SEND_ASF:
2185		cmd.opcode = GPCMD_REPORT_KEY;
2186		cmd.bytes[8] = 8;
2187		cmd.bytes[9] = 5 | (a->lsasf.agid << 6);
2188		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
2189		    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2190		if (error)
2191			return (error);
2192		a->lsasf.asf = bf[7] & 1;
2193		return (0);
2194
2195	case DVD_HOST_SEND_CHALLENGE:
2196		cmd.opcode = GPCMD_SEND_KEY;
2197		cmd.bytes[8] = 16;
2198		cmd.bytes[9] = 1 | (a->hsc.agid << 6);
2199		bf[1] = 14;
2200		dvd_copy_challenge(&bf[4], a->hsc.chal);
2201		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 16,
2202		    CDRETRIES, 30000, NULL, XS_CTL_DATA_OUT);
2203		if (error)
2204			return (error);
2205		a->type = DVD_LU_SEND_KEY1;
2206		return (0);
2207
2208	case DVD_HOST_SEND_KEY2:
2209		cmd.opcode = GPCMD_SEND_KEY;
2210		cmd.bytes[8] = 12;
2211		cmd.bytes[9] = 3 | (a->hsk.agid << 6);
2212		bf[1] = 10;
2213		dvd_copy_key(&bf[4], a->hsk.key);
2214		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 12,
2215		    CDRETRIES, 30000, NULL, XS_CTL_DATA_OUT);
2216		if (error) {
2217			a->type = DVD_AUTH_FAILURE;
2218			return (error);
2219		}
2220		a->type = DVD_AUTH_ESTABLISHED;
2221		return (0);
2222
2223	case DVD_INVALIDATE_AGID:
2224		cmd.opcode = GPCMD_REPORT_KEY;
2225		cmd.bytes[9] = 0x3f | (a->lsa.agid << 6);
2226		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 16,
2227		    CDRETRIES, 30000, NULL, 0);
2228		if (error)
2229			return (error);
2230		return (0);
2231
2232	case DVD_LU_SEND_RPC_STATE:
2233		cmd.opcode = GPCMD_REPORT_KEY;
2234		cmd.bytes[8] = 8;
2235		cmd.bytes[9] = 8 | (0 << 6);
2236		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
2237		    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2238		if (error)
2239			return (error);
2240		a->lrpcs.type = (bf[4] >> 6) & 3;
2241		a->lrpcs.vra = (bf[4] >> 3) & 7;
2242		a->lrpcs.ucca = (bf[4]) & 7;
2243		a->lrpcs.region_mask = bf[5];
2244		a->lrpcs.rpc_scheme = bf[6];
2245		return (0);
2246
2247	case DVD_HOST_SEND_RPC_STATE:
2248		cmd.opcode = GPCMD_SEND_KEY;
2249		cmd.bytes[8] = 8;
2250		cmd.bytes[9] = 6 | (0 << 6);
2251		bf[1] = 6;
2252		bf[4] = a->hrpcs.pdrc;
2253		error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
2254		    CDRETRIES, 30000, NULL, XS_CTL_DATA_OUT);
2255		if (error)
2256			return (error);
2257		return (0);
2258
2259	default:
2260		return (ENOTTY);
2261	}
2262}
2263
2264static int
2265dvd_read_physical(struct cd_softc *cd, dvd_struct *s)
2266{
2267	struct scsipi_generic cmd;
2268	u_int8_t bf[4 + 4 * 20], *bufp;
2269	int error;
2270	struct dvd_layer *layer;
2271	int i;
2272
2273	memset(cmd.bytes, 0, 15);
2274	memset(bf, 0, sizeof(bf));
2275	cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
2276	cmd.bytes[6] = s->type;
2277	_lto2b(sizeof(bf), &cmd.bytes[7]);
2278
2279	cmd.bytes[5] = s->physical.layer_num;
2280	error = scsipi_command(cd->sc_periph, &cmd, 12, bf, sizeof(bf),
2281	    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2282	if (error)
2283		return (error);
2284	for (i = 0, bufp = &bf[4], layer = &s->physical.layer[0]; i < 4;
2285	     i++, bufp += 20, layer++) {
2286		memset(layer, 0, sizeof(*layer));
2287                layer->book_version = bufp[0] & 0xf;
2288                layer->book_type = bufp[0] >> 4;
2289                layer->min_rate = bufp[1] & 0xf;
2290                layer->disc_size = bufp[1] >> 4;
2291                layer->layer_type = bufp[2] & 0xf;
2292                layer->track_path = (bufp[2] >> 4) & 1;
2293                layer->nlayers = (bufp[2] >> 5) & 3;
2294                layer->track_density = bufp[3] & 0xf;
2295                layer->linear_density = bufp[3] >> 4;
2296                layer->start_sector = _4btol(&bufp[4]);
2297                layer->end_sector = _4btol(&bufp[8]);
2298                layer->end_sector_l0 = _4btol(&bufp[12]);
2299                layer->bca = bufp[16] >> 7;
2300	}
2301	return (0);
2302}
2303
2304static int
2305dvd_read_copyright(struct cd_softc *cd, dvd_struct *s)
2306{
2307	struct scsipi_generic cmd;
2308	u_int8_t bf[8];
2309	int error;
2310
2311	memset(cmd.bytes, 0, 15);
2312	memset(bf, 0, sizeof(bf));
2313	cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
2314	cmd.bytes[6] = s->type;
2315	_lto2b(sizeof(bf), &cmd.bytes[7]);
2316
2317	cmd.bytes[5] = s->copyright.layer_num;
2318	error = scsipi_command(cd->sc_periph, &cmd, 12, bf, sizeof(bf),
2319	    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2320	if (error)
2321		return (error);
2322	s->copyright.cpst = bf[4];
2323	s->copyright.rmi = bf[5];
2324	return (0);
2325}
2326
2327static int
2328dvd_read_disckey(struct cd_softc *cd, dvd_struct *s)
2329{
2330	struct scsipi_generic cmd;
2331	u_int8_t *bf;
2332	int error;
2333
2334	bf = malloc(4 + 2048, M_TEMP, M_WAITOK|M_ZERO);
2335	if (bf == NULL)
2336		return EIO;
2337	memset(cmd.bytes, 0, 15);
2338	cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
2339	cmd.bytes[6] = s->type;
2340	_lto2b(4 + 2048, &cmd.bytes[7]);
2341
2342	cmd.bytes[9] = s->disckey.agid << 6;
2343	error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 4 + 2048,
2344	    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2345	if (error == 0)
2346		memcpy(s->disckey.value, &bf[4], 2048);
2347	free(bf, M_TEMP);
2348	return error;
2349}
2350
2351static int
2352dvd_read_bca(struct cd_softc *cd, dvd_struct *s)
2353{
2354	struct scsipi_generic cmd;
2355	u_int8_t bf[4 + 188];
2356	int error;
2357
2358	memset(cmd.bytes, 0, 15);
2359	memset(bf, 0, sizeof(bf));
2360	cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
2361	cmd.bytes[6] = s->type;
2362	_lto2b(sizeof(bf), &cmd.bytes[7]);
2363
2364	error = scsipi_command(cd->sc_periph, &cmd, 12, bf, sizeof(bf),
2365	    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2366	if (error)
2367		return (error);
2368	s->bca.len = _2btol(&bf[0]);
2369	if (s->bca.len < 12 || s->bca.len > 188)
2370		return (EIO);
2371	memcpy(s->bca.value, &bf[4], s->bca.len);
2372	return (0);
2373}
2374
2375static int
2376dvd_read_manufact(struct cd_softc *cd, dvd_struct *s)
2377{
2378	struct scsipi_generic cmd;
2379	u_int8_t *bf;
2380	int error;
2381
2382	bf = malloc(4 + 2048, M_TEMP, M_WAITOK|M_ZERO);
2383	if (bf == NULL)
2384		return (EIO);
2385	memset(cmd.bytes, 0, 15);
2386	cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
2387	cmd.bytes[6] = s->type;
2388	_lto2b(4 + 2048, &cmd.bytes[7]);
2389
2390	error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 4 + 2048,
2391	    CDRETRIES, 30000, NULL, XS_CTL_DATA_IN);
2392	if (error == 0) {
2393		s->manufact.len = _2btol(&bf[0]);
2394		if (s->manufact.len >= 0 && s->manufact.len <= 2048)
2395			memcpy(s->manufact.value, &bf[4], s->manufact.len);
2396		else
2397			error = EIO;
2398	}
2399	free(bf, M_TEMP);
2400	return error;
2401}
2402
2403static int
2404dvd_read_struct(struct cd_softc *cd, dvd_struct *s)
2405{
2406
2407	switch (s->type) {
2408	case DVD_STRUCT_PHYSICAL:
2409		return (dvd_read_physical(cd, s));
2410	case DVD_STRUCT_COPYRIGHT:
2411		return (dvd_read_copyright(cd, s));
2412	case DVD_STRUCT_DISCKEY:
2413		return (dvd_read_disckey(cd, s));
2414	case DVD_STRUCT_BCA:
2415		return (dvd_read_bca(cd, s));
2416	case DVD_STRUCT_MANUFACT:
2417		return (dvd_read_manufact(cd, s));
2418	default:
2419		return (EINVAL);
2420	}
2421}
2422
2423static int
2424cd_mode_sense(struct cd_softc *cd, u_int8_t byte2, void *sense, size_t size,
2425    int page, int flags, int *big)
2426{
2427
2428	if (cd->sc_periph->periph_quirks & PQUIRK_ONLYBIG) {
2429		*big = 1;
2430		return scsipi_mode_sense_big(cd->sc_periph, byte2, page, sense,
2431		    size + sizeof(struct scsi_mode_parameter_header_10),
2432		    flags, CDRETRIES, 20000);
2433	} else {
2434		*big = 0;
2435		return scsipi_mode_sense(cd->sc_periph, byte2, page, sense,
2436		    size + sizeof(struct scsi_mode_parameter_header_6),
2437		    flags, CDRETRIES, 20000);
2438	}
2439}
2440
2441static int
2442cd_mode_select(struct cd_softc *cd, u_int8_t byte2, void *sense, size_t size,
2443    int flags, int big)
2444{
2445
2446	if (big) {
2447		struct scsi_mode_parameter_header_10 *header = sense;
2448
2449		_lto2b(0, header->data_length);
2450		return scsipi_mode_select_big(cd->sc_periph, byte2, sense,
2451		    size + sizeof(struct scsi_mode_parameter_header_10),
2452		    flags, CDRETRIES, 20000);
2453	} else {
2454		struct scsi_mode_parameter_header_6 *header = sense;
2455
2456		header->data_length = 0;
2457		return scsipi_mode_select(cd->sc_periph, byte2, sense,
2458		    size + sizeof(struct scsi_mode_parameter_header_6),
2459		    flags, CDRETRIES, 20000);
2460	}
2461}
2462
2463static int
2464cd_set_pa_immed(struct cd_softc *cd, int flags)
2465{
2466	struct {
2467		union {
2468			struct scsi_mode_parameter_header_6 small;
2469			struct scsi_mode_parameter_header_10 big;
2470		} header;
2471		struct cd_audio_page page;
2472	} data;
2473	int error;
2474	uint8_t oflags;
2475	int big, byte2;
2476	struct cd_audio_page *page;
2477
2478	byte2 = SMS_DBD;
2479try_again:
2480	if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
2481	    AUDIO_PAGE, flags, &big)) != 0) {
2482		if (byte2 == SMS_DBD) {
2483			/* Device may not understand DBD; retry without */
2484			byte2 = 0;
2485			goto try_again;
2486		}
2487		return (error);
2488	}
2489
2490	if (big)
2491		page = (void *)((u_long)&data.header.big +
2492				sizeof data.header.big +
2493				_2btol(data.header.big.blk_desc_len));
2494	else
2495		page = (void *)((u_long)&data.header.small +
2496				sizeof data.header.small +
2497				data.header.small.blk_desc_len);
2498
2499	oflags = page->flags;
2500	page->flags &= ~CD_PA_SOTC;
2501	page->flags |= CD_PA_IMMED;
2502	if (oflags == page->flags)
2503		return (0);
2504
2505	return (cd_mode_select(cd, SMS_PF, &data,
2506	    sizeof(struct scsi_mode_page_header) + page->pg_length,
2507	    flags, big));
2508}
2509
2510static int
2511cd_setchan(struct cd_softc *cd, int p0, int p1, int p2, int p3, int flags)
2512{
2513	struct {
2514		union {
2515			struct scsi_mode_parameter_header_6 small;
2516			struct scsi_mode_parameter_header_10 big;
2517		} header;
2518		struct cd_audio_page page;
2519	} data;
2520	int error;
2521	int big, byte2;
2522	struct cd_audio_page *page;
2523
2524	byte2 = SMS_DBD;
2525try_again:
2526	if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
2527	    AUDIO_PAGE, flags, &big)) != 0) {
2528		if (byte2 == SMS_DBD) {
2529			/* Device may not understand DBD; retry without */
2530			byte2 = 0;
2531			goto try_again;
2532		}
2533		return (error);
2534	}
2535
2536	if (big)
2537		page = (void *)((u_long)&data.header.big +
2538				sizeof data.header.big +
2539				_2btol(data.header.big.blk_desc_len));
2540	else
2541		page = (void *)((u_long)&data.header.small +
2542				sizeof data.header.small +
2543				data.header.small.blk_desc_len);
2544
2545	page->port[0].channels = p0;
2546	page->port[1].channels = p1;
2547	page->port[2].channels = p2;
2548	page->port[3].channels = p3;
2549
2550	return (cd_mode_select(cd, SMS_PF, &data,
2551	    sizeof(struct scsi_mode_page_header) + page->pg_length,
2552	    flags, big));
2553}
2554
2555static int
2556cd_getvol(struct cd_softc *cd, struct ioc_vol *arg, int flags)
2557{
2558	struct {
2559		union {
2560			struct scsi_mode_parameter_header_6 small;
2561			struct scsi_mode_parameter_header_10 big;
2562		} header;
2563		struct cd_audio_page page;
2564	} data;
2565	int error;
2566	int big, byte2;
2567	struct cd_audio_page *page;
2568
2569	byte2 = SMS_DBD;
2570try_again:
2571	if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
2572	    AUDIO_PAGE, flags, &big)) != 0) {
2573		if (byte2 == SMS_DBD) {
2574			/* Device may not understand DBD; retry without */
2575			byte2 = 0;
2576			goto try_again;
2577		}
2578		return (error);
2579	}
2580
2581	if (big)
2582		page = (void *)((u_long)&data.header.big +
2583				sizeof data.header.big +
2584				_2btol(data.header.big.blk_desc_len));
2585	else
2586		page = (void *)((u_long)&data.header.small +
2587				sizeof data.header.small +
2588				data.header.small.blk_desc_len);
2589
2590	arg->vol[0] = page->port[0].volume;
2591	arg->vol[1] = page->port[1].volume;
2592	arg->vol[2] = page->port[2].volume;
2593	arg->vol[3] = page->port[3].volume;
2594
2595	return (0);
2596}
2597
2598static int
2599cd_setvol(struct cd_softc *cd, const struct ioc_vol *arg, int flags)
2600{
2601	struct {
2602		union {
2603			struct scsi_mode_parameter_header_6 small;
2604			struct scsi_mode_parameter_header_10 big;
2605		} header;
2606		struct cd_audio_page page;
2607	} data, mask;
2608	int error;
2609	int big, byte2;
2610	struct cd_audio_page *page, *page2;
2611
2612	byte2 = SMS_DBD;
2613try_again:
2614	if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
2615	    AUDIO_PAGE, flags, &big)) != 0) {
2616		if (byte2 == SMS_DBD) {
2617			/* Device may not understand DBD; retry without */
2618			byte2 = 0;
2619			goto try_again;
2620		}
2621		return (error);
2622	}
2623	if ((error = cd_mode_sense(cd, byte2, &mask, sizeof(mask.page),
2624	    AUDIO_PAGE|SMS_PCTRL_CHANGEABLE, flags, &big)) != 0)
2625		return (error);
2626
2627	if (big) {
2628		page = (void *)((u_long)&data.header.big +
2629				sizeof data.header.big +
2630				_2btol(data.header.big.blk_desc_len));
2631		page2 = (void *)((u_long)&mask.header.big +
2632				sizeof mask.header.big +
2633				_2btol(mask.header.big.blk_desc_len));
2634	} else {
2635		page = (void *)((u_long)&data.header.small +
2636				sizeof data.header.small +
2637				data.header.small.blk_desc_len);
2638		page2 = (void *)((u_long)&mask.header.small +
2639				sizeof mask.header.small +
2640				mask.header.small.blk_desc_len);
2641	}
2642
2643	page->port[0].volume = arg->vol[0] & page2->port[0].volume;
2644	page->port[1].volume = arg->vol[1] & page2->port[1].volume;
2645	page->port[2].volume = arg->vol[2] & page2->port[2].volume;
2646	page->port[3].volume = arg->vol[3] & page2->port[3].volume;
2647
2648	page->port[0].channels = CHANNEL_0;
2649	page->port[1].channels = CHANNEL_1;
2650
2651	return (cd_mode_select(cd, SMS_PF, &data,
2652	    sizeof(struct scsi_mode_page_header) + page->pg_length,
2653	    flags, big));
2654}
2655
2656static int
2657cd_load_unload(struct cd_softc *cd, struct ioc_load_unload *args)
2658{
2659	struct scsipi_load_unload cmd;
2660
2661	memset(&cmd, 0, sizeof(cmd));
2662	cmd.opcode = LOAD_UNLOAD;
2663	cmd.options = args->options;    /* ioctl uses MMC values */
2664	cmd.slot = args->slot;
2665
2666	return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
2667	    CDRETRIES, 200000, NULL, 0));
2668}
2669
2670static int
2671cd_setblksize(struct cd_softc *cd)
2672{
2673	struct {
2674		union {
2675			struct scsi_mode_parameter_header_6 small;
2676			struct scsi_mode_parameter_header_10 big;
2677		} header;
2678		struct scsi_general_block_descriptor blk_desc;
2679	} data;
2680	int error;
2681	int big, bsize;
2682	struct scsi_general_block_descriptor *bdesc;
2683
2684	if ((error = cd_mode_sense(cd, 0, &data, sizeof(data.blk_desc), 0, 0,
2685	    &big)) != 0)
2686		return (error);
2687
2688	if (big) {
2689		bdesc = (void *)(&data.header.big + 1);
2690		bsize = _2btol(data.header.big.blk_desc_len);
2691	} else {
2692		bdesc = (void *)(&data.header.small + 1);
2693		bsize = data.header.small.blk_desc_len;
2694	}
2695
2696	if (bsize == 0) {
2697printf("cd_setblksize: trying to change bsize, but no blk_desc\n");
2698		return (EINVAL);
2699	}
2700	if (_3btol(bdesc->blklen) == 2048) {
2701printf("cd_setblksize: trying to change bsize, but blk_desc is correct\n");
2702		return (EINVAL);
2703	}
2704
2705	_lto3b(2048, bdesc->blklen);
2706
2707	return (cd_mode_select(cd, SMS_PF, &data, sizeof(data.blk_desc), 0,
2708	    big));
2709}
2710
2711
2712static int
2713mmc_profile2class(uint16_t mmc_profile)
2714{
2715	switch (mmc_profile) {
2716	case 0x01 : /* SCSI discs */
2717	case 0x02 :
2718		/* this can't happen really, cd.c wouldn't have matched */
2719		return MMC_CLASS_DISC;
2720	case 0x03 : /* Magneto Optical with sector erase */
2721	case 0x04 : /* Magneto Optical write once        */
2722	case 0x05 : /* Advance Storage Magneto Optical   */
2723		return MMC_CLASS_MO;
2724	case 0x00 : /* Unknown MMC profile, can also be CD-ROM */
2725	case 0x08 : /* CD-ROM  */
2726	case 0x09 : /* CD-R    */
2727	case 0x0a : /* CD-RW   */
2728		return MMC_CLASS_CD;
2729	case 0x10 : /* DVD-ROM */
2730	case 0x11 : /* DVD-R   */
2731	case 0x12 : /* DVD-RAM */
2732	case 0x13 : /* DVD-RW restricted overwrite */
2733	case 0x14 : /* DVD-RW sequential */
2734	case 0x1a : /* DVD+RW  */
2735	case 0x1b : /* DVD+R   */
2736	case 0x2a : /* DVD+RW Dual layer */
2737	case 0x2b : /* DVD+R Dual layer */
2738	case 0x50 : /* HD DVD-ROM */
2739	case 0x51 : /* HD DVD-R   */
2740	case 0x52 : /* HD DVD-RW; DVD-RAM like */
2741		return MMC_CLASS_DVD;
2742	case 0x40 : /* BD-ROM  */
2743	case 0x41 : /* BD-R Sequential recording (SRM) */
2744	case 0x42 : /* BD-R Ramdom Recording (RRM) */
2745	case 0x43 : /* BD-RE */
2746		return MMC_CLASS_BD;
2747	}
2748	return MMC_CLASS_UNKN;
2749}
2750
2751
2752/*
2753 * Drive/media combination is reflected in a series of features that can
2754 * either be current or dormant. We try to make sense out of them to create a
2755 * set of easy to use flags that abstract the device/media capabilities.
2756 */
2757
2758static void
2759mmc_process_feature(struct mmc_discinfo *mmc_discinfo,
2760		    uint16_t feature, int cur, uint8_t *rpos)
2761{
2762	uint32_t blockingnr;
2763	uint64_t flags;
2764
2765	if (cur == 1) {
2766		flags = mmc_discinfo->mmc_cur;
2767	} else {
2768		flags = mmc_discinfo->mmc_cap;
2769	}
2770
2771	switch (feature) {
2772	case 0x0010 :	/* random readable feature */
2773		blockingnr  =  rpos[5] | (rpos[4] << 8);
2774		if (blockingnr > 1)
2775			flags |= MMC_CAP_PACKET;
2776
2777		/* RW error page */
2778		break;
2779	case 0x0020 :	/* random writable feature */
2780		flags |= MMC_CAP_RECORDABLE;
2781		flags |= MMC_CAP_REWRITABLE;
2782		blockingnr  =  rpos[9] | (rpos[8] << 8);
2783		if (blockingnr > 1)
2784			flags |= MMC_CAP_PACKET;
2785		break;
2786	case 0x0021 :	/* incremental streaming write feature */
2787		flags |= MMC_CAP_RECORDABLE;
2788		flags |= MMC_CAP_SEQUENTIAL;
2789		if (cur)
2790			mmc_discinfo->link_block_penalty = rpos[4];
2791		if (rpos[2] & 1)
2792			flags |= MMC_CAP_ZEROLINKBLK;
2793		break;
2794	case 0x0022 : 	/* (obsolete) erase support feature */
2795		flags |= MMC_CAP_RECORDABLE;
2796		flags |= MMC_CAP_ERASABLE;
2797		break;
2798	case 0x0023 :	/* formatting media support feature */
2799		flags |= MMC_CAP_RECORDABLE;
2800		flags |= MMC_CAP_FORMATTABLE;
2801		break;
2802	case 0x0024 :	/* hardware assised defect management feature */
2803		flags |= MMC_CAP_HW_DEFECTFREE;
2804		break;
2805	case 0x0025 : 	/* write once */
2806		flags |= MMC_CAP_RECORDABLE;
2807		break;
2808	case 0x0026 :	/* restricted overwrite feature */
2809		flags |= MMC_CAP_RECORDABLE;
2810		flags |= MMC_CAP_REWRITABLE;
2811		flags |= MMC_CAP_STRICTOVERWRITE;
2812		break;
2813	case 0x0028 :	/* MRW formatted media support feature */
2814		flags |= MMC_CAP_MRW;
2815		break;
2816	case 0x002b :	/* DVD+R read (and opt. write) support */
2817		flags |= MMC_CAP_SEQUENTIAL;
2818		if (rpos[0] & 1) /* write support */
2819			flags |= MMC_CAP_RECORDABLE;
2820		break;
2821	case 0x002c :	/* rigid restricted overwrite feature */
2822		flags |= MMC_CAP_RECORDABLE;
2823		flags |= MMC_CAP_REWRITABLE;
2824		flags |= MMC_CAP_STRICTOVERWRITE;
2825		if (rpos[0] & 1) /* blank bit */
2826			flags |= MMC_CAP_BLANKABLE;
2827		break;
2828	case 0x002d :	/* track at once recording feature */
2829		flags |= MMC_CAP_RECORDABLE;
2830		flags |= MMC_CAP_SEQUENTIAL;
2831		break;
2832	case 0x002f :	/* DVD-R/-RW write feature */
2833		flags |= MMC_CAP_RECORDABLE;
2834		if (rpos[0] & 2) /* DVD-RW bit */
2835			flags |= MMC_CAP_BLANKABLE;
2836		break;
2837	case 0x0038 :	/* BD-R SRM with pseudo overwrite */
2838		flags |= MMC_CAP_PSEUDOOVERWRITE;
2839		break;
2840	default :
2841		/* ignore */
2842		break;
2843	}
2844
2845	if (cur == 1) {
2846		mmc_discinfo->mmc_cur = flags;
2847	} else {
2848		mmc_discinfo->mmc_cap = flags;
2849	}
2850}
2851
2852static int
2853mmc_getdiscinfo_cdrom(struct scsipi_periph *periph,
2854		      struct mmc_discinfo *mmc_discinfo)
2855{
2856	struct scsipi_read_toc      gtoc_cmd;
2857	struct scsipi_toc_header   *toc_hdr;
2858	struct scsipi_toc_msinfo   *toc_msinfo;
2859	const uint32_t buffer_size = 1024;
2860	uint32_t req_size;
2861	uint8_t  *buffer;
2862	int error, flags;
2863
2864	buffer = malloc(buffer_size, M_TEMP, M_WAITOK);
2865	/*
2866	 * Fabricate mmc_discinfo for CD-ROM. Some values are really `dont
2867	 * care' but others might be of interest to programs.
2868	 */
2869
2870	mmc_discinfo->disc_state	 = MMC_STATE_FULL;
2871	mmc_discinfo->last_session_state = MMC_STATE_FULL;
2872	mmc_discinfo->bg_format_state    = MMC_BGFSTATE_COMPLETED;
2873	mmc_discinfo->link_block_penalty = 7;	/* not relevant */
2874
2875	/* get number of sessions and first tracknr in last session */
2876	flags = XS_CTL_DATA_IN;
2877	memset(&gtoc_cmd, 0, sizeof(gtoc_cmd));
2878	gtoc_cmd.opcode      = READ_TOC;
2879	gtoc_cmd.addr_mode   = CD_MSF;		/* not relevant        */
2880	gtoc_cmd.resp_format = CD_TOC_MSINFO;	/* multisession info   */
2881	gtoc_cmd.from_track  = 0;		/* reserved, must be 0 */
2882	req_size = sizeof(*toc_hdr) + sizeof(*toc_msinfo);
2883	_lto2b(req_size, gtoc_cmd.data_len);
2884
2885	error = scsipi_command(periph,
2886		(void *)&gtoc_cmd, sizeof(gtoc_cmd),
2887		(void *)buffer,    req_size,
2888		CDRETRIES, 30000, NULL, flags);
2889	if (error)
2890		goto out;
2891	toc_hdr    = (struct scsipi_toc_header *)  buffer;
2892	toc_msinfo = (struct scsipi_toc_msinfo *) (buffer + 4);
2893	mmc_discinfo->num_sessions = toc_hdr->last - toc_hdr->first + 1;
2894	mmc_discinfo->first_track  = toc_hdr->first;
2895	mmc_discinfo->first_track_last_session = toc_msinfo->tracknr;
2896
2897	/* get last track of last session */
2898	flags = XS_CTL_DATA_IN;
2899	gtoc_cmd.resp_format  = CD_TOC_FORM;	/* formatted toc */
2900	req_size = sizeof(*toc_hdr);
2901	_lto2b(req_size, gtoc_cmd.data_len);
2902
2903	error = scsipi_command(periph,
2904		(void *)&gtoc_cmd, sizeof(gtoc_cmd),
2905		(void *)buffer,    req_size,
2906		CDRETRIES, 30000, NULL, flags);
2907	if (error)
2908		goto out;
2909	toc_hdr    = (struct scsipi_toc_header *) buffer;
2910	mmc_discinfo->last_track_last_session = toc_hdr->last;
2911	mmc_discinfo->num_tracks = toc_hdr->last - toc_hdr->first + 1;
2912
2913	/* TODO how to handle disc_barcode and disc_id */
2914	/* done */
2915
2916out:
2917	free(buffer, M_TEMP);
2918	return error;
2919}
2920
2921static int
2922mmc_getdiscinfo_dvdrom(struct scsipi_periph *periph,
2923		       struct mmc_discinfo *mmc_discinfo)
2924{
2925	struct scsipi_read_toc   gtoc_cmd;
2926	struct scsipi_toc_header toc_hdr;
2927	uint32_t req_size;
2928	int error, flags;
2929
2930	/*
2931	 * Fabricate mmc_discinfo for DVD-ROM. Some values are really `dont
2932	 * care' but others might be of interest to programs.
2933	 */
2934
2935	mmc_discinfo->disc_state	 = MMC_STATE_FULL;
2936	mmc_discinfo->last_session_state = MMC_STATE_FULL;
2937	mmc_discinfo->bg_format_state    = MMC_BGFSTATE_COMPLETED;
2938	mmc_discinfo->link_block_penalty = 16;	/* not relevant */
2939
2940	/* get number of sessions and first tracknr in last session */
2941	flags = XS_CTL_DATA_IN;
2942	memset(&gtoc_cmd, 0, sizeof(gtoc_cmd));
2943	gtoc_cmd.opcode      = READ_TOC;
2944	gtoc_cmd.addr_mode   = 0;		/* LBA                 */
2945	gtoc_cmd.resp_format = CD_TOC_FORM;	/* multisession info   */
2946	gtoc_cmd.from_track  = 1;		/* first track         */
2947	req_size = sizeof(toc_hdr);
2948	_lto2b(req_size, gtoc_cmd.data_len);
2949
2950	error = scsipi_command(periph,
2951		(void *)&gtoc_cmd, sizeof(gtoc_cmd),
2952		(void *)&toc_hdr,  req_size,
2953		CDRETRIES, 30000, NULL, flags);
2954	if (error)
2955		return error;
2956
2957	/* DVD-ROM squashes the track/session space */
2958	mmc_discinfo->num_sessions = toc_hdr.last - toc_hdr.first + 1;
2959	mmc_discinfo->num_tracks   = mmc_discinfo->num_sessions;
2960	mmc_discinfo->first_track  = toc_hdr.first;
2961	mmc_discinfo->first_track_last_session = toc_hdr.last;
2962	mmc_discinfo->last_track_last_session  = toc_hdr.last;
2963
2964	/* TODO how to handle disc_barcode and disc_id */
2965	/* done */
2966	return 0;
2967}
2968
2969static int
2970mmc_getdiscinfo(struct scsipi_periph *periph,
2971		struct mmc_discinfo *mmc_discinfo)
2972{
2973	struct scsipi_get_configuration   gc_cmd;
2974	struct scsipi_get_conf_data      *gc;
2975	struct scsipi_get_conf_feature   *gcf;
2976	struct scsipi_read_discinfo       di_cmd;
2977	struct scsipi_read_discinfo_data  di;
2978	const uint32_t buffer_size = 1024;
2979	uint32_t feat_tbl_len, pos;
2980	u_long   last_lba;
2981	uint8_t  *buffer, *fpos;
2982	int feature, last_feature, features_len, feature_cur, feature_len;
2983	int lsb, msb, error, flags;
2984
2985	feat_tbl_len = buffer_size;
2986
2987	buffer = malloc(buffer_size, M_TEMP, M_WAITOK);
2988
2989	/* initialise structure */
2990	memset(mmc_discinfo, 0, sizeof(struct mmc_discinfo));
2991	mmc_discinfo->mmc_profile = 0x00;	/* unknown */
2992	mmc_discinfo->mmc_class   = MMC_CLASS_UNKN;
2993	mmc_discinfo->mmc_cur     = 0;
2994	mmc_discinfo->mmc_cap     = 0;
2995	mmc_discinfo->link_block_penalty = 0;
2996
2997	/* determine mmc profile and class */
2998	flags = XS_CTL_DATA_IN;
2999	memset(&gc_cmd, 0, sizeof(gc_cmd));
3000	gc_cmd.opcode = GET_CONFIGURATION;
3001	_lto2b(GET_CONF_NO_FEATURES_LEN, gc_cmd.data_len);
3002
3003	gc = (struct scsipi_get_conf_data *) buffer;
3004
3005	error = scsipi_command(periph,
3006		(void *)&gc_cmd, sizeof(gc_cmd),
3007		(void *) gc,     GET_CONF_NO_FEATURES_LEN,
3008		CDRETRIES, 30000, NULL, flags);
3009	if (error)
3010		goto out;
3011
3012	mmc_discinfo->mmc_profile = _2btol(gc->mmc_profile);
3013	mmc_discinfo->mmc_class = mmc_profile2class(mmc_discinfo->mmc_profile);
3014
3015	/* assume 2048 sector size unless told otherwise */
3016	mmc_discinfo->sector_size = 2048;
3017	error = read_cd_capacity(periph, &mmc_discinfo->sector_size, &last_lba);
3018	if (error)
3019		goto out;
3020
3021	mmc_discinfo->last_possible_lba = (uint32_t) last_lba;
3022
3023	/* Read in all features to determine device capabilities */
3024	last_feature = feature = 0;
3025	do {
3026		/* determine mmc profile and class */
3027		flags = XS_CTL_DATA_IN;
3028		memset(&gc_cmd, 0, sizeof(gc_cmd));
3029		gc_cmd.opcode = GET_CONFIGURATION;
3030		_lto2b(last_feature, gc_cmd.start_at_feature);
3031		_lto2b(feat_tbl_len, gc_cmd.data_len);
3032		memset(gc, 0, feat_tbl_len);
3033
3034		error = scsipi_command(periph,
3035			(void *)&gc_cmd, sizeof(gc_cmd),
3036			(void *) gc,     feat_tbl_len,
3037			CDRETRIES, 30000, NULL, flags);
3038		if (error) {
3039			/* ieeek... break out of loop... i dunno what to do */
3040			break;
3041		}
3042
3043		features_len = _4btol(gc->data_len);
3044		if (features_len < 4 || features_len > feat_tbl_len)
3045			break;
3046
3047		pos  = 0;
3048		fpos = &gc->feature_desc[0];
3049		while (pos < features_len - 4) {
3050			gcf = (struct scsipi_get_conf_feature *) fpos;
3051
3052			feature     = _2btol(gcf->featurecode);
3053			feature_cur = gcf->flags & 1;
3054			feature_len = gcf->additional_length;
3055
3056			mmc_process_feature(mmc_discinfo,
3057					    feature, feature_cur,
3058					    gcf->feature_dependent);
3059
3060			last_feature = MAX(last_feature, feature);
3061#ifdef DIAGNOSTIC
3062			/* assert((feature_len & 3) == 0); */
3063			if ((feature_len & 3) != 0) {
3064				printf("feature %d having length %d\n",
3065					feature, feature_len);
3066			}
3067#endif
3068
3069			pos  += 4 + feature_len;
3070			fpos += 4 + feature_len;
3071		}
3072		/* unlikely to ever grow past our 1kb buffer */
3073	} while (features_len >= 0xffff);
3074
3075	/*
3076	 * Fixup CD-RW drives that are on crack.
3077	 *
3078	 * Some drives report the capability to incrementally write
3079	 * sequentially on CD-R(W) media...  nice, but this should not be
3080	 * active for a fixed packet formatted CD-RW media. Other report the
3081	 * ability of HW_DEFECTFREE even when the media is NOT MRW
3082	 * formatted....
3083	 */
3084	if (mmc_discinfo->mmc_profile == 0x0a) {
3085		if ((mmc_discinfo->mmc_cur & MMC_CAP_SEQUENTIAL) == 0)
3086			mmc_discinfo->mmc_cur |= MMC_CAP_STRICTOVERWRITE;
3087		if (mmc_discinfo->mmc_cur & MMC_CAP_STRICTOVERWRITE)
3088			mmc_discinfo->mmc_cur &= ~MMC_CAP_SEQUENTIAL;
3089		if (mmc_discinfo->mmc_cur & MMC_CAP_MRW) {
3090			mmc_discinfo->mmc_cur &= ~MMC_CAP_SEQUENTIAL;
3091			mmc_discinfo->mmc_cur &= ~MMC_CAP_STRICTOVERWRITE;
3092		} else {
3093			mmc_discinfo->mmc_cur &= ~MMC_CAP_HW_DEFECTFREE;
3094		}
3095	}
3096	if (mmc_discinfo->mmc_profile == 0x09) {
3097		mmc_discinfo->mmc_cur &= ~MMC_CAP_REWRITABLE;
3098	}
3099
3100#ifdef DEBUG
3101	printf("CD mmc %d, mmc_cur 0x%"PRIx64", mmc_cap 0x%"PRIx64"\n",
3102		mmc_discinfo->mmc_profile,
3103	 	mmc_discinfo->mmc_cur, mmc_discinfo->mmc_cap);
3104#endif
3105
3106	/* read in disc state and number of sessions and tracks */
3107	flags = XS_CTL_DATA_IN | XS_CTL_SILENT;
3108	memset(&di_cmd, 0, sizeof(di_cmd));
3109	di_cmd.opcode = READ_DISCINFO;
3110	di_cmd.data_len[1] = READ_DISCINFO_BIGSIZE;
3111
3112	error = scsipi_command(periph,
3113		(void *)&di_cmd, sizeof(di_cmd),
3114		(void *)&di,     READ_DISCINFO_BIGSIZE,
3115		CDRETRIES, 30000, NULL, flags);
3116
3117	if (error) {
3118		/* discinfo call failed, emulate for cd-rom/dvd-rom */
3119		if (mmc_discinfo->mmc_profile == 0x08) /* CD-ROM */
3120			return mmc_getdiscinfo_cdrom(periph, mmc_discinfo);
3121		if (mmc_discinfo->mmc_profile == 0x10) /* DVD-ROM */
3122			return mmc_getdiscinfo_dvdrom(periph, mmc_discinfo);
3123		/* CD/DVD drive is violating specs */
3124		error = EIO;
3125		goto out;
3126	}
3127
3128	/* call went OK */
3129	mmc_discinfo->disc_state         =  di.disc_state & 3;
3130	mmc_discinfo->last_session_state = (di.disc_state >> 2) & 3;
3131	mmc_discinfo->bg_format_state    = (di.disc_state2 & 3);
3132
3133	lsb = di.num_sessions_lsb;
3134	msb = di.num_sessions_msb;
3135	mmc_discinfo->num_sessions = lsb | (msb << 8);
3136
3137	mmc_discinfo->first_track = di.first_track;
3138	lsb = di.first_track_last_session_lsb;
3139	msb = di.first_track_last_session_msb;
3140	mmc_discinfo->first_track_last_session = lsb | (msb << 8);
3141	lsb = di.last_track_last_session_lsb;
3142	msb = di.last_track_last_session_msb;
3143	mmc_discinfo->last_track_last_session  = lsb | (msb << 8);
3144
3145	mmc_discinfo->num_tracks = mmc_discinfo->last_track_last_session -
3146		mmc_discinfo->first_track + 1;
3147
3148	/* set misc. flags and parameters from this disc info */
3149	if (di.disc_state  &  16)
3150		mmc_discinfo->mmc_cur |= MMC_CAP_BLANKABLE;
3151
3152	if (di.disc_state2 & 128) {
3153		mmc_discinfo->disc_id = _4btol(di.discid);
3154		mmc_discinfo->disc_flags |= MMC_DFLAGS_DISCIDVALID;
3155	}
3156	if (di.disc_state2 &  64) {
3157		mmc_discinfo->disc_barcode = _8btol(di.disc_bar_code);
3158		mmc_discinfo->disc_flags |= MMC_DFLAGS_BARCODEVALID;
3159	}
3160	if (di.disc_state2 &  32)
3161		mmc_discinfo->disc_flags |= MMC_DFLAGS_UNRESTRICTED;
3162
3163	if (di.disc_state2 &  16) {
3164		mmc_discinfo->application_code = di.application_code;
3165		mmc_discinfo->disc_flags |= MMC_DFLAGS_APPCODEVALID;
3166	}
3167
3168	/* done */
3169
3170out:
3171	free(buffer, M_TEMP);
3172	return error;
3173}
3174
3175static int
3176mmc_gettrackinfo_cdrom(struct scsipi_periph *periph,
3177		       struct mmc_trackinfo *trackinfo)
3178{
3179	struct scsipi_read_toc            gtoc_cmd;
3180	struct scsipi_toc_header         *toc_hdr;
3181	struct scsipi_toc_rawtoc         *rawtoc;
3182	uint32_t track_start, track_end, track_size;
3183	uint32_t last_recorded, next_writable;
3184	uint32_t lba, next_track_start, lead_out;
3185	const uint32_t buffer_size = 4 * 1024;	/* worst case TOC estimate */
3186	uint8_t *buffer;
3187	uint8_t track_sessionnr, last_tracknr, sessionnr, adr, tno, point;
3188	uint8_t control, tmin, tsec, tframe, pmin, psec, pframe;
3189	int size, req_size;
3190	int error, flags;
3191
3192	buffer = malloc(buffer_size, M_TEMP, M_WAITOK);
3193
3194	/*
3195	 * Emulate read trackinfo for CD-ROM using the raw-TOC.
3196	 *
3197	 * Not all information is present and this presents a problem.  Track
3198	 * starts are known for each track but other values are deducted.
3199	 *
3200	 * For a complete overview of `magic' values used here, see the
3201	 * SCSI/ATAPI MMC documentation. Note that the `magic' values have no
3202	 * names, they are specified as numbers.
3203	 */
3204
3205	/* get raw toc to process, first header to check size */
3206	flags = XS_CTL_DATA_IN | XS_CTL_SILENT;
3207	memset(&gtoc_cmd, 0, sizeof(gtoc_cmd));
3208	gtoc_cmd.opcode      = READ_TOC;
3209	gtoc_cmd.addr_mode   = CD_MSF;		/* not relevant     */
3210	gtoc_cmd.resp_format = CD_TOC_RAW;	/* raw toc          */
3211	gtoc_cmd.from_track  = 1;		/* first session    */
3212	req_size = sizeof(*toc_hdr);
3213	_lto2b(req_size, gtoc_cmd.data_len);
3214
3215	error = scsipi_command(periph,
3216		(void *)&gtoc_cmd, sizeof(gtoc_cmd),
3217		(void *)buffer,    req_size,
3218		CDRETRIES, 30000, NULL, flags);
3219	if (error)
3220		goto out;
3221	toc_hdr = (struct scsipi_toc_header *) buffer;
3222	if (_2btol(toc_hdr->length) > buffer_size - 2) {
3223#ifdef DIAGNOSTIC
3224		printf("increase buffersize in mmc_readtrackinfo_cdrom\n");
3225#endif
3226		error = ENOBUFS;
3227		goto out;
3228	}
3229
3230	/* read in complete raw toc */
3231	req_size = _2btol(toc_hdr->length);
3232	req_size = 2*((req_size + 1) / 2);	/* for ATAPI */
3233	_lto2b(req_size, gtoc_cmd.data_len);
3234
3235	error = scsipi_command(periph,
3236		(void *)&gtoc_cmd, sizeof(gtoc_cmd),
3237		(void *)buffer,    req_size,
3238		CDRETRIES, 30000, NULL, flags);
3239	if (error)
3240		goto out;
3241
3242	toc_hdr = (struct scsipi_toc_header *) buffer;
3243	rawtoc  = (struct scsipi_toc_rawtoc *) (buffer + 4);
3244
3245	track_start      = 0;
3246	track_end        = 0;
3247	track_size       = 0;
3248	last_recorded    = 0;
3249	next_writable    = 0;
3250	flags            = 0;
3251
3252	last_tracknr     = 1;
3253	next_track_start = 0;
3254	track_sessionnr  = MAXTRACK;	/* by definition */
3255	lead_out         = 0;
3256
3257	size = req_size - sizeof(struct scsipi_toc_header) + 1;
3258	while (size > 0) {
3259		/* get track start and session end */
3260		tno       = rawtoc->tno;
3261		sessionnr = rawtoc->sessionnr;
3262		adr       = rawtoc->adrcontrol >> 4;
3263		control   = rawtoc->adrcontrol & 0xf;
3264		point     = rawtoc->point;
3265		tmin      = rawtoc->min;
3266		tsec      = rawtoc->sec;
3267		tframe    = rawtoc->frame;
3268		pmin      = rawtoc->pmin;
3269		psec      = rawtoc->psec;
3270		pframe    = rawtoc->pframe;
3271
3272		if (tno == 0 && sessionnr && adr == 1) {
3273			lba = hmsf2lba(0, pmin, psec, pframe);
3274			if (point == trackinfo->tracknr) {
3275				track_start = lba;
3276				track_sessionnr = sessionnr;
3277			}
3278			if (point == trackinfo->tracknr + 1) {
3279				/* estimate size */
3280				track_size = lba - track_start;
3281				next_track_start = lba;
3282			}
3283			if (point == 0xa2) {
3284				lead_out = lba;
3285			}
3286			if (point <= 0x63) {
3287				/* CD's ok, DVD are glued */
3288				last_tracknr = point;
3289			}
3290			if (sessionnr == track_sessionnr) {
3291				last_recorded = lead_out;
3292			}
3293		}
3294		if (tno == 0 && sessionnr && adr == 5) {
3295			lba = hmsf2lba(0, tmin, tsec, tframe);
3296			if (sessionnr == track_sessionnr) {
3297				next_writable = lba;
3298			}
3299		}
3300
3301		if ((control & (3<<2)) == 4)		/* 01xxb */
3302			flags |= MMC_TRACKINFO_DATA;
3303		if ((control & (1<<2)) == 0) {		/* x0xxb */
3304			flags |= MMC_TRACKINFO_AUDIO;
3305			if (control & 1)		/* xxx1b */
3306				flags |= MMC_TRACKINFO_PRE_EMPH;
3307		}
3308
3309		rawtoc++;
3310		size -= sizeof(struct scsipi_toc_rawtoc);
3311	}
3312
3313	/* process found values; some voodoo */
3314	/* if no tracksize tracknr is the last of the disc */
3315	if ((track_size == 0) && last_recorded) {
3316		track_size = last_recorded - track_start;
3317	}
3318	/* if last_recorded < tracksize, tracksize is overestimated */
3319	if (last_recorded) {
3320		if (last_recorded - track_start <= track_size) {
3321			track_size = last_recorded - track_start;
3322			flags |= MMC_TRACKINFO_LRA_VALID;
3323		}
3324	}
3325	/* check if its a the last track of the sector */
3326	if (next_writable) {
3327		if (next_track_start > next_writable)
3328			flags |= MMC_TRACKINFO_NWA_VALID;
3329	}
3330
3331	/* no flag set -> no values */
3332	if ((flags & MMC_TRACKINFO_LRA_VALID) == 0)
3333		last_recorded = 0;
3334	if ((flags & MMC_TRACKINFO_NWA_VALID) == 0)
3335		next_writable = 0;
3336
3337	/* fill in */
3338	/* trackinfo->tracknr preserved */
3339	trackinfo->sessionnr  = track_sessionnr;
3340	trackinfo->track_mode = 7;	/* data, incremental  */
3341	trackinfo->data_mode  = 8;	/* 2048 bytes mode1   */
3342
3343	trackinfo->flags = flags;
3344	trackinfo->track_start   = track_start;
3345	trackinfo->next_writable = next_writable;
3346	trackinfo->free_blocks   = 0;
3347	trackinfo->packet_size   = 1;
3348	trackinfo->track_size    = track_size;
3349	trackinfo->last_recorded = last_recorded;
3350
3351out:
3352	free(buffer, M_TEMP);
3353	return error;
3354
3355}
3356
3357static int
3358mmc_gettrackinfo_dvdrom(struct scsipi_periph *periph,
3359			struct mmc_trackinfo *trackinfo)
3360{
3361	struct scsipi_read_toc            gtoc_cmd;
3362	struct scsipi_toc_header         *toc_hdr;
3363	struct scsipi_toc_formatted      *toc;
3364	uint32_t tracknr, track_start, track_size;
3365	uint32_t lba, lead_out;
3366	const uint32_t buffer_size = 4 * 1024;	/* worst case TOC estimate */
3367	uint8_t *buffer;
3368	uint8_t control, last_tracknr;
3369	int size, req_size;
3370	int error, flags;
3371
3372
3373	buffer = malloc(buffer_size, M_TEMP, M_WAITOK);
3374	/*
3375	 * Emulate read trackinfo for DVD-ROM. We can't use the raw-TOC as the
3376	 * CD-ROM emulation uses since the specification tells us that no such
3377	 * thing is defined for DVD's. The reason for this is due to the large
3378	 * number of tracks and that would clash with the `magic' values. This
3379	 * suxs.
3380	 *
3381	 * Not all information is present and this presents a problem.
3382	 * Track starts are known for each track but other values are
3383	 * deducted.
3384	 */
3385
3386	/* get formatted toc to process, first header to check size */
3387	flags = XS_CTL_DATA_IN | XS_CTL_SILENT;
3388	memset(&gtoc_cmd, 0, sizeof(gtoc_cmd));
3389	gtoc_cmd.opcode      = READ_TOC;
3390	gtoc_cmd.addr_mode   = 0;		/* lba's please     */
3391	gtoc_cmd.resp_format = CD_TOC_FORM;	/* formatted toc    */
3392	gtoc_cmd.from_track  = 1;		/* first track      */
3393	req_size = sizeof(*toc_hdr);
3394	_lto2b(req_size, gtoc_cmd.data_len);
3395
3396	error = scsipi_command(periph,
3397		(void *)&gtoc_cmd, sizeof(gtoc_cmd),
3398		(void *)buffer,    req_size,
3399		CDRETRIES, 30000, NULL, flags);
3400	if (error)
3401		goto out;
3402	toc_hdr = (struct scsipi_toc_header *) buffer;
3403	if (_2btol(toc_hdr->length) > buffer_size - 2) {
3404#ifdef DIAGNOSTIC
3405		printf("incease buffersize in mmc_readtrackinfo_dvdrom\n");
3406#endif
3407		error = ENOBUFS;
3408		goto out;
3409	}
3410
3411	/* read in complete formatted toc */
3412	req_size = _2btol(toc_hdr->length);
3413	_lto2b(req_size, gtoc_cmd.data_len);
3414
3415	error = scsipi_command(periph,
3416		(void *)&gtoc_cmd, sizeof(gtoc_cmd),
3417		(void *)buffer,    req_size,
3418		CDRETRIES, 30000, NULL, flags);
3419	if (error)
3420		goto out;
3421
3422	toc_hdr = (struct scsipi_toc_header *)     buffer;
3423	toc     = (struct scsipi_toc_formatted *) (buffer + 4);
3424
3425	/* as in read disc info, all sessions are converted to tracks      */
3426	/* track 1..  -> offsets, sizes can be (rougly) estimated (16 ECC) */
3427	/* last track -> we got the size from the lead-out                 */
3428
3429	tracknr      = 0;
3430	last_tracknr = toc_hdr->last;
3431	track_start  = 0;
3432	track_size   = 0;
3433	lead_out     = 0;
3434	flags        = 0;
3435
3436	size = req_size - sizeof(struct scsipi_toc_header) + 1;
3437	while (size > 0) {
3438		/* remember, DVD-ROM: tracknr == sessionnr */
3439		lba     = _4btol(toc->msf_lba);
3440		tracknr = toc->tracknr;
3441		control = toc->adrcontrol & 0xf;
3442
3443		if (trackinfo->tracknr == tracknr) {
3444			track_start = lba;
3445		}
3446		if (trackinfo->tracknr == tracknr+1) {
3447			track_size  = lba - track_start;
3448			track_size -= 16;	/* link block ? */
3449		}
3450		if (tracknr == 0xAA) {
3451			lead_out = lba;
3452		}
3453
3454		if ((control & (3<<2)) == 4)		/* 01xxb */
3455			flags |= MMC_TRACKINFO_DATA;
3456		if ((control & (1<<2)) == 0) {		/* x0xxb */
3457			flags |= MMC_TRACKINFO_AUDIO;
3458			if (control & (1<<3))		/* 10xxb */
3459				flags |= MMC_TRACKINFO_AUDIO_4CHAN;
3460			if (control & 1)		/* xxx1b */
3461				flags |= MMC_TRACKINFO_PRE_EMPH;
3462		}
3463
3464		toc++;
3465		size -= sizeof(struct scsipi_toc_formatted);
3466	}
3467	if (trackinfo->tracknr == last_tracknr) {
3468		track_size = lead_out - track_start;
3469	}
3470
3471	/* fill in */
3472	/* trackinfo->tracknr preserved */
3473	trackinfo->sessionnr  = trackinfo->tracknr;
3474	trackinfo->track_mode = 0;	/* unknown */
3475	trackinfo->data_mode  = 8;	/* 2048 bytes mode1   */
3476
3477	trackinfo->flags         = flags;
3478	trackinfo->track_start   = track_start;
3479	trackinfo->next_writable = 0;
3480	trackinfo->free_blocks   = 0;
3481	trackinfo->packet_size   = 16;	/* standard length 16 blocks ECC */
3482	trackinfo->track_size    = track_size;
3483	trackinfo->last_recorded = 0;
3484
3485out:
3486	free(buffer, M_TEMP);
3487	return error;
3488}
3489
3490static int
3491mmc_gettrackinfo(struct scsipi_periph *periph,
3492		 struct mmc_trackinfo *trackinfo)
3493{
3494	struct scsipi_read_trackinfo      ti_cmd;
3495	struct scsipi_read_trackinfo_data ti;
3496	struct scsipi_get_configuration   gc_cmd;
3497	struct scsipi_get_conf_data       gc;
3498	int error, flags;
3499	int mmc_profile;
3500
3501	/* set up SCSI call with track number from trackinfo.tracknr */
3502	flags = XS_CTL_DATA_IN | XS_CTL_SILENT;
3503	memset(&ti_cmd, 0, sizeof(ti_cmd));
3504	ti_cmd.opcode    = READ_TRACKINFO;
3505	ti_cmd.addr_type = READ_TRACKINFO_ADDR_TRACK;
3506	ti_cmd.data_len[1] = READ_TRACKINFO_RETURNSIZE;
3507
3508	/* trackinfo.tracknr contains number of tracks to query */
3509	_lto4b(trackinfo->tracknr, ti_cmd.address);
3510	error = scsipi_command(periph,
3511		(void *)&ti_cmd, sizeof(ti_cmd),
3512		(void *)&ti,     READ_TRACKINFO_RETURNSIZE,
3513		CDRETRIES, 30000, NULL, flags);
3514
3515	if (error) {
3516		/* trackinfo call failed, emulate for cd-rom/dvd-rom */
3517		/* first determine mmc profile */
3518		flags = XS_CTL_DATA_IN;
3519		memset(&gc_cmd, 0, sizeof(gc_cmd));
3520		gc_cmd.opcode = GET_CONFIGURATION;
3521		_lto2b(GET_CONF_NO_FEATURES_LEN, gc_cmd.data_len);
3522
3523		error = scsipi_command(periph,
3524			(void *)&gc_cmd, sizeof(gc_cmd),
3525			(void *)&gc,     GET_CONF_NO_FEATURES_LEN,
3526			CDRETRIES, 30000, NULL, flags);
3527		if (error)
3528			return error;
3529		mmc_profile = _2btol(gc.mmc_profile);
3530
3531		/* choose emulation */
3532		if (mmc_profile == 0x08) /* CD-ROM */
3533			return mmc_gettrackinfo_cdrom(periph, trackinfo);
3534		if (mmc_profile == 0x10) /* DVD-ROM */
3535			return mmc_gettrackinfo_dvdrom(periph, trackinfo);
3536		/* CD/DVD drive is violating specs */
3537		return EIO;
3538	}
3539
3540	/* (re)initialise structure */
3541	memset(trackinfo, 0, sizeof(struct mmc_trackinfo));
3542
3543	/* account for short returns screwing up track and session msb */
3544	if ((ti.data_len[1] | (ti.data_len[0] << 8)) <= 32) {
3545		ti.track_msb   = 0;
3546		ti.session_msb = 0;
3547	}
3548
3549	trackinfo->tracknr    = ti.track_lsb   | (ti.track_msb   << 8);
3550	trackinfo->sessionnr  = ti.session_lsb | (ti.session_msb << 8);
3551	trackinfo->track_mode = ti.track_info_1 & 0xf;
3552	trackinfo->data_mode  = ti.track_info_2 & 0xf;
3553
3554	flags = 0;
3555	if (ti.track_info_1 & 0x10)
3556		flags |= MMC_TRACKINFO_COPY;
3557	if (ti.track_info_1 & 0x20)
3558		flags |= MMC_TRACKINFO_DAMAGED;
3559	if (ti.track_info_2 & 0x10)
3560		flags |= MMC_TRACKINFO_FIXED_PACKET;
3561	if (ti.track_info_2 & 0x20)
3562		flags |= MMC_TRACKINFO_INCREMENTAL;
3563	if (ti.track_info_2 & 0x40)
3564		flags |= MMC_TRACKINFO_BLANK;
3565	if (ti.track_info_2 & 0x80)
3566		flags |= MMC_TRACKINFO_RESERVED;
3567	if (ti.data_valid   & 0x01)
3568		flags |= MMC_TRACKINFO_NWA_VALID;
3569	if (ti.data_valid   & 0x02)
3570		flags |= MMC_TRACKINFO_LRA_VALID;
3571	if ((trackinfo->track_mode & (3<<2)) == 4)		/* 01xxb */
3572		flags |= MMC_TRACKINFO_DATA;
3573	if ((trackinfo->track_mode & (1<<2)) == 0) {		/* x0xxb */
3574		flags |= MMC_TRACKINFO_AUDIO;
3575		if (trackinfo->track_mode & (1<<3))		/* 10xxb */
3576			flags |= MMC_TRACKINFO_AUDIO_4CHAN;
3577		if (trackinfo->track_mode & 1)			/* xxx1b */
3578			flags |= MMC_TRACKINFO_PRE_EMPH;
3579	}
3580
3581	trackinfo->flags = flags;
3582	trackinfo->track_start    = _4btol(ti.track_start);
3583	trackinfo->next_writable  = _4btol(ti.next_writable);
3584	trackinfo->free_blocks    = _4btol(ti.free_blocks);
3585	trackinfo->packet_size    = _4btol(ti.packet_size);
3586	trackinfo->track_size     = _4btol(ti.track_size);
3587	trackinfo->last_recorded  = _4btol(ti.last_recorded);
3588
3589	return 0;
3590}
3591
3592static int
3593mmc_doclose(struct scsipi_periph *periph, int param, int func) {
3594	struct scsipi_close_tracksession close_cmd;
3595	int error, flags;
3596
3597	/* set up SCSI call with track number */
3598	flags = XS_CTL_DATA_OUT;
3599	memset(&close_cmd, 0, sizeof(close_cmd));
3600	close_cmd.opcode    = CLOSE_TRACKSESSION;
3601	close_cmd.function  = func;
3602	_lto2b(param, close_cmd.tracksessionnr);
3603
3604	error = scsipi_command(periph,
3605		(void *) &close_cmd, sizeof(close_cmd),
3606		NULL, 0,
3607		CDRETRIES, 120000, NULL, flags);
3608
3609	return error;
3610}
3611
3612static int
3613mmc_do_closetrack(struct scsipi_periph *periph, struct mmc_op *mmc_op)
3614{
3615	int mmc_profile = mmc_op->mmc_profile;
3616
3617	switch (mmc_profile) {
3618	case 0x12 : /* DVD-RAM */
3619	case 0x1a : /* DVD+RW  */
3620	case 0x2a : /* DVD+RW Dual layer */
3621	case 0x42 : /* BD-R Ramdom Recording (RRM) */
3622	case 0x43 : /* BD-RE */
3623	case 0x52 : /* HD DVD-RW ; DVD-RAM like */
3624		return EINVAL;
3625	}
3626
3627	return mmc_doclose(periph, mmc_op->tracknr, 1);
3628}
3629
3630static int
3631mmc_do_close_or_finalise(struct scsipi_periph *periph, struct mmc_op *mmc_op)
3632{
3633	uint8_t blob[MS5LEN], *page5;
3634	int mmc_profile = mmc_op->mmc_profile;
3635	int func, close, flags;
3636	int error;
3637
3638	close = (mmc_op->operation == MMC_OP_CLOSESESSION);
3639
3640	switch (mmc_profile) {
3641	case 0x09 : /* CD-R       */
3642	case 0x0a : /* CD-RW      */
3643		/* Special case : need to update MS field in mode page 5 */
3644		memset(blob, 0, sizeof(blob));
3645		page5 = blob+8;
3646
3647		flags = XS_CTL_DATA_IN;
3648		error = scsipi_mode_sense_big(periph, SMS_PF, 5,
3649		    (void *)blob, sizeof(blob), flags, CDRETRIES, 20000);
3650		if (error)
3651			return error;
3652
3653		/* set multi session field when closing a session only */
3654		page5[3] &= 63;
3655		if (close)
3656			page5[3] |= 3 << 6;
3657
3658		flags = XS_CTL_DATA_OUT;
3659		error = scsipi_mode_select_big(periph, SMS_PF,
3660		    (void *)blob, sizeof(blob), flags, CDRETRIES, 20000);
3661		if (error)
3662			return error;
3663		/* and use funtion 2 */
3664		func = 2;
3665		break;
3666	case 0x11 : /* DVD-R (DL) */
3667	case 0x13 : /* DVD-RW restricted overwrite */
3668	case 0x14 : /* DVD-RW sequential */
3669		func = close ? 2 : 3;
3670		break;
3671	case 0x1b : /* DVD+R   */
3672	case 0x2b : /* DVD+R Dual layer */
3673	case 0x51 : /* HD DVD-R   */
3674	case 0x41 : /* BD-R Sequential recording (SRM) */
3675		func = close ? 2 : 6;
3676		break;
3677	case 0x12 : /* DVD-RAM */
3678	case 0x1a : /* DVD+RW  */
3679	case 0x2a : /* DVD+RW Dual layer */
3680	case 0x42 : /* BD-R Ramdom Recording (RRM) */
3681	case 0x43 : /* BD-RE */
3682	case 0x52 : /* HD DVD-RW; DVD-RAM like */
3683		return EINVAL;
3684	default:
3685		printf("MMC close/finalise passed wrong device type! (%d)\n",
3686		    mmc_profile);
3687		return EINVAL;
3688	}
3689
3690	return mmc_doclose(periph, mmc_op->sessionnr, func);
3691}
3692
3693static int
3694mmc_do_reserve_track(struct scsipi_periph *periph, struct mmc_op *mmc_op)
3695{
3696	struct scsipi_reserve_track reserve_cmd;
3697	uint32_t extent;
3698	int error, flags;
3699
3700	/* TODO make mmc safeguards? */
3701	extent = mmc_op->extent;
3702	/* TODO min/max support? */
3703
3704	/* set up SCSI call with requested space */
3705	flags = XS_CTL_DATA_OUT;
3706	memset(&reserve_cmd, 0, sizeof(reserve_cmd));
3707	reserve_cmd.opcode = RESERVE_TRACK;
3708	_lto4b(extent, reserve_cmd.reservation_size);
3709
3710	error = scsipi_command(periph,
3711		(void *) &reserve_cmd, sizeof(reserve_cmd),
3712		NULL, 0,
3713		CDRETRIES, 30000, NULL, flags);
3714
3715	return error;
3716}
3717
3718static int
3719mmc_do_reserve_track_nwa(struct scsipi_periph *periph, struct mmc_op *mmc_op)
3720{
3721	/* XXX assumes that NWA given is valid */
3722	switch (mmc_op->mmc_profile) {
3723	case 0x09 : /* CD-R       */
3724		/* XXX unknown boundary checks XXX */
3725		if (mmc_op->extent <= 152)
3726			return EINVAL;
3727		/* CD-R takes 152 sectors to close track */
3728		mmc_op->extent -= 152;
3729		return mmc_do_reserve_track(periph, mmc_op);
3730	case 0x11 : /* DVD-R (DL) */
3731	case 0x1b : /* DVD+R   */
3732	case 0x2b : /* DVD+R Dual layer */
3733		if (mmc_op->extent % 16)
3734			return EINVAL;
3735		/* upto one ECC block of 16 sectors lost */
3736		mmc_op->extent -= 16;
3737		return mmc_do_reserve_track(periph, mmc_op);
3738	case 0x41 : /* BD-R Sequential recording (SRM) */
3739	case 0x51 : /* HD DVD-R   */
3740		if (mmc_op->extent % 32)
3741			return EINVAL;
3742		/* one ECC block of 32 sectors lost (AFAIK) */
3743		mmc_op->extent -= 32;
3744		return mmc_do_reserve_track(periph, mmc_op);
3745	}
3746
3747	/* unknown behaviour or invalid disc type */
3748	return EINVAL;
3749}
3750
3751static int
3752mmc_do_repair_track(struct scsipi_periph *periph, struct mmc_op *mmc_op)
3753{
3754	struct scsipi_repair_track repair_cmd;
3755	int error, flags;
3756
3757	/* TODO make mmc safeguards? */
3758
3759	/* set up SCSI call with track number */
3760	flags = XS_CTL_DATA_OUT;
3761	memset(&repair_cmd, 0, sizeof(repair_cmd));
3762	repair_cmd.opcode = REPAIR_TRACK;
3763	_lto2b(mmc_op->tracknr, repair_cmd.tracknr);
3764
3765	error = scsipi_command(periph,
3766		(void *) &repair_cmd, sizeof(repair_cmd),
3767		NULL, 0,
3768		CDRETRIES, 30000, NULL, flags);
3769
3770	return error;
3771}
3772
3773static int
3774mmc_do_op(struct scsipi_periph *periph, struct mmc_op *mmc_op)
3775{
3776	/* guard operation value */
3777	if (mmc_op->operation < 1 || mmc_op->operation > MMC_OP_MAX)
3778		return EINVAL;
3779
3780	/* synchronise cache is special since it doesn't rely on mmc_profile */
3781	if (mmc_op->operation == MMC_OP_SYNCHRONISECACHE)
3782		return cdcachesync(periph, 0);
3783
3784	/* zero mmc_profile means unknown disc so operations are not defined */
3785	if (mmc_op->mmc_profile == 0) {
3786#ifdef DEBUG
3787		printf("mmc_do_op called with mmc_profile = 0\n");
3788#endif
3789		return EINVAL;
3790	}
3791
3792	/* do the operations */
3793	switch (mmc_op->operation) {
3794	case MMC_OP_CLOSETRACK   :
3795		return mmc_do_closetrack(periph, mmc_op);
3796	case MMC_OP_CLOSESESSION :
3797	case MMC_OP_FINALISEDISC :
3798		return mmc_do_close_or_finalise(periph, mmc_op);
3799	case MMC_OP_RESERVETRACK :
3800		return mmc_do_reserve_track(periph, mmc_op);
3801	case MMC_OP_RESERVETRACK_NWA :
3802		return mmc_do_reserve_track_nwa(periph, mmc_op);
3803	case MMC_OP_REPAIRTRACK  :
3804		return mmc_do_repair_track(periph, mmc_op);
3805	case MMC_OP_UNCLOSELASTSESSION :
3806		/* TODO unclose last session support */
3807		return EINVAL;
3808	default :
3809		printf("mmc_do_op: unhandled operation %d\n", mmc_op->operation);
3810	}
3811
3812	return EINVAL;
3813}
3814
3815static int
3816mmc_setup_writeparams(struct scsipi_periph *periph,
3817		      struct mmc_writeparams *mmc_writeparams)
3818{
3819	struct mmc_trackinfo trackinfo;
3820	uint8_t blob[MS5LEN];
3821	uint8_t *page5;
3822	int flags, error;
3823	int track_mode, data_mode;
3824
3825	/* setup mode page 5 for CD only */
3826	if (mmc_writeparams->mmc_class != MMC_CLASS_CD)
3827		return 0;
3828
3829	memset(blob, 0, sizeof(blob));
3830	page5 = blob+8;
3831
3832	/* read mode page 5 (with header) */
3833	flags = XS_CTL_DATA_IN;
3834	error = scsipi_mode_sense_big(periph, SMS_PF, 5, (void *)blob,
3835	    sizeof(blob), flags, CDRETRIES, 20000);
3836	if (error)
3837		return error;
3838
3839	/* set page length for reasurance */
3840	page5[1] = P5LEN;	/* page length */
3841
3842	/* write type packet/incremental */
3843	page5[2] &= 0xf0;
3844
3845	/* set specified mode parameters */
3846	track_mode = mmc_writeparams->track_mode;
3847	data_mode  = mmc_writeparams->data_mode;
3848	if (track_mode <= 0 || track_mode > 15)
3849		return EINVAL;
3850	if (data_mode < 1 || data_mode > 2)
3851		return EINVAL;
3852
3853	/* if a tracknr is passed, setup according to the track */
3854	if (mmc_writeparams->tracknr > 0) {
3855		trackinfo.tracknr = mmc_writeparams->tracknr;
3856		error = mmc_gettrackinfo(periph, &trackinfo);
3857		if (error)
3858			return error;
3859		if ((trackinfo.flags & MMC_TRACKINFO_BLANK) == 0) {
3860			track_mode = trackinfo.track_mode;
3861			data_mode  = trackinfo.data_mode;
3862		}
3863		mmc_writeparams->blockingnr = trackinfo.packet_size;
3864	}
3865
3866	/* copy track mode and data mode from trackinfo */
3867	page5[3] &= 16;		/* keep only `Copy' bit */
3868	page5[3] |= (3 << 6) | track_mode;
3869	page5[4] &= 0xf0;	/* wipe data block type */
3870	if (data_mode == 1) {
3871		/* select ISO mode 1 (CD only) */
3872		page5[4] |= 8;
3873		/* select session format normal disc (CD only) */
3874		page5[8] = 0;
3875	} else {
3876		/* select ISO mode 2; XA form 1 (CD only) */
3877		page5[4] |= 10;
3878		/* select session format CD-ROM XA disc (CD only) */
3879		page5[8] = 0x20;
3880	}
3881	if (mmc_writeparams->mmc_cur & MMC_CAP_SEQUENTIAL) {
3882		if (mmc_writeparams->mmc_cur & MMC_CAP_ZEROLINKBLK) {
3883			/* set BUFE buffer underrun protection */
3884			page5[2] |= 1<<6;
3885		}
3886		/* allow for multi session */
3887		page5[3] |= 3 << 6;
3888	} else {
3889		/* select fixed packets */
3890		page5[3] |= 1<<5;
3891		_lto4b(mmc_writeparams->blockingnr, &(page5[10]));
3892	}
3893
3894	/* write out updated mode page 5 (with header) */
3895	flags = XS_CTL_DATA_OUT;
3896	error = scsipi_mode_select_big(periph, SMS_PF, (void *)blob,
3897	    sizeof(blob), flags, CDRETRIES, 20000);
3898	if (error)
3899		return error;
3900
3901	return 0;
3902}
3903
3904static void
3905cd_set_geometry(struct cd_softc *cd)
3906{
3907	struct disk_geom *dg = &cd->sc_dk.dk_geom;
3908
3909	memset(dg, 0, sizeof(*dg));
3910
3911	dg->dg_secperunit = cd->params.disksize;
3912	dg->dg_secsize = cd->params.blksize;
3913
3914	disk_set_info(cd->sc_dev, &cd->sc_dk, NULL);
3915}
3916