The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/scsipi/cd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 16d0eb877af37dccfc791e8e0785dffa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.