[BACK]Return to cd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / scsipi

Annotation of src/sys/dev/scsipi/cd.c, Revision 1.227

1.227   ! reinoud     1: /*     $NetBSD: cd.c,v 1.226 2005/09/05 21:16:24 reinoud Exp $ */
1.30      cgd         2:
1.115     mycroft     3: /*-
1.206     mycroft     4:  * Copyright (c) 1998, 2001, 2003, 2004 The NetBSD Foundation, Inc.
1.115     mycroft     5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Charles M. Hannum.
1.23      mycroft     9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
1.115     mycroft    20:  *        This product includes software developed by the NetBSD
                     21:  *        Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
1.23      mycroft    25:  *
1.115     mycroft    26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
1.23      mycroft    37:  */
                     38:
                     39: /*
                     40:  * Originally written by Julian Elischer (julian@tfs.com)
1.1       cgd        41:  * for TRW Financial Systems for use under the MACH(2.5) operating system.
                     42:  *
                     43:  * TRW Financial Systems, in accordance with their agreement with Carnegie
                     44:  * Mellon University, makes this software available to CMU to distribute
                     45:  * or use in any manner that they see fit as long as this message is kept with
                     46:  * the software. For this reason TFS also grants any other persons or
                     47:  * organisations permission to use or modify this software.
                     48:  *
                     49:  * TFS supplies this software to be publicly redistributed
                     50:  * on the understanding that TFS is not responsible for the correct
                     51:  * functioning of this software in any circumstances.
                     52:  *
1.23      mycroft    53:  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
1.1       cgd        54:  */
1.159     lukem      55:
                     56: #include <sys/cdefs.h>
1.227   ! reinoud    57: __KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.226 2005/09/05 21:16:24 reinoud Exp $");
1.1       cgd        58:
1.106     explorer   59: #include "rnd.h"
                     60:
1.19      mycroft    61: #include <sys/param.h>
1.34      mycroft    62: #include <sys/systm.h>
                     63: #include <sys/kernel.h>
1.19      mycroft    64: #include <sys/file.h>
                     65: #include <sys/stat.h>
                     66: #include <sys/ioctl.h>
                     67: #include <sys/buf.h>
1.211     yamt       68: #include <sys/bufq.h>
1.19      mycroft    69: #include <sys/uio.h>
                     70: #include <sys/malloc.h>
                     71: #include <sys/errno.h>
1.23      mycroft    72: #include <sys/device.h>
1.19      mycroft    73: #include <sys/disklabel.h>
1.23      mycroft    74: #include <sys/disk.h>
                     75: #include <sys/cdio.h>
1.132     mycroft    76: #include <sys/dvdio.h>
1.119     bouyer     77: #include <sys/scsiio.h>
1.82      christos   78: #include <sys/proc.h>
1.90      christos   79: #include <sys/conf.h>
1.129     enami      80: #include <sys/vnode.h>
1.106     explorer   81: #if NRND > 0
1.105     explorer   82: #include <sys/rnd.h>
1.106     explorer   83: #endif
1.19      mycroft    84:
1.219     thorpej    85: #include <dev/scsipi/scsi_spc.h>
1.101     bouyer     86: #include <dev/scsipi/scsipi_all.h>
                     87: #include <dev/scsipi/scsipi_cd.h>
1.103     enami      88: #include <dev/scsipi/scsipi_disk.h>    /* rw_big and start_stop come */
1.188     mycroft    89: #include <dev/scsipi/scsi_all.h>
1.103     enami      90:                                        /* from there */
1.101     bouyer     91: #include <dev/scsipi/scsi_disk.h>      /* rw comes from there */
                     92: #include <dev/scsipi/scsipiconf.h>
1.205     bouyer     93: #include <dev/scsipi/scsipi_base.h>
1.110     cgd        94: #include <dev/scsipi/cdvar.h>
1.103     enami      95:
1.35      cgd        96: #define        CDUNIT(z)                       DISKUNIT(z)
                     97: #define        CDPART(z)                       DISKPART(z)
1.129     enami      98: #define        CDMINOR(unit, part)             DISKMINOR(unit, part)
1.35      cgd        99: #define        MAKECDDEV(maj, unit, part)      MAKEDISKDEV(maj, unit, part)
1.1       cgd       100:
1.103     enami     101: #define MAXTRACK       99
                    102: #define CD_BLOCK_OFFSET        150
                    103: #define CD_FRAMES      75
                    104: #define CD_SECS                60
1.101     bouyer    105:
                    106: struct cd_toc {
1.103     enami     107:        struct ioc_toc_header header;
                    108:        struct cd_toc_entry entries[MAXTRACK+1]; /* One extra for the */
                    109:                                                 /* leadout */
1.101     bouyer    110: };
1.23      mycroft   111:
1.202     thorpej   112: static void    cdstart(struct scsipi_periph *);
1.203     bouyer    113: static void    cdrestart(void *);
1.202     thorpej   114: static void    cdminphys(struct buf *);
                    115: static void    cdgetdefaultlabel(struct cd_softc *, struct disklabel *);
                    116: static void    cdgetdisklabel(struct cd_softc *);
1.206     mycroft   117: static void    cddone(struct scsipi_xfer *, int);
1.202     thorpej   118: static void    cdbounce(struct buf *);
                    119: static int     cd_interpret_sense(struct scsipi_xfer *);
1.218     reinoud   120: static u_long  cd_size(struct cd_softc *, int);
1.202     thorpej   121: static int     cd_play(struct cd_softc *, int, int);
                    122: static int     cd_play_tracks(struct cd_softc *, int, int, int, int);
                    123: static int     cd_play_msf(struct cd_softc *, int, int, int, int, int, int);
                    124: static int     cd_pause(struct cd_softc *, int);
                    125: static int     cd_reset(struct cd_softc *);
                    126: static int     cd_read_subchannel(struct cd_softc *, int, int, int,
                    127:                    struct cd_sub_channel_info *, int, int);
1.213     reinoud   128: static int     cd_read_toc_f0(struct cd_softc *, int, int, void *, int, int, int);
1.202     thorpej   129: static int     cd_get_parms(struct cd_softc *, int);
                    130: static int     cd_load_toc(struct cd_softc *, struct cd_toc *, int);
                    131: static int     cdreadmsaddr(struct cd_softc *, int *);
                    132:
                    133: static int     dvd_auth(struct cd_softc *, dvd_authinfo *);
                    134: static int     dvd_read_physical(struct cd_softc *, dvd_struct *);
                    135: static int     dvd_read_copyright(struct cd_softc *, dvd_struct *);
                    136: static int     dvd_read_disckey(struct cd_softc *, dvd_struct *);
                    137: static int     dvd_read_bca(struct cd_softc *, dvd_struct *);
                    138: static int     dvd_read_manufact(struct cd_softc *, dvd_struct *);
                    139: static int     dvd_read_struct(struct cd_softc *, dvd_struct *);
                    140:
1.218     reinoud   141: static int     cd_mode_sense(struct cd_softc *, u_int8_t, void *, size_t, int,
1.202     thorpej   142:                    int, int *);
1.218     reinoud   143: static int     cd_mode_select(struct cd_softc *, u_int8_t, void *, size_t,
1.202     thorpej   144:                    int, int);
                    145: static int     cd_setchan(struct cd_softc *, int, int, int, int, int);
                    146: static int     cd_getvol(struct cd_softc *, struct ioc_vol *, int);
                    147: static int     cd_setvol(struct cd_softc *, const struct ioc_vol *, int);
                    148: static int     cd_set_pa_immed(struct cd_softc *, int);
                    149: static int     cd_load_unload(struct cd_softc *, struct ioc_load_unload *);
                    150: static int     cd_setblksize(struct cd_softc *);
                    151:
                    152: static int     cdmatch(struct device *, struct cfdata *, void *);
                    153: static void    cdattach(struct device *, struct device *, void *);
                    154: static int     cdactivate(struct device *, enum devact);
                    155: static int     cddetach(struct device *, int);
1.190     mycroft   156:
                    157: CFATTACH_DECL(cd, sizeof(struct cd_softc), cdmatch, cdattach, cddetach,
                    158:     cdactivate);
                    159:
1.111     cgd       160: extern struct cfdriver cd_cd;
                    161:
1.202     thorpej   162: static const struct scsipi_inquiry_pattern cd_patterns[] = {
1.190     mycroft   163:        {T_CDROM, T_REMOV,
                    164:         "",         "",                 ""},
                    165:        {T_WORM, T_REMOV,
                    166:         "",         "",                 ""},
                    167: #if 0
                    168:        {T_CDROM, T_REMOV, /* more luns */
                    169:         "PIONEER ", "CD-ROM DRM-600  ", ""},
                    170: #endif
                    171:        {T_DIRECT, T_REMOV,
                    172:         "NEC                 CD-ROM DRIVE:260", "", ""},
                    173: };
                    174:
1.202     thorpej   175: static dev_type_open(cdopen);
                    176: static dev_type_close(cdclose);
                    177: static dev_type_read(cdread);
                    178: static dev_type_write(cdwrite);
                    179: static dev_type_ioctl(cdioctl);
                    180: static dev_type_strategy(cdstrategy);
                    181: static dev_type_dump(cddump);
                    182: static dev_type_size(cdsize);
1.166     gehenna   183:
                    184: const struct bdevsw cd_bdevsw = {
                    185:        cdopen, cdclose, cdstrategy, cdioctl, cddump, cdsize, D_DISK
                    186: };
                    187:
                    188: const struct cdevsw cd_cdevsw = {
                    189:        cdopen, cdclose, cdread, cdwrite, cdioctl,
1.168     jdolecek  190:        nostop, notty, nopoll, nommap, nokqfilter, D_DISK
1.166     gehenna   191: };
                    192:
1.202     thorpej   193: static struct dkdriver cddkdriver = { cdstrategy };
1.23      mycroft   194:
1.202     thorpej   195: static const struct scsipi_periphsw cd_switch = {
1.144     kenh      196:        cd_interpret_sense,     /* use our error handler first */
1.23      mycroft   197:        cdstart,                /* we have a queue, which is started by this */
                    198:        NULL,                   /* we do not have an async handler */
1.79      thorpej   199:        cddone,                 /* deal with stats at interrupt time */
1.23      mycroft   200: };
1.1       cgd       201:
1.6       deraadt   202: /*
                    203:  * The routine called by the low level scsi routine when it discovers
                    204:  * A device suitable for this driver
                    205:  */
1.202     thorpej   206: static int
                    207: cdmatch(struct device *parent, struct cfdata *match, void *aux)
1.190     mycroft   208: {
                    209:        struct scsipibus_attach_args *sa = aux;
                    210:        int priority;
                    211:
                    212:        (void)scsipi_inqmatch(&sa->sa_inqbuf,
1.223     christos  213:            cd_patterns, sizeof(cd_patterns) / sizeof(cd_patterns[0]),
1.190     mycroft   214:            sizeof(cd_patterns[0]), &priority);
                    215:
                    216:        return (priority);
                    217: }
                    218:
1.202     thorpej   219: static void
                    220: cdattach(struct device *parent, struct device *self, void *aux)
1.101     bouyer    221: {
1.190     mycroft   222:        struct cd_softc *cd = (void *)self;
                    223:        struct scsipibus_attach_args *sa = aux;
                    224:        struct scsipi_periph *periph = sa->sa_periph;
                    225:
1.145     bouyer    226:        SC_DEBUG(periph, SCSIPI_DB2, ("cdattach: "));
1.3       deraadt   227:
1.206     mycroft   228:        lockinit(&cd->sc_lock, PRIBIO | PCATCH, "cdlock", 0, 0);
                    229:
1.190     mycroft   230:        if (scsipi_periph_bustype(sa->sa_periph) == SCSIPI_BUSTYPE_SCSI &&
                    231:            periph->periph_version == 0)
                    232:                cd->flags |= CDF_ANCIENT;
                    233:
1.164     hannken   234:        bufq_alloc(&cd->buf_queue, BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK);
1.135     thorpej   235:
1.203     bouyer    236:        callout_init(&cd->sc_callout);
                    237:
1.23      mycroft   238:        /*
                    239:         * Store information needed to contact our base driver
                    240:         */
1.145     bouyer    241:        cd->sc_periph = periph;
                    242:
                    243:        periph->periph_dev = &cd->sc_dev;
                    244:        periph->periph_switch = &cd_switch;
                    245:
                    246:        /*
                    247:         * Increase our openings to the maximum-per-periph
                    248:         * supported by the adapter.  This will either be
                    249:         * clamped down or grown by the adapter if necessary.
                    250:         */
                    251:        periph->periph_openings =
                    252:            SCSIPI_CHAN_MAX_PERIPH(periph->periph_channel);
                    253:        periph->periph_flags |= PERIPH_GROW_OPENINGS;
1.23      mycroft   254:
1.79      thorpej   255:        /*
                    256:         * Initialize and attach the disk structure.
                    257:         */
1.82      christos  258:        cd->sc_dk.dk_driver = &cddkdriver;
1.79      thorpej   259:        cd->sc_dk.dk_name = cd->sc_dev.dv_xname;
                    260:        disk_attach(&cd->sc_dk);
1.103     enami     261:
1.96      christos  262:        printf("\n");
1.105     explorer  263:
1.106     explorer  264: #if NRND > 0
1.124     explorer  265:        rnd_attach_source(&cd->rnd_source, cd->sc_dev.dv_xname,
                    266:                          RND_TYPE_DISK, 0);
1.106     explorer  267: #endif
1.129     enami     268: }
                    269:
1.202     thorpej   270: static int
                    271: cdactivate(struct device *self, enum devact act)
1.129     enami     272: {
                    273:        int rv = 0;
                    274:
                    275:        switch (act) {
                    276:        case DVACT_ACTIVATE:
                    277:                rv = EOPNOTSUPP;
                    278:                break;
                    279:
                    280:        case DVACT_DEACTIVATE:
                    281:                /*
                    282:                 * Nothing to do; we key off the device's DVF_ACTIVE.
                    283:                 */
                    284:                break;
                    285:        }
                    286:        return (rv);
                    287: }
                    288:
1.202     thorpej   289: static int
                    290: cddetach(struct device *self, int flags)
1.129     enami     291: {
                    292:        struct cd_softc *cd = (struct cd_softc *) self;
1.148     drochner  293:        int s, bmaj, cmaj, i, mn;
1.129     enami     294:
                    295:        /* locate the major number */
1.166     gehenna   296:        bmaj = bdevsw_lookup_major(&cd_bdevsw);
                    297:        cmaj = cdevsw_lookup_major(&cd_cdevsw);
1.129     enami     298:
1.206     mycroft   299:        /* Nuke the vnodes for any open instances */
                    300:        for (i = 0; i < MAXPARTITIONS; i++) {
                    301:                mn = CDMINOR(self->dv_unit, i);
                    302:                vdevgone(bmaj, mn, mn, VBLK);
                    303:                vdevgone(cmaj, mn, mn, VCHR);
                    304:        }
                    305:
1.203     bouyer    306:        /* kill any pending restart */
                    307:        callout_stop(&cd->sc_callout);
                    308:
1.129     enami     309:        s = splbio();
                    310:
                    311:        /* Kill off any queued buffers. */
1.221     yamt      312:        bufq_drain(&cd->buf_queue);
1.129     enami     313:
1.164     hannken   314:        bufq_free(&cd->buf_queue);
                    315:
1.129     enami     316:        /* Kill off any pending commands. */
1.145     bouyer    317:        scsipi_kill_pending(cd->sc_periph);
1.129     enami     318:
                    319:        splx(s);
                    320:
1.206     mycroft   321:        lockmgr(&cd->sc_lock, LK_DRAIN, 0);
1.129     enami     322:
                    323:        /* Detach from the disk list. */
                    324:        disk_detach(&cd->sc_dk);
                    325:
                    326: #if 0
                    327:        /* Get rid of the shutdown hook. */
                    328:        if (cd->sc_sdhook != NULL)
                    329:                shutdownhook_disestablish(cd->sc_sdhook);
                    330: #endif
                    331:
                    332: #if NRND > 0
                    333:        /* Unhook the entropy source. */
                    334:        rnd_detach_source(&cd->rnd_source);
                    335: #endif
                    336:
                    337:        return (0);
1.1       cgd       338: }
                    339:
1.65      mycroft   340: /*
1.23      mycroft   341:  * open the device. Make sure the partition info is a up-to-date as can be.
                    342:  */
1.220     perry     343: static int
1.202     thorpej   344: cdopen(dev_t dev, int flag, int fmt, struct proc *p)
1.1       cgd       345: {
1.47      mycroft   346:        struct cd_softc *cd;
1.145     bouyer    347:        struct scsipi_periph *periph;
                    348:        struct scsipi_adapter *adapt;
1.65      mycroft   349:        int unit, part;
                    350:        int error;
1.224     bouyer    351:        int rawpart;
1.23      mycroft   352:
                    353:        unit = CDUNIT(dev);
1.83      thorpej   354:        if (unit >= cd_cd.cd_ndevs)
1.103     enami     355:                return (ENXIO);
1.83      thorpej   356:        cd = cd_cd.cd_devs[unit];
1.103     enami     357:        if (cd == NULL)
                    358:                return (ENXIO);
1.23      mycroft   359:
1.145     bouyer    360:        periph = cd->sc_periph;
                    361:        adapt = periph->periph_channel->chan_adapter;
1.119     bouyer    362:        part = CDPART(dev);
1.1       cgd       363:
1.145     bouyer    364:        SC_DEBUG(periph, SCSIPI_DB1,
1.23      mycroft   365:            ("cdopen: dev=0x%x (unit %d (of %d), partition %d)\n", dev, unit,
1.92      christos  366:            cd_cd.cd_ndevs, CDPART(dev)));
1.3       deraadt   367:
1.116     thorpej   368:        /*
                    369:         * If this is the first open of this device, add a reference
                    370:         * to the adapter.
                    371:         */
                    372:        if (cd->sc_dk.dk_openmask == 0 &&
1.145     bouyer    373:            (error = scsipi_adapter_addref(adapt)) != 0)
1.116     thorpej   374:                return (error);
                    375:
1.206     mycroft   376:        if ((error = lockmgr(&cd->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
1.116     thorpej   377:                goto bad4;
1.41      mycroft   378:
1.224     bouyer    379:        rawpart = (part == RAW_PART && fmt == S_IFCHR);
1.145     bouyer    380:        if ((periph->periph_flags & PERIPH_OPEN) != 0) {
1.43      mycroft   381:                /*
                    382:                 * If any partition is open, but the disk has been invalidated,
                    383:                 * disallow further opens.
                    384:                 */
1.145     bouyer    385:                if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 &&
1.224     bouyer    386:                        !rawpart) {
1.66      mycroft   387:                        error = EIO;
                    388:                        goto bad3;
                    389:                }
1.43      mycroft   390:        } else {
1.195     mycroft   391:                int silent;
                    392:
1.224     bouyer    393:                if (rawpart)
1.195     mycroft   394:                        silent = XS_CTL_SILENT;
                    395:                else
                    396:                        silent = 0;
                    397:
1.51      mycroft   398:                /* Check that it is still responding and ok. */
1.145     bouyer    399:                error = scsipi_test_unit_ready(periph,
1.130     thorpej   400:                    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
1.196     mycroft   401:                    silent);
1.192     mycroft   402:
                    403:                /*
                    404:                 * Start the pack spinning if necessary. Always allow the
                    405:                 * raw parition to be opened, for raw IOCTLs. Data transfers
                    406:                 * will check for SDEV_MEDIA_LOADED.
                    407:                 */
1.194     mycroft   408:                if (error == EIO) {
1.195     mycroft   409:                        int error2;
1.192     mycroft   410:
                    411:                        error2 = scsipi_start(periph, SSS_START, silent);
                    412:                        switch (error2) {
                    413:                        case 0:
                    414:                                error = 0;
                    415:                                break;
1.194     mycroft   416:                        case EIO:
1.192     mycroft   417:                        case EINVAL:
                    418:                                break;
                    419:                        default:
                    420:                                error = error2;
                    421:                                break;
1.155     ad        422:                        }
1.119     bouyer    423:                }
1.195     mycroft   424:                if (error) {
1.224     bouyer    425:                        if (rawpart)
1.195     mycroft   426:                                goto out;
1.192     mycroft   427:                        goto bad3;
1.195     mycroft   428:                }
1.53      mycroft   429:
1.145     bouyer    430:                periph->periph_flags |= PERIPH_OPEN;
1.44      mycroft   431:
1.41      mycroft   432:                /* Lock the pack in. */
1.219     thorpej   433:                error = scsipi_prevent(periph, SPAMR_PREVENT_DT,
1.130     thorpej   434:                    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE);
1.145     bouyer    435:                SC_DEBUG(periph, SCSIPI_DB1,
1.103     enami     436:                    ("cdopen: scsipi_prevent, error=%d\n", error));
1.224     bouyer    437:                if (error) {
                    438:                        if (rawpart)
                    439:                                goto out;
1.51      mycroft   440:                        goto bad;
1.224     bouyer    441:                }
1.50      mycroft   442:
1.145     bouyer    443:                if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
1.41      mycroft   444:                        /* Load the physical device parameters. */
                    445:                        if (cd_get_parms(cd, 0) != 0) {
1.224     bouyer    446:                                if (rawpart)
                    447:                                        goto out;
1.41      mycroft   448:                                error = ENXIO;
1.224     bouyer    449:                                goto bad;
1.41      mycroft   450:                        }
1.224     bouyer    451:                        periph->periph_flags |= PERIPH_MEDIA_LOADED;
1.145     bouyer    452:                        SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded "));
1.41      mycroft   453:
                    454:                        /* Fabricate a disk label. */
                    455:                        cdgetdisklabel(cd);
1.145     bouyer    456:                        SC_DEBUG(periph, SCSIPI_DB3, ("Disklabel fabricated "));
1.41      mycroft   457:                }
1.65      mycroft   458:        }
1.23      mycroft   459:
1.43      mycroft   460:        /* Check that the partition exists. */
1.36      mycroft   461:        if (part != RAW_PART &&
1.79      thorpej   462:            (part >= cd->sc_dk.dk_label->d_npartitions ||
1.103     enami     463:            cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
1.23      mycroft   464:                error = ENXIO;
                    465:                goto bad;
                    466:        }
                    467:
1.119     bouyer    468: out:   /* Insure only one open at a time. */
1.36      mycroft   469:        switch (fmt) {
                    470:        case S_IFCHR:
1.37      mycroft   471:                cd->sc_dk.dk_copenmask |= (1 << part);
1.36      mycroft   472:                break;
                    473:        case S_IFBLK:
1.37      mycroft   474:                cd->sc_dk.dk_bopenmask |= (1 << part);
1.36      mycroft   475:                break;
1.1       cgd       476:        }
1.103     enami     477:        cd->sc_dk.dk_openmask =
                    478:            cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
1.36      mycroft   479:
1.145     bouyer    480:        SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n"));
1.206     mycroft   481:        lockmgr(&cd->sc_lock, LK_RELEASE, NULL);
1.103     enami     482:        return (0);
1.23      mycroft   483:
1.145     bouyer    484:        periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
1.41      mycroft   485:
1.23      mycroft   486: bad:
1.37      mycroft   487:        if (cd->sc_dk.dk_openmask == 0) {
1.219     thorpej   488:                scsipi_prevent(periph, SPAMR_ALLOW,
1.130     thorpej   489:                    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE);
1.145     bouyer    490:                periph->periph_flags &= ~PERIPH_OPEN;
1.65      mycroft   491:        }
1.41      mycroft   492:
1.53      mycroft   493: bad3:
1.206     mycroft   494:        lockmgr(&cd->sc_lock, LK_RELEASE, NULL);
1.116     thorpej   495: bad4:
                    496:        if (cd->sc_dk.dk_openmask == 0)
1.145     bouyer    497:                scsipi_adapter_delref(adapt);
1.103     enami     498:        return (error);
1.1       cgd       499: }
                    500:
1.23      mycroft   501: /*
                    502:  * close the device.. only called if we are the LAST
                    503:  * occurence of an open device
                    504:  */
1.220     perry     505: static int
1.202     thorpej   506: cdclose(dev_t dev, int flag, int fmt, struct proc *p)
1.1       cgd       507: {
1.83      thorpej   508:        struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(dev)];
1.145     bouyer    509:        struct scsipi_periph *periph = cd->sc_periph;
                    510:        struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
1.36      mycroft   511:        int part = CDPART(dev);
1.65      mycroft   512:        int error;
                    513:
1.206     mycroft   514:        if ((error = lockmgr(&cd->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
1.103     enami     515:                return (error);
1.36      mycroft   516:
                    517:        switch (fmt) {
                    518:        case S_IFCHR:
1.37      mycroft   519:                cd->sc_dk.dk_copenmask &= ~(1 << part);
1.36      mycroft   520:                break;
                    521:        case S_IFBLK:
1.37      mycroft   522:                cd->sc_dk.dk_bopenmask &= ~(1 << part);
1.36      mycroft   523:                break;
                    524:        }
1.103     enami     525:        cd->sc_dk.dk_openmask =
                    526:            cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
1.23      mycroft   527:
1.37      mycroft   528:        if (cd->sc_dk.dk_openmask == 0) {
1.145     bouyer    529:                scsipi_wait_drain(periph);
1.43      mycroft   530:
1.219     thorpej   531:                scsipi_prevent(periph, SPAMR_ALLOW,
1.130     thorpej   532:                    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
                    533:                    XS_CTL_IGNORE_NOT_READY);
1.145     bouyer    534:                periph->periph_flags &= ~PERIPH_OPEN;
1.117     thorpej   535:
1.145     bouyer    536:                scsipi_wait_drain(periph);
1.116     thorpej   537:
1.145     bouyer    538:                scsipi_adapter_delref(adapt);
1.1       cgd       539:        }
1.43      mycroft   540:
1.206     mycroft   541:        lockmgr(&cd->sc_lock, LK_RELEASE, NULL);
1.103     enami     542:        return (0);
1.23      mycroft   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:  */
1.202     thorpej   550: static void
                    551: cdstrategy(struct buf *bp)
1.23      mycroft   552: {
1.83      thorpej   553:        struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(bp->b_dev)];
1.136     thorpej   554:        struct disklabel *lp;
1.145     bouyer    555:        struct scsipi_periph *periph = cd->sc_periph;
1.136     thorpej   556:        daddr_t blkno;
1.145     bouyer    557:        int s;
1.4       deraadt   558:
1.145     bouyer    559:        SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdstrategy "));
                    560:        SC_DEBUG(cd->sc_periph, SCSIPI_DB1,
1.210     dogcow    561:            ("%d bytes @ blk %" PRId64 "\n", bp->b_bcount, bp->b_blkno));
1.76      mycroft   562:        /*
1.119     bouyer    563:         * If the device has been made invalid, error out
                    564:         * maybe the media changed
1.76      mycroft   565:         */
1.145     bouyer    566:        if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
                    567:                if (periph->periph_flags & PERIPH_OPEN)
1.120     bouyer    568:                        bp->b_error = EIO;
                    569:                else
                    570:                        bp->b_error = ENODEV;
1.76      mycroft   571:                goto bad;
                    572:        }
1.136     thorpej   573:
                    574:        lp = cd->sc_dk.dk_label;
                    575:
1.23      mycroft   576:        /*
1.122     bouyer    577:         * The transfer must be a whole number of blocks, offset must not
                    578:         * be negative.
1.23      mycroft   579:         */
1.136     thorpej   580:        if ((bp->b_bcount % lp->d_secsize) != 0 ||
1.122     bouyer    581:            bp->b_blkno < 0 ) {
1.119     bouyer    582:                bp->b_error = EINVAL;
1.1       cgd       583:                goto bad;
                    584:        }
1.23      mycroft   585:        /*
                    586:         * If it's a null transfer, return immediately
                    587:         */
                    588:        if (bp->b_bcount == 0)
1.1       cgd       589:                goto done;
1.48      mycroft   590:
1.23      mycroft   591:        /*
1.48      mycroft   592:         * Do bounds checking, adjust transfer. if error, process.
                    593:         * If end of partition, just return.
1.23      mycroft   594:         */
1.181     fvdl      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 {
1.183     thorpej   600:                if (bounds_check_with_label(&cd->sc_dk, bp,
1.181     fvdl      601:                    (cd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0)
                    602:                        goto done;
                    603:        }
1.36      mycroft   604:
1.136     thorpej   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:
1.154     eeh       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 buf *nbp;
                    628:                        void *bounce = NULL;
                    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 bad;
                    636:                        }
                    637:                        count = ((blkno * lp->d_secsize) % cd->params.blksize);
                    638:                        /* XXX Store starting offset in bp->b_rawblkno */
                    639:                        bp->b_rawblkno = count;
                    640:
                    641:                        count += bp->b_bcount;
                    642:                        count = roundup(count, cd->params.blksize);
                    643:
                    644:                        blkno = ((blkno * lp->d_secsize) / cd->params.blksize);
                    645:                        s = splbio();
                    646:                        nbp = pool_get(&bufpool, PR_NOWAIT);
                    647:                        splx(s);
                    648:                        if (!nbp) {
                    649:                                /* No memory -- fail the iop. */
                    650:                                bp->b_error = ENOMEM;
                    651:                                goto bad;
                    652:                        }
                    653:                        bounce = malloc(count, M_DEVBUF, M_NOWAIT);
                    654:                        if (!bounce) {
                    655:                                /* No memory -- fail the iop. */
                    656:                                s = splbio();
                    657:                                pool_put(&bufpool, nbp);
                    658:                                splx(s);
                    659:                                bp->b_error = ENOMEM;
                    660:                                goto bad;
                    661:                        }
                    662:
                    663:                        /* Set up the IOP to the bounce buffer. */
1.179     thorpej   664:                        BUF_INIT(nbp);
1.154     eeh       665:                        nbp->b_error = 0;
                    666:                        nbp->b_proc = bp->b_proc;
                    667:                        nbp->b_vp = NULLVP;
                    668:
                    669:                        nbp->b_bcount = count;
                    670:                        nbp->b_bufsize = count;
                    671:                        nbp->b_data = bounce;
                    672:
                    673:                        nbp->b_rawblkno = blkno;
                    674:
                    675:                        /* We need to do a read-modify-write operation */
                    676:                        nbp->b_flags = bp->b_flags | B_READ | B_CALL;
                    677:                        nbp->b_iodone = cdbounce;
                    678:
                    679:                        /* Put ptr to orig buf in b_private and use new buf */
                    680:                        nbp->b_private = bp;
1.199     yamt      681:
                    682:                        BIO_COPYPRIO(nbp, bp);
                    683:
1.154     eeh       684:                        bp = nbp;
                    685:
                    686:                } else {
                    687:                        /* Xfer is aligned -- just adjust the start block */
                    688:                        bp->b_rawblkno = (blkno * lp->d_secsize) /
                    689:                                cd->params.blksize;
                    690:                }
                    691:        }
1.145     bouyer    692:        s = splbio();
1.1       cgd       693:
1.23      mycroft   694:        /*
1.145     bouyer    695:         * Place it in the queue of disk activities for this disk.
                    696:         *
                    697:         * XXX Only do disksort() if the current operating mode does not
                    698:         * XXX include tagged queueing.
1.23      mycroft   699:         */
1.164     hannken   700:        BUFQ_PUT(&cd->buf_queue, bp);
1.1       cgd       701:
1.23      mycroft   702:        /*
                    703:         * Tell the device to get going on the transfer if it's
                    704:         * not doing anything, otherwise just wait for completion
                    705:         */
1.145     bouyer    706:        cdstart(cd->sc_periph);
1.1       cgd       707:
1.145     bouyer    708:        splx(s);
1.1       cgd       709:        return;
1.23      mycroft   710:
1.1       cgd       711: bad:
                    712:        bp->b_flags |= B_ERROR;
                    713: done:
1.23      mycroft   714:        /*
                    715:         * Correctly set the buf to indicate a completed xfer
                    716:         */
                    717:        bp->b_resid = bp->b_bcount;
1.1       cgd       718:        biodone(bp);
                    719: }
                    720:
1.23      mycroft   721: /*
                    722:  * cdstart looks to see if there is a buf waiting for the device
                    723:  * and that the device is not already busy. If both are true,
                    724:  * It deques the buf and creates a scsi command to perform the
1.101     bouyer    725:  * transfer in the buf. The transfer request will call scsipi_done
1.23      mycroft   726:  * on completion, which will in turn call this routine again
                    727:  * so that the next queued transfer is performed.
                    728:  * The bufs are queued by the strategy routine (cdstrategy)
                    729:  *
                    730:  * This routine is also called after other non-queued requests
                    731:  * have been made of the scsi driver, to ensure that the queue
                    732:  * continues to be drained.
                    733:  *
                    734:  * must be called at the correct (highish) spl level
1.204     bouyer    735:  * cdstart() is called at splbio from cdstrategy, cdrestart and scsipi_done
1.23      mycroft   736:  */
1.220     perry     737: static void
1.202     thorpej   738: cdstart(struct scsipi_periph *periph)
1.23      mycroft   739: {
1.145     bouyer    740:        struct cd_softc *cd = (void *)periph->periph_dev;
1.23      mycroft   741:        struct buf *bp = 0;
1.212     thorpej   742:        struct scsipi_rw_10 cmd_big;
                    743:        struct scsi_rw_6 cmd_small;
1.101     bouyer    744:        struct scsipi_generic *cmdp;
1.205     bouyer    745:        struct scsipi_xfer *xs;
1.145     bouyer    746:        int flags, nblks, cmdlen, error;
1.1       cgd       747:
1.145     bouyer    748:        SC_DEBUG(periph, SCSIPI_DB2, ("cdstart "));
1.23      mycroft   749:        /*
1.58      mycroft   750:         * Check if the device has room for another command
1.23      mycroft   751:         */
1.145     bouyer    752:        while (periph->periph_active < periph->periph_openings) {
1.23      mycroft   753:                /*
                    754:                 * there is excess capacity, but a special waits
                    755:                 * It'll need the adapter as soon as we clear out of the
                    756:                 * way and let it run (user level wait).
                    757:                 */
1.145     bouyer    758:                if (periph->periph_flags & PERIPH_WAITING) {
                    759:                        periph->periph_flags &= ~PERIPH_WAITING;
                    760:                        wakeup((caddr_t)periph);
1.23      mycroft   761:                        return;
                    762:                }
1.1       cgd       763:
1.23      mycroft   764:                /*
1.120     bouyer    765:                 * If the device has become invalid, abort all the
1.23      mycroft   766:                 * reads and writes until all files have been closed and
1.47      mycroft   767:                 * re-opened
1.23      mycroft   768:                 */
1.203     bouyer    769:                if (__predict_false(
                    770:                    (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
                    771:                        if ((bp = BUFQ_GET(&cd->buf_queue)) != NULL) {
                    772:                                bp->b_error = EIO;
                    773:                                bp->b_flags |= B_ERROR;
                    774:                                bp->b_resid = bp->b_bcount;
                    775:                                biodone(bp);
                    776:                                continue;
                    777:                        } else {
                    778:                                return;
                    779:                        }
1.29      chopps    780:                }
1.23      mycroft   781:
                    782:                /*
1.203     bouyer    783:                 * See if there is a buf with work for us to do..
                    784:                 */
                    785:                if ((bp = BUFQ_PEEK(&cd->buf_queue)) == NULL)
                    786:                        return;
                    787:
                    788:                /*
1.136     thorpej   789:                 * We have a buf, now we should make a command.
1.23      mycroft   790:                 */
1.220     perry     791:
1.154     eeh       792:                nblks = howmany(bp->b_bcount, cd->params.blksize);
1.1       cgd       793:
1.23      mycroft   794:                /*
1.78      thorpej   795:                 *  Fill out the scsi command.  If the transfer will
                    796:                 *  fit in a "small" cdb, use it.
1.23      mycroft   797:                 */
1.136     thorpej   798:                if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) &&
1.145     bouyer    799:                    ((nblks & 0xff) == nblks) &&
1.188     mycroft   800:                    !(periph->periph_quirks & PQUIRK_ONLYBIG)) {
1.78      thorpej   801:                        /*
                    802:                         * We can fit in a small cdb.
                    803:                         */
1.152     thorpej   804:                        memset(&cmd_small, 0, sizeof(cmd_small));
1.78      thorpej   805:                        cmd_small.opcode = (bp->b_flags & B_READ) ?
1.212     thorpej   806:                            SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND;
1.136     thorpej   807:                        _lto3b(bp->b_rawblkno, cmd_small.addr);
1.78      thorpej   808:                        cmd_small.length = nblks & 0xff;
                    809:                        cmdlen = sizeof(cmd_small);
1.101     bouyer    810:                        cmdp = (struct scsipi_generic *)&cmd_small;
1.190     mycroft   811:                } else {
1.78      thorpej   812:                        /*
                    813:                         * Need a large cdb.
                    814:                         */
1.152     thorpej   815:                        memset(&cmd_big, 0, sizeof(cmd_big));
1.78      thorpej   816:                        cmd_big.opcode = (bp->b_flags & B_READ) ?
1.212     thorpej   817:                            READ_10 : WRITE_10;
1.136     thorpej   818:                        _lto4b(bp->b_rawblkno, cmd_big.addr);
1.84      mycroft   819:                        _lto2b(nblks, cmd_big.length);
1.78      thorpej   820:                        cmdlen = sizeof(cmd_big);
1.101     bouyer    821:                        cmdp = (struct scsipi_generic *)&cmd_big;
1.78      thorpej   822:                }
1.1       cgd       823:
1.79      thorpej   824:                /* Instrumentation. */
                    825:                disk_busy(&cd->sc_dk);
                    826:
1.23      mycroft   827:                /*
1.145     bouyer    828:                 * Figure out what flags to use.
                    829:                 */
1.165     hannken   830:                flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG;
1.145     bouyer    831:                if (bp->b_flags & B_READ)
1.146     thorpej   832:                        flags |= XS_CTL_DATA_IN;
1.147     tsutsui   833:                else
                    834:                        flags |= XS_CTL_DATA_OUT;
1.145     bouyer    835:
                    836:                /*
1.23      mycroft   837:                 * Call the routine that chats with the adapter.
                    838:                 * Note: we cannot sleep as we may be an interrupt
                    839:                 */
1.205     bouyer    840:                xs = scsipi_make_xs(periph, cmdp, cmdlen,
1.218     reinoud   841:                    (u_char *)bp->b_data, bp->b_bcount,
1.145     bouyer    842:                    CDRETRIES, 30000, bp, flags);
1.205     bouyer    843:                if (__predict_false(xs == NULL)) {
1.203     bouyer    844:                        /*
                    845:                         * out of memory. Keep this buffer in the queue, and
                    846:                         * retry later.
                    847:                         */
                    848:                        callout_reset(&cd->sc_callout, hz / 2, cdrestart,
                    849:                            periph);
                    850:                        return;
                    851:                }
1.205     bouyer    852:                /*
                    853:                 * need to dequeue the buffer before queuing the command,
                    854:                 * because cdstart may be called recursively from the
                    855:                 * HBA driver
                    856:                 */
1.203     bouyer    857: #ifdef DIAGNOSTIC
                    858:                if (BUFQ_GET(&cd->buf_queue) != bp)
                    859:                        panic("cdstart(): dequeued wrong buf");
                    860: #else
                    861:                BUFQ_GET(&cd->buf_queue);
                    862: #endif
1.207     mycroft   863:                error = scsipi_execute_xs(xs);
1.205     bouyer    864:                /* with a scsipi_xfer preallocated, scsipi_command can't fail */
                    865:                KASSERT(error == 0);
1.23      mycroft   866:        }
1.70      mycroft   867: }
                    868:
1.202     thorpej   869: static void
1.203     bouyer    870: cdrestart(void *v)
                    871: {
                    872:        int s = splbio();
                    873:        cdstart((struct scsipi_periph *)v);
                    874:        splx(s);
                    875: }
                    876:
                    877: static void
1.206     mycroft   878: cddone(struct scsipi_xfer *xs, int error)
1.79      thorpej   879: {
1.145     bouyer    880:        struct cd_softc *cd = (void *)xs->xs_periph->periph_dev;
1.206     mycroft   881:        struct buf *bp = xs->bp;
1.79      thorpej   882:
1.206     mycroft   883:        if (bp) {
                    884:                bp->b_error = error;
                    885:                bp->b_resid = xs->resid;
                    886:                if (error)
                    887:                        bp->b_flags |= B_ERROR;
                    888:
                    889:                disk_unbusy(&cd->sc_dk, bp->b_bcount - bp->b_resid,
                    890:                    (bp->b_flags & B_READ));
1.106     explorer  891: #if NRND > 0
1.206     mycroft   892:                rnd_add_uint32(&cd->rnd_source, bp->b_rawblkno);
1.106     explorer  893: #endif
1.206     mycroft   894:
                    895:                biodone(bp);
1.105     explorer  896:        }
1.144     kenh      897: }
                    898:
1.202     thorpej   899: static void
                    900: cdbounce(struct buf *bp)
1.154     eeh       901: {
                    902:        struct buf *obp = (struct buf *)bp->b_private;
                    903:
                    904:        if (bp->b_flags & B_ERROR) {
                    905:                /* EEK propagate the error and free the memory */
                    906:                goto done;
                    907:        }
                    908:        if (obp->b_flags & B_READ) {
                    909:                /* Copy data to the final destination and free the buf. */
1.220     perry     910:                memcpy(obp->b_data, bp->b_data+obp->b_rawblkno,
1.154     eeh       911:                        obp->b_bcount);
                    912:        } else {
                    913:                /*
                    914:                 * XXXX This is a CD-ROM -- READ ONLY -- why do we bother with
                    915:                 * XXXX any of this write stuff?
                    916:                 */
                    917:                if (bp->b_flags & B_READ) {
                    918:                        struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(bp->b_dev)];
                    919:                        struct buf *nbp;
                    920:                        int s;
                    921:
                    922:                        /* Read part of RMW complete. */
                    923:                        memcpy(bp->b_data+obp->b_rawblkno, obp->b_data,
                    924:                                obp->b_bcount);
                    925:
                    926:                        s = splbio();
                    927:
                    928:                        /* We need to alloc a new buf. */
                    929:                        nbp = pool_get(&bufpool, PR_NOWAIT);
                    930:                        if (!nbp) {
                    931:                                splx(s);
                    932:                                /* No buf available. */
                    933:                                bp->b_flags |= B_ERROR;
                    934:                                bp->b_error = ENOMEM;
                    935:                                bp->b_resid = bp->b_bcount;
                    936:                        }
                    937:
                    938:                        /* Set up the IOP to the bounce buffer. */
1.179     thorpej   939:                        BUF_INIT(nbp);
1.154     eeh       940:                        nbp->b_error = 0;
                    941:                        nbp->b_proc = bp->b_proc;
                    942:                        nbp->b_vp = NULLVP;
                    943:
                    944:                        nbp->b_bcount = bp->b_bcount;
                    945:                        nbp->b_bufsize = bp->b_bufsize;
                    946:                        nbp->b_data = bp->b_data;
                    947:
                    948:                        nbp->b_rawblkno = bp->b_rawblkno;
                    949:
                    950:                        /* We need to do a read-modify-write operation */
                    951:                        nbp->b_flags = obp->b_flags | B_CALL;
                    952:                        nbp->b_iodone = cdbounce;
                    953:
                    954:                        /* Put ptr to orig buf in b_private and use new buf */
                    955:                        nbp->b_private = obp;
                    956:
                    957:                        /*
                    958:                         * Place it in the queue of disk activities for this
                    959:                         * disk.
                    960:                         *
                    961:                         * XXX Only do disksort() if the current operating mode
                    962:                         * XXX does not include tagged queueing.
                    963:                         */
1.164     hannken   964:                        BUFQ_PUT(&cd->buf_queue, nbp);
1.154     eeh       965:
                    966:                        /*
                    967:                         * Tell the device to get going on the transfer if it's
                    968:                         * not doing anything, otherwise just wait for
                    969:                         * completion
                    970:                         */
                    971:                        cdstart(cd->sc_periph);
                    972:
                    973:                        splx(s);
                    974:                        return;
                    975:
                    976:                }
                    977:        }
                    978: done:
                    979:        obp->b_flags |= (bp->b_flags&(B_EINTR|B_ERROR));
                    980:        obp->b_error = bp->b_error;
                    981:        obp->b_resid = bp->b_resid;
                    982:        free(bp->b_data, M_DEVBUF);
                    983:        biodone(obp);
                    984: }
                    985:
1.202     thorpej   986: static int
                    987: cd_interpret_sense(struct scsipi_xfer *xs)
1.144     kenh      988: {
1.145     bouyer    989:        struct scsipi_periph *periph = xs->xs_periph;
1.219     thorpej   990:        struct scsi_sense_data *sense = &xs->sense.scsi_sense;
1.145     bouyer    991:        int retval = EJUSTRETURN;
1.144     kenh      992:
                    993:        /*
                    994:         * If it isn't a extended or extended/deferred error, let
                    995:         * the generic code handle it.
                    996:         */
1.222     drochner  997:        if (SSD_RCODE(sense->response_code) != SSD_RCODE_CURRENT &&
                    998:            SSD_RCODE(sense->response_code) != SSD_RCODE_DEFERRED)
1.144     kenh      999:                return (retval);
                   1000:
1.156     ad       1001:        /*
                   1002:         * If we got a "Unit not ready" (SKEY_NOT_READY) and "Logical Unit
                   1003:         * Is In The Process of Becoming Ready" (Sense code 0x04,0x01), then
                   1004:         * wait a bit for the drive to spin up
                   1005:         */
1.144     kenh     1006:
1.219     thorpej  1007:        if (SSD_SENSE_KEY(sense->flags) == SKEY_NOT_READY &&
                   1008:            sense->asc == 0x4 &&
                   1009:            sense->ascq == 0x01)        {
1.144     kenh     1010:                /*
1.156     ad       1011:                 * Sleep for 5 seconds to wait for the drive to spin up
1.144     kenh     1012:                 */
1.156     ad       1013:
                   1014:                SC_DEBUG(periph, SCSIPI_DB1, ("Waiting 5 sec for CD "
                   1015:                                                "spinup\n"));
1.177     thorpej  1016:                if (!callout_pending(&periph->periph_callout))
1.162     bouyer   1017:                        scsipi_periph_freeze(periph, 1);
1.156     ad       1018:                callout_reset(&periph->periph_callout,
                   1019:                    5 * hz, scsipi_periph_timed_thaw, periph);
                   1020:                retval = ERESTART;
1.155     ad       1021:        }
1.144     kenh     1022:        return (retval);
1.79      thorpej  1023: }
                   1024:
1.202     thorpej  1025: static void
                   1026: cdminphys(struct buf *bp)
1.85      mycroft  1027: {
1.87      mycroft  1028:        struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(bp->b_dev)];
1.223     christos 1029:        long xmax;
1.85      mycroft  1030:
                   1031:        /*
                   1032:         * If the device is ancient, we want to make sure that
                   1033:         * the transfer fits into a 6-byte cdb.
                   1034:         *
                   1035:         * XXX Note that the SCSI-I spec says that 256-block transfers
                   1036:         * are allowed in a 6-byte read/write, and are specified
                   1037:         * by settng the "length" to 0.  However, we're conservative
                   1038:         * here, allowing only 255-block transfers in case an
                   1039:         * ancient device gets confused by length == 0.  A length of 0
                   1040:         * in a 10-byte read/write actually means 0 blocks.
                   1041:         */
                   1042:        if (cd->flags & CDF_ANCIENT) {
1.223     christos 1043:                xmax = cd->sc_dk.dk_label->d_secsize * 0xff;
1.85      mycroft  1044:
1.223     christos 1045:                if (bp->b_bcount > xmax)
                   1046:                        bp->b_bcount = xmax;
1.85      mycroft  1047:        }
                   1048:
1.145     bouyer   1049:        (*cd->sc_periph->periph_channel->chan_adapter->adapt_minphys)(bp);
1.85      mycroft  1050: }
                   1051:
1.202     thorpej  1052: static int
                   1053: cdread(dev_t dev, struct uio *uio, int ioflag)
1.70      mycroft  1054: {
                   1055:
1.85      mycroft  1056:        return (physio(cdstrategy, NULL, dev, B_READ, cdminphys, uio));
1.70      mycroft  1057: }
                   1058:
1.202     thorpej  1059: static int
                   1060: cdwrite(dev_t dev, struct uio *uio, int ioflag)
1.70      mycroft  1061: {
                   1062:
1.85      mycroft  1063:        return (physio(cdstrategy, NULL, dev, B_WRITE, cdminphys, uio));
1.23      mycroft  1064: }
                   1065:
1.202     thorpej  1066: #if 0  /* XXX Not used */
1.23      mycroft  1067: /*
1.198     wiz      1068:  * conversion between minute-seconde-frame and logical block address
                   1069:  * addresses format
1.103     enami    1070:  */
1.202     thorpej  1071: static void
1.218     reinoud  1072: lba2msf(u_long lba, u_char *m, u_char *s, u_char *f)
1.220     perry    1073: {
1.218     reinoud  1074:        u_long tmp;
1.103     enami    1075:
                   1076:        tmp = lba + CD_BLOCK_OFFSET;    /* offset of first logical frame */
                   1077:        tmp &= 0xffffff;                /* negative lbas use only 24 bits */
                   1078:        *m = tmp / (CD_SECS * CD_FRAMES);
                   1079:        tmp %= (CD_SECS * CD_FRAMES);
                   1080:        *s = tmp / CD_FRAMES;
                   1081:        *f = tmp % CD_FRAMES;
                   1082: }
1.101     bouyer   1083:
1.218     reinoud  1084: static u_long
                   1085: msf2lba(u_char m, u_char s, u_char f)
1.103     enami    1086: {
                   1087:
                   1088:        return ((((m * CD_SECS) + s) * CD_FRAMES + f) - CD_BLOCK_OFFSET);
                   1089: }
1.202     thorpej  1090: #endif /* XXX Not used */
1.101     bouyer   1091:
1.202     thorpej  1092: static int
                   1093: cdreadmsaddr(struct cd_softc *cd, int *addr)
1.163     drochner 1094: {
                   1095:        struct scsipi_periph *periph = cd->sc_periph;
                   1096:        int error;
                   1097:        struct cd_toc toc;
                   1098:        struct cd_toc_entry *cte;
                   1099:
1.213     reinoud  1100:        error = cd_read_toc_f0(cd, 0, 0, &toc,
1.163     drochner 1101:            sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry),
                   1102:            XS_CTL_DATA_ONSTACK,
                   1103:            0x40 /* control word for "get MS info" */);
                   1104:
                   1105:        if (error)
                   1106:                return (error);
                   1107:
                   1108:        cte = &toc.entries[0];
                   1109:        if (periph->periph_quirks & PQUIRK_LITTLETOC) {
                   1110:                cte->addr.lba = le32toh(cte->addr.lba);
                   1111:                toc.header.len = le16toh(toc.header.len);
                   1112:        } else {
                   1113:                cte->addr.lba = be32toh(cte->addr.lba);
                   1114:                toc.header.len = be16toh(toc.header.len);
                   1115:        }
                   1116:
                   1117:        *addr = (toc.header.len >= 10 && cte->track > 1) ?
                   1118:                cte->addr.lba : 0;
                   1119:        return 0;
                   1120: }
1.101     bouyer   1121:
1.226     reinoud  1122: /* synchronise caches code from sd.c, move to scsipi_ioctl.c ? */
                   1123: static int
                   1124: cdcachesync(struct scsipi_periph *periph, int flags) {
                   1125:        struct scsi_synchronize_cache_10 cmd;
                   1126:
                   1127:        /*
                   1128:         * Issue a SYNCHRONIZE CACHE. MMC devices have to issue with address 0
                   1129:         * and length 0 as it can't synchronise parts of the disc per spec.
                   1130:         * We ignore ILLEGAL REQUEST in the event that the command is not
                   1131:         * supported by the device, and poll for completion so that we know
                   1132:         * that the cache has actually been flushed.
                   1133:         *
                   1134:         * XXX should we handle the PQUIRK_NOSYNCCACHE ?
                   1135:         */
                   1136:
                   1137:        memset(&cmd, 0, sizeof(cmd));
                   1138:        cmd.opcode = SCSI_SYNCHRONIZE_CACHE_10;
                   1139:
                   1140:        return (scsipi_command(periph, (void *)&cmd, sizeof(cmd), 0, 0,
                   1141:            CDRETRIES, 30000, NULL, flags | XS_CTL_IGNORE_ILLEGAL_REQUEST));
                   1142: }
                   1143:
1.101     bouyer   1144: /*
1.23      mycroft  1145:  * Perform special action on behalf of the user.
                   1146:  * Knows about the internals of this device
                   1147:  */
1.202     thorpej  1148: static int
1.218     reinoud  1149: cdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1.1       cgd      1150: {
1.83      thorpej  1151:        struct cd_softc *cd = cd_cd.cd_devs[CDUNIT(dev)];
1.145     bouyer   1152:        struct scsipi_periph *periph = cd->sc_periph;
1.121     bouyer   1153:        int part = CDPART(dev);
1.171     fvdl     1154:        int error = 0;
1.142     fvdl     1155: #ifdef __HAVE_OLD_DISKLABEL
1.171     fvdl     1156:        struct disklabel *newlabel = NULL;
1.142     fvdl     1157: #endif
1.1       cgd      1158:
1.145     bouyer   1159:        SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdioctl 0x%lx ", cmd));
1.1       cgd      1160:
1.23      mycroft  1161:        /*
1.119     bouyer   1162:         * If the device is not valid, some IOCTLs can still be
                   1163:         * handled on the raw partition. Check this here.
1.23      mycroft  1164:         */
1.145     bouyer   1165:        if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
1.119     bouyer   1166:                switch (cmd) {
                   1167:                case DIOCWLABEL:
                   1168:                case DIOCLOCK:
1.121     bouyer   1169:                case ODIOCEJECT:
1.119     bouyer   1170:                case DIOCEJECT:
1.226     reinoud  1171:                case DIOCCACHESYNC:
1.119     bouyer   1172:                case SCIOCIDENTIFY:
                   1173:                case OSCIOCIDENTIFY:
                   1174:                case SCIOCCOMMAND:
                   1175:                case SCIOCDEBUG:
                   1176:                case CDIOCGETVOL:
                   1177:                case CDIOCSETVOL:
                   1178:                case CDIOCSETMONO:
                   1179:                case CDIOCSETSTEREO:
                   1180:                case CDIOCSETMUTE:
                   1181:                case CDIOCSETLEFT:
                   1182:                case CDIOCSETRIGHT:
                   1183:                case CDIOCCLOSE:
1.120     bouyer   1184:                case CDIOCEJECT:
1.119     bouyer   1185:                case CDIOCALLOW:
                   1186:                case CDIOCPREVENT:
                   1187:                case CDIOCSETDEBUG:
                   1188:                case CDIOCCLRDEBUG:
                   1189:                case CDIOCRESET:
                   1190:                case SCIOCRESET:
                   1191:                case CDIOCLOADUNLOAD:
1.132     mycroft  1192:                case DVD_AUTH:
                   1193:                case DVD_READ_STRUCT:
1.121     bouyer   1194:                        if (part == RAW_PART)
1.119     bouyer   1195:                                break;
                   1196:                /* FALLTHROUGH */
                   1197:                default:
1.145     bouyer   1198:                        if ((periph->periph_flags & PERIPH_OPEN) == 0)
1.120     bouyer   1199:                                return (ENODEV);
                   1200:                        else
                   1201:                                return (EIO);
1.119     bouyer   1202:                }
                   1203:        }
1.1       cgd      1204:
1.23      mycroft  1205:        switch (cmd) {
1.1       cgd      1206:        case DIOCGDINFO:
1.79      thorpej  1207:                *(struct disklabel *)addr = *(cd->sc_dk.dk_label);
1.103     enami    1208:                return (0);
1.142     fvdl     1209: #ifdef __HAVE_OLD_DISKLABEL
                   1210:        case ODIOCGDINFO:
1.171     fvdl     1211:                newlabel = malloc(sizeof (*newlabel), M_TEMP, M_WAITOK);
                   1212:                if (newlabel == NULL)
                   1213:                        return (EIO);
                   1214:                memcpy(newlabel, cd->sc_dk.dk_label, sizeof (*newlabel));
                   1215:                if (newlabel->d_npartitions > OLDMAXPARTITIONS)
                   1216:                        error = ENOTTY;
                   1217:                else
                   1218:                        memcpy(addr, newlabel, sizeof (struct olddisklabel));
                   1219:                free(newlabel, M_TEMP);
                   1220:                return error;
1.142     fvdl     1221: #endif
1.1       cgd      1222:
1.23      mycroft  1223:        case DIOCGPART:
1.79      thorpej  1224:                ((struct partinfo *)addr)->disklab = cd->sc_dk.dk_label;
1.36      mycroft  1225:                ((struct partinfo *)addr)->part =
1.121     bouyer   1226:                    &cd->sc_dk.dk_label->d_partitions[part];
1.103     enami    1227:                return (0);
1.1       cgd      1228:
1.23      mycroft  1229:        case DIOCWDINFO:
                   1230:        case DIOCSDINFO:
1.142     fvdl     1231: #ifdef __HAVE_OLD_DISKLABEL
                   1232:        case ODIOCWDINFO:
                   1233:        case ODIOCSDINFO:
                   1234: #endif
                   1235:        {
                   1236:                struct disklabel *lp;
                   1237:
1.171     fvdl     1238:                if ((flag & FWRITE) == 0)
                   1239:                        return (EBADF);
                   1240:
1.142     fvdl     1241: #ifdef __HAVE_OLD_DISKLABEL
                   1242:                if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
1.171     fvdl     1243:                        newlabel = malloc(sizeof (*newlabel), M_TEMP, M_WAITOK);
                   1244:                        if (newlabel == NULL)
                   1245:                                return (EIO);
                   1246:                        memset(newlabel, 0, sizeof newlabel);
                   1247:                        memcpy(newlabel, addr, sizeof (struct olddisklabel));
                   1248:                        lp = newlabel;
1.142     fvdl     1249:                } else
                   1250: #endif
                   1251:                lp = (struct disklabel *)addr;
                   1252:
1.206     mycroft  1253:                if ((error = lockmgr(&cd->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
1.171     fvdl     1254:                        goto bad;
1.65      mycroft  1255:                cd->flags |= CDF_LABELLING;
1.58      mycroft  1256:
1.79      thorpej  1257:                error = setdisklabel(cd->sc_dk.dk_label,
1.142     fvdl     1258:                    lp, /*cd->sc_dk.dk_openmask : */0,
1.79      thorpej  1259:                    cd->sc_dk.dk_cpulabel);
1.60      mycroft  1260:                if (error == 0) {
1.101     bouyer   1261:                        /* XXX ? */
1.60      mycroft  1262:                }
1.58      mycroft  1263:
                   1264:                cd->flags &= ~CDF_LABELLING;
1.206     mycroft  1265:                lockmgr(&cd->sc_lock, LK_RELEASE, NULL);
1.171     fvdl     1266: bad:
                   1267: #ifdef __HAVE_OLD_DISKLABEL
                   1268:                if (newlabel != NULL)
                   1269:                        free(newlabel, M_TEMP);
                   1270: #endif
1.103     enami    1271:                return (error);
1.142     fvdl     1272:        }
1.23      mycroft  1273:
                   1274:        case DIOCWLABEL:
1.103     enami    1275:                return (EBADF);
1.23      mycroft  1276:
1.104     thorpej  1277:        case DIOCGDEFLABEL:
                   1278:                cdgetdefaultlabel(cd, (struct disklabel *)addr);
                   1279:                return (0);
1.142     fvdl     1280:
                   1281: #ifdef __HAVE_OLD_DISKLABEL
                   1282:        case ODIOCGDEFLABEL:
1.171     fvdl     1283:                newlabel = malloc(sizeof (*newlabel), M_TEMP, M_WAITOK);
                   1284:                if (newlabel == NULL)
                   1285:                        return (EIO);
                   1286:                cdgetdefaultlabel(cd, newlabel);
                   1287:                if (newlabel->d_npartitions > OLDMAXPARTITIONS)
                   1288:                        error = ENOTTY;
                   1289:                else
                   1290:                        memcpy(addr, newlabel, sizeof (struct olddisklabel));
                   1291:                free(newlabel, M_TEMP);
                   1292:                return error;
1.142     fvdl     1293: #endif
1.104     thorpej  1294:
1.23      mycroft  1295:        case CDIOCPLAYTRACKS: {
1.225     reinoud  1296:                /* PLAY_MSF command */
1.36      mycroft  1297:                struct ioc_play_track *args = (struct ioc_play_track *)addr;
1.101     bouyer   1298:
1.188     mycroft  1299:                if ((error = cd_set_pa_immed(cd, 0)) != 0)
1.103     enami    1300:                        return (error);
                   1301:                return (cd_play_tracks(cd, args->start_track,
                   1302:                    args->start_index, args->end_track, args->end_index));
1.23      mycroft  1303:        }
                   1304:        case CDIOCPLAYMSF: {
1.225     reinoud  1305:                /* PLAY_MSF command */
1.82      christos 1306:                struct ioc_play_msf *args = (struct ioc_play_msf *)addr;
1.101     bouyer   1307:
1.188     mycroft  1308:                if ((error = cd_set_pa_immed(cd, 0)) != 0)
1.103     enami    1309:                        return (error);
                   1310:                return (cd_play_msf(cd, args->start_m, args->start_s,
                   1311:                    args->start_f, args->end_m, args->end_s, args->end_f));
1.23      mycroft  1312:        }
                   1313:        case CDIOCPLAYBLOCKS: {
1.225     reinoud  1314:                /* PLAY command */
1.82      christos 1315:                struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr;
1.101     bouyer   1316:
1.188     mycroft  1317:                if ((error = cd_set_pa_immed(cd, 0)) != 0)
1.103     enami    1318:                        return (error);
                   1319:                return (cd_play(cd, args->blk, args->len));
1.23      mycroft  1320:        }
                   1321:        case CDIOCREADSUBCHANNEL: {
1.225     reinoud  1322:                /* READ_SUBCHANNEL command */
1.103     enami    1323:                struct ioc_read_subchannel *args =
                   1324:                    (struct ioc_read_subchannel *)addr;
1.23      mycroft  1325:                struct cd_sub_channel_info data;
1.218     reinoud  1326:                u_int len = args->data_len;
1.103     enami    1327:
1.23      mycroft  1328:                if (len > sizeof(data) ||
                   1329:                    len < sizeof(struct cd_sub_channel_header))
1.103     enami    1330:                        return (EINVAL);
1.82      christos 1331:                error = cd_read_subchannel(cd, args->address_format,
1.141     enami    1332:                    args->data_format, args->track, &data, len,
                   1333:                    XS_CTL_DATA_ONSTACK);
1.82      christos 1334:                if (error)
1.103     enami    1335:                        return (error);
1.84      mycroft  1336:                len = min(len, _2btol(data.header.data_len) +
                   1337:                    sizeof(struct cd_sub_channel_header));
1.103     enami    1338:                return (copyout(&data, args->data, len));
1.23      mycroft  1339:        }
                   1340:        case CDIOREADTOCHEADER: {
1.225     reinoud  1341:                /* READ TOC format 0 command, static header */
1.23      mycroft  1342:                struct ioc_toc_header th;
1.103     enami    1343:
1.213     reinoud  1344:                if ((error = cd_read_toc_f0(cd, 0, 0, &th, sizeof(th),
1.141     enami    1345:                    XS_CTL_DATA_ONSTACK, 0)) != 0)
1.103     enami    1346:                        return (error);
1.157     tsutsui  1347:                if (cd->sc_periph->periph_quirks & PQUIRK_LITTLETOC)
                   1348:                        th.len = le16toh(th.len);
                   1349:                else
                   1350:                        th.len = be16toh(th.len);
1.153     thorpej  1351:                memcpy(addr, &th, sizeof(th));
1.103     enami    1352:                return (0);
1.23      mycroft  1353:        }
                   1354:        case CDIOREADTOCENTRYS: {
1.225     reinoud  1355:                /* READ TOC format 0 command, entries */
1.101     bouyer   1356:                struct cd_toc toc;
1.23      mycroft  1357:                struct ioc_read_toc_entry *te =
1.103     enami    1358:                    (struct ioc_read_toc_entry *)addr;
1.23      mycroft  1359:                struct ioc_toc_header *th;
1.103     enami    1360:                struct cd_toc_entry *cte;
1.218     reinoud  1361:                u_int len = te->data_len;
1.101     bouyer   1362:                int ntracks;
1.23      mycroft  1363:
1.101     bouyer   1364:                th = &toc.header;
                   1365:
                   1366:                if (len > sizeof(toc.entries) ||
1.23      mycroft  1367:                    len < sizeof(struct cd_toc_entry))
1.103     enami    1368:                        return (EINVAL);
1.213     reinoud  1369:                error = cd_read_toc_f0(cd, te->address_format, te->starting_track,
1.141     enami    1370:                    &toc, len + sizeof(struct ioc_toc_header),
                   1371:                    XS_CTL_DATA_ONSTACK, 0);
1.82      christos 1372:                if (error)
1.103     enami    1373:                        return (error);
1.101     bouyer   1374:                if (te->address_format == CD_LBA_FORMAT)
1.103     enami    1375:                        for (ntracks =
                   1376:                            th->ending_track - th->starting_track + 1;
                   1377:                            ntracks >= 0; ntracks--) {
                   1378:                                cte = &toc.entries[ntracks];
                   1379:                                cte->addr_type = CD_LBA_FORMAT;
1.157     tsutsui  1380:                                if (periph->periph_quirks & PQUIRK_LITTLETOC)
                   1381:                                        cte->addr.lba = le32toh(cte->addr.lba);
                   1382:                                else
                   1383:                                        cte->addr.lba = be32toh(cte->addr.lba);
1.101     bouyer   1384:                        }
1.157     tsutsui  1385:                if (periph->periph_quirks & PQUIRK_LITTLETOC)
                   1386:                        th->len = le16toh(th->len);
                   1387:                else
                   1388:                        th->len = be16toh(th->len);
1.101     bouyer   1389:                len = min(len, th->len - (sizeof(th->starting_track) +
1.103     enami    1390:                    sizeof(th->ending_track)));
                   1391:                return (copyout(toc.entries, te->data, len));
1.23      mycroft  1392:        }
1.118     is       1393:        case CDIOREADMSADDR: {
1.225     reinoud  1394:                /* READ TOC format 0 command, length of first track only */
1.118     is       1395:                int sessno = *(int*)addr;
                   1396:
                   1397:                if (sessno != 0)
                   1398:                        return (EINVAL);
                   1399:
1.163     drochner 1400:                return (cdreadmsaddr(cd, (int*)addr));
1.118     is       1401:        }
1.23      mycroft  1402:        case CDIOCSETPATCH: {
1.36      mycroft  1403:                struct ioc_patch *arg = (struct ioc_patch *)addr;
1.101     bouyer   1404:
1.188     mycroft  1405:                return (cd_setchan(cd, arg->patch[0], arg->patch[1],
                   1406:                    arg->patch[2], arg->patch[3], 0));
1.23      mycroft  1407:        }
                   1408:        case CDIOCGETVOL: {
1.225     reinoud  1409:                /* MODE SENSE command (AUDIO page) */
1.36      mycroft  1410:                struct ioc_vol *arg = (struct ioc_vol *)addr;
1.101     bouyer   1411:
1.188     mycroft  1412:                return (cd_getvol(cd, arg, 0));
1.23      mycroft  1413:        }
                   1414:        case CDIOCSETVOL: {
1.225     reinoud  1415:                /* MODE SENSE/MODE SELECT commands (AUDIO page) */
1.36      mycroft  1416:                struct ioc_vol *arg = (struct ioc_vol *)addr;
1.101     bouyer   1417:
1.188     mycroft  1418:                return (cd_setvol(cd, arg, 0));
1.23      mycroft  1419:        }
1.101     bouyer   1420:        case CDIOCSETMONO:
1.225     reinoud  1421:                /* MODE SENSE/MODE SELECT commands (AUDIO page) */
1.188     mycroft  1422:                return (cd_setchan(cd, BOTH_CHANNEL, BOTH_CHANNEL,
                   1423:                    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1.101     bouyer   1424:
                   1425:        case CDIOCSETSTEREO:
1.225     reinoud  1426:                /* MODE SENSE/MODE SELECT commands (AUDIO page) */
1.188     mycroft  1427:                return (cd_setchan(cd, LEFT_CHANNEL, RIGHT_CHANNEL,
                   1428:                    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1.101     bouyer   1429:
                   1430:        case CDIOCSETMUTE:
1.225     reinoud  1431:                /* MODE SENSE/MODE SELECT commands (AUDIO page) */
1.188     mycroft  1432:                return (cd_setchan(cd, MUTE_CHANNEL, MUTE_CHANNEL,
                   1433:                    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1.101     bouyer   1434:
                   1435:        case CDIOCSETLEFT:
1.225     reinoud  1436:                /* MODE SENSE/MODE SELECT commands (AUDIO page) */
1.188     mycroft  1437:                return (cd_setchan(cd, LEFT_CHANNEL, LEFT_CHANNEL,
                   1438:                    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1.101     bouyer   1439:
                   1440:        case CDIOCSETRIGHT:
1.225     reinoud  1441:                /* MODE SENSE/MODE SELECT commands (AUDIO page) */
1.188     mycroft  1442:                return (cd_setchan(cd, RIGHT_CHANNEL, RIGHT_CHANNEL,
                   1443:                    MUTE_CHANNEL, MUTE_CHANNEL, 0));
1.101     bouyer   1444:
1.1       cgd      1445:        case CDIOCRESUME:
1.225     reinoud  1446:                /* PAUSE command */
1.103     enami    1447:                return (cd_pause(cd, PA_RESUME));
1.1       cgd      1448:        case CDIOCPAUSE:
1.225     reinoud  1449:                /* PAUSE command */
1.103     enami    1450:                return (cd_pause(cd, PA_PAUSE));
1.1       cgd      1451:        case CDIOCSTART:
1.145     bouyer   1452:                return (scsipi_start(periph, SSS_START, 0));
1.1       cgd      1453:        case CDIOCSTOP:
1.145     bouyer   1454:                return (scsipi_start(periph, SSS_STOP, 0));
1.112     mycroft  1455:        case CDIOCCLOSE:
1.220     perry    1456:                return (scsipi_start(periph, SSS_START|SSS_LOEJ,
1.130     thorpej  1457:                    XS_CTL_IGNORE_NOT_READY | XS_CTL_IGNORE_MEDIA_CHANGE));
1.121     bouyer   1458:        case DIOCEJECT:
                   1459:                if (*(int *)addr == 0) {
                   1460:                        /*
                   1461:                         * Don't force eject: check that we are the only
                   1462:                         * partition open. If so, unlock it.
                   1463:                         */
                   1464:                        if ((cd->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
                   1465:                            cd->sc_dk.dk_bopenmask + cd->sc_dk.dk_copenmask ==
                   1466:                            cd->sc_dk.dk_openmask) {
1.219     thorpej  1467:                                error = scsipi_prevent(periph, SPAMR_ALLOW,
1.130     thorpej  1468:                                    XS_CTL_IGNORE_NOT_READY);
1.121     bouyer   1469:                                if (error)
                   1470:                                        return (error);
                   1471:                        } else {
1.220     perry    1472:                                return (EBUSY);
1.121     bouyer   1473:                        }
                   1474:                }
                   1475:                /* FALLTHROUGH */
1.81      thorpej  1476:        case CDIOCEJECT: /* FALLTHROUGH */
1.121     bouyer   1477:        case ODIOCEJECT:
1.145     bouyer   1478:                return (scsipi_start(periph, SSS_STOP|SSS_LOEJ, 0));
1.226     reinoud  1479:        case DIOCCACHESYNC:
                   1480:                /* SYNCHRONISE CACHES command */
                   1481:                return (cdcachesync(periph, 0));
1.23      mycroft  1482:        case CDIOCALLOW:
1.219     thorpej  1483:                return (scsipi_prevent(periph, SPAMR_ALLOW, 0));
1.23      mycroft  1484:        case CDIOCPREVENT:
1.219     thorpej  1485:                return (scsipi_prevent(periph, SPAMR_PREVENT_DT, 0));
1.81      thorpej  1486:        case DIOCLOCK:
1.145     bouyer   1487:                return (scsipi_prevent(periph,
1.219     thorpej  1488:                    (*(int *)addr) ? SPAMR_PREVENT_DT : SPAMR_ALLOW, 0));
1.1       cgd      1489:        case CDIOCSETDEBUG:
1.145     bouyer   1490:                cd->sc_periph->periph_dbflags |= (SCSIPI_DB1 | SCSIPI_DB2);
1.103     enami    1491:                return (0);
1.1       cgd      1492:        case CDIOCCLRDEBUG:
1.145     bouyer   1493:                cd->sc_periph->periph_dbflags &= ~(SCSIPI_DB1 | SCSIPI_DB2);
1.103     enami    1494:                return (0);
1.1       cgd      1495:        case CDIOCRESET:
1.119     bouyer   1496:        case SCIOCRESET:
1.103     enami    1497:                return (cd_reset(cd));
1.188     mycroft  1498:        case CDIOCLOADUNLOAD:
1.225     reinoud  1499:                /* LOAD_UNLOAD command */
1.188     mycroft  1500:                return (cd_load_unload(cd, (struct ioc_load_unload *)addr));
1.132     mycroft  1501:        case DVD_AUTH:
1.225     reinoud  1502:                /* GPCMD_REPORT_KEY or GPCMD_SEND_KEY command */
1.132     mycroft  1503:                return (dvd_auth(cd, (dvd_authinfo *)addr));
                   1504:        case DVD_READ_STRUCT:
1.225     reinoud  1505:                /* GPCMD_READ_DVD_STRUCTURE command */
1.132     mycroft  1506:                return (dvd_read_struct(cd, (dvd_struct *)addr));
1.1       cgd      1507:        default:
1.121     bouyer   1508:                if (part != RAW_PART)
1.103     enami    1509:                        return (ENOTTY);
1.185     fvdl     1510:                return (scsipi_do_ioctl(periph, dev, cmd, addr, flag, p));
1.1       cgd      1511:        }
1.41      mycroft  1512:
1.23      mycroft  1513: #ifdef DIAGNOSTIC
                   1514:        panic("cdioctl: impossible");
                   1515: #endif
1.1       cgd      1516: }
                   1517:
1.202     thorpej  1518: static void
                   1519: cdgetdefaultlabel(struct cd_softc *cd, struct disklabel *lp)
1.1       cgd      1520: {
1.163     drochner 1521:        int lastsession;
1.41      mycroft  1522:
1.152     thorpej  1523:        memset(lp, 0, sizeof(struct disklabel));
1.23      mycroft  1524:
1.72      mycroft  1525:        lp->d_secsize = cd->params.blksize;
                   1526:        lp->d_ntracks = 1;
                   1527:        lp->d_nsectors = 100;
                   1528:        lp->d_ncylinders = (cd->params.disksize / 100) + 1;
                   1529:        lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
                   1530:
1.145     bouyer   1531:        switch (scsipi_periph_bustype(cd->sc_periph)) {
                   1532:        case SCSIPI_BUSTYPE_SCSI:
1.114     drochner 1533:                lp->d_type = DTYPE_SCSI;
                   1534:                break;
1.145     bouyer   1535:        case SCSIPI_BUSTYPE_ATAPI:
1.114     drochner 1536:                lp->d_type = DTYPE_ATAPI;
                   1537:                break;
                   1538:        }
1.190     mycroft  1539:        /*
                   1540:         * XXX
                   1541:         * We could probe the mode pages to figure out what kind of disc it is.
                   1542:         * Is this worthwhile?
                   1543:         */
1.197     mycroft  1544:        strncpy(lp->d_typename, "mydisc", 16);
1.72      mycroft  1545:        strncpy(lp->d_packname, "fictitious", 16);
                   1546:        lp->d_secperunit = cd->params.disksize;
                   1547:        lp->d_rpm = 300;
                   1548:        lp->d_interleave = 1;
                   1549:        lp->d_flags = D_REMOVABLE;
                   1550:
1.163     drochner 1551:        if (cdreadmsaddr(cd, &lastsession) != 0)
                   1552:                lastsession = 0;
                   1553:
1.72      mycroft  1554:        lp->d_partitions[0].p_offset = 0;
1.163     drochner 1555: #ifdef notyet /* have to fix bounds_check_with_label() first */
                   1556:        lp->d_partitions[0].p_size = lp->d_secperunit;
                   1557: #else
1.72      mycroft  1558:        lp->d_partitions[0].p_size =
                   1559:            lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
1.163     drochner 1560: #endif
                   1561:        lp->d_partitions[0].p_cdsession = lastsession;
1.72      mycroft  1562:        lp->d_partitions[0].p_fstype = FS_ISO9660;
                   1563:        lp->d_partitions[RAW_PART].p_offset = 0;
1.163     drochner 1564: #ifdef notyet
                   1565:        lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
                   1566: #else
1.72      mycroft  1567:        lp->d_partitions[RAW_PART].p_size =
                   1568:            lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
1.163     drochner 1569: #endif
1.72      mycroft  1570:        lp->d_partitions[RAW_PART].p_fstype = FS_ISO9660;
                   1571:        lp->d_npartitions = RAW_PART + 1;
                   1572:
                   1573:        lp->d_magic = DISKMAGIC;
                   1574:        lp->d_magic2 = DISKMAGIC;
                   1575:        lp->d_checksum = dkcksum(lp);
1.104     thorpej  1576: }
                   1577:
                   1578: /*
                   1579:  * Load the label information on the named device
                   1580:  * Actually fabricate a disklabel
                   1581:  *
                   1582:  * EVENTUALLY take information about different
                   1583:  * data tracks from the TOC and put it in the disklabel
                   1584:  */
1.202     thorpej  1585: static void
                   1586: cdgetdisklabel(struct cd_softc *cd)
1.104     thorpej  1587: {
                   1588:        struct disklabel *lp = cd->sc_dk.dk_label;
1.182     dsl      1589:        const char *errstring;
1.154     eeh      1590:
                   1591:        memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
                   1592:
                   1593:        cdgetdefaultlabel(cd, lp);
                   1594:
                   1595:        /*
                   1596:         * Call the generic disklabel extraction routine
                   1597:         */
                   1598:        errstring = readdisklabel(MAKECDDEV(0, cd->sc_dev.dv_unit, RAW_PART),
                   1599:            cdstrategy, lp, cd->sc_dk.dk_cpulabel);
                   1600:        if (errstring) {
                   1601:                printf("%s: %s\n", cd->sc_dev.dv_xname, errstring);
                   1602:                goto error;
                   1603:        }
                   1604:        return;
1.104     thorpej  1605:
1.154     eeh      1606: error:
                   1607:        /* Reset to default label -- should print a warning */
1.152     thorpej  1608:        memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
1.104     thorpej  1609:
                   1610:        cdgetdefaultlabel(cd, lp);
1.23      mycroft  1611: }
1.1       cgd      1612:
1.227   ! reinoud  1613: static int
        !          1614: read_cd_capacity(struct scsipi_periph *periph, int *blksize, u_long *size)
        !          1615: {
        !          1616:        struct scsipi_read_cd_capacity cmd;
        !          1617:        struct scsipi_read_cd_cap_data data;
        !          1618:        int error, flags;
        !          1619:
        !          1620:        /* if the device doesn't grog capacity, return the dummies */
        !          1621:        if (periph->periph_quirks & PQUIRK_NOCAPACITY)
        !          1622:                return 0;
        !          1623:
        !          1624:        /* issue the request */
        !          1625:        flags = XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK;
        !          1626:        memset(&cmd, 0, sizeof(cmd));
        !          1627:        cmd.opcode = READ_CD_CAPACITY;
        !          1628:
        !          1629:        error = scsipi_command(periph,
        !          1630:            (void *) &cmd,  sizeof(cmd),
        !          1631:            (void *) &data, sizeof(data),
        !          1632:            CDRETRIES, 30000, NULL, flags);
        !          1633:        if (error)
        !          1634:                return error;
        !          1635:
        !          1636:        /* retrieve values and sanity check them */
        !          1637:        *blksize = _4btol(data.length);
        !          1638:
        !          1639:        /* blksize is 2048 for CD, but some drives give gibberish */
        !          1640:        if ((*blksize < 512) || ((*blksize & 511) != 0))
        !          1641:                *blksize = 2048;        /* some drives lie ! */
        !          1642:
        !          1643:        *size = _4btol(data.addr);
        !          1644:        if (*size < 100)
        !          1645:                *size = 400000;
        !          1646:
        !          1647:        return 0;
        !          1648: }
        !          1649:
1.23      mycroft  1650: /*
                   1651:  * Find out from the device what it's capacity is
                   1652:  */
1.218     reinoud  1653: static u_long
1.202     thorpej  1654: cd_size(struct cd_softc *cd, int flags)
1.23      mycroft  1655: {
1.47      mycroft  1656:        int blksize;
1.218     reinoud  1657:        u_long size;
1.227   ! reinoud  1658:        int error;
1.23      mycroft  1659:
1.227   ! reinoud  1660:        /* set up fake values */
        !          1661:        blksize = 2048;
        !          1662:        size    = 400000;
1.101     bouyer   1663:
1.227   ! reinoud  1664:        /* if this function bounces with an error return fake value */
        !          1665:        error = read_cd_capacity(cd->sc_periph, &blksize, &size);
        !          1666:        if (error)
        !          1667:                return size;
1.1       cgd      1668:
1.188     mycroft  1669:        if (blksize != 2048) {
                   1670:                if (cd_setblksize(cd) == 0)
                   1671:                        blksize = 2048;
                   1672:        }
1.227   ! reinoud  1673:        cd->params.blksize     = blksize;
        !          1674:        cd->params.disksize    = size-1;   /* disklabel is exclusive */
1.218     reinoud  1675:        cd->params.disksize512 = ((u_int64_t)cd->params.disksize * blksize) / DEV_BSIZE;
1.34      mycroft  1676:
1.145     bouyer   1677:        SC_DEBUG(cd->sc_periph, SCSIPI_DB2,
                   1678:            ("cd_size: %d %ld\n", blksize, size));
1.227   ! reinoud  1679:
        !          1680:        return size;
1.23      mycroft  1681: }
                   1682:
                   1683: /*
                   1684:  * Get scsi driver to send a "start playing" command
                   1685:  */
1.202     thorpej  1686: static int
                   1687: cd_play(struct cd_softc *cd, int blkno, int nblks)
1.1       cgd      1688: {
1.209     mycroft  1689:        struct scsipi_play cmd;
1.1       cgd      1690:
1.209     mycroft  1691:        memset(&cmd, 0, sizeof(cmd));
                   1692:        cmd.opcode = PLAY;
                   1693:        _lto4b(blkno, cmd.blk_addr);
                   1694:        _lto2b(nblks, cmd.xfer_len);
                   1695:
                   1696:        return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
                   1697:            CDRETRIES, 30000, NULL, 0));
1.23      mycroft  1698: }
                   1699:
                   1700: /*
                   1701:  * Get scsi driver to send a "start playing" command
                   1702:  */
1.202     thorpej  1703: static int
                   1704: cd_play_tracks(struct cd_softc *cd, int strack, int sindex, int etrack,
                   1705:     int eindex)
1.1       cgd      1706: {
1.101     bouyer   1707:        struct cd_toc toc;
                   1708:        int error;
                   1709:
                   1710:        if (!etrack)
1.103     enami    1711:                return (EIO);
1.101     bouyer   1712:        if (strack > etrack)
1.103     enami    1713:                return (EINVAL);
1.101     bouyer   1714:
1.141     enami    1715:        if ((error = cd_load_toc(cd, &toc, XS_CTL_DATA_ONSTACK)) != 0)
1.103     enami    1716:                return (error);
1.1       cgd      1717:
1.101     bouyer   1718:        if (++etrack > (toc.header.ending_track+1))
                   1719:                etrack = toc.header.ending_track+1;
1.23      mycroft  1720:
1.101     bouyer   1721:        strack -= toc.header.starting_track;
                   1722:        etrack -= toc.header.starting_track;
                   1723:        if (strack < 0)
1.103     enami    1724:                return (EINVAL);
1.1       cgd      1725:
1.103     enami    1726:        return (cd_play_msf(cd, toc.entries[strack].addr.msf.minute,
                   1727:            toc.entries[strack].addr.msf.second,
                   1728:            toc.entries[strack].addr.msf.frame,
                   1729:            toc.entries[etrack].addr.msf.minute,
                   1730:            toc.entries[etrack].addr.msf.second,
                   1731:            toc.entries[etrack].addr.msf.frame));
1.23      mycroft  1732: }
                   1733:
                   1734: /*
                   1735:  * Get scsi driver to send a "play msf" command
                   1736:  */
1.202     thorpej  1737: static int
                   1738: cd_play_msf(struct cd_softc *cd, int startm, int starts, int startf, int endm,
                   1739:     int ends, int endf)
1.17      brezak   1740: {
1.209     mycroft  1741:        struct scsipi_play_msf cmd;
                   1742:
                   1743:        memset(&cmd, 0, sizeof(cmd));
                   1744:        cmd.opcode = PLAY_MSF;
                   1745:        cmd.start_m = startm;
                   1746:        cmd.start_s = starts;
                   1747:        cmd.start_f = startf;
                   1748:        cmd.end_m = endm;
                   1749:        cmd.end_s = ends;
                   1750:        cmd.end_f = endf;
1.17      brezak   1751:
1.209     mycroft  1752:        return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
                   1753:            CDRETRIES, 30000, NULL, 0));
1.23      mycroft  1754: }
                   1755:
                   1756: /*
                   1757:  * Get scsi driver to send a "start up" command
                   1758:  */
1.202     thorpej  1759: static int
                   1760: cd_pause(struct cd_softc *cd, int go)
1.1       cgd      1761: {
1.209     mycroft  1762:        struct scsipi_pause cmd;
                   1763:
                   1764:        memset(&cmd, 0, sizeof(cmd));
                   1765:        cmd.opcode = PAUSE;
                   1766:        cmd.resume = go & 0xff;
1.1       cgd      1767:
1.209     mycroft  1768:        return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
                   1769:            CDRETRIES, 30000, NULL, 0));
1.23      mycroft  1770: }
1.1       cgd      1771:
1.23      mycroft  1772: /*
                   1773:  * Get scsi driver to send a "RESET" command
                   1774:  */
1.202     thorpej  1775: static int
                   1776: cd_reset(struct cd_softc *cd)
1.23      mycroft  1777: {
                   1778:
1.208     mycroft  1779:        return (scsipi_command(cd->sc_periph, 0, 0, 0, 0,
1.130     thorpej  1780:            CDRETRIES, 30000, NULL, XS_CTL_RESET));
1.23      mycroft  1781: }
                   1782:
                   1783: /*
                   1784:  * Read subchannel
                   1785:  */
1.202     thorpej  1786: static int
                   1787: cd_read_subchannel(struct cd_softc *cd, int mode, int format, int track,
                   1788:     struct cd_sub_channel_info *data, int len, int flags)
1.1       cgd      1789: {
1.209     mycroft  1790:        struct scsipi_read_subchannel cmd;
1.1       cgd      1791:
1.209     mycroft  1792:        memset(&cmd, 0, sizeof(cmd));
                   1793:        cmd.opcode = READ_SUBCHANNEL;
1.23      mycroft  1794:        if (mode == CD_MSF_FORMAT)
1.209     mycroft  1795:                cmd.byte2 |= CD_MSF;
                   1796:        cmd.byte3 = SRS_SUBQ;
                   1797:        cmd.subchan_format = format;
                   1798:        cmd.track = track;
                   1799:        _lto2b(len, cmd.data_len);
                   1800:
1.208     mycroft  1801:        return (scsipi_command(cd->sc_periph,
1.209     mycroft  1802:            (void *)&cmd, sizeof(struct scsipi_read_subchannel),
                   1803:            (void *)data, len,
1.145     bouyer   1804:            CDRETRIES, 30000, NULL, flags | XS_CTL_DATA_IN | XS_CTL_SILENT));
1.23      mycroft  1805: }
1.1       cgd      1806:
1.23      mycroft  1807: /*
                   1808:  * Read table of contents
                   1809:  */
1.202     thorpej  1810: static int
1.213     reinoud  1811: cd_read_toc_f0(struct cd_softc *cd, int mode, int start, void *data, int len,
1.202     thorpej  1812:     int flags, int control)
1.1       cgd      1813: {
1.209     mycroft  1814:        struct scsipi_read_toc cmd;
1.1       cgd      1815:        int ntoc;
1.23      mycroft  1816:
1.209     mycroft  1817:        memset(&cmd, 0, sizeof(cmd));
1.103     enami    1818: #if 0
                   1819:        if (len != sizeof(struct ioc_toc_header))
                   1820:                ntoc = ((len) - sizeof(struct ioc_toc_header)) /
                   1821:                    sizeof(struct cd_toc_entry);
                   1822:        else
                   1823: #endif
1.23      mycroft  1824:        ntoc = len;
1.209     mycroft  1825:        cmd.opcode = READ_TOC;
1.23      mycroft  1826:        if (mode == CD_MSF_FORMAT)
1.213     reinoud  1827:                cmd.addr_mode |= CD_MSF;
                   1828:        cmd.resp_format = 0;
1.209     mycroft  1829:        cmd.from_track = start;
                   1830:        _lto2b(ntoc, cmd.data_len);
                   1831:        cmd.control = control;
                   1832:
1.208     mycroft  1833:        return (scsipi_command(cd->sc_periph,
1.209     mycroft  1834:            (void *)&cmd, sizeof(cmd), (void *)data, len, CDRETRIES,
1.145     bouyer   1835:            30000, NULL, flags | XS_CTL_DATA_IN));
1.1       cgd      1836: }
                   1837:
1.202     thorpej  1838: static int
                   1839: cd_load_toc(struct cd_softc *cd, struct cd_toc *toc, int flags)
1.101     bouyer   1840: {
1.102     bouyer   1841:        int ntracks, len, error;
1.101     bouyer   1842:
1.214     reinoud  1843:        if ((error = cd_read_toc_f0(cd, 0, 0, toc, sizeof(toc->header),
1.141     enami    1844:            flags, 0)) != 0)
1.103     enami    1845:                return (error);
1.101     bouyer   1846:
                   1847:        ntracks = toc->header.ending_track - toc->header.starting_track + 1;
1.103     enami    1848:        len = (ntracks + 1) * sizeof(struct cd_toc_entry) +
                   1849:            sizeof(toc->header);
1.214     reinoud  1850:        if ((error = cd_read_toc_f0(cd, CD_MSF_FORMAT, 0, toc, len,
1.141     enami    1851:            flags, 0)) != 0)
1.103     enami    1852:                return (error);
                   1853:        return (0);
1.101     bouyer   1854: }
                   1855:
1.23      mycroft  1856: /*
                   1857:  * Get the scsi driver to send a full inquiry to the device and use the
                   1858:  * results to fill out the disk parameter structure.
                   1859:  */
1.202     thorpej  1860: static int
                   1861: cd_get_parms(struct cd_softc *cd, int flags)
1.1       cgd      1862: {
1.4       deraadt  1863:
1.23      mycroft  1864:        /*
                   1865:         * give a number of sectors so that sec * trks * cyls
1.73      mycroft  1866:         * is <= disk_size
1.23      mycroft  1867:         */
1.41      mycroft  1868:        if (cd_size(cd, flags) == 0)
1.103     enami    1869:                return (ENXIO);
                   1870:        return (0);
1.1       cgd      1871: }
                   1872:
1.202     thorpej  1873: static int
                   1874: cdsize(dev_t dev)
1.1       cgd      1875: {
                   1876:
1.61      mycroft  1877:        /* CD-ROMs are read-only. */
1.103     enami    1878:        return (-1);
1.27      mycroft  1879: }
                   1880:
1.202     thorpej  1881: static int
                   1882: cddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
1.27      mycroft  1883: {
                   1884:
                   1885:        /* Not implemented. */
1.103     enami    1886:        return (ENXIO);
1.132     mycroft  1887: }
                   1888:
                   1889: #define        dvd_copy_key(dst, src)          memcpy((dst), (src), sizeof(dvd_key))
                   1890: #define        dvd_copy_challenge(dst, src)    memcpy((dst), (src), sizeof(dvd_challenge))
                   1891:
1.202     thorpej  1892: static int
                   1893: dvd_auth(struct cd_softc *cd, dvd_authinfo *a)
1.132     mycroft  1894: {
                   1895:        struct scsipi_generic cmd;
1.223     christos 1896:        u_int8_t bf[20];
1.132     mycroft  1897:        int error;
                   1898:
                   1899:        memset(cmd.bytes, 0, 15);
1.223     christos 1900:        memset(bf, 0, sizeof(bf));
1.132     mycroft  1901:
                   1902:        switch (a->type) {
                   1903:        case DVD_LU_SEND_AGID:
                   1904:                cmd.opcode = GPCMD_REPORT_KEY;
                   1905:                cmd.bytes[8] = 8;
                   1906:                cmd.bytes[9] = 0 | (0 << 6);
1.223     christos 1907:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
1.141     enami    1908:                    CDRETRIES, 30000, NULL,
                   1909:                    XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  1910:                if (error)
                   1911:                        return (error);
1.223     christos 1912:                a->lsa.agid = bf[7] >> 6;
1.132     mycroft  1913:                return (0);
                   1914:
                   1915:        case DVD_LU_SEND_CHALLENGE:
                   1916:                cmd.opcode = GPCMD_REPORT_KEY;
                   1917:                cmd.bytes[8] = 16;
                   1918:                cmd.bytes[9] = 1 | (a->lsc.agid << 6);
1.223     christos 1919:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 16,
1.141     enami    1920:                    CDRETRIES, 30000, NULL,
                   1921:                    XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  1922:                if (error)
                   1923:                        return (error);
1.223     christos 1924:                dvd_copy_challenge(a->lsc.chal, &bf[4]);
1.132     mycroft  1925:                return (0);
                   1926:
                   1927:        case DVD_LU_SEND_KEY1:
                   1928:                cmd.opcode = GPCMD_REPORT_KEY;
                   1929:                cmd.bytes[8] = 12;
                   1930:                cmd.bytes[9] = 2 | (a->lsk.agid << 6);
1.223     christos 1931:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 12,
1.141     enami    1932:                    CDRETRIES, 30000, NULL,
                   1933:                    XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  1934:                if (error)
                   1935:                        return (error);
1.223     christos 1936:                dvd_copy_key(a->lsk.key, &bf[4]);
1.132     mycroft  1937:                return (0);
                   1938:
                   1939:        case DVD_LU_SEND_TITLE_KEY:
                   1940:                cmd.opcode = GPCMD_REPORT_KEY;
                   1941:                _lto4b(a->lstk.lba, &cmd.bytes[1]);
                   1942:                cmd.bytes[8] = 12;
                   1943:                cmd.bytes[9] = 4 | (a->lstk.agid << 6);
1.223     christos 1944:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 12,
1.141     enami    1945:                    CDRETRIES, 30000, NULL,
                   1946:                    XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  1947:                if (error)
                   1948:                        return (error);
1.223     christos 1949:                a->lstk.cpm = (bf[4] >> 7) & 1;
                   1950:                a->lstk.cp_sec = (bf[4] >> 6) & 1;
                   1951:                a->lstk.cgms = (bf[4] >> 4) & 3;
                   1952:                dvd_copy_key(a->lstk.title_key, &bf[5]);
1.132     mycroft  1953:                return (0);
                   1954:
                   1955:        case DVD_LU_SEND_ASF:
                   1956:                cmd.opcode = GPCMD_REPORT_KEY;
                   1957:                cmd.bytes[8] = 8;
                   1958:                cmd.bytes[9] = 5 | (a->lsasf.agid << 6);
1.223     christos 1959:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
1.141     enami    1960:                    CDRETRIES, 30000, NULL,
                   1961:                    XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  1962:                if (error)
                   1963:                        return (error);
1.223     christos 1964:                a->lsasf.asf = bf[7] & 1;
1.132     mycroft  1965:                return (0);
                   1966:
                   1967:        case DVD_HOST_SEND_CHALLENGE:
                   1968:                cmd.opcode = GPCMD_SEND_KEY;
                   1969:                cmd.bytes[8] = 16;
                   1970:                cmd.bytes[9] = 1 | (a->hsc.agid << 6);
1.223     christos 1971:                bf[1] = 14;
                   1972:                dvd_copy_challenge(&bf[4], a->hsc.chal);
                   1973:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 16,
1.141     enami    1974:                    CDRETRIES, 30000, NULL,
1.158     bouyer   1975:                    XS_CTL_DATA_OUT|XS_CTL_DATA_ONSTACK);
1.132     mycroft  1976:                if (error)
                   1977:                        return (error);
                   1978:                a->type = DVD_LU_SEND_KEY1;
                   1979:                return (0);
                   1980:
                   1981:        case DVD_HOST_SEND_KEY2:
                   1982:                cmd.opcode = GPCMD_SEND_KEY;
                   1983:                cmd.bytes[8] = 12;
                   1984:                cmd.bytes[9] = 3 | (a->hsk.agid << 6);
1.223     christos 1985:                bf[1] = 10;
                   1986:                dvd_copy_key(&bf[4], a->hsk.key);
                   1987:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 12,
1.141     enami    1988:                    CDRETRIES, 30000, NULL,
1.158     bouyer   1989:                    XS_CTL_DATA_OUT|XS_CTL_DATA_ONSTACK);
1.132     mycroft  1990:                if (error) {
                   1991:                        a->type = DVD_AUTH_FAILURE;
                   1992:                        return (error);
                   1993:                }
                   1994:                a->type = DVD_AUTH_ESTABLISHED;
                   1995:                return (0);
                   1996:
                   1997:        case DVD_INVALIDATE_AGID:
                   1998:                cmd.opcode = GPCMD_REPORT_KEY;
                   1999:                cmd.bytes[9] = 0x3f | (a->lsa.agid << 6);
1.223     christos 2000:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 16,
1.132     mycroft  2001:                    CDRETRIES, 30000, NULL, 0);
1.161     veego    2002:                if (error)
                   2003:                        return (error);
                   2004:                return (0);
                   2005:
                   2006:        case DVD_LU_SEND_RPC_STATE:
                   2007:                cmd.opcode = GPCMD_REPORT_KEY;
                   2008:                cmd.bytes[8] = 8;
                   2009:                cmd.bytes[9] = 8 | (0 << 6);
1.223     christos 2010:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
1.161     veego    2011:                    CDRETRIES, 30000, NULL,
                   2012:                    XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
                   2013:                if (error)
                   2014:                        return (error);
1.223     christos 2015:                a->lrpcs.type = (bf[4] >> 6) & 3;
                   2016:                a->lrpcs.vra = (bf[4] >> 3) & 7;
                   2017:                a->lrpcs.ucca = (bf[4]) & 7;
                   2018:                a->lrpcs.region_mask = bf[5];
                   2019:                a->lrpcs.rpc_scheme = bf[6];
1.161     veego    2020:                return (0);
                   2021:
                   2022:        case DVD_HOST_SEND_RPC_STATE:
                   2023:                cmd.opcode = GPCMD_SEND_KEY;
                   2024:                cmd.bytes[8] = 8;
                   2025:                cmd.bytes[9] = 6 | (0 << 6);
1.223     christos 2026:                bf[1] = 6;
                   2027:                bf[4] = a->hrpcs.pdrc;
                   2028:                error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 8,
1.161     veego    2029:                    CDRETRIES, 30000, NULL,
                   2030:                    XS_CTL_DATA_OUT|XS_CTL_DATA_ONSTACK);
1.132     mycroft  2031:                if (error)
                   2032:                        return (error);
                   2033:                return (0);
                   2034:
                   2035:        default:
                   2036:                return (ENOTTY);
                   2037:        }
                   2038: }
                   2039:
1.202     thorpej  2040: static int
                   2041: dvd_read_physical(struct cd_softc *cd, dvd_struct *s)
1.132     mycroft  2042: {
                   2043:        struct scsipi_generic cmd;
1.223     christos 2044:        u_int8_t bf[4 + 4 * 20], *bufp;
1.132     mycroft  2045:        int error;
                   2046:        struct dvd_layer *layer;
                   2047:        int i;
                   2048:
                   2049:        memset(cmd.bytes, 0, 15);
1.223     christos 2050:        memset(bf, 0, sizeof(bf));
1.132     mycroft  2051:        cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
                   2052:        cmd.bytes[6] = s->type;
1.223     christos 2053:        _lto2b(sizeof(bf), &cmd.bytes[7]);
1.132     mycroft  2054:
                   2055:        cmd.bytes[5] = s->physical.layer_num;
1.223     christos 2056:        error = scsipi_command(cd->sc_periph, &cmd, 12, bf, sizeof(bf),
1.141     enami    2057:            CDRETRIES, 30000, NULL, XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  2058:        if (error)
                   2059:                return (error);
1.223     christos 2060:        for (i = 0, bufp = &bf[4], layer = &s->physical.layer[0]; i < 4;
1.132     mycroft  2061:             i++, bufp += 20, layer++) {
                   2062:                memset(layer, 0, sizeof(*layer));
                   2063:                 layer->book_version = bufp[0] & 0xf;
                   2064:                 layer->book_type = bufp[0] >> 4;
                   2065:                 layer->min_rate = bufp[1] & 0xf;
                   2066:                 layer->disc_size = bufp[1] >> 4;
                   2067:                 layer->layer_type = bufp[2] & 0xf;
                   2068:                 layer->track_path = (bufp[2] >> 4) & 1;
                   2069:                 layer->nlayers = (bufp[2] >> 5) & 3;
                   2070:                 layer->track_density = bufp[3] & 0xf;
                   2071:                 layer->linear_density = bufp[3] >> 4;
1.133     mycroft  2072:                 layer->start_sector = _4btol(&bufp[4]);
                   2073:                 layer->end_sector = _4btol(&bufp[8]);
                   2074:                 layer->end_sector_l0 = _4btol(&bufp[12]);
1.132     mycroft  2075:                 layer->bca = bufp[16] >> 7;
                   2076:        }
                   2077:        return (0);
                   2078: }
                   2079:
1.202     thorpej  2080: static int
                   2081: dvd_read_copyright(struct cd_softc *cd, dvd_struct *s)
1.132     mycroft  2082: {
                   2083:        struct scsipi_generic cmd;
1.223     christos 2084:        u_int8_t bf[8];
1.132     mycroft  2085:        int error;
                   2086:
                   2087:        memset(cmd.bytes, 0, 15);
1.223     christos 2088:        memset(bf, 0, sizeof(bf));
1.132     mycroft  2089:        cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
                   2090:        cmd.bytes[6] = s->type;
1.223     christos 2091:        _lto2b(sizeof(bf), &cmd.bytes[7]);
1.132     mycroft  2092:
                   2093:        cmd.bytes[5] = s->copyright.layer_num;
1.223     christos 2094:        error = scsipi_command(cd->sc_periph, &cmd, 12, bf, sizeof(bf),
1.141     enami    2095:            CDRETRIES, 30000, NULL, XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  2096:        if (error)
                   2097:                return (error);
1.223     christos 2098:        s->copyright.cpst = bf[4];
                   2099:        s->copyright.rmi = bf[5];
1.132     mycroft  2100:        return (0);
                   2101: }
                   2102:
1.202     thorpej  2103: static int
                   2104: dvd_read_disckey(struct cd_softc *cd, dvd_struct *s)
1.132     mycroft  2105: {
                   2106:        struct scsipi_generic cmd;
1.223     christos 2107:        u_int8_t *bf;
1.132     mycroft  2108:        int error;
                   2109:
1.223     christos 2110:        bf = malloc(4 + 2048, M_TEMP, M_WAITOK|M_ZERO);
                   2111:        if (bf == NULL)
1.171     fvdl     2112:                return EIO;
1.132     mycroft  2113:        memset(cmd.bytes, 0, 15);
                   2114:        cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
                   2115:        cmd.bytes[6] = s->type;
1.172     jmcneill 2116:        _lto2b(4 + 2048, &cmd.bytes[7]);
1.132     mycroft  2117:
                   2118:        cmd.bytes[9] = s->disckey.agid << 6;
1.223     christos 2119:        error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 4 + 2048,
1.141     enami    2120:            CDRETRIES, 30000, NULL, XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.171     fvdl     2121:        if (error == 0)
1.223     christos 2122:                memcpy(s->disckey.value, &bf[4], 2048);
                   2123:        free(bf, M_TEMP);
1.171     fvdl     2124:        return error;
1.132     mycroft  2125: }
                   2126:
1.202     thorpej  2127: static int
                   2128: dvd_read_bca(struct cd_softc *cd, dvd_struct *s)
1.132     mycroft  2129: {
                   2130:        struct scsipi_generic cmd;
1.223     christos 2131:        u_int8_t bf[4 + 188];
1.132     mycroft  2132:        int error;
                   2133:
                   2134:        memset(cmd.bytes, 0, 15);
1.223     christos 2135:        memset(bf, 0, sizeof(bf));
1.132     mycroft  2136:        cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
                   2137:        cmd.bytes[6] = s->type;
1.223     christos 2138:        _lto2b(sizeof(bf), &cmd.bytes[7]);
1.132     mycroft  2139:
1.223     christos 2140:        error = scsipi_command(cd->sc_periph, &cmd, 12, bf, sizeof(bf),
1.141     enami    2141:            CDRETRIES, 30000, NULL, XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.132     mycroft  2142:        if (error)
                   2143:                return (error);
1.223     christos 2144:        s->bca.len = _2btol(&bf[0]);
1.132     mycroft  2145:        if (s->bca.len < 12 || s->bca.len > 188)
                   2146:                return (EIO);
1.223     christos 2147:        memcpy(s->bca.value, &bf[4], s->bca.len);
1.132     mycroft  2148:        return (0);
                   2149: }
                   2150:
1.202     thorpej  2151: static int
                   2152: dvd_read_manufact(struct cd_softc *cd, dvd_struct *s)
1.132     mycroft  2153: {
                   2154:        struct scsipi_generic cmd;
1.223     christos 2155:        u_int8_t *bf;
1.132     mycroft  2156:        int error;
                   2157:
1.223     christos 2158:        bf = malloc(4 + 2048, M_TEMP, M_WAITOK|M_ZERO);
                   2159:        if (bf == NULL)
1.171     fvdl     2160:                return (EIO);
1.132     mycroft  2161:        memset(cmd.bytes, 0, 15);
                   2162:        cmd.opcode = GPCMD_READ_DVD_STRUCTURE;
                   2163:        cmd.bytes[6] = s->type;
1.173     jmcneill 2164:        _lto2b(4 + 2048, &cmd.bytes[7]);
1.132     mycroft  2165:
1.223     christos 2166:        error = scsipi_command(cd->sc_periph, &cmd, 12, bf, 4 + 2048,
1.141     enami    2167:            CDRETRIES, 30000, NULL, XS_CTL_DATA_IN|XS_CTL_DATA_ONSTACK);
1.171     fvdl     2168:        if (error == 0) {
1.223     christos 2169:                s->manufact.len = _2btol(&bf[0]);
1.171     fvdl     2170:                if (s->manufact.len >= 0 && s->manufact.len <= 2048)
1.223     christos 2171:                        memcpy(s->manufact.value, &bf[4], s->manufact.len);
1.171     fvdl     2172:                else
                   2173:                        error = EIO;
                   2174:        }
1.223     christos 2175:        free(bf, M_TEMP);
1.171     fvdl     2176:        return error;
1.132     mycroft  2177: }
                   2178:
1.202     thorpej  2179: static int
                   2180: dvd_read_struct(struct cd_softc *cd, dvd_struct *s)
1.132     mycroft  2181: {
                   2182:
                   2183:        switch (s->type) {
                   2184:        case DVD_STRUCT_PHYSICAL:
                   2185:                return (dvd_read_physical(cd, s));
                   2186:        case DVD_STRUCT_COPYRIGHT:
                   2187:                return (dvd_read_copyright(cd, s));
                   2188:        case DVD_STRUCT_DISCKEY:
                   2189:                return (dvd_read_disckey(cd, s));
                   2190:        case DVD_STRUCT_BCA:
                   2191:                return (dvd_read_bca(cd, s));
                   2192:        case DVD_STRUCT_MANUFACT:
                   2193:                return (dvd_read_manufact(cd, s));
                   2194:        default:
                   2195:                return (EINVAL);
1.188     mycroft  2196:        }
                   2197: }
                   2198:
                   2199: static int
1.218     reinoud  2200: cd_mode_sense(struct cd_softc *cd, u_int8_t byte2, void *sense, size_t size,
1.202     thorpej  2201:     int page, int flags, int *big)
1.188     mycroft  2202: {
                   2203:
                   2204:        if (cd->sc_periph->periph_quirks & PQUIRK_ONLYBIG) {
                   2205:                *big = 1;
                   2206:                return scsipi_mode_sense_big(cd->sc_periph, byte2, page, sense,
1.219     thorpej  2207:                    size + sizeof(struct scsi_mode_parameter_header_10),
1.191     mycroft  2208:                    flags | XS_CTL_DATA_ONSTACK, CDRETRIES, 20000);
1.188     mycroft  2209:        } else {
                   2210:                *big = 0;
                   2211:                return scsipi_mode_sense(cd->sc_periph, byte2, page, sense,
1.219     thorpej  2212:                    size + sizeof(struct scsi_mode_parameter_header_6),
1.191     mycroft  2213:                    flags | XS_CTL_DATA_ONSTACK, CDRETRIES, 20000);
                   2214:        }
                   2215: }
                   2216:
                   2217: static int
1.218     reinoud  2218: cd_mode_select(struct cd_softc *cd, u_int8_t byte2, void *sense, size_t size,
1.202     thorpej  2219:     int flags, int big)
1.191     mycroft  2220: {
                   2221:
                   2222:        if (big) {
1.219     thorpej  2223:                struct scsi_mode_parameter_header_10 *header = sense;
1.191     mycroft  2224:
                   2225:                _lto2b(0, header->data_length);
                   2226:                return scsipi_mode_select_big(cd->sc_periph, byte2, sense,
1.219     thorpej  2227:                    size + sizeof(struct scsi_mode_parameter_header_10),
1.191     mycroft  2228:                    flags | XS_CTL_DATA_ONSTACK, CDRETRIES, 20000);
                   2229:        } else {
1.219     thorpej  2230:                struct scsi_mode_parameter_header_6 *header = sense;
1.191     mycroft  2231:
                   2232:                header->data_length = 0;
                   2233:                return scsipi_mode_select(cd->sc_periph, byte2, sense,
1.219     thorpej  2234:                    size + sizeof(struct scsi_mode_parameter_header_6),
1.191     mycroft  2235:                    flags | XS_CTL_DATA_ONSTACK, CDRETRIES, 20000);
1.188     mycroft  2236:        }
                   2237: }
                   2238:
1.202     thorpej  2239: static int
                   2240: cd_set_pa_immed(struct cd_softc *cd, int flags)
1.188     mycroft  2241: {
                   2242:        struct {
                   2243:                union {
1.219     thorpej  2244:                        struct scsi_mode_parameter_header_6 small;
                   2245:                        struct scsi_mode_parameter_header_10 big;
1.188     mycroft  2246:                } header;
                   2247:                struct cd_audio_page page;
                   2248:        } data;
                   2249:        int error;
                   2250:        uint8_t oflags;
1.201     pk       2251:        int big, byte2;
1.188     mycroft  2252:        struct cd_audio_page *page;
                   2253:
1.201     pk       2254:        byte2 = SMS_DBD;
                   2255: try_again:
                   2256:        if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
                   2257:            AUDIO_PAGE, flags, &big)) != 0) {
                   2258:                if (byte2 == SMS_DBD) {
                   2259:                        /* Device may not understand DBD; retry without */
                   2260:                        byte2 = 0;
                   2261:                        goto try_again;
                   2262:                }
1.188     mycroft  2263:                return (error);
1.201     pk       2264:        }
1.188     mycroft  2265:
                   2266:        if (big)
1.218     reinoud  2267:                page = (void *)((u_long)&data.header.big +
1.201     pk       2268:                                sizeof data.header.big +
                   2269:                                _2btol(data.header.big.blk_desc_len));
1.188     mycroft  2270:        else
1.218     reinoud  2271:                page = (void *)((u_long)&data.header.small +
1.201     pk       2272:                                sizeof data.header.small +
                   2273:                                data.header.small.blk_desc_len);
1.188     mycroft  2274:
                   2275:        oflags = page->flags;
                   2276:        page->flags &= ~CD_PA_SOTC;
                   2277:        page->flags |= CD_PA_IMMED;
1.189     mycroft  2278:        if (oflags == page->flags)
1.188     mycroft  2279:                return (0);
                   2280:
1.191     mycroft  2281:        return (cd_mode_select(cd, SMS_PF, &data,
1.219     thorpej  2282:            sizeof(struct scsi_mode_page_header) + page->pg_length,
1.191     mycroft  2283:            flags, big));
1.188     mycroft  2284: }
                   2285:
1.202     thorpej  2286: static int
                   2287: cd_setchan(struct cd_softc *cd, int p0, int p1, int p2, int p3, int flags)
1.188     mycroft  2288: {
                   2289:        struct {
                   2290:                union {
1.219     thorpej  2291:                        struct scsi_mode_parameter_header_6 small;
                   2292:                        struct scsi_mode_parameter_header_10 big;
1.188     mycroft  2293:                } header;
                   2294:                struct cd_audio_page page;
                   2295:        } data;
                   2296:        int error;
1.201     pk       2297:        int big, byte2;
1.188     mycroft  2298:        struct cd_audio_page *page;
                   2299:
1.201     pk       2300:        byte2 = SMS_DBD;
                   2301: try_again:
                   2302:        if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
                   2303:            AUDIO_PAGE, flags, &big)) != 0) {
                   2304:                if (byte2 == SMS_DBD) {
                   2305:                        /* Device may not understand DBD; retry without */
                   2306:                        byte2 = 0;
                   2307:                        goto try_again;
                   2308:                }
1.188     mycroft  2309:                return (error);
1.201     pk       2310:        }
1.188     mycroft  2311:
                   2312:        if (big)
1.218     reinoud  2313:                page = (void *)((u_long)&data.header.big +
1.201     pk       2314:                                sizeof data.header.big +
                   2315:                                _2btol(data.header.big.blk_desc_len));
1.188     mycroft  2316:        else
1.218     reinoud  2317:                page = (void *)((u_long)&data.header.small +
1.201     pk       2318:                                sizeof data.header.small +
                   2319:                                data.header.small.blk_desc_len);
1.188     mycroft  2320:
                   2321:        page->port[0].channels = p0;
                   2322:        page->port[1].channels = p1;
                   2323:        page->port[2].channels = p2;
                   2324:        page->port[3].channels = p3;
                   2325:
1.191     mycroft  2326:        return (cd_mode_select(cd, SMS_PF, &data,
1.219     thorpej  2327:            sizeof(struct scsi_mode_page_header) + page->pg_length,
1.191     mycroft  2328:            flags, big));
1.188     mycroft  2329: }
                   2330:
1.202     thorpej  2331: static int
                   2332: cd_getvol(struct cd_softc *cd, struct ioc_vol *arg, int flags)
1.188     mycroft  2333: {
                   2334:        struct {
                   2335:                union {
1.219     thorpej  2336:                        struct scsi_mode_parameter_header_6 small;
                   2337:                        struct scsi_mode_parameter_header_10 big;
1.188     mycroft  2338:                } header;
                   2339:                struct cd_audio_page page;
                   2340:        } data;
                   2341:        int error;
1.201     pk       2342:        int big, byte2;
1.188     mycroft  2343:        struct cd_audio_page *page;
                   2344:
1.201     pk       2345:        byte2 = SMS_DBD;
                   2346: try_again:
                   2347:        if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
                   2348:            AUDIO_PAGE, flags, &big)) != 0) {
                   2349:                if (byte2 == SMS_DBD) {
                   2350:                        /* Device may not understand DBD; retry without */
                   2351:                        byte2 = 0;
                   2352:                        goto try_again;
                   2353:                }
1.188     mycroft  2354:                return (error);
1.201     pk       2355:        }
1.188     mycroft  2356:
                   2357:        if (big)
1.218     reinoud  2358:                page = (void *)((u_long)&data.header.big +
1.201     pk       2359:                                sizeof data.header.big +
                   2360:                                _2btol(data.header.big.blk_desc_len));
1.188     mycroft  2361:        else
1.218     reinoud  2362:                page = (void *)((u_long)&data.header.small +
1.201     pk       2363:                                sizeof data.header.small +
                   2364:                                data.header.small.blk_desc_len);
1.188     mycroft  2365:
                   2366:        arg->vol[0] = page->port[0].volume;
                   2367:        arg->vol[1] = page->port[1].volume;
                   2368:        arg->vol[2] = page->port[2].volume;
                   2369:        arg->vol[3] = page->port[3].volume;
                   2370:
                   2371:        return (0);
                   2372: }
                   2373:
1.202     thorpej  2374: static int
                   2375: cd_setvol(struct cd_softc *cd, const struct ioc_vol *arg, int flags)
1.188     mycroft  2376: {
                   2377:        struct {
                   2378:                union {
1.219     thorpej  2379:                        struct scsi_mode_parameter_header_6 small;
                   2380:                        struct scsi_mode_parameter_header_10 big;
1.188     mycroft  2381:                } header;
                   2382:                struct cd_audio_page page;
                   2383:        } data, mask;
                   2384:        int error;
1.201     pk       2385:        int big, byte2;
1.188     mycroft  2386:        struct cd_audio_page *page, *page2;
                   2387:
1.201     pk       2388:        byte2 = SMS_DBD;
                   2389: try_again:
                   2390:        if ((error = cd_mode_sense(cd, byte2, &data, sizeof(data.page),
                   2391:            AUDIO_PAGE, flags, &big)) != 0) {
                   2392:                if (byte2 == SMS_DBD) {
                   2393:                        /* Device may not understand DBD; retry without */
                   2394:                        byte2 = 0;
                   2395:                        goto try_again;
                   2396:                }
1.188     mycroft  2397:                return (error);
1.201     pk       2398:        }
                   2399:        if ((error = cd_mode_sense(cd, byte2, &mask, sizeof(mask.page),
1.219     thorpej  2400:            AUDIO_PAGE|SMS_PCTRL_CHANGEABLE, flags, &big)) != 0)
1.188     mycroft  2401:                return (error);
                   2402:
                   2403:        if (big) {
1.218     reinoud  2404:                page = (void *)((u_long)&data.header.big +
1.201     pk       2405:                                sizeof data.header.big +
                   2406:                                _2btol(data.header.big.blk_desc_len));
1.218     reinoud  2407:                page2 = (void *)((u_long)&mask.header.big +
1.201     pk       2408:                                sizeof mask.header.big +
                   2409:                                _2btol(mask.header.big.blk_desc_len));
1.188     mycroft  2410:        } else {
1.218     reinoud  2411:                page = (void *)((u_long)&data.header.small +
1.201     pk       2412:                                sizeof data.header.small +
                   2413:                                data.header.small.blk_desc_len);
1.218     reinoud  2414:                page2 = (void *)((u_long)&mask.header.small +
1.201     pk       2415:                                sizeof mask.header.small +
                   2416:                                mask.header.small.blk_desc_len);
1.188     mycroft  2417:        }
                   2418:
                   2419:        page->port[0].volume = arg->vol[0] & page2->port[0].volume;
                   2420:        page->port[1].volume = arg->vol[1] & page2->port[1].volume;
                   2421:        page->port[2].volume = arg->vol[2] & page2->port[2].volume;
                   2422:        page->port[3].volume = arg->vol[3] & page2->port[3].volume;
                   2423:
                   2424:        page->port[0].channels = CHANNEL_0;
                   2425:        page->port[1].channels = CHANNEL_1;
                   2426:
1.191     mycroft  2427:        return (cd_mode_select(cd, SMS_PF, &data,
1.219     thorpej  2428:            sizeof(struct scsi_mode_page_header) + page->pg_length,
1.191     mycroft  2429:            flags, big));
1.188     mycroft  2430: }
                   2431:
1.202     thorpej  2432: static int
                   2433: cd_load_unload(struct cd_softc *cd, struct ioc_load_unload *args)
1.188     mycroft  2434: {
1.209     mycroft  2435:        struct scsipi_load_unload cmd;
1.188     mycroft  2436:
1.209     mycroft  2437:        memset(&cmd, 0, sizeof(cmd));
                   2438:        cmd.opcode = LOAD_UNLOAD;
                   2439:        cmd.options = args->options;    /* ioctl uses MMC values */
                   2440:        cmd.slot = args->slot;
1.188     mycroft  2441:
1.209     mycroft  2442:        return (scsipi_command(cd->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
                   2443:            CDRETRIES, 200000, NULL, 0));
1.188     mycroft  2444: }
                   2445:
1.202     thorpej  2446: static int
                   2447: cd_setblksize(struct cd_softc *cd)
1.188     mycroft  2448: {
                   2449:        struct {
                   2450:                union {
1.219     thorpej  2451:                        struct scsi_mode_parameter_header_6 small;
                   2452:                        struct scsi_mode_parameter_header_10 big;
1.188     mycroft  2453:                } header;
1.219     thorpej  2454:                struct scsi_general_block_descriptor blk_desc;
1.188     mycroft  2455:        } data;
                   2456:        int error;
                   2457:        int big, bsize;
1.219     thorpej  2458:        struct scsi_general_block_descriptor *bdesc;
1.188     mycroft  2459:
1.191     mycroft  2460:        if ((error = cd_mode_sense(cd, 0, &data, sizeof(data.blk_desc), 0, 0,
1.188     mycroft  2461:            &big)) != 0)
                   2462:                return (error);
                   2463:
                   2464:        if (big) {
                   2465:                bdesc = (void *)(&data.header.big + 1);
                   2466:                bsize = _2btol(data.header.big.blk_desc_len);
                   2467:        } else {
                   2468:                bdesc = (void *)(&data.header.small + 1);
                   2469:                bsize = data.header.small.blk_desc_len;
                   2470:        }
                   2471:
                   2472:        if (bsize == 0) {
1.189     mycroft  2473: printf("cd_setblksize: trying to change bsize, but no blk_desc\n");
1.188     mycroft  2474:                return (EINVAL);
                   2475:        }
                   2476:        if (_3btol(bdesc->blklen) == 2048) {
1.189     mycroft  2477: printf("cd_setblksize: trying to change bsize, but blk_desc is correct\n");
1.188     mycroft  2478:                return (EINVAL);
                   2479:        }
1.220     perry    2480:
1.188     mycroft  2481:        _lto3b(2048, bdesc->blklen);
                   2482:
1.193     mycroft  2483:        return (cd_mode_select(cd, SMS_PF, &data, sizeof(data.blk_desc), 0,
                   2484:            big));
1.1       cgd      2485: }
1.227   ! reinoud  2486:

CVSweb <webmaster@jp.NetBSD.org>