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/cam/scsi/scsi_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 /*-
    2  * Copyright (c) 1997 Justin T. Gibbs.
    3  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Kenneth D. Merry.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions, and the following disclaimer,
   11  *    without modification, immediately at the beginning of the file.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*-
   29  * Portions of this driver taken from the original FreeBSD cd driver.
   30  * Written by Julian Elischer (julian@tfs.com)
   31  * for TRW Financial Systems for use under the MACH(2.5) operating system.
   32  *
   33  * TRW Financial Systems, in accordance with their agreement with Carnegie
   34  * Mellon University, makes this software available to CMU to distribute
   35  * or use in any manner that they see fit as long as this message is kept with
   36  * the software. For this reason TFS also grants any other persons or
   37  * organisations permission to use or modify this software.
   38  *
   39  * TFS supplies this software to be publicly redistributed
   40  * on the understanding that TFS is not responsible for the correct
   41  * functioning of this software in any circumstances.
   42  *
   43  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
   44  *
   45  *      from: cd.c,v 1.83 1997/05/04 15:24:22 joerg Exp $
   46  */
   47 
   48 #include <sys/cdefs.h>
   49 __FBSDID("$FreeBSD$");
   50 
   51 #include "opt_cd.h"
   52 
   53 #include <sys/param.h>
   54 #include <sys/systm.h>
   55 #include <sys/kernel.h>
   56 #include <sys/bio.h>
   57 #include <sys/conf.h>
   58 #include <sys/disk.h>
   59 #include <sys/malloc.h>
   60 #include <sys/cdio.h>
   61 #include <sys/cdrio.h>
   62 #include <sys/dvdio.h>
   63 #include <sys/devicestat.h>
   64 #include <sys/sysctl.h>
   65 #include <sys/taskqueue.h>
   66 #include <geom/geom_disk.h>
   67 
   68 #include <cam/cam.h>
   69 #include <cam/cam_ccb.h>
   70 #include <cam/cam_periph.h>
   71 #include <cam/cam_xpt_periph.h>
   72 #include <cam/cam_queue.h>
   73 #include <cam/cam_sim.h>
   74 
   75 #include <cam/scsi/scsi_message.h>
   76 #include <cam/scsi/scsi_da.h>
   77 #include <cam/scsi/scsi_cd.h>
   78 
   79 #define LEADOUT         0xaa            /* leadout toc entry */
   80 
   81 struct cd_params {
   82         u_int32_t blksize;
   83         u_long    disksize;
   84 };
   85 
   86 typedef enum {
   87         CD_Q_NONE               = 0x00,
   88         CD_Q_NO_TOUCH           = 0x01,
   89         CD_Q_BCD_TRACKS         = 0x02,
   90         CD_Q_NO_CHANGER         = 0x04,
   91         CD_Q_CHANGER            = 0x08,
   92         CD_Q_10_BYTE_ONLY       = 0x10
   93 } cd_quirks;
   94 
   95 typedef enum {
   96         CD_FLAG_INVALID         = 0x0001,
   97         CD_FLAG_NEW_DISC        = 0x0002,
   98         CD_FLAG_DISC_LOCKED     = 0x0004,
   99         CD_FLAG_DISC_REMOVABLE  = 0x0008,
  100         CD_FLAG_TAGGED_QUEUING  = 0x0010,
  101         CD_FLAG_CHANGER         = 0x0040,
  102         CD_FLAG_ACTIVE          = 0x0080,
  103         CD_FLAG_SCHED_ON_COMP   = 0x0100,
  104         CD_FLAG_RETRY_UA        = 0x0200,
  105         CD_FLAG_VALID_MEDIA     = 0x0400,
  106         CD_FLAG_VALID_TOC       = 0x0800,
  107         CD_FLAG_SCTX_INIT       = 0x1000,
  108         CD_FLAG_OPEN            = 0x2000
  109 } cd_flags;
  110 
  111 typedef enum {
  112         CD_CCB_PROBE            = 0x01,
  113         CD_CCB_BUFFER_IO        = 0x02,
  114         CD_CCB_WAITING          = 0x03,
  115         CD_CCB_TYPE_MASK        = 0x0F,
  116         CD_CCB_RETRY_UA         = 0x10
  117 } cd_ccb_state;
  118 
  119 typedef enum {
  120         CHANGER_TIMEOUT_SCHED           = 0x01,
  121         CHANGER_SHORT_TMOUT_SCHED       = 0x02,
  122         CHANGER_MANUAL_CALL             = 0x04,
  123         CHANGER_NEED_TIMEOUT            = 0x08
  124 } cd_changer_flags;
  125 
  126 #define ccb_state ppriv_field0
  127 #define ccb_bp ppriv_ptr1
  128 
  129 struct cd_tocdata {
  130         struct ioc_toc_header header;
  131         struct cd_toc_entry entries[100];
  132 };
  133 
  134 struct cd_toc_single {
  135         struct ioc_toc_header header;
  136         struct cd_toc_entry entry;
  137 };
  138 
  139 typedef enum {
  140         CD_STATE_PROBE,
  141         CD_STATE_NORMAL
  142 } cd_state;
  143 
  144 struct cd_softc {
  145         cam_pinfo               pinfo;
  146         cd_state                state;
  147         volatile cd_flags       flags;
  148         struct bio_queue_head   bio_queue;
  149         LIST_HEAD(, ccb_hdr)    pending_ccbs;
  150         struct cd_params        params;
  151         union ccb               saved_ccb;
  152         cd_quirks               quirks;
  153         STAILQ_ENTRY(cd_softc)  changer_links;
  154         struct cdchanger        *changer;
  155         int                     bufs_left;
  156         struct cam_periph       *periph;
  157         int                     minimum_command_size;
  158         int                     outstanding_cmds;
  159         struct task             sysctl_task;
  160         struct sysctl_ctx_list  sysctl_ctx;
  161         struct sysctl_oid       *sysctl_tree;
  162         STAILQ_HEAD(, cd_mode_params)   mode_queue;
  163         struct cd_tocdata       toc;
  164         struct disk             *disk;
  165 };
  166 
  167 struct cd_page_sizes {
  168         int page;
  169         int page_size;
  170 };
  171 
  172 static struct cd_page_sizes cd_page_size_table[] =
  173 {
  174         { AUDIO_PAGE, sizeof(struct cd_audio_page)}
  175 };
  176 
  177 struct cd_quirk_entry {
  178         struct scsi_inquiry_pattern inq_pat;
  179         cd_quirks quirks;
  180 };
  181 
  182 /*
  183  * The changer quirk entries aren't strictly necessary.  Basically, what
  184  * they do is tell cdregister() up front that a device is a changer.
  185  * Otherwise, it will figure that fact out once it sees a LUN on the device
  186  * that is greater than 0.  If it is known up front that a device is a changer,
  187  * all I/O to the device will go through the changer scheduling routines, as
  188  * opposed to the "normal" CD code.
  189  *
  190  * NOTE ON 10_BYTE_ONLY quirks:  Any 10_BYTE_ONLY quirks MUST be because
  191  * your device hangs when it gets a 10 byte command.  Adding a quirk just
  192  * to get rid of the informative diagnostic message is not acceptable.  All
  193  * 10_BYTE_ONLY quirks must be documented in full in a PR (which should be
  194  * referenced in a comment along with the quirk) , and must be approved by
  195  * ken@FreeBSD.org.  Any quirks added that don't adhere to this policy may
  196  * be removed until the submitter can explain why they are needed.
  197  * 10_BYTE_ONLY quirks will be removed (as they will no longer be necessary)
  198  * when the CAM_NEW_TRAN_CODE work is done.
  199  */
  200 static struct cd_quirk_entry cd_quirk_table[] =
  201 {
  202         {
  203                 { T_CDROM, SIP_MEDIA_REMOVABLE, "NRC", "MBR-7", "*"},
  204                  /*quirks*/ CD_Q_CHANGER
  205         },
  206         {
  207                 { T_CDROM, SIP_MEDIA_REMOVABLE, "PIONEER", "CD-ROM DRM*",
  208                   "*"}, /* quirks */ CD_Q_CHANGER
  209         },
  210         {
  211                 { T_CDROM, SIP_MEDIA_REMOVABLE, "NAKAMICH", "MJ-*", "*"},
  212                  /* quirks */ CD_Q_CHANGER
  213         },
  214         {
  215                 { T_CDROM, SIP_MEDIA_REMOVABLE, "CHINON", "CD-ROM CDS-535","*"},
  216                 /* quirks */ CD_Q_BCD_TRACKS
  217         }
  218 };
  219 
  220 static  disk_open_t     cdopen;
  221 static  disk_close_t    cdclose;
  222 static  disk_ioctl_t    cdioctl;
  223 static  disk_strategy_t cdstrategy;
  224 
  225 static  periph_init_t   cdinit;
  226 static  periph_ctor_t   cdregister;
  227 static  periph_dtor_t   cdcleanup;
  228 static  periph_start_t  cdstart;
  229 static  periph_oninv_t  cdoninvalidate;
  230 static  void            cdasync(void *callback_arg, u_int32_t code,
  231                                 struct cam_path *path, void *arg);
  232 static  int             cdcmdsizesysctl(SYSCTL_HANDLER_ARGS);
  233 static  void            cdshorttimeout(void *arg);
  234 static  void            cdschedule(struct cam_periph *periph, int priority);
  235 static  void            cdrunchangerqueue(void *arg);
  236 static  void            cdchangerschedule(struct cd_softc *softc);
  237 static  int             cdrunccb(union ccb *ccb,
  238                                  int (*error_routine)(union ccb *ccb,
  239                                                       u_int32_t cam_flags,
  240                                                       u_int32_t sense_flags),
  241                                  u_int32_t cam_flags, u_int32_t sense_flags);
  242 static  union ccb       *cdgetccb(struct cam_periph *periph,
  243                                   u_int32_t priority);
  244 static  void            cddone(struct cam_periph *periph,
  245                                union ccb *start_ccb);
  246 static  union cd_pages  *cdgetpage(struct cd_mode_params *mode_params);
  247 static  int             cdgetpagesize(int page_num);
  248 static  void            cdprevent(struct cam_periph *periph, int action);
  249 static  int             cdcheckmedia(struct cam_periph *periph);
  250 static  int             cdsize(struct cam_periph *periph, u_int32_t *size);
  251 static  int             cd6byteworkaround(union ccb *ccb);
  252 static  int             cderror(union ccb *ccb, u_int32_t cam_flags,
  253                                 u_int32_t sense_flags);
  254 static  int             cdreadtoc(struct cam_periph *periph, u_int32_t mode, 
  255                                   u_int32_t start, u_int8_t *data, 
  256                                   u_int32_t len, u_int32_t sense_flags);
  257 static  int             cdgetmode(struct cam_periph *periph, 
  258                                   struct cd_mode_params *data, u_int32_t page);
  259 static  int             cdsetmode(struct cam_periph *periph,
  260                                   struct cd_mode_params *data);
  261 static  int             cdplay(struct cam_periph *periph, u_int32_t blk, 
  262                                u_int32_t len);
  263 static  int             cdreadsubchannel(struct cam_periph *periph, 
  264                                          u_int32_t mode, u_int32_t format, 
  265                                          int track, 
  266                                          struct cd_sub_channel_info *data, 
  267                                          u_int32_t len);
  268 static  int             cdplaymsf(struct cam_periph *periph, u_int32_t startm, 
  269                                   u_int32_t starts, u_int32_t startf, 
  270                                   u_int32_t endm, u_int32_t ends, 
  271                                   u_int32_t endf);
  272 static  int             cdplaytracks(struct cam_periph *periph, 
  273                                      u_int32_t strack, u_int32_t sindex,
  274                                      u_int32_t etrack, u_int32_t eindex);
  275 static  int             cdpause(struct cam_periph *periph, u_int32_t go);
  276 static  int             cdstopunit(struct cam_periph *periph, u_int32_t eject);
  277 static  int             cdstartunit(struct cam_periph *periph, int load);
  278 static  int             cdsetspeed(struct cam_periph *periph,
  279                                    u_int32_t rdspeed, u_int32_t wrspeed);
  280 static  int             cdreportkey(struct cam_periph *periph,
  281                                     struct dvd_authinfo *authinfo);
  282 static  int             cdsendkey(struct cam_periph *periph,
  283                                   struct dvd_authinfo *authinfo);
  284 static  int             cdreaddvdstructure(struct cam_periph *periph,
  285                                            struct dvd_struct *dvdstruct);
  286 
  287 static struct periph_driver cddriver =
  288 {
  289         cdinit, "cd",
  290         TAILQ_HEAD_INITIALIZER(cddriver.units), /* generation */ 0
  291 };
  292 
  293 PERIPHDRIVER_DECLARE(cd, cddriver);
  294 
  295 #ifndef CHANGER_MIN_BUSY_SECONDS
  296 #define CHANGER_MIN_BUSY_SECONDS        5
  297 #endif
  298 #ifndef CHANGER_MAX_BUSY_SECONDS
  299 #define CHANGER_MAX_BUSY_SECONDS        15
  300 #endif
  301 
  302 static int changer_min_busy_seconds = CHANGER_MIN_BUSY_SECONDS;
  303 static int changer_max_busy_seconds = CHANGER_MAX_BUSY_SECONDS;
  304 
  305 SYSCTL_NODE(_kern_cam, OID_AUTO, cd, CTLFLAG_RD, 0, "CAM CDROM driver");
  306 SYSCTL_NODE(_kern_cam_cd, OID_AUTO, changer, CTLFLAG_RD, 0, "CD Changer");
  307 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, min_busy_seconds, CTLFLAG_RW,
  308            &changer_min_busy_seconds, 0, "Minimum changer scheduling quantum");
  309 TUNABLE_INT("kern.cam.cd.changer.min_busy_seconds", &changer_min_busy_seconds);
  310 SYSCTL_INT(_kern_cam_cd_changer, OID_AUTO, max_busy_seconds, CTLFLAG_RW,
  311            &changer_max_busy_seconds, 0, "Maximum changer scheduling quantum");
  312 TUNABLE_INT("kern.cam.cd.changer.max_busy_seconds", &changer_max_busy_seconds);
  313 
  314 struct cdchanger {
  315         path_id_t                        path_id;
  316         target_id_t                      target_id;
  317         int                              num_devices;
  318         struct camq                      devq;
  319         struct timeval                   start_time;
  320         struct cd_softc                  *cur_device;
  321         struct callout                   short_handle;
  322         struct callout                   long_handle;
  323         volatile cd_changer_flags        flags;
  324         STAILQ_ENTRY(cdchanger)          changer_links;
  325         STAILQ_HEAD(chdevlist, cd_softc) chluns;
  326 };
  327 
  328 static struct mtx changerq_mtx;
  329 static STAILQ_HEAD(changerlist, cdchanger) changerq;
  330 static int num_changers;
  331 
  332 MALLOC_DEFINE(M_SCSICD, "scsi_cd", "scsi_cd buffers");
  333 
  334 static void
  335 cdinit(void)
  336 {
  337         cam_status status;
  338 
  339         mtx_init(&changerq_mtx, "cdchangerq", "SCSI CD Changer List", MTX_DEF);
  340         STAILQ_INIT(&changerq);
  341 
  342         /*
  343          * Install a global async callback.  This callback will
  344          * receive async callbacks like "new device found".
  345          */
  346         status = xpt_register_async(AC_FOUND_DEVICE, cdasync, NULL, NULL);
  347 
  348         if (status != CAM_REQ_CMP) {
  349                 printf("cd: Failed to attach master async callback "
  350                        "due to status 0x%x!\n", status);
  351         }
  352 }
  353 
  354 static void
  355 cdoninvalidate(struct cam_periph *periph)
  356 {
  357         struct cd_softc *softc;
  358 
  359         softc = (struct cd_softc *)periph->softc;
  360 
  361         /*
  362          * De-register any async callbacks.
  363          */
  364         xpt_register_async(0, cdasync, periph, periph->path);
  365 
  366         softc->flags |= CD_FLAG_INVALID;
  367 
  368         /*
  369          * Return all queued I/O with ENXIO.
  370          * XXX Handle any transactions queued to the card
  371          *     with XPT_ABORT_CCB.
  372          */
  373         bioq_flush(&softc->bio_queue, NULL, ENXIO);
  374 
  375         /*
  376          * If this device is part of a changer, and it was scheduled
  377          * to run, remove it from the run queue since we just nuked
  378          * all of its scheduled I/O.
  379          */
  380         if ((softc->flags & CD_FLAG_CHANGER)
  381          && (softc->pinfo.index != CAM_UNQUEUED_INDEX))
  382                 camq_remove(&softc->changer->devq, softc->pinfo.index);
  383 
  384         disk_gone(softc->disk);
  385         xpt_print(periph->path, "lost device\n");
  386 }
  387 
  388 static void
  389 cdcleanup(struct cam_periph *periph)
  390 {
  391         struct cd_softc *softc;
  392 
  393         softc = (struct cd_softc *)periph->softc;
  394 
  395         xpt_print(periph->path, "removing device entry\n");
  396 
  397         if ((softc->flags & CD_FLAG_SCTX_INIT) != 0
  398             && sysctl_ctx_free(&softc->sysctl_ctx) != 0) {
  399                 xpt_print(periph->path, "can't remove sysctl context\n");
  400         }
  401 
  402         /*
  403          * In the queued, non-active case, the device in question
  404          * has already been removed from the changer run queue.  Since this
  405          * device is active, we need to de-activate it, and schedule
  406          * another device to run.  (if there is another one to run)
  407          */
  408         if ((softc->flags & CD_FLAG_CHANGER)
  409          && (softc->flags & CD_FLAG_ACTIVE)) {
  410 
  411                 /*
  412                  * The purpose of the short timeout is soley to determine
  413                  * whether the current device has finished or not.  Well,
  414                  * since we're removing the active device, we know that it
  415                  * is finished.  So, get rid of the short timeout.
  416                  * Otherwise, if we're in the time period before the short
  417                  * timeout fires, and there are no other devices in the
  418                  * queue to run, there won't be any other device put in the
  419                  * active slot.  i.e., when we call cdrunchangerqueue()
  420                  * below, it won't do anything.  Then, when the short
  421                  * timeout fires, it'll look at the "current device", which
  422                  * we are free below, and possibly panic the kernel on a
  423                  * bogus pointer reference.
  424                  *
  425                  * The long timeout doesn't really matter, since we
  426                  * decrement the qfrozen_cnt to indicate that there is
  427                  * nothing in the active slot now.  Therefore, there won't
  428                  * be any bogus pointer references there.
  429                  */
  430                 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
  431                         callout_stop(&softc->changer->short_handle);
  432                         softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
  433                 }
  434                 softc->changer->devq.qfrozen_cnt--;
  435                 softc->changer->flags |= CHANGER_MANUAL_CALL;
  436                 cdrunchangerqueue(softc->changer);
  437         }
  438 
  439         /*
  440          * If we're removing the last device on the changer, go ahead and
  441          * remove the changer device structure.
  442          */
  443         if ((softc->flags & CD_FLAG_CHANGER)
  444          && (--softc->changer->num_devices == 0)) {
  445 
  446                 /*
  447                  * Theoretically, there shouldn't be any timeouts left, but
  448                  * I'm not completely sure that that will be the case.  So,
  449                  * it won't hurt to check and see if there are any left.
  450                  */
  451                 if (softc->changer->flags & CHANGER_TIMEOUT_SCHED) {
  452                         callout_stop(&softc->changer->long_handle);
  453                         softc->changer->flags &= ~CHANGER_TIMEOUT_SCHED;
  454                 }
  455 
  456                 if (softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
  457                         callout_stop(&softc->changer->short_handle);
  458                         softc->changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
  459                 }
  460 
  461                 mtx_lock(&changerq_mtx);
  462                 STAILQ_REMOVE(&changerq, softc->changer, cdchanger,
  463                               changer_links);
  464                 num_changers--;
  465                 mtx_unlock(&changerq_mtx);
  466                 xpt_print(periph->path, "removing changer entry\n");
  467                 free(softc->changer, M_DEVBUF);
  468         }
  469         cam_periph_unlock(periph);
  470         disk_destroy(softc->disk);
  471         cam_periph_lock(periph);
  472         free(softc, M_DEVBUF);
  473 }
  474 
  475 static void
  476 cdasync(void *callback_arg, u_int32_t code,
  477         struct cam_path *path, void *arg)
  478 {
  479         struct cam_periph *periph;
  480 
  481         periph = (struct cam_periph *)callback_arg;
  482         switch (code) {
  483         case AC_FOUND_DEVICE:
  484         {
  485                 struct ccb_getdev *cgd;
  486                 cam_status status;
  487 
  488                 cgd = (struct ccb_getdev *)arg;
  489                 if (cgd == NULL)
  490                         break;
  491 
  492                 if (SID_TYPE(&cgd->inq_data) != T_CDROM
  493                     && SID_TYPE(&cgd->inq_data) != T_WORM)
  494                         break;
  495 
  496                 /*
  497                  * Allocate a peripheral instance for
  498                  * this device and start the probe
  499                  * process.
  500                  */
  501                 status = cam_periph_alloc(cdregister, cdoninvalidate,
  502                                           cdcleanup, cdstart,
  503                                           "cd", CAM_PERIPH_BIO,
  504                                           cgd->ccb_h.path, cdasync,
  505                                           AC_FOUND_DEVICE, cgd);
  506 
  507                 if (status != CAM_REQ_CMP
  508                  && status != CAM_REQ_INPROG)
  509                         printf("cdasync: Unable to attach new device "
  510                                "due to status 0x%x\n", status);
  511 
  512                 break;
  513         }
  514         case AC_SENT_BDR:
  515         case AC_BUS_RESET:
  516         {
  517                 struct cd_softc *softc;
  518                 struct ccb_hdr *ccbh;
  519 
  520                 softc = (struct cd_softc *)periph->softc;
  521                 /*
  522                  * Don't fail on the expected unit attention
  523                  * that will occur.
  524                  */
  525                 softc->flags |= CD_FLAG_RETRY_UA;
  526                 LIST_FOREACH(ccbh, &softc->pending_ccbs, periph_links.le)
  527                         ccbh->ccb_state |= CD_CCB_RETRY_UA;
  528                 /* FALLTHROUGH */
  529         }
  530         default:
  531                 cam_periph_async(periph, code, path, arg);
  532                 break;
  533         }
  534 }
  535 
  536 static void
  537 cdsysctlinit(void *context, int pending)
  538 {
  539         struct cam_periph *periph;
  540         struct cd_softc *softc;
  541         char tmpstr[80], tmpstr2[80];
  542 
  543         periph = (struct cam_periph *)context;
  544         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  545                 return;
  546 
  547         softc = (struct cd_softc *)periph->softc;
  548         snprintf(tmpstr, sizeof(tmpstr), "CAM CD unit %d", periph->unit_number);
  549         snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number);
  550 
  551         mtx_lock(&Giant);
  552 
  553         sysctl_ctx_init(&softc->sysctl_ctx);
  554         softc->flags |= CD_FLAG_SCTX_INIT;
  555         softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx,
  556                 SYSCTL_STATIC_CHILDREN(_kern_cam_cd), OID_AUTO,
  557                 tmpstr2, CTLFLAG_RD, 0, tmpstr);
  558 
  559         if (softc->sysctl_tree == NULL) {
  560                 printf("cdsysctlinit: unable to allocate sysctl tree\n");
  561                 mtx_unlock(&Giant);
  562                 cam_periph_release(periph);
  563                 return;
  564         }
  565 
  566         /*
  567          * Now register the sysctl handler, so the user can the value on
  568          * the fly.
  569          */
  570         SYSCTL_ADD_PROC(&softc->sysctl_ctx,SYSCTL_CHILDREN(softc->sysctl_tree),
  571                 OID_AUTO, "minimum_cmd_size", CTLTYPE_INT | CTLFLAG_RW,
  572                 &softc->minimum_command_size, 0, cdcmdsizesysctl, "I",
  573                 "Minimum CDB size");
  574 
  575         mtx_unlock(&Giant);
  576         cam_periph_release(periph);
  577 }
  578 
  579 /*
  580  * We have a handler function for this so we can check the values when the
  581  * user sets them, instead of every time we look at them.
  582  */
  583 static int
  584 cdcmdsizesysctl(SYSCTL_HANDLER_ARGS)
  585 {
  586         int error, value;
  587 
  588         value = *(int *)arg1;
  589 
  590         error = sysctl_handle_int(oidp, &value, 0, req);
  591 
  592         if ((error != 0)
  593          || (req->newptr == NULL))
  594                 return (error);
  595 
  596         /*
  597          * The only real values we can have here are 6 or 10.  I don't
  598          * really forsee having 12 be an option at any time in the future.
  599          * So if the user sets something less than or equal to 6, we'll set
  600          * it to 6.  If he sets something greater than 6, we'll set it to 10.
  601          *
  602          * I suppose we could just return an error here for the wrong values,
  603          * but I don't think it's necessary to do so, as long as we can
  604          * determine the user's intent without too much trouble.
  605          */
  606         if (value < 6)
  607                 value = 6;
  608         else if (value > 6)
  609                 value = 10;
  610 
  611         *(int *)arg1 = value;
  612 
  613         return (0);
  614 }
  615 
  616 static cam_status
  617 cdregister(struct cam_periph *periph, void *arg)
  618 {
  619         struct cd_softc *softc;
  620         struct ccb_pathinq cpi;
  621         struct ccb_getdev *cgd;
  622         char tmpstr[80];
  623         caddr_t match;
  624 
  625         cgd = (struct ccb_getdev *)arg;
  626         if (periph == NULL) {
  627                 printf("cdregister: periph was NULL!!\n");
  628                 return(CAM_REQ_CMP_ERR);
  629         }
  630         if (cgd == NULL) {
  631                 printf("cdregister: no getdev CCB, can't register device\n");
  632                 return(CAM_REQ_CMP_ERR);
  633         }
  634 
  635         softc = (struct cd_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
  636 
  637         if (softc == NULL) {
  638                 printf("cdregister: Unable to probe new device. "
  639                        "Unable to allocate softc\n");                           
  640                 return(CAM_REQ_CMP_ERR);
  641         }
  642 
  643         bzero(softc, sizeof(*softc));
  644         LIST_INIT(&softc->pending_ccbs);
  645         STAILQ_INIT(&softc->mode_queue);
  646         softc->state = CD_STATE_PROBE;
  647         bioq_init(&softc->bio_queue);
  648         if (SID_IS_REMOVABLE(&cgd->inq_data))
  649                 softc->flags |= CD_FLAG_DISC_REMOVABLE;
  650         if ((cgd->inq_data.flags & SID_CmdQue) != 0)
  651                 softc->flags |= CD_FLAG_TAGGED_QUEUING;
  652 
  653         periph->softc = softc;
  654         softc->periph = periph;
  655 
  656         /*
  657          * See if this device has any quirks.
  658          */
  659         match = cam_quirkmatch((caddr_t)&cgd->inq_data,
  660                                (caddr_t)cd_quirk_table,
  661                                sizeof(cd_quirk_table)/sizeof(*cd_quirk_table),
  662                                sizeof(*cd_quirk_table), scsi_inquiry_match);
  663 
  664         if (match != NULL)
  665                 softc->quirks = ((struct cd_quirk_entry *)match)->quirks;
  666         else
  667                 softc->quirks = CD_Q_NONE;
  668 
  669         /* Check if the SIM does not want 6 byte commands */
  670         xpt_setup_ccb(&cpi.ccb_h, periph->path, /*priority*/1);
  671         cpi.ccb_h.func_code = XPT_PATH_INQ;
  672         xpt_action((union ccb *)&cpi);
  673         if (cpi.ccb_h.status == CAM_REQ_CMP && (cpi.hba_misc & PIM_NO_6_BYTE))
  674                 softc->quirks |= CD_Q_10_BYTE_ONLY;
  675 
  676         TASK_INIT(&softc->sysctl_task, 0, cdsysctlinit, periph);
  677 
  678         /* The default is 6 byte commands, unless quirked otherwise */
  679         if (softc->quirks & CD_Q_10_BYTE_ONLY)
  680                 softc->minimum_command_size = 10;
  681         else
  682                 softc->minimum_command_size = 6;
  683 
  684         /*
  685          * Load the user's default, if any.
  686          */
  687         snprintf(tmpstr, sizeof(tmpstr), "kern.cam.cd.%d.minimum_cmd_size",
  688                  periph->unit_number);
  689         TUNABLE_INT_FETCH(tmpstr, &softc->minimum_command_size);
  690 
  691         /* 6 and 10 are the only permissible values here. */
  692         if (softc->minimum_command_size < 6)
  693                 softc->minimum_command_size = 6;
  694         else if (softc->minimum_command_size > 6)
  695                 softc->minimum_command_size = 10;
  696 
  697         /*
  698          * We need to register the statistics structure for this device,
  699          * but we don't have the blocksize yet for it.  So, we register
  700          * the structure and indicate that we don't have the blocksize
  701          * yet.  Unlike other SCSI peripheral drivers, we explicitly set
  702          * the device type here to be CDROM, rather than just ORing in
  703          * the device type.  This is because this driver can attach to either
  704          * CDROM or WORM devices, and we want this peripheral driver to
  705          * show up in the devstat list as a CD peripheral driver, not a
  706          * WORM peripheral driver.  WORM drives will also have the WORM
  707          * driver attached to them.
  708          */
  709         cam_periph_unlock(periph);
  710         softc->disk = disk_alloc();
  711         softc->disk->d_devstat = devstat_new_entry("cd", 
  712                           periph->unit_number, 0,
  713                           DEVSTAT_BS_UNAVAILABLE,
  714                           DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_SCSI,
  715                           DEVSTAT_PRIORITY_CD);
  716         softc->disk->d_open = cdopen;
  717         softc->disk->d_close = cdclose;
  718         softc->disk->d_strategy = cdstrategy;
  719         softc->disk->d_ioctl = cdioctl;
  720         softc->disk->d_name = "cd";
  721         softc->disk->d_unit = periph->unit_number;
  722         softc->disk->d_drv1 = periph;
  723         softc->disk->d_flags = 0;
  724         disk_create(softc->disk, DISK_VERSION);
  725         cam_periph_lock(periph);
  726 
  727         /*
  728          * Add an async callback so that we get
  729          * notified if this device goes away.
  730          */
  731         xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
  732                            cdasync, periph, periph->path);
  733 
  734         /*
  735          * If the target lun is greater than 0, we most likely have a CD
  736          * changer device.  Check the quirk entries as well, though, just
  737          * in case someone has a CD tower with one lun per drive or
  738          * something like that.  Also, if we know up front that a
  739          * particular device is a changer, we can mark it as such starting
  740          * with lun 0, instead of lun 1.  It shouldn't be necessary to have
  741          * a quirk entry to define something as a changer, however.
  742          */
  743         if (((cgd->ccb_h.target_lun > 0)
  744           && ((softc->quirks & CD_Q_NO_CHANGER) == 0))
  745          || ((softc->quirks & CD_Q_CHANGER) != 0)) {
  746                 struct cdchanger *nchanger;
  747                 struct cam_periph *nperiph;
  748                 struct cam_path *path;
  749                 cam_status status;
  750                 int found;
  751 
  752                 /* Set the changer flag in the current device's softc */
  753                 softc->flags |= CD_FLAG_CHANGER;
  754 
  755                 /*
  756                  * Now, look around for an existing changer device with the
  757                  * same path and target ID as the current device.
  758                  */
  759                 mtx_lock(&changerq_mtx);
  760                 for (found = 0,
  761                      nchanger = (struct cdchanger *)STAILQ_FIRST(&changerq);
  762                      nchanger != NULL;
  763                      nchanger = STAILQ_NEXT(nchanger, changer_links)){
  764                         if ((nchanger->path_id == cgd->ccb_h.path_id) 
  765                          && (nchanger->target_id == cgd->ccb_h.target_id)) {
  766                                 found = 1;
  767                                 break;
  768                         }
  769                 }
  770                 mtx_unlock(&changerq_mtx);
  771 
  772                 /*
  773                  * If we found a matching entry, just add this device to
  774                  * the list of devices on this changer.
  775                  */
  776                 if (found == 1) {
  777                         struct chdevlist *chlunhead;
  778 
  779                         chlunhead = &nchanger->chluns;
  780 
  781                         /*
  782                          * XXX KDM look at consolidating this code with the
  783                          * code below in a separate function.
  784                          */
  785 
  786                         /*
  787                          * Create a path with lun id 0, and see if we can
  788                          * find a matching device
  789                          */
  790                         status = xpt_create_path(&path, /*periph*/ periph,
  791                                                  cgd->ccb_h.path_id,
  792                                                  cgd->ccb_h.target_id, 0);
  793 
  794                         if ((status == CAM_REQ_CMP)
  795                          && ((nperiph = cam_periph_find(path, "cd")) != NULL)){
  796                                 struct cd_softc *nsoftc;
  797 
  798                                 nsoftc = (struct cd_softc *)nperiph->softc;
  799 
  800                                 if ((nsoftc->flags & CD_FLAG_CHANGER) == 0){
  801                                         nsoftc->flags |= CD_FLAG_CHANGER;
  802                                         nchanger->num_devices++;
  803                                         if (camq_resize(&nchanger->devq,
  804                                            nchanger->num_devices)!=CAM_REQ_CMP){
  805                                                 printf("cdregister: "
  806                                                        "camq_resize "
  807                                                        "failed, changer "
  808                                                        "support may "
  809                                                        "be messed up\n");
  810                                         }
  811                                         nsoftc->changer = nchanger;
  812                                         nsoftc->pinfo.index =CAM_UNQUEUED_INDEX;
  813 
  814                                         STAILQ_INSERT_TAIL(&nchanger->chluns,
  815                                                           nsoftc,changer_links);
  816                                 }
  817                                 xpt_free_path(path);
  818                         } else if (status == CAM_REQ_CMP)
  819                                 xpt_free_path(path);
  820                         else {
  821                                 printf("cdregister: unable to allocate path\n"
  822                                        "cdregister: changer support may be "
  823                                        "broken\n");
  824                         }
  825 
  826                         nchanger->num_devices++;
  827 
  828                         softc->changer = nchanger;
  829                         softc->pinfo.index = CAM_UNQUEUED_INDEX;
  830 
  831                         if (camq_resize(&nchanger->devq,
  832                             nchanger->num_devices) != CAM_REQ_CMP) {
  833                                 printf("cdregister: camq_resize "
  834                                        "failed, changer support may "
  835                                        "be messed up\n");
  836                         }
  837 
  838                         STAILQ_INSERT_TAIL(chlunhead, softc, changer_links);
  839                 }
  840                 /*
  841                  * In this case, we don't already have an entry for this
  842                  * particular changer, so we need to create one, add it to
  843                  * the queue, and queue this device on the list for this
  844                  * changer.  Before we queue this device, however, we need
  845                  * to search for lun id 0 on this target, and add it to the
  846                  * queue first, if it exists.  (and if it hasn't already
  847                  * been marked as part of the changer.)
  848                  */
  849                 else {
  850                         nchanger = malloc(sizeof(struct cdchanger),
  851                                 M_DEVBUF, M_NOWAIT);
  852 
  853                         if (nchanger == NULL) {
  854                                 softc->flags &= ~CD_FLAG_CHANGER;
  855                                 printf("cdregister: unable to malloc "
  856                                        "changer structure\ncdregister: "
  857                                        "changer support disabled\n");
  858 
  859                                 /*
  860                                  * Yes, gotos can be gross but in this case
  861                                  * I think it's justified..
  862                                  */
  863                                 goto cdregisterexit;
  864                         }
  865 
  866                         /* zero the structure */
  867                         bzero(nchanger, sizeof(struct cdchanger));
  868 
  869                         if (camq_init(&nchanger->devq, 1) != 0) {
  870                                 softc->flags &= ~CD_FLAG_CHANGER;
  871                                 printf("cdregister: changer support "
  872                                        "disabled\n");
  873                                 goto cdregisterexit;
  874                         }
  875 
  876                         nchanger->path_id = cgd->ccb_h.path_id;
  877                         nchanger->target_id = cgd->ccb_h.target_id;
  878 
  879                         /* this is superfluous, but it makes things clearer */
  880                         nchanger->num_devices = 0;
  881 
  882                         STAILQ_INIT(&nchanger->chluns);
  883 
  884                         callout_init_mtx(&nchanger->long_handle,
  885                             periph->sim->mtx, 0);
  886                         callout_init_mtx(&nchanger->short_handle,
  887                             periph->sim->mtx, 0);
  888 
  889                         mtx_lock(&changerq_mtx);
  890                         num_changers++;
  891                         STAILQ_INSERT_TAIL(&changerq, nchanger,
  892                                            changer_links);
  893                         mtx_unlock(&changerq_mtx);
  894                         
  895                         /*
  896                          * Create a path with lun id 0, and see if we can
  897                          * find a matching device
  898                          */
  899                         status = xpt_create_path(&path, /*periph*/ periph,
  900                                                  cgd->ccb_h.path_id,
  901                                                  cgd->ccb_h.target_id, 0);
  902 
  903                         /*
  904                          * If we were able to allocate the path, and if we
  905                          * find a matching device and it isn't already
  906                          * marked as part of a changer, then we add it to
  907                          * the current changer.
  908                          */
  909                         if ((status == CAM_REQ_CMP)
  910                          && ((nperiph = cam_periph_find(path, "cd")) != NULL)
  911                          && ((((struct cd_softc *)periph->softc)->flags &
  912                                CD_FLAG_CHANGER) == 0)) {
  913                                 struct cd_softc *nsoftc;
  914 
  915                                 nsoftc = (struct cd_softc *)nperiph->softc;
  916 
  917                                 nsoftc->flags |= CD_FLAG_CHANGER;
  918                                 nchanger->num_devices++;
  919                                 if (camq_resize(&nchanger->devq,
  920                                     nchanger->num_devices) != CAM_REQ_CMP) {
  921                                         printf("cdregister: camq_resize "
  922                                                "failed, changer support may "
  923                                                "be messed up\n");
  924                                 }
  925                                 nsoftc->changer = nchanger;
  926                                 nsoftc->pinfo.index = CAM_UNQUEUED_INDEX;
  927 
  928                                 STAILQ_INSERT_TAIL(&nchanger->chluns,
  929                                                    nsoftc, changer_links);
  930                                 xpt_free_path(path);
  931                         } else if (status == CAM_REQ_CMP)
  932                                 xpt_free_path(path);
  933                         else {
  934                                 printf("cdregister: unable to allocate path\n"
  935                                        "cdregister: changer support may be "
  936                                        "broken\n");
  937                         }
  938 
  939                         softc->changer = nchanger;
  940                         softc->pinfo.index = CAM_UNQUEUED_INDEX;
  941                         nchanger->num_devices++;
  942                         if (camq_resize(&nchanger->devq,
  943                             nchanger->num_devices) != CAM_REQ_CMP) {
  944                                 printf("cdregister: camq_resize "
  945                                        "failed, changer support may "
  946                                        "be messed up\n");
  947                         }
  948                         STAILQ_INSERT_TAIL(&nchanger->chluns, softc,
  949                                            changer_links);
  950                 }
  951         }
  952 
  953 cdregisterexit:
  954 
  955         /*
  956          * Refcount and block open attempts until we are setup
  957          * Can't block
  958          */
  959         (void)cam_periph_hold(periph, PRIBIO);
  960 
  961         if ((softc->flags & CD_FLAG_CHANGER) == 0)
  962                 xpt_schedule(periph, /*priority*/5);
  963         else
  964                 cdschedule(periph, /*priority*/ 5);
  965 
  966         return(CAM_REQ_CMP);
  967 }
  968 
  969 static int
  970 cdopen(struct disk *dp)
  971 {
  972         struct cam_periph *periph;
  973         struct cd_softc *softc;
  974         int error;
  975 
  976         periph = (struct cam_periph *)dp->d_drv1;
  977         if (periph == NULL)
  978                 return (ENXIO);
  979 
  980         softc = (struct cd_softc *)periph->softc;
  981 
  982         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  983                 return(ENXIO);
  984 
  985         cam_periph_lock(periph);
  986 
  987         if (softc->flags & CD_FLAG_INVALID) {
  988                 cam_periph_unlock(periph);
  989                 cam_periph_release(periph);
  990                 return(ENXIO);
  991         }
  992 
  993         if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
  994                 cam_periph_unlock(periph);
  995                 cam_periph_release(periph);
  996                 return (error);
  997         }
  998 
  999         /* Closes aren't symmetrical with opens, so fix up the refcounting. */
 1000         if (softc->flags & CD_FLAG_OPEN)
 1001                 cam_periph_release(periph);
 1002         else
 1003                 softc->flags |= CD_FLAG_OPEN;
 1004 
 1005         /*
 1006          * Check for media, and set the appropriate flags.  We don't bail
 1007          * if we don't have media, but then we don't allow anything but the
 1008          * CDIOCEJECT/CDIOCCLOSE ioctls if there is no media.
 1009          */
 1010         cdcheckmedia(periph);
 1011 
 1012         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdopen\n"));
 1013         cam_periph_unhold(periph);
 1014         cam_periph_unlock(periph);
 1015 
 1016         return (0);
 1017 }
 1018 
 1019 static int
 1020 cdclose(struct disk *dp)
 1021 {
 1022         struct  cam_periph *periph;
 1023         struct  cd_softc *softc;
 1024 
 1025         periph = (struct cam_periph *)dp->d_drv1;
 1026         if (periph == NULL)
 1027                 return (ENXIO); 
 1028 
 1029         softc = (struct cd_softc *)periph->softc;
 1030 
 1031         cam_periph_lock(periph);
 1032         cam_periph_hold(periph, PRIBIO);
 1033 
 1034         if ((softc->flags & CD_FLAG_DISC_REMOVABLE) != 0)
 1035                 cdprevent(periph, PR_ALLOW);
 1036 
 1037         /*
 1038          * Since we're closing this CD, mark the blocksize as unavailable.
 1039          * It will be marked as available when the CD is opened again.
 1040          */
 1041         softc->disk->d_devstat->flags |= DEVSTAT_BS_UNAVAILABLE;
 1042 
 1043         /*
 1044          * We'll check the media and toc again at the next open().
 1045          */
 1046         softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC|CD_FLAG_OPEN);
 1047 
 1048         cam_periph_unhold(periph);
 1049         cam_periph_unlock(periph);
 1050         cam_periph_release(periph);
 1051 
 1052         return (0);
 1053 }
 1054 
 1055 static void
 1056 cdshorttimeout(void *arg)
 1057 {
 1058         struct cdchanger *changer;
 1059 
 1060         changer = (struct cdchanger *)arg;
 1061 
 1062         /* Always clear the short timeout flag, since that's what we're in */
 1063         changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
 1064 
 1065         /*
 1066          * Check to see if there is any more pending or outstanding I/O for
 1067          * this device.  If not, move it out of the active slot.
 1068          */
 1069         if ((bioq_first(&changer->cur_device->bio_queue) == NULL)
 1070          && (changer->cur_device->outstanding_cmds == 0)) {
 1071                 changer->flags |= CHANGER_MANUAL_CALL;
 1072                 cdrunchangerqueue(changer);
 1073         }
 1074 }
 1075 
 1076 /*
 1077  * This is a wrapper for xpt_schedule.  It only applies to changers.
 1078  */
 1079 static void
 1080 cdschedule(struct cam_periph *periph, int priority)
 1081 {
 1082         struct cd_softc *softc;
 1083 
 1084         softc = (struct cd_softc *)periph->softc;
 1085 
 1086         /*
 1087          * If this device isn't currently queued, and if it isn't
 1088          * the active device, then we queue this device and run the
 1089          * changer queue if there is no timeout scheduled to do it.
 1090          * If this device is the active device, just schedule it
 1091          * to run again.  If this device is queued, there should be
 1092          * a timeout in place already that will make sure it runs.
 1093          */
 1094         if ((softc->pinfo.index == CAM_UNQUEUED_INDEX) 
 1095          && ((softc->flags & CD_FLAG_ACTIVE) == 0)) {
 1096                 /*
 1097                  * We don't do anything with the priority here.
 1098                  * This is strictly a fifo queue.
 1099                  */
 1100                 softc->pinfo.priority = 1;
 1101                 softc->pinfo.generation = ++softc->changer->devq.generation;
 1102                 camq_insert(&softc->changer->devq, (cam_pinfo *)softc);
 1103 
 1104                 /*
 1105                  * Since we just put a device in the changer queue,
 1106                  * check and see if there is a timeout scheduled for
 1107                  * this changer.  If so, let the timeout handle
 1108                  * switching this device into the active slot.  If
 1109                  * not, manually call the timeout routine to
 1110                  * bootstrap things.
 1111                  */
 1112                 if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0)
 1113                  && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0)
 1114                  && ((softc->changer->flags & CHANGER_SHORT_TMOUT_SCHED)==0)){
 1115                         softc->changer->flags |= CHANGER_MANUAL_CALL;
 1116                         cdrunchangerqueue(softc->changer);
 1117                 }
 1118         } else if ((softc->flags & CD_FLAG_ACTIVE)
 1119                 && ((softc->flags & CD_FLAG_SCHED_ON_COMP) == 0))
 1120                 xpt_schedule(periph, priority);
 1121 }
 1122 
 1123 static void
 1124 cdrunchangerqueue(void *arg)
 1125 {
 1126         struct cd_softc *softc;
 1127         struct cdchanger *changer;
 1128         int called_from_timeout;
 1129 
 1130         changer = (struct cdchanger *)arg;
 1131 
 1132         /*
 1133          * If we have NOT been called from cdstrategy() or cddone(), and
 1134          * instead from a timeout routine, go ahead and clear the
 1135          * timeout flag.
 1136          */
 1137         if ((changer->flags & CHANGER_MANUAL_CALL) == 0) {
 1138                 changer->flags &= ~CHANGER_TIMEOUT_SCHED;
 1139                 called_from_timeout = 1;
 1140         } else
 1141                 called_from_timeout = 0;
 1142 
 1143         /* Always clear the manual call flag */
 1144         changer->flags &= ~CHANGER_MANUAL_CALL;
 1145 
 1146         /* nothing to do if the queue is empty */
 1147         if (changer->devq.entries <= 0) {
 1148                 return;
 1149         }
 1150 
 1151         /*
 1152          * If the changer queue is frozen, that means we have an active
 1153          * device.
 1154          */
 1155         if (changer->devq.qfrozen_cnt > 0) {
 1156 
 1157                 /*
 1158                  * We always need to reset the frozen count and clear the
 1159                  * active flag.
 1160                  */
 1161                 changer->devq.qfrozen_cnt--;
 1162                 changer->cur_device->flags &= ~CD_FLAG_ACTIVE;
 1163                 changer->cur_device->flags &= ~CD_FLAG_SCHED_ON_COMP;
 1164 
 1165                 if (changer->cur_device->outstanding_cmds > 0) {
 1166                         changer->cur_device->flags |= CD_FLAG_SCHED_ON_COMP;
 1167                         changer->cur_device->bufs_left = 
 1168                                 changer->cur_device->outstanding_cmds;
 1169                         if (called_from_timeout) {
 1170                                 callout_reset(&changer->long_handle,
 1171                                     changer_max_busy_seconds * hz,
 1172                                     cdrunchangerqueue, changer);
 1173                                 changer->flags |= CHANGER_TIMEOUT_SCHED;
 1174                         }
 1175                         return;
 1176                 }
 1177 
 1178                 /*
 1179                  * Check to see whether the current device has any I/O left
 1180                  * to do.  If so, requeue it at the end of the queue.  If
 1181                  * not, there is no need to requeue it.
 1182                  */
 1183                 if (bioq_first(&changer->cur_device->bio_queue) != NULL) {
 1184 
 1185                         changer->cur_device->pinfo.generation =
 1186                                 ++changer->devq.generation;
 1187                         camq_insert(&changer->devq,
 1188                                 (cam_pinfo *)changer->cur_device);
 1189                 } 
 1190         }
 1191 
 1192         softc = (struct cd_softc *)camq_remove(&changer->devq, CAMQ_HEAD);
 1193 
 1194         changer->cur_device = softc;
 1195 
 1196         changer->devq.qfrozen_cnt++;
 1197         softc->flags |= CD_FLAG_ACTIVE;
 1198 
 1199         /* Just in case this device is waiting */
 1200         wakeup(&softc->changer);
 1201         xpt_schedule(softc->periph, /*priority*/ 1);
 1202 
 1203         /*
 1204          * Get rid of any pending timeouts, and set a flag to schedule new
 1205          * ones so this device gets its full time quantum.
 1206          */
 1207         if (changer->flags & CHANGER_TIMEOUT_SCHED) {
 1208                 callout_stop(&changer->long_handle);
 1209                 changer->flags &= ~CHANGER_TIMEOUT_SCHED;
 1210         }
 1211 
 1212         if (changer->flags & CHANGER_SHORT_TMOUT_SCHED) {
 1213                 callout_stop(&changer->short_handle);
 1214                 changer->flags &= ~CHANGER_SHORT_TMOUT_SCHED;
 1215         }
 1216 
 1217         /*
 1218          * We need to schedule timeouts, but we only do this after the
 1219          * first transaction has completed.  This eliminates the changer
 1220          * switch time.
 1221          */
 1222         changer->flags |= CHANGER_NEED_TIMEOUT;
 1223 }
 1224 
 1225 static void
 1226 cdchangerschedule(struct cd_softc *softc)
 1227 {
 1228         struct cdchanger *changer;
 1229 
 1230         changer = softc->changer;
 1231 
 1232         /*
 1233          * If this is a changer, and this is the current device,
 1234          * and this device has at least the minimum time quantum to
 1235          * run, see if we can switch it out.
 1236          */
 1237         if ((softc->flags & CD_FLAG_ACTIVE) 
 1238          && ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0)
 1239          && ((changer->flags & CHANGER_NEED_TIMEOUT) == 0)) {
 1240                 /*
 1241                  * We try three things here.  The first is that we
 1242                  * check to see whether the schedule on completion
 1243                  * flag is set.  If it is, we decrement the number
 1244                  * of buffers left, and if it's zero, we reschedule.
 1245                  * Next, we check to see whether the pending buffer
 1246                  * queue is empty and whether there are no
 1247                  * outstanding transactions.  If so, we reschedule.
 1248                  * Next, we see if the pending buffer queue is empty.
 1249                  * If it is, we set the number of buffers left to
 1250                  * the current active buffer count and set the
 1251                  * schedule on complete flag.
 1252                  */
 1253                 if (softc->flags & CD_FLAG_SCHED_ON_COMP) {
 1254                         if (--softc->bufs_left == 0) {
 1255                                 softc->changer->flags |=
 1256                                         CHANGER_MANUAL_CALL;
 1257                                 softc->flags &= ~CD_FLAG_SCHED_ON_COMP;
 1258                                 cdrunchangerqueue(softc->changer);
 1259                         }
 1260                 } else if ((bioq_first(&softc->bio_queue) == NULL)
 1261                         && (softc->outstanding_cmds == 0)) {
 1262                         softc->changer->flags |= CHANGER_MANUAL_CALL;
 1263                         cdrunchangerqueue(softc->changer);
 1264                 }
 1265         } else if ((softc->changer->flags & CHANGER_NEED_TIMEOUT) 
 1266                 && (softc->flags & CD_FLAG_ACTIVE)) {
 1267 
 1268                 /*
 1269                  * Now that the first transaction to this
 1270                  * particular device has completed, we can go ahead
 1271                  * and schedule our timeouts.
 1272                  */
 1273                 if ((changer->flags & CHANGER_TIMEOUT_SCHED) == 0) {
 1274                         callout_reset(&changer->long_handle,
 1275                             changer_max_busy_seconds * hz,
 1276                             cdrunchangerqueue, changer);
 1277                         changer->flags |= CHANGER_TIMEOUT_SCHED;
 1278                 } else
 1279                         printf("cdchangerschedule: already have a long"
 1280                                " timeout!\n");
 1281 
 1282                 if ((changer->flags & CHANGER_SHORT_TMOUT_SCHED) == 0) {
 1283                         callout_reset(&changer->short_handle,
 1284                             changer_min_busy_seconds * hz,
 1285                             cdshorttimeout, changer);
 1286                         changer->flags |= CHANGER_SHORT_TMOUT_SCHED;
 1287                 } else
 1288                         printf("cdchangerschedule: already have a short "
 1289                                "timeout!\n");
 1290 
 1291                 /*
 1292                  * We just scheduled timeouts, no need to schedule
 1293                  * more.
 1294                  */
 1295                 changer->flags &= ~CHANGER_NEED_TIMEOUT;
 1296 
 1297         }
 1298 }
 1299 
 1300 static int
 1301 cdrunccb(union ccb *ccb, int (*error_routine)(union ccb *ccb,
 1302                                               u_int32_t cam_flags,
 1303                                               u_int32_t sense_flags),
 1304          u_int32_t cam_flags, u_int32_t sense_flags)
 1305 {
 1306         struct cd_softc *softc;
 1307         struct cam_periph *periph;
 1308         int error;
 1309 
 1310         periph = xpt_path_periph(ccb->ccb_h.path);
 1311         softc = (struct cd_softc *)periph->softc;
 1312 
 1313         error = cam_periph_runccb(ccb, error_routine, cam_flags, sense_flags,
 1314                                   softc->disk->d_devstat);
 1315 
 1316         if (softc->flags & CD_FLAG_CHANGER)
 1317                 cdchangerschedule(softc);
 1318 
 1319         return(error);
 1320 }
 1321 
 1322 static union ccb *
 1323 cdgetccb(struct cam_periph *periph, u_int32_t priority)
 1324 {
 1325         struct cd_softc *softc;
 1326 
 1327         softc = (struct cd_softc *)periph->softc;
 1328 
 1329         if (softc->flags & CD_FLAG_CHANGER) {
 1330                 /*
 1331                  * This should work the first time this device is woken up,
 1332                  * but just in case it doesn't, we use a while loop.
 1333                  */
 1334                 while ((softc->flags & CD_FLAG_ACTIVE) == 0) {
 1335                         /*
 1336                          * If this changer isn't already queued, queue it up.
 1337                          */
 1338                         if (softc->pinfo.index == CAM_UNQUEUED_INDEX) {
 1339                                 softc->pinfo.priority = 1;
 1340                                 softc->pinfo.generation =
 1341                                         ++softc->changer->devq.generation;
 1342                                 camq_insert(&softc->changer->devq,
 1343                                             (cam_pinfo *)softc);
 1344                         }
 1345                         if (((softc->changer->flags & CHANGER_TIMEOUT_SCHED)==0)
 1346                          && ((softc->changer->flags & CHANGER_NEED_TIMEOUT)==0)
 1347                          && ((softc->changer->flags
 1348                               & CHANGER_SHORT_TMOUT_SCHED)==0)) {
 1349                                 softc->changer->flags |= CHANGER_MANUAL_CALL;
 1350                                 cdrunchangerqueue(softc->changer);
 1351                         } else
 1352                                 msleep(&softc->changer, periph->sim->mtx,
 1353                                     PRIBIO, "cgticb", 0);
 1354                 }
 1355         }
 1356         return(cam_periph_getccb(periph, priority));
 1357 }
 1358 
 1359 
 1360 /*
 1361  * Actually translate the requested transfer into one the physical driver
 1362  * can understand.  The transfer is described by a buf and will include
 1363  * only one physical transfer.
 1364  */
 1365 static void
 1366 cdstrategy(struct bio *bp)
 1367 {
 1368         struct cam_periph *periph;
 1369         struct cd_softc *softc;
 1370 
 1371         periph = (struct cam_periph *)bp->bio_disk->d_drv1;
 1372         if (periph == NULL) {
 1373                 biofinish(bp, NULL, ENXIO);
 1374                 return;
 1375         }
 1376 
 1377         cam_periph_lock(periph);
 1378         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstrategy\n"));
 1379 
 1380         softc = (struct cd_softc *)periph->softc;
 1381 
 1382         /*
 1383          * If the device has been made invalid, error out
 1384          */
 1385         if ((softc->flags & CD_FLAG_INVALID)) {
 1386                 cam_periph_unlock(periph);
 1387                 biofinish(bp, NULL, ENXIO);
 1388                 return;
 1389         }
 1390 
 1391         /*
 1392          * If we don't have valid media, look for it before trying to
 1393          * schedule the I/O.
 1394          */
 1395         if ((softc->flags & CD_FLAG_VALID_MEDIA) == 0) {
 1396                 int error;
 1397 
 1398                 error = cdcheckmedia(periph);
 1399                 if (error != 0) {
 1400                         cam_periph_unlock(periph);
 1401                         biofinish(bp, NULL, error);
 1402                         return;
 1403                 }
 1404         }
 1405 
 1406         /*
 1407          * Place it in the queue of disk activities for this disk
 1408          */
 1409         bioq_disksort(&softc->bio_queue, bp);
 1410 
 1411         /*
 1412          * Schedule ourselves for performing the work.  We do things
 1413          * differently for changers.
 1414          */
 1415         if ((softc->flags & CD_FLAG_CHANGER) == 0)
 1416                 xpt_schedule(periph, /* XXX priority */1);
 1417         else
 1418                 cdschedule(periph, /* priority */ 1);
 1419 
 1420         cam_periph_unlock(periph);
 1421         return;
 1422 }
 1423 
 1424 static void
 1425 cdstart(struct cam_periph *periph, union ccb *start_ccb)
 1426 {
 1427         struct cd_softc *softc;
 1428         struct bio *bp;
 1429         struct ccb_scsiio *csio;
 1430         struct scsi_read_capacity_data *rcap;
 1431 
 1432         softc = (struct cd_softc *)periph->softc;
 1433 
 1434         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdstart\n"));
 1435 
 1436         switch (softc->state) {
 1437         case CD_STATE_NORMAL:
 1438         {
 1439                 bp = bioq_first(&softc->bio_queue);
 1440                 if (periph->immediate_priority <= periph->pinfo.priority) {
 1441                         start_ccb->ccb_h.ccb_state = CD_CCB_WAITING;
 1442 
 1443                         SLIST_INSERT_HEAD(&periph->ccb_list, &start_ccb->ccb_h,
 1444                                           periph_links.sle);
 1445                         periph->immediate_priority = CAM_PRIORITY_NONE;
 1446                         wakeup(&periph->ccb_list);
 1447                 } else if (bp == NULL) {
 1448                         xpt_release_ccb(start_ccb);
 1449                 } else {
 1450                         bioq_remove(&softc->bio_queue, bp);
 1451 
 1452                         devstat_start_transaction_bio(softc->disk->d_devstat, bp);
 1453 
 1454                         scsi_read_write(&start_ccb->csio,
 1455                                         /*retries*/4,
 1456                                         /* cbfcnp */ cddone,
 1457                                         MSG_SIMPLE_Q_TAG,
 1458                                         /* read */bp->bio_cmd == BIO_READ,
 1459                                         /* byte2 */ 0,
 1460                                         /* minimum_cmd_size */ 10,
 1461                                         /* lba */ bp->bio_offset /
 1462                                           softc->params.blksize,
 1463                                         bp->bio_bcount / softc->params.blksize,
 1464                                         /* data_ptr */ bp->bio_data,
 1465                                         /* dxfer_len */ bp->bio_bcount,
 1466                                         /* sense_len */ SSD_FULL_SIZE,
 1467                                         /* timeout */ 30000);
 1468                         start_ccb->ccb_h.ccb_state = CD_CCB_BUFFER_IO;
 1469 
 1470                         
 1471                         LIST_INSERT_HEAD(&softc->pending_ccbs,
 1472                                          &start_ccb->ccb_h, periph_links.le);
 1473                         softc->outstanding_cmds++;
 1474 
 1475                         /* We expect a unit attention from this device */
 1476                         if ((softc->flags & CD_FLAG_RETRY_UA) != 0) {
 1477                                 start_ccb->ccb_h.ccb_state |= CD_CCB_RETRY_UA;
 1478                                 softc->flags &= ~CD_FLAG_RETRY_UA;
 1479                         }
 1480 
 1481                         start_ccb->ccb_h.ccb_bp = bp;
 1482                         bp = bioq_first(&softc->bio_queue);
 1483 
 1484                         xpt_action(start_ccb);
 1485                 }
 1486                 if (bp != NULL) {
 1487                         /* Have more work to do, so ensure we stay scheduled */
 1488                         xpt_schedule(periph, /* XXX priority */1);
 1489                 }
 1490                 break;
 1491         }
 1492         case CD_STATE_PROBE:
 1493         {
 1494 
 1495                 rcap = (struct scsi_read_capacity_data *)malloc(sizeof(*rcap),
 1496                                                                 M_SCSICD,
 1497                                                                 M_NOWAIT);
 1498                 if (rcap == NULL) {
 1499                         xpt_print(periph->path,
 1500                             "cdstart: Couldn't malloc read_capacity data\n");
 1501                         /* cd_free_periph??? */
 1502                         break;
 1503                 }
 1504                 csio = &start_ccb->csio;
 1505                 scsi_read_capacity(csio,
 1506                                    /*retries*/1,
 1507                                    cddone,
 1508                                    MSG_SIMPLE_Q_TAG,
 1509                                    rcap,
 1510                                    SSD_FULL_SIZE,
 1511                                    /*timeout*/20000);
 1512                 start_ccb->ccb_h.ccb_bp = NULL;
 1513                 start_ccb->ccb_h.ccb_state = CD_CCB_PROBE;
 1514                 xpt_action(start_ccb);
 1515                 break;
 1516         }
 1517         }
 1518 }
 1519 
 1520 static void
 1521 cddone(struct cam_periph *periph, union ccb *done_ccb)
 1522 { 
 1523         struct cd_softc *softc;
 1524         struct ccb_scsiio *csio;
 1525 
 1526         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cddone\n"));
 1527 
 1528         softc = (struct cd_softc *)periph->softc;
 1529         csio = &done_ccb->csio;
 1530 
 1531         switch (csio->ccb_h.ccb_state & CD_CCB_TYPE_MASK) {
 1532         case CD_CCB_BUFFER_IO:
 1533         {
 1534                 struct bio      *bp;
 1535                 int             error;
 1536 
 1537                 bp = (struct bio *)done_ccb->ccb_h.ccb_bp;
 1538                 error = 0;
 1539 
 1540                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
 1541                         int sf;
 1542 
 1543                         if ((done_ccb->ccb_h.ccb_state & CD_CCB_RETRY_UA) != 0)
 1544                                 sf = SF_RETRY_UA;
 1545                         else
 1546                                 sf = 0;
 1547 
 1548                         error = cderror(done_ccb, CAM_RETRY_SELTO, sf);
 1549                         if (error == ERESTART) {
 1550                                 /*
 1551                                  * A retry was scheuled, so
 1552                                  * just return.
 1553                                  */
 1554                                 return;
 1555                         }
 1556                 }
 1557 
 1558                 if (error != 0) {
 1559                         xpt_print(periph->path,
 1560                             "cddone: got error %#x back\n", error);
 1561                         bioq_flush(&softc->bio_queue, NULL, EIO);
 1562                         bp->bio_resid = bp->bio_bcount;
 1563                         bp->bio_error = error;
 1564                         bp->bio_flags |= BIO_ERROR;
 1565                         cam_release_devq(done_ccb->ccb_h.path,
 1566                                          /*relsim_flags*/0,
 1567                                          /*reduction*/0,
 1568                                          /*timeout*/0,
 1569                                          /*getcount_only*/0);
 1570 
 1571                 } else {
 1572                         bp->bio_resid = csio->resid;
 1573                         bp->bio_error = 0;
 1574                         if (bp->bio_resid != 0) {
 1575                                 /*
 1576                                  * Short transfer ??? 
 1577                                  * XXX: not sure this is correct for partial
 1578                                  * transfers at EOM
 1579                                  */
 1580                                 bp->bio_flags |= BIO_ERROR;
 1581                         }
 1582                 }
 1583 
 1584                 LIST_REMOVE(&done_ccb->ccb_h, periph_links.le);
 1585                 softc->outstanding_cmds--;
 1586 
 1587                 if (softc->flags & CD_FLAG_CHANGER)
 1588                         cdchangerschedule(softc);
 1589 
 1590                 biofinish(bp, NULL, 0);
 1591                 break;
 1592         }
 1593         case CD_CCB_PROBE:
 1594         {
 1595                 struct     scsi_read_capacity_data *rdcap;
 1596                 char       announce_buf[120]; /*
 1597                                                * Currently (9/30/97) the 
 1598                                                * longest possible announce 
 1599                                                * buffer is 108 bytes, for the 
 1600                                                * first error case below.  
 1601                                                * That is 39 bytes for the 
 1602                                                * basic string, 16 bytes for the
 1603                                                * biggest sense key (hardware 
 1604                                                * error), 52 bytes for the
 1605                                                * text of the largest sense 
 1606                                                * qualifier valid for a CDROM,
 1607                                                * (0x72, 0x03 or 0x04,
 1608                                                * 0x03), and one byte for the
 1609                                                * null terminating character.
 1610                                                * To allow for longer strings, 
 1611                                                * the announce buffer is 120
 1612                                                * bytes.
 1613                                                */
 1614                 struct     cd_params *cdp;
 1615 
 1616                 cdp = &softc->params;
 1617 
 1618                 rdcap = (struct scsi_read_capacity_data *)csio->data_ptr;
 1619                 
 1620                 cdp->disksize = scsi_4btoul (rdcap->addr) + 1;
 1621                 cdp->blksize = scsi_4btoul (rdcap->length);
 1622 
 1623                 if ((csio->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) {
 1624 
 1625                         snprintf(announce_buf, sizeof(announce_buf),
 1626                                 "cd present [%lu x %lu byte records]",
 1627                                 cdp->disksize, (u_long)cdp->blksize);
 1628 
 1629                 } else {
 1630                         int     error;
 1631                         /*
 1632                          * Retry any UNIT ATTENTION type errors.  They
 1633                          * are expected at boot.
 1634                          */
 1635                         error = cderror(done_ccb, CAM_RETRY_SELTO,
 1636                                         SF_RETRY_UA | SF_NO_PRINT);
 1637                         if (error == ERESTART) {
 1638                                 /*
 1639                                  * A retry was scheuled, so
 1640                                  * just return.
 1641                                  */
 1642                                 return;
 1643                         } else if (error != 0) {
 1644 
 1645                                 struct scsi_sense_data *sense;
 1646                                 int asc, ascq;
 1647                                 int sense_key, error_code;
 1648                                 int have_sense;
 1649                                 cam_status status;
 1650                                 struct ccb_getdev cgd;
 1651 
 1652                                 /* Don't wedge this device's queue */
 1653                                 cam_release_devq(done_ccb->ccb_h.path,
 1654                                                  /*relsim_flags*/0,
 1655                                                  /*reduction*/0,
 1656                                                  /*timeout*/0,
 1657                                                  /*getcount_only*/0);
 1658 
 1659                                 status = done_ccb->ccb_h.status;
 1660 
 1661                                 xpt_setup_ccb(&cgd.ccb_h, 
 1662                                               done_ccb->ccb_h.path,
 1663                                               /* priority */ 1);
 1664                                 cgd.ccb_h.func_code = XPT_GDEV_TYPE;
 1665                                 xpt_action((union ccb *)&cgd);
 1666 
 1667                                 if (((csio->ccb_h.flags & CAM_SENSE_PHYS) != 0)
 1668                                  || ((csio->ccb_h.flags & CAM_SENSE_PTR) != 0)
 1669                                  || ((status & CAM_AUTOSNS_VALID) == 0))
 1670                                         have_sense = FALSE;
 1671                                 else
 1672                                         have_sense = TRUE;
 1673 
 1674                                 if (have_sense) {
 1675                                         sense = &csio->sense_data;
 1676                                         scsi_extract_sense(sense, &error_code,
 1677                                                            &sense_key, 
 1678                                                            &asc, &ascq);
 1679                                 }
 1680                                 /*
 1681                                  * Attach to anything that claims to be a
 1682                                  * CDROM or WORM device, as long as it
 1683                                  * doesn't return a "Logical unit not
 1684                                  * supported" (0x25) error.
 1685                                  */
 1686                                 if ((have_sense) && (asc != 0x25)
 1687                                  && (error_code == SSD_CURRENT_ERROR)) {
 1688                                         const char *sense_key_desc;
 1689                                         const char *asc_desc;
 1690 
 1691                                         scsi_sense_desc(sense_key, asc, ascq,
 1692                                                         &cgd.inq_data,
 1693                                                         &sense_key_desc,
 1694                                                         &asc_desc);
 1695                                         snprintf(announce_buf,
 1696                                             sizeof(announce_buf),
 1697                                                 "Attempt to query device "
 1698                                                 "size failed: %s, %s",
 1699                                                 sense_key_desc,
 1700                                                 asc_desc);
 1701                                 } else if ((have_sense == 0) 
 1702                                       && ((status & CAM_STATUS_MASK) ==
 1703                                            CAM_SCSI_STATUS_ERROR)
 1704                                       && (csio->scsi_status ==
 1705                                           SCSI_STATUS_BUSY)) {
 1706                                         snprintf(announce_buf,
 1707                                             sizeof(announce_buf),
 1708                                             "Attempt to query device "
 1709                                             "size failed: SCSI Status: %s",
 1710                                             scsi_status_string(csio));
 1711                                 } else if (SID_TYPE(&cgd.inq_data) == T_CDROM) {
 1712                                         /*
 1713                                          * We only print out an error for
 1714                                          * CDROM type devices.  For WORM
 1715                                          * devices, we don't print out an
 1716                                          * error since a few WORM devices
 1717                                          * don't support CDROM commands.
 1718                                          * If we have sense information, go
 1719                                          * ahead and print it out.
 1720                                          * Otherwise, just say that we 
 1721                                          * couldn't attach.
 1722                                          */
 1723 
 1724                                         /*
 1725                                          * Just print out the error, not
 1726                                          * the full probe message, when we
 1727                                          * don't attach.
 1728                                          */
 1729                                         if (have_sense)
 1730                                                 scsi_sense_print(
 1731                                                         &done_ccb->csio);
 1732                                         else {
 1733                                                 xpt_print(periph->path,
 1734                                                     "got CAM status %#x\n",
 1735                                                     done_ccb->ccb_h.status);
 1736                                         }
 1737                                         xpt_print(periph->path, "fatal error, "
 1738                                             "failed to attach to device\n");
 1739                                         /*
 1740                                          * Invalidate this peripheral.
 1741                                          */
 1742                                         cam_periph_invalidate(periph);
 1743 
 1744                                         announce_buf[0] = '\0';
 1745                                 } else {
 1746 
 1747                                         /*
 1748                                          * Invalidate this peripheral.
 1749                                          */
 1750                                         cam_periph_invalidate(periph);
 1751                                         announce_buf[0] = '\0';
 1752                                 }
 1753                         }
 1754                 }
 1755                 free(rdcap, M_SCSICD);
 1756                 if (announce_buf[0] != '\0') {
 1757                         xpt_announce_periph(periph, announce_buf);
 1758                         if (softc->flags & CD_FLAG_CHANGER)
 1759                                 cdchangerschedule(softc);
 1760                         /*
 1761                          * Create our sysctl variables, now that we know
 1762                          * we have successfully attached.
 1763                          */
 1764                         taskqueue_enqueue(taskqueue_thread,&softc->sysctl_task);
 1765                 }
 1766                 softc->state = CD_STATE_NORMAL;         
 1767                 /*
 1768                  * Since our peripheral may be invalidated by an error
 1769                  * above or an external event, we must release our CCB
 1770                  * before releasing the probe lock on the peripheral.
 1771                  * The peripheral will only go away once the last lock
 1772                  * is removed, and we need it around for the CCB release
 1773                  * operation.
 1774                  */
 1775                 xpt_release_ccb(done_ccb);
 1776                 cam_periph_unhold(periph);
 1777                 return;
 1778         }
 1779         case CD_CCB_WAITING:
 1780         {
 1781                 /* Caller will release the CCB */
 1782                 CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 
 1783                           ("trying to wakeup ccbwait\n"));
 1784 
 1785                 wakeup(&done_ccb->ccb_h.cbfcnp);
 1786                 return;
 1787         }
 1788         default:
 1789                 break;
 1790         }
 1791         xpt_release_ccb(done_ccb);
 1792 }
 1793 
 1794 static union cd_pages *
 1795 cdgetpage(struct cd_mode_params *mode_params)
 1796 {
 1797         union cd_pages *page;
 1798 
 1799         if (mode_params->cdb_size == 10)
 1800                 page = (union cd_pages *)find_mode_page_10(
 1801                         (struct scsi_mode_header_10 *)mode_params->mode_buf);
 1802         else
 1803                 page = (union cd_pages *)find_mode_page_6(
 1804                         (struct scsi_mode_header_6 *)mode_params->mode_buf);
 1805 
 1806         return (page);
 1807 }
 1808 
 1809 static int
 1810 cdgetpagesize(int page_num)
 1811 {
 1812         int i;
 1813 
 1814         for (i = 0; i < (sizeof(cd_page_size_table)/
 1815              sizeof(cd_page_size_table[0])); i++) {
 1816                 if (cd_page_size_table[i].page == page_num)
 1817                         return (cd_page_size_table[i].page_size);
 1818         }
 1819 
 1820         return (-1);
 1821 }
 1822 
 1823 static int
 1824 cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
 1825 {
 1826 
 1827         struct  cam_periph *periph;
 1828         struct  cd_softc *softc;
 1829         int     nocopyout, error = 0;
 1830 
 1831         periph = (struct cam_periph *)dp->d_drv1;
 1832         if (periph == NULL)
 1833                 return(ENXIO);  
 1834 
 1835         cam_periph_lock(periph);
 1836         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdioctl\n"));
 1837 
 1838         softc = (struct cd_softc *)periph->softc;
 1839 
 1840         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 
 1841                   ("trying to do ioctl %#lx\n", cmd));
 1842 
 1843         if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
 1844                 cam_periph_unlock(periph);
 1845                 cam_periph_release(periph);
 1846                 return (error);
 1847         }
 1848 
 1849         /*
 1850          * If we don't have media loaded, check for it.  If still don't
 1851          * have media loaded, we can only do a load or eject.
 1852          *
 1853          * We only care whether media is loaded if this is a cd-specific ioctl
 1854          * (thus the IOCGROUP check below).  Note that this will break if
 1855          * anyone adds any ioctls into the switch statement below that don't
 1856          * have their ioctl group set to 'c'.
 1857          */
 1858         if (((softc->flags & CD_FLAG_VALID_MEDIA) == 0)
 1859          && ((cmd != CDIOCCLOSE)
 1860           && (cmd != CDIOCEJECT))
 1861          && (IOCGROUP(cmd) == 'c')) {
 1862                 error = cdcheckmedia(periph);
 1863                 if (error != 0) {
 1864                         cam_periph_unhold(periph);
 1865                         cam_periph_unlock(periph);
 1866                         return (error);
 1867                 }
 1868         }
 1869         /*
 1870          * Drop the lock here so later mallocs can use WAITOK.  The periph
 1871          * is essentially locked still with the cam_periph_hold call above.
 1872          */
 1873         cam_periph_unlock(periph);
 1874 
 1875         nocopyout = 0;
 1876         switch (cmd) {
 1877 
 1878         case CDIOCPLAYTRACKS:
 1879                 {
 1880                         struct ioc_play_track *args
 1881                             = (struct ioc_play_track *) addr;
 1882                         struct cd_mode_params params;
 1883                         union cd_pages *page;
 1884 
 1885                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 1886                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 1887                                                  M_WAITOK | M_ZERO);
 1888 
 1889                         cam_periph_lock(periph);
 1890                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 1891                                   ("trying to do CDIOCPLAYTRACKS\n"));
 1892 
 1893                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 1894                         if (error) {
 1895                                 free(params.mode_buf, M_SCSICD);
 1896                                 cam_periph_unlock(periph);
 1897                                 break;
 1898                         }
 1899                         page = cdgetpage(&params);
 1900 
 1901                         page->audio.flags &= ~CD_PA_SOTC;
 1902                         page->audio.flags |= CD_PA_IMMED;
 1903                         error = cdsetmode(periph, &params);
 1904                         free(params.mode_buf, M_SCSICD);
 1905                         if (error) {
 1906                                 cam_periph_unlock(periph);
 1907                                 break;
 1908                         }
 1909 
 1910                         /*
 1911                          * This was originally implemented with the PLAY
 1912                          * AUDIO TRACK INDEX command, but that command was
 1913                          * deprecated after SCSI-2.  Most (all?) SCSI CDROM
 1914                          * drives support it but ATAPI and ATAPI-derivative
 1915                          * drives don't seem to support it.  So we keep a
 1916                          * cache of the table of contents and translate
 1917                          * track numbers to MSF format.
 1918                          */
 1919                         if (softc->flags & CD_FLAG_VALID_TOC) {
 1920                                 union msf_lba *sentry, *eentry;
 1921                                 int st, et;
 1922 
 1923                                 if (args->end_track <
 1924                                     softc->toc.header.ending_track + 1)
 1925                                         args->end_track++;
 1926                                 if (args->end_track >
 1927                                     softc->toc.header.ending_track + 1)
 1928                                         args->end_track =
 1929                                             softc->toc.header.ending_track + 1;
 1930                                 st = args->start_track -
 1931                                         softc->toc.header.starting_track;
 1932                                 et = args->end_track -
 1933                                         softc->toc.header.starting_track;
 1934                                 if ((st < 0)
 1935                                  || (et < 0)
 1936                                  || (st > (softc->toc.header.ending_track -
 1937                                      softc->toc.header.starting_track))) {
 1938                                         error = EINVAL;
 1939                                         break;
 1940                                 }
 1941                                 sentry = &softc->toc.entries[st].addr;
 1942                                 eentry = &softc->toc.entries[et].addr;
 1943                                 error = cdplaymsf(periph,
 1944                                                   sentry->msf.minute,
 1945                                                   sentry->msf.second,
 1946                                                   sentry->msf.frame,
 1947                                                   eentry->msf.minute,
 1948                                                   eentry->msf.second,
 1949                                                   eentry->msf.frame);
 1950                         } else {
 1951                                 /*
 1952                                  * If we don't have a valid TOC, try the
 1953                                  * play track index command.  It is part of
 1954                                  * the SCSI-2 spec, but was removed in the
 1955                                  * MMC specs.  ATAPI and ATAPI-derived
 1956                                  * drives don't support it.
 1957                                  */
 1958                                 if (softc->quirks & CD_Q_BCD_TRACKS) {
 1959                                         args->start_track =
 1960                                                 bin2bcd(args->start_track);
 1961                                         args->end_track =
 1962                                                 bin2bcd(args->end_track);
 1963                                 }
 1964                                 error = cdplaytracks(periph,
 1965                                                      args->start_track,
 1966                                                      args->start_index,
 1967                                                      args->end_track,
 1968                                                      args->end_index);
 1969                         }
 1970                         cam_periph_unlock(periph);
 1971                 }
 1972                 break;
 1973         case CDIOCPLAYMSF:
 1974                 {
 1975                         struct ioc_play_msf *args
 1976                                 = (struct ioc_play_msf *) addr;
 1977                         struct cd_mode_params params;
 1978                         union cd_pages *page;
 1979 
 1980                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 1981                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 1982                                                  M_WAITOK | M_ZERO);
 1983 
 1984                         cam_periph_lock(periph);
 1985                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 1986                                   ("trying to do CDIOCPLAYMSF\n"));
 1987 
 1988                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 1989                         if (error) {
 1990                                 free(params.mode_buf, M_SCSICD);
 1991                                 cam_periph_unlock(periph);
 1992                                 break;
 1993                         }
 1994                         page = cdgetpage(&params);
 1995 
 1996                         page->audio.flags &= ~CD_PA_SOTC;
 1997                         page->audio.flags |= CD_PA_IMMED;
 1998                         error = cdsetmode(periph, &params);
 1999                         free(params.mode_buf, M_SCSICD);
 2000                         if (error) {
 2001                                 cam_periph_unlock(periph);
 2002                                 break;
 2003                         }
 2004                         error = cdplaymsf(periph,
 2005                                           args->start_m,
 2006                                           args->start_s,
 2007                                           args->start_f,
 2008                                           args->end_m,
 2009                                           args->end_s,
 2010                                           args->end_f);
 2011                         cam_periph_unlock(periph);
 2012                 }
 2013                 break;
 2014         case CDIOCPLAYBLOCKS:
 2015                 {
 2016                         struct ioc_play_blocks *args
 2017                                 = (struct ioc_play_blocks *) addr;
 2018                         struct cd_mode_params params;
 2019                         union cd_pages *page;
 2020 
 2021                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2022                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 2023                                                  M_WAITOK | M_ZERO);
 2024 
 2025                         cam_periph_lock(periph);
 2026                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2027                                   ("trying to do CDIOCPLAYBLOCKS\n"));
 2028 
 2029 
 2030                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2031                         if (error) {
 2032                                 free(params.mode_buf, M_SCSICD);
 2033                                 cam_periph_unlock(periph);
 2034                                 break;
 2035                         }
 2036                         page = cdgetpage(&params);
 2037 
 2038                         page->audio.flags &= ~CD_PA_SOTC;
 2039                         page->audio.flags |= CD_PA_IMMED;
 2040                         error = cdsetmode(periph, &params);
 2041                         free(params.mode_buf, M_SCSICD);
 2042                         if (error) {
 2043                                 cam_periph_unlock(periph);
 2044                                 break;
 2045                         }
 2046                         error = cdplay(periph, args->blk, args->len);
 2047                         cam_periph_unlock(periph);
 2048                 }
 2049                 break;
 2050         case CDIOCREADSUBCHANNEL_SYSSPACE:
 2051                 nocopyout = 1;
 2052                 /* Fallthrough */
 2053         case CDIOCREADSUBCHANNEL:
 2054                 {
 2055                         struct ioc_read_subchannel *args
 2056                                 = (struct ioc_read_subchannel *) addr;
 2057                         struct cd_sub_channel_info *data;
 2058                         u_int32_t len = args->data_len;
 2059 
 2060                         data = malloc(sizeof(struct cd_sub_channel_info), 
 2061                                       M_SCSICD, M_WAITOK);
 2062 
 2063                         cam_periph_lock(periph);
 2064                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2065                                   ("trying to do CDIOCREADSUBCHANNEL\n"));
 2066 
 2067                         if ((len > sizeof(struct cd_sub_channel_info)) ||
 2068                             (len < sizeof(struct cd_sub_channel_header))) {
 2069                                 printf(
 2070                                         "scsi_cd: cdioctl: "
 2071                                         "cdioreadsubchannel: error, len=%d\n",
 2072                                         len);
 2073                                 error = EINVAL;
 2074                                 free(data, M_SCSICD);
 2075                                 cam_periph_unlock(periph);
 2076                                 break;
 2077                         }
 2078 
 2079                         if (softc->quirks & CD_Q_BCD_TRACKS)
 2080                                 args->track = bin2bcd(args->track);
 2081 
 2082                         error = cdreadsubchannel(periph, args->address_format,
 2083                                 args->data_format, args->track, data, len);
 2084 
 2085                         if (error) {
 2086                                 free(data, M_SCSICD);
 2087                                 cam_periph_unlock(periph);
 2088                                 break;
 2089                         }
 2090                         if (softc->quirks & CD_Q_BCD_TRACKS)
 2091                                 data->what.track_info.track_number =
 2092                                     bcd2bin(data->what.track_info.track_number);
 2093                         len = min(len, ((data->header.data_len[0] << 8) +
 2094                                 data->header.data_len[1] +
 2095                                 sizeof(struct cd_sub_channel_header)));
 2096                         cam_periph_unlock(periph);
 2097                         if (nocopyout == 0) {
 2098                                 if (copyout(data, args->data, len) != 0) {
 2099                                         error = EFAULT;
 2100                                 }
 2101                         } else {
 2102                                 bcopy(data, args->data, len);
 2103                         }
 2104                         free(data, M_SCSICD);
 2105                 }
 2106                 break;
 2107 
 2108         case CDIOREADTOCHEADER:
 2109                 {
 2110                         struct ioc_toc_header *th;
 2111 
 2112                         th = malloc(sizeof(struct ioc_toc_header), M_SCSICD,
 2113                                     M_WAITOK);
 2114 
 2115                         cam_periph_lock(periph);
 2116                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2117                                   ("trying to do CDIOREADTOCHEADER\n"));
 2118 
 2119                         error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 
 2120                                           sizeof (*th), /*sense_flags*/0);
 2121                         if (error) {
 2122                                 free(th, M_SCSICD);
 2123                                 cam_periph_unlock(periph);
 2124                                 break;
 2125                         }
 2126                         if (softc->quirks & CD_Q_BCD_TRACKS) {
 2127                                 /* we are going to have to convert the BCD
 2128                                  * encoding on the cd to what is expected
 2129                                  */
 2130                                 th->starting_track = 
 2131                                         bcd2bin(th->starting_track);
 2132                                 th->ending_track = bcd2bin(th->ending_track);
 2133                         }
 2134                         th->len = ntohs(th->len);
 2135                         bcopy(th, addr, sizeof(*th));
 2136                         free(th, M_SCSICD);
 2137                         cam_periph_unlock(periph);
 2138                 }
 2139                 break;
 2140         case CDIOREADTOCENTRYS:
 2141                 {
 2142                         struct cd_tocdata *data;
 2143                         struct cd_toc_single *lead;
 2144                         struct ioc_read_toc_entry *te =
 2145                                 (struct ioc_read_toc_entry *) addr;
 2146                         struct ioc_toc_header *th;
 2147                         u_int32_t len, readlen, idx, num;
 2148                         u_int32_t starting_track = te->starting_track;
 2149 
 2150                         data = malloc(sizeof(*data), M_SCSICD, M_WAITOK);
 2151                         lead = malloc(sizeof(*lead), M_SCSICD, M_WAITOK);
 2152 
 2153                         cam_periph_lock(periph);
 2154                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2155                                   ("trying to do CDIOREADTOCENTRYS\n"));
 2156 
 2157                         if (te->data_len < sizeof(struct cd_toc_entry)
 2158                          || (te->data_len % sizeof(struct cd_toc_entry)) != 0
 2159                          || (te->address_format != CD_MSF_FORMAT
 2160                           && te->address_format != CD_LBA_FORMAT)) {
 2161                                 error = EINVAL;
 2162                                 printf("scsi_cd: error in readtocentries, "
 2163                                        "returning EINVAL\n");
 2164                                 free(data, M_SCSICD);
 2165                                 free(lead, M_SCSICD);
 2166                                 cam_periph_unlock(periph);
 2167                                 break;
 2168                         }
 2169 
 2170                         th = &data->header;
 2171                         error = cdreadtoc(periph, 0, 0, (u_int8_t *)th, 
 2172                                           sizeof (*th), /*sense_flags*/0);
 2173                         if (error) {
 2174                                 free(data, M_SCSICD);
 2175                                 free(lead, M_SCSICD);
 2176                                 cam_periph_unlock(periph);
 2177                                 break;
 2178                         }
 2179 
 2180                         if (softc->quirks & CD_Q_BCD_TRACKS) {
 2181                                 /* we are going to have to convert the BCD
 2182                                  * encoding on the cd to what is expected
 2183                                  */
 2184                                 th->starting_track =
 2185                                     bcd2bin(th->starting_track);
 2186                                 th->ending_track = bcd2bin(th->ending_track);
 2187                         }
 2188 
 2189                         if (starting_track == 0)
 2190                                 starting_track = th->starting_track;
 2191                         else if (starting_track == LEADOUT)
 2192                                 starting_track = th->ending_track + 1;
 2193                         else if (starting_track < th->starting_track ||
 2194                                  starting_track > th->ending_track + 1) {
 2195                                 printf("scsi_cd: error in readtocentries, "
 2196                                        "returning EINVAL\n");
 2197                                 free(data, M_SCSICD);
 2198                                 free(lead, M_SCSICD);
 2199                                 cam_periph_unlock(periph);
 2200                                 error = EINVAL;
 2201                                 break;
 2202                         }
 2203 
 2204                         /* calculate reading length without leadout entry */
 2205                         readlen = (th->ending_track - starting_track + 1) *
 2206                                   sizeof(struct cd_toc_entry);
 2207 
 2208                         /* and with leadout entry */
 2209                         len = readlen + sizeof(struct cd_toc_entry);
 2210                         if (te->data_len < len) {
 2211                                 len = te->data_len;
 2212                                 if (readlen > len)
 2213                                         readlen = len;
 2214                         }
 2215                         if (len > sizeof(data->entries)) {
 2216                                 printf("scsi_cd: error in readtocentries, "
 2217                                        "returning EINVAL\n");
 2218                                 error = EINVAL;
 2219                                 free(data, M_SCSICD);
 2220                                 free(lead, M_SCSICD);
 2221                                 cam_periph_unlock(periph);
 2222                                 break;
 2223                         }
 2224                         num = len / sizeof(struct cd_toc_entry);
 2225 
 2226                         if (readlen > 0) {
 2227                                 error = cdreadtoc(periph, te->address_format,
 2228                                                   starting_track,
 2229                                                   (u_int8_t *)data,
 2230                                                   readlen + sizeof (*th),
 2231                                                   /*sense_flags*/0);
 2232                                 if (error) {
 2233                                         free(data, M_SCSICD);
 2234                                         free(lead, M_SCSICD);
 2235                                         cam_periph_unlock(periph);
 2236                                         break;
 2237                                 }
 2238                         }
 2239 
 2240                         /* make leadout entry if needed */
 2241                         idx = starting_track + num - 1;
 2242                         if (softc->quirks & CD_Q_BCD_TRACKS)
 2243                                 th->ending_track = bcd2bin(th->ending_track);
 2244                         if (idx == th->ending_track + 1) {
 2245                                 error = cdreadtoc(periph, te->address_format,
 2246                                                   LEADOUT, (u_int8_t *)lead,
 2247                                                   sizeof(*lead),
 2248                                                   /*sense_flags*/0);
 2249                                 if (error) {
 2250                                         free(data, M_SCSICD);
 2251                                         free(lead, M_SCSICD);
 2252                                         cam_periph_unlock(periph);
 2253                                         break;
 2254                                 }
 2255                                 data->entries[idx - starting_track] = 
 2256                                         lead->entry;
 2257                         }
 2258                         if (softc->quirks & CD_Q_BCD_TRACKS) {
 2259                                 for (idx = 0; idx < num - 1; idx++) {
 2260                                         data->entries[idx].track =
 2261                                             bcd2bin(data->entries[idx].track);
 2262                                 }
 2263                         }
 2264 
 2265                         cam_periph_unlock(periph);
 2266                         error = copyout(data->entries, te->data, len);
 2267                         free(data, M_SCSICD);
 2268                         free(lead, M_SCSICD);
 2269                 }
 2270                 break;
 2271         case CDIOREADTOCENTRY:
 2272                 {
 2273                         struct cd_toc_single *data;
 2274                         struct ioc_read_toc_single_entry *te =
 2275                                 (struct ioc_read_toc_single_entry *) addr;
 2276                         struct ioc_toc_header *th;
 2277                         u_int32_t track;
 2278 
 2279                         data = malloc(sizeof(*data), M_SCSICD, M_WAITOK);
 2280 
 2281                         cam_periph_lock(periph);
 2282                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2283                                   ("trying to do CDIOREADTOCENTRY\n"));
 2284 
 2285                         if (te->address_format != CD_MSF_FORMAT
 2286                             && te->address_format != CD_LBA_FORMAT) {
 2287                                 printf("error in readtocentry, "
 2288                                        " returning EINVAL\n");
 2289                                 free(data, M_SCSICD);
 2290                                 error = EINVAL;
 2291                                 cam_periph_unlock(periph);
 2292                                 break;
 2293                         }
 2294 
 2295                         th = &data->header;
 2296                         error = cdreadtoc(periph, 0, 0, (u_int8_t *)th,
 2297                                           sizeof (*th), /*sense_flags*/0);
 2298                         if (error) {
 2299                                 free(data, M_SCSICD);
 2300                                 cam_periph_unlock(periph);
 2301                                 break;
 2302                         }
 2303 
 2304                         if (softc->quirks & CD_Q_BCD_TRACKS) {
 2305                                 /* we are going to have to convert the BCD
 2306                                  * encoding on the cd to what is expected
 2307                                  */
 2308                                 th->starting_track =
 2309                                     bcd2bin(th->starting_track);
 2310                                 th->ending_track = bcd2bin(th->ending_track);
 2311                         }
 2312                         track = te->track;
 2313                         if (track == 0)
 2314                                 track = th->starting_track;
 2315                         else if (track == LEADOUT)
 2316                                 /* OK */;
 2317                         else if (track < th->starting_track ||
 2318                                  track > th->ending_track + 1) {
 2319                                 printf("error in readtocentry, "
 2320                                        " returning EINVAL\n");
 2321                                 free(data, M_SCSICD);
 2322                                 error = EINVAL;
 2323                                 cam_periph_unlock(periph);
 2324                                 break;
 2325                         }
 2326 
 2327                         error = cdreadtoc(periph, te->address_format, track,
 2328                                           (u_int8_t *)data, sizeof(*data),
 2329                                           /*sense_flags*/0);
 2330                         if (error) {
 2331                                 free(data, M_SCSICD);
 2332                                 cam_periph_unlock(periph);
 2333                                 break;
 2334                         }
 2335 
 2336                         if (softc->quirks & CD_Q_BCD_TRACKS)
 2337                                 data->entry.track = bcd2bin(data->entry.track);
 2338                         bcopy(&data->entry, &te->entry,
 2339                               sizeof(struct cd_toc_entry));
 2340                         free(data, M_SCSICD);
 2341                         cam_periph_unlock(periph);
 2342                 }
 2343                 break;
 2344         case CDIOCSETPATCH:
 2345                 {
 2346                         struct ioc_patch *arg = (struct ioc_patch *)addr;
 2347                         struct cd_mode_params params;
 2348                         union cd_pages *page;
 2349 
 2350                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2351                         params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
 2352                                                  M_WAITOK | M_ZERO);
 2353 
 2354                         cam_periph_lock(periph);
 2355                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2356                                   ("trying to do CDIOCSETPATCH\n"));
 2357 
 2358                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2359                         if (error) {
 2360                                 free(params.mode_buf, M_SCSICD);
 2361                                 cam_periph_unlock(periph);
 2362                                 break;
 2363                         }
 2364                         page = cdgetpage(&params);
 2365 
 2366                         page->audio.port[LEFT_PORT].channels = 
 2367                                 arg->patch[0];
 2368                         page->audio.port[RIGHT_PORT].channels = 
 2369                                 arg->patch[1];
 2370                         page->audio.port[2].channels = arg->patch[2];
 2371                         page->audio.port[3].channels = arg->patch[3];
 2372                         error = cdsetmode(periph, &params);
 2373                         free(params.mode_buf, M_SCSICD);
 2374                         cam_periph_unlock(periph);
 2375                 }
 2376                 break;
 2377         case CDIOCGETVOL:
 2378                 {
 2379                         struct ioc_vol *arg = (struct ioc_vol *) addr;
 2380                         struct cd_mode_params params;
 2381                         union cd_pages *page;
 2382 
 2383                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2384                         params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
 2385                                                  M_WAITOK | M_ZERO);
 2386 
 2387                         cam_periph_lock(periph);
 2388                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2389                                   ("trying to do CDIOCGETVOL\n"));
 2390 
 2391                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2392                         if (error) {
 2393                                 free(params.mode_buf, M_SCSICD);
 2394                                 cam_periph_unlock(periph);
 2395                                 break;
 2396                         }
 2397                         page = cdgetpage(&params);
 2398 
 2399                         arg->vol[LEFT_PORT] = 
 2400                                 page->audio.port[LEFT_PORT].volume;
 2401                         arg->vol[RIGHT_PORT] = 
 2402                                 page->audio.port[RIGHT_PORT].volume;
 2403                         arg->vol[2] = page->audio.port[2].volume;
 2404                         arg->vol[3] = page->audio.port[3].volume;
 2405                         free(params.mode_buf, M_SCSICD);
 2406                         cam_periph_unlock(periph);
 2407                 }
 2408                 break;
 2409         case CDIOCSETVOL:
 2410                 {
 2411                         struct ioc_vol *arg = (struct ioc_vol *) addr;
 2412                         struct cd_mode_params params;
 2413                         union cd_pages *page;
 2414 
 2415                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2416                         params.mode_buf = malloc(params.alloc_len, M_SCSICD, 
 2417                                                  M_WAITOK | M_ZERO);
 2418 
 2419                         cam_periph_lock(periph);
 2420                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2421                                   ("trying to do CDIOCSETVOL\n"));
 2422 
 2423                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2424                         if (error) {
 2425                                 free(params.mode_buf, M_SCSICD);
 2426                                 cam_periph_unlock(periph);
 2427                                 break;
 2428                         }
 2429                         page = cdgetpage(&params);
 2430 
 2431                         page->audio.port[LEFT_PORT].channels = CHANNEL_0;
 2432                         page->audio.port[LEFT_PORT].volume = 
 2433                                 arg->vol[LEFT_PORT];
 2434                         page->audio.port[RIGHT_PORT].channels = CHANNEL_1;
 2435                         page->audio.port[RIGHT_PORT].volume = 
 2436                                 arg->vol[RIGHT_PORT];
 2437                         page->audio.port[2].volume = arg->vol[2];
 2438                         page->audio.port[3].volume = arg->vol[3];
 2439                         error = cdsetmode(periph, &params);
 2440                         cam_periph_unlock(periph);
 2441                         free(params.mode_buf, M_SCSICD);
 2442                 }
 2443                 break;
 2444         case CDIOCSETMONO:
 2445                 {
 2446                         struct cd_mode_params params;
 2447                         union cd_pages *page;
 2448 
 2449                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2450                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 2451                                                  M_WAITOK | M_ZERO);
 2452 
 2453                         cam_periph_lock(periph);
 2454                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2455                                   ("trying to do CDIOCSETMONO\n"));
 2456 
 2457                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2458                         if (error) {
 2459                                 free(params.mode_buf, M_SCSICD);
 2460                                 cam_periph_unlock(periph);
 2461                                 break;
 2462                         }
 2463                         page = cdgetpage(&params);
 2464 
 2465                         page->audio.port[LEFT_PORT].channels = 
 2466                                 LEFT_CHANNEL | RIGHT_CHANNEL;
 2467                         page->audio.port[RIGHT_PORT].channels = 
 2468                                 LEFT_CHANNEL | RIGHT_CHANNEL;
 2469                         page->audio.port[2].channels = 0;
 2470                         page->audio.port[3].channels = 0;
 2471                         error = cdsetmode(periph, &params);
 2472                         cam_periph_unlock(periph);
 2473                         free(params.mode_buf, M_SCSICD);
 2474                 }
 2475                 break;
 2476         case CDIOCSETSTEREO:
 2477                 {
 2478                         struct cd_mode_params params;
 2479                         union cd_pages *page;
 2480 
 2481                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2482                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 2483                                                  M_WAITOK | M_ZERO);
 2484 
 2485                         cam_periph_lock(periph);
 2486                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2487                                   ("trying to do CDIOCSETSTEREO\n"));
 2488 
 2489                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2490                         if (error) {
 2491                                 free(params.mode_buf, M_SCSICD);
 2492                                 cam_periph_unlock(periph);
 2493                                 break;
 2494                         }
 2495                         page = cdgetpage(&params);
 2496 
 2497                         page->audio.port[LEFT_PORT].channels = 
 2498                                 LEFT_CHANNEL;
 2499                         page->audio.port[RIGHT_PORT].channels = 
 2500                                 RIGHT_CHANNEL;
 2501                         page->audio.port[2].channels = 0;
 2502                         page->audio.port[3].channels = 0;
 2503                         error = cdsetmode(periph, &params);
 2504                         free(params.mode_buf, M_SCSICD);
 2505                         cam_periph_unlock(periph);
 2506                 }
 2507                 break;
 2508         case CDIOCSETMUTE:
 2509                 {
 2510                         struct cd_mode_params params;
 2511                         union cd_pages *page;
 2512 
 2513                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2514                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 2515                                                  M_WAITOK | M_ZERO);
 2516 
 2517                         cam_periph_lock(periph);
 2518                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2519                                   ("trying to do CDIOCSETMUTE\n"));
 2520 
 2521                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2522                         if (error) {
 2523                                 free(&params, M_SCSICD);
 2524                                 cam_periph_unlock(periph);
 2525                                 break;
 2526                         }
 2527                         page = cdgetpage(&params);
 2528 
 2529                         page->audio.port[LEFT_PORT].channels = 0;
 2530                         page->audio.port[RIGHT_PORT].channels = 0;
 2531                         page->audio.port[2].channels = 0;
 2532                         page->audio.port[3].channels = 0;
 2533                         error = cdsetmode(periph, &params);
 2534                         free(params.mode_buf, M_SCSICD);
 2535                         cam_periph_unlock(periph);
 2536                 }
 2537                 break;
 2538         case CDIOCSETLEFT:
 2539                 {
 2540                         struct cd_mode_params params;
 2541                         union cd_pages *page;
 2542 
 2543                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2544                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 2545                                                  M_WAITOK | M_ZERO);
 2546 
 2547                         cam_periph_lock(periph);
 2548                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2549                                   ("trying to do CDIOCSETLEFT\n"));
 2550 
 2551                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2552                         if (error) {
 2553                                 free(params.mode_buf, M_SCSICD);
 2554                                 cam_periph_unlock(periph);
 2555                                 break;
 2556                         }
 2557                         page = cdgetpage(&params);
 2558 
 2559                         page->audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
 2560                         page->audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
 2561                         page->audio.port[2].channels = 0;
 2562                         page->audio.port[3].channels = 0;
 2563                         error = cdsetmode(periph, &params);
 2564                         free(params.mode_buf, M_SCSICD);
 2565                         cam_periph_unlock(periph);
 2566                 }
 2567                 break;
 2568         case CDIOCSETRIGHT:
 2569                 {
 2570                         struct cd_mode_params params;
 2571                         union cd_pages *page;
 2572 
 2573                         params.alloc_len = sizeof(union cd_mode_data_6_10);
 2574                         params.mode_buf = malloc(params.alloc_len, M_SCSICD,
 2575                                                  M_WAITOK | M_ZERO);
 2576 
 2577                         cam_periph_lock(periph);
 2578                         CAM_DEBUG(periph->path, CAM_DEBUG_SUBTRACE, 
 2579                                   ("trying to do CDIOCSETRIGHT\n"));
 2580 
 2581                         error = cdgetmode(periph, &params, AUDIO_PAGE);
 2582                         if (error) {
 2583                                 free(params.mode_buf, M_SCSICD);
 2584                                 cam_periph_unlock(periph);
 2585                                 break;
 2586                         }
 2587                         page = cdgetpage(&params);
 2588 
 2589                         page->audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
 2590                         page->audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
 2591                         page->audio.port[2].channels = 0;
 2592                         page->audio.port[3].channels = 0;
 2593                         error = cdsetmode(periph, &params);
 2594                         free(params.mode_buf, M_SCSICD);
 2595                         cam_periph_unlock(periph);
 2596                 }
 2597                 break;
 2598         case CDIOCRESUME:
 2599                 cam_periph_lock(periph);
 2600                 error = cdpause(periph, 1);
 2601                 cam_periph_unlock(periph);
 2602                 break;
 2603         case CDIOCPAUSE:
 2604                 cam_periph_lock(periph);
 2605                 error = cdpause(periph, 0);
 2606                 cam_periph_unlock(periph);
 2607                 break;
 2608         case CDIOCSTART:
 2609                 cam_periph_lock(periph);
 2610                 error = cdstartunit(periph, 0);
 2611                 cam_periph_unlock(periph);
 2612                 break;
 2613         case CDIOCCLOSE:
 2614                 cam_periph_lock(periph);
 2615                 error = cdstartunit(periph, 1);
 2616                 cam_periph_unlock(periph);
 2617                 break;
 2618         case CDIOCSTOP:
 2619                 cam_periph_lock(periph);
 2620                 error = cdstopunit(periph, 0);
 2621                 cam_periph_unlock(periph);
 2622                 break;
 2623         case CDIOCEJECT:
 2624                 cam_periph_lock(periph);
 2625                 error = cdstopunit(periph, 1);
 2626                 cam_periph_unlock(periph);
 2627                 break;
 2628         case CDIOCALLOW:
 2629                 cam_periph_lock(periph);
 2630                 cdprevent(periph, PR_ALLOW);
 2631                 cam_periph_unlock(periph);
 2632                 break;
 2633         case CDIOCPREVENT:
 2634                 cam_periph_lock(periph);
 2635                 cdprevent(periph, PR_PREVENT);
 2636                 cam_periph_unlock(periph);
 2637                 break;
 2638         case CDIOCSETDEBUG:
 2639                 /* sc_link->flags |= (SDEV_DB1 | SDEV_DB2); */
 2640                 error = ENOTTY;
 2641                 break;
 2642         case CDIOCCLRDEBUG:
 2643                 /* sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2); */
 2644                 error = ENOTTY;
 2645                 break;
 2646         case CDIOCRESET:
 2647                 /* return (cd_reset(periph)); */
 2648                 error = ENOTTY;
 2649                 break;
 2650         case CDRIOCREADSPEED:
 2651                 cam_periph_lock(periph);
 2652                 error = cdsetspeed(periph, *(u_int32_t *)addr, CDR_MAX_SPEED);
 2653                 cam_periph_unlock(periph);
 2654                 break;
 2655         case CDRIOCWRITESPEED:
 2656                 cam_periph_lock(periph);
 2657                 error = cdsetspeed(periph, CDR_MAX_SPEED, *(u_int32_t *)addr);
 2658                 cam_periph_unlock(periph);
 2659                 break;
 2660         case DVDIOCSENDKEY:
 2661         case DVDIOCREPORTKEY: {
 2662                 struct dvd_authinfo *authinfo;
 2663 
 2664                 authinfo = (struct dvd_authinfo *)addr;
 2665 
 2666                 cam_periph_lock(periph);
 2667                 if (cmd == DVDIOCREPORTKEY)
 2668                         error = cdreportkey(periph, authinfo);
 2669                 else
 2670                         error = cdsendkey(periph, authinfo);
 2671                 cam_periph_unlock(periph);
 2672                 break;
 2673                 }
 2674         case DVDIOCREADSTRUCTURE: {
 2675                 struct dvd_struct *dvdstruct;
 2676 
 2677                 dvdstruct = (struct dvd_struct *)addr;
 2678 
 2679                 cam_periph_lock(periph);
 2680                 error = cdreaddvdstructure(periph, dvdstruct);
 2681                 cam_periph_unlock(periph);
 2682 
 2683                 break;
 2684         }
 2685         default:
 2686                 cam_periph_lock(periph);
 2687                 error = cam_periph_ioctl(periph, cmd, addr, cderror);
 2688                 cam_periph_unlock(periph);
 2689                 break;
 2690         }
 2691 
 2692         cam_periph_lock(periph);
 2693         cam_periph_unhold(periph);
 2694         
 2695         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("leaving cdioctl\n"));
 2696         if (error && bootverbose) {
 2697                 printf("scsi_cd.c::ioctl cmd=%08lx error=%d\n", cmd, error);
 2698         }
 2699         cam_periph_unlock(periph);
 2700 
 2701         return (error);
 2702 }
 2703 
 2704 static void
 2705 cdprevent(struct cam_periph *periph, int action)
 2706 {
 2707         union   ccb *ccb;
 2708         struct  cd_softc *softc;
 2709         int     error;
 2710 
 2711         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdprevent\n"));
 2712 
 2713         softc = (struct cd_softc *)periph->softc;
 2714         
 2715         if (((action == PR_ALLOW)
 2716           && (softc->flags & CD_FLAG_DISC_LOCKED) == 0)
 2717          || ((action == PR_PREVENT)
 2718           && (softc->flags & CD_FLAG_DISC_LOCKED) != 0)) {
 2719                 return;
 2720         }
 2721             
 2722         ccb = cdgetccb(periph, /* priority */ 1);
 2723 
 2724         scsi_prevent(&ccb->csio, 
 2725                      /*retries*/ 1,
 2726                      cddone,
 2727                      MSG_SIMPLE_Q_TAG,
 2728                      action,
 2729                      SSD_FULL_SIZE,
 2730                      /* timeout */60000);
 2731         
 2732         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 2733                         /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
 2734 
 2735         xpt_release_ccb(ccb);
 2736 
 2737         if (error == 0) {
 2738                 if (action == PR_ALLOW)
 2739                         softc->flags &= ~CD_FLAG_DISC_LOCKED;
 2740                 else
 2741                         softc->flags |= CD_FLAG_DISC_LOCKED;
 2742         }
 2743 }
 2744 
 2745 /*
 2746  * XXX: the disk media and sector size is only really able to change
 2747  * XXX: while the device is closed.
 2748  */
 2749 static int
 2750 cdcheckmedia(struct cam_periph *periph)
 2751 {
 2752         struct cd_softc *softc;
 2753         struct ioc_toc_header *toch;
 2754         struct cd_toc_single leadout;
 2755         u_int32_t size, toclen;
 2756         int error, num_entries, cdindex;
 2757 
 2758         softc = (struct cd_softc *)periph->softc;
 2759 
 2760         cdprevent(periph, PR_PREVENT);
 2761         softc->disk->d_maxsize = DFLTPHYS;
 2762         softc->disk->d_sectorsize = 2048;
 2763         softc->disk->d_mediasize = 0;
 2764 
 2765         /*
 2766          * Get the disc size and block size.  If we can't get it, we don't
 2767          * have media, most likely.
 2768          */
 2769         if ((error = cdsize(periph, &size)) != 0) {
 2770                 softc->flags &= ~(CD_FLAG_VALID_MEDIA|CD_FLAG_VALID_TOC);
 2771                 cdprevent(periph, PR_ALLOW);
 2772                 return (error);
 2773         } else
 2774                 softc->flags |= CD_FLAG_VALID_MEDIA;
 2775 
 2776         /*
 2777          * Now we check the table of contents.  This (currently) is only
 2778          * used for the CDIOCPLAYTRACKS ioctl.  It may be used later to do
 2779          * things like present a separate entry in /dev for each track,
 2780          * like that acd(4) driver does.
 2781          */
 2782         bzero(&softc->toc, sizeof(softc->toc));
 2783         toch = &softc->toc.header;
 2784         /*
 2785          * We will get errors here for media that doesn't have a table of
 2786          * contents.  According to the MMC-3 spec: "When a Read TOC/PMA/ATIP
 2787          * command is presented for a DDCD/CD-R/RW media, where the first TOC
 2788          * has not been recorded (no complete session) and the Format codes
 2789          * 0000b, 0001b, or 0010b are specified, this command shall be rejected
 2790          * with an INVALID FIELD IN CDB.  Devices that are not capable of
 2791          * reading an incomplete session on DDC/CD-R/RW media shall report
 2792          * CANNOT READ MEDIUM - INCOMPATIBLE FORMAT."
 2793          *
 2794          * So this isn't fatal if we can't read the table of contents, it
 2795          * just means that the user won't be able to issue the play tracks
 2796          * ioctl, and likely lots of other stuff won't work either.  They
 2797          * need to burn the CD before we can do a whole lot with it.  So
 2798          * we don't print anything here if we get an error back.
 2799          */
 2800         error = cdreadtoc(periph, 0, 0, (u_int8_t *)toch, sizeof(*toch),
 2801                           SF_NO_PRINT);
 2802         /*
 2803          * Errors in reading the table of contents aren't fatal, we just
 2804          * won't have a valid table of contents cached.
 2805          */
 2806         if (error != 0) {
 2807                 error = 0;
 2808                 bzero(&softc->toc, sizeof(softc->toc));
 2809                 goto bailout;
 2810         }
 2811 
 2812         if (softc->quirks & CD_Q_BCD_TRACKS) {
 2813                 toch->starting_track = bcd2bin(toch->starting_track);
 2814                 toch->ending_track = bcd2bin(toch->ending_track);
 2815         }
 2816 
 2817         /* Number of TOC entries, plus leadout */
 2818         num_entries = (toch->ending_track - toch->starting_track) + 2;
 2819 
 2820         if (num_entries <= 0)
 2821                 goto bailout;
 2822 
 2823         toclen = num_entries * sizeof(struct cd_toc_entry);
 2824 
 2825         error = cdreadtoc(periph, CD_MSF_FORMAT, toch->starting_track,
 2826                           (u_int8_t *)&softc->toc, toclen + sizeof(*toch),
 2827                           SF_NO_PRINT);
 2828         if (error != 0) {
 2829                 error = 0;
 2830                 bzero(&softc->toc, sizeof(softc->toc));
 2831                 goto bailout;
 2832         }
 2833 
 2834         if (softc->quirks & CD_Q_BCD_TRACKS) {
 2835                 toch->starting_track = bcd2bin(toch->starting_track);
 2836                 toch->ending_track = bcd2bin(toch->ending_track);
 2837         }
 2838         /*
 2839          * XXX KDM is this necessary?  Probably only if the drive doesn't
 2840          * return leadout information with the table of contents.
 2841          */
 2842         cdindex = toch->starting_track + num_entries -1;
 2843         if (cdindex == toch->ending_track + 1) {
 2844 
 2845                 error = cdreadtoc(periph, CD_MSF_FORMAT, LEADOUT, 
 2846                                   (u_int8_t *)&leadout, sizeof(leadout),
 2847                                   SF_NO_PRINT);
 2848                 if (error != 0) {
 2849                         error = 0;
 2850                         goto bailout;
 2851                 }
 2852                 softc->toc.entries[cdindex - toch->starting_track] =
 2853                         leadout.entry;
 2854         }
 2855         if (softc->quirks & CD_Q_BCD_TRACKS) {
 2856                 for (cdindex = 0; cdindex < num_entries - 1; cdindex++) {
 2857                         softc->toc.entries[cdindex].track =
 2858                                 bcd2bin(softc->toc.entries[cdindex].track);
 2859                 }
 2860         }
 2861 
 2862         softc->flags |= CD_FLAG_VALID_TOC;
 2863         softc->disk->d_maxsize = DFLTPHYS;
 2864         softc->disk->d_sectorsize = softc->params.blksize;
 2865         softc->disk->d_mediasize =
 2866             (off_t)softc->params.blksize * softc->params.disksize;
 2867 
 2868 bailout:
 2869 
 2870         /*
 2871          * We unconditionally (re)set the blocksize each time the
 2872          * CD device is opened.  This is because the CD can change,
 2873          * and therefore the blocksize might change.
 2874          * XXX problems here if some slice or partition is still
 2875          * open with the old size?
 2876          */
 2877         if ((softc->disk->d_devstat->flags & DEVSTAT_BS_UNAVAILABLE) != 0)
 2878                 softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
 2879         softc->disk->d_devstat->block_size = softc->params.blksize;
 2880 
 2881         return (error);
 2882 }
 2883 
 2884 static int
 2885 cdsize(struct cam_periph *periph, u_int32_t *size)
 2886 {
 2887         struct cd_softc *softc;
 2888         union ccb *ccb;
 2889         struct scsi_read_capacity_data *rcap_buf;
 2890         int error;
 2891 
 2892         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering cdsize\n"));
 2893 
 2894         softc = (struct cd_softc *)periph->softc;
 2895              
 2896         ccb = cdgetccb(periph, /* priority */ 1);
 2897 
 2898         /* XXX Should be M_WAITOK */
 2899         rcap_buf = malloc(sizeof(struct scsi_read_capacity_data), 
 2900                           M_SCSICD, M_NOWAIT);
 2901         if (rcap_buf == NULL)
 2902                 return (ENOMEM);
 2903 
 2904         scsi_read_capacity(&ccb->csio, 
 2905                            /*retries*/ 1,
 2906                            cddone,
 2907                            MSG_SIMPLE_Q_TAG,
 2908                            rcap_buf,
 2909                            SSD_FULL_SIZE,
 2910                            /* timeout */20000);
 2911 
 2912         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 2913                          /*sense_flags*/SF_RETRY_UA|SF_NO_PRINT);
 2914 
 2915         xpt_release_ccb(ccb);
 2916 
 2917         softc->params.disksize = scsi_4btoul(rcap_buf->addr) + 1;
 2918         softc->params.blksize  = scsi_4btoul(rcap_buf->length);
 2919         /*
 2920          * SCSI-3 mandates that the reported blocksize shall be 2048.
 2921          * Older drives sometimes report funny values, trim it down to
 2922          * 2048, or other parts of the kernel will get confused.
 2923          *
 2924          * XXX we leave drives alone that might report 512 bytes, as
 2925          * well as drives reporting more weird sizes like perhaps 4K.
 2926          */
 2927         if (softc->params.blksize > 2048 && softc->params.blksize <= 2352)
 2928                 softc->params.blksize = 2048;
 2929 
 2930         free(rcap_buf, M_SCSICD);
 2931         *size = softc->params.disksize;
 2932 
 2933         return (error);
 2934 
 2935 }
 2936 
 2937 static int
 2938 cd6byteworkaround(union ccb *ccb)
 2939 {
 2940         u_int8_t *cdb;
 2941         struct cam_periph *periph;
 2942         struct cd_softc *softc;
 2943         struct cd_mode_params *params;
 2944         int frozen, found;
 2945 
 2946         periph = xpt_path_periph(ccb->ccb_h.path);
 2947         softc = (struct cd_softc *)periph->softc;
 2948 
 2949         cdb = ccb->csio.cdb_io.cdb_bytes;
 2950 
 2951         if ((ccb->ccb_h.flags & CAM_CDB_POINTER)
 2952          || ((cdb[0] != MODE_SENSE_6)
 2953           && (cdb[0] != MODE_SELECT_6)))
 2954                 return (0);
 2955 
 2956         /*
 2957          * Because there is no convenient place to stash the overall
 2958          * cd_mode_params structure pointer, we have to grab it like this.
 2959          * This means that ALL MODE_SENSE and MODE_SELECT requests in the
 2960          * cd(4) driver MUST go through cdgetmode() and cdsetmode()!
 2961          *
 2962          * XXX It would be nice if, at some point, we could increase the
 2963          * number of available peripheral private pointers.  Both pointers
 2964          * are currently used in most every peripheral driver.
 2965          */
 2966         found = 0;
 2967 
 2968         STAILQ_FOREACH(params, &softc->mode_queue, links) {
 2969                 if (params->mode_buf == ccb->csio.data_ptr) {
 2970                         found = 1;
 2971                         break;
 2972                 }
 2973         }
 2974 
 2975         /*
 2976          * This shouldn't happen.  All mode sense and mode select
 2977          * operations in the cd(4) driver MUST go through cdgetmode() and
 2978          * cdsetmode()!
 2979          */
 2980         if (found == 0) {
 2981                 xpt_print(periph->path,
 2982                     "mode buffer not found in mode queue!\n");
 2983                 return (0);
 2984         }
 2985 
 2986         params->cdb_size = 10;
 2987         softc->minimum_command_size = 10;
 2988         xpt_print(ccb->ccb_h.path,
 2989             "%s(6) failed, increasing minimum CDB size to 10 bytes\n",
 2990             (cdb[0] == MODE_SENSE_6) ? "MODE_SENSE" : "MODE_SELECT");
 2991 
 2992         if (cdb[0] == MODE_SENSE_6) {
 2993                 struct scsi_mode_sense_10 ms10;
 2994                 struct scsi_mode_sense_6 *ms6;
 2995                 int len;
 2996 
 2997                 ms6 = (struct scsi_mode_sense_6 *)cdb;
 2998 
 2999                 bzero(&ms10, sizeof(ms10));
 3000                 ms10.opcode = MODE_SENSE_10;
 3001                 ms10.byte2 = ms6->byte2;
 3002                 ms10.page = ms6->page;
 3003 
 3004                 /*
 3005                  * 10 byte mode header, block descriptor,
 3006                  * sizeof(union cd_pages)
 3007                  */
 3008                 len = sizeof(struct cd_mode_data_10);
 3009                 ccb->csio.dxfer_len = len;
 3010 
 3011                 scsi_ulto2b(len, ms10.length);
 3012                 ms10.control = ms6->control;
 3013                 bcopy(&ms10, cdb, 10);
 3014                 ccb->csio.cdb_len = 10;
 3015         } else {
 3016                 struct scsi_mode_select_10 ms10;
 3017                 struct scsi_mode_select_6 *ms6;
 3018                 struct scsi_mode_header_6 *header6;
 3019                 struct scsi_mode_header_10 *header10;
 3020                 struct scsi_mode_page_header *page_header;
 3021                 int blk_desc_len, page_num, page_size, len;
 3022 
 3023                 ms6 = (struct scsi_mode_select_6 *)cdb;
 3024 
 3025                 bzero(&ms10, sizeof(ms10));
 3026                 ms10.opcode = MODE_SELECT_10;
 3027                 ms10.byte2 = ms6->byte2;
 3028 
 3029                 header6 = (struct scsi_mode_header_6 *)params->mode_buf;
 3030                 header10 = (struct scsi_mode_header_10 *)params->mode_buf;
 3031 
 3032                 page_header = find_mode_page_6(header6);
 3033                 page_num = page_header->page_code;
 3034 
 3035                 blk_desc_len = header6->blk_desc_len;
 3036 
 3037                 page_size = cdgetpagesize(page_num);
 3038 
 3039                 if (page_size != (page_header->page_length +
 3040                     sizeof(*page_header)))
 3041                         page_size = page_header->page_length +
 3042                                 sizeof(*page_header);
 3043 
 3044                 len = sizeof(*header10) + blk_desc_len + page_size;
 3045 
 3046                 len = min(params->alloc_len, len);
 3047 
 3048                 /*
 3049                  * Since the 6 byte parameter header is shorter than the 10
 3050                  * byte parameter header, we need to copy the actual mode
 3051                  * page data, and the block descriptor, if any, so things wind
 3052                  * up in the right place.  The regions will overlap, but
 3053                  * bcopy() does the right thing.
 3054                  */
 3055                 bcopy(params->mode_buf + sizeof(*header6),
 3056                       params->mode_buf + sizeof(*header10),
 3057                       len - sizeof(*header10));
 3058 
 3059                 /* Make sure these fields are set correctly. */
 3060                 scsi_ulto2b(0, header10->data_length);
 3061                 header10->medium_type = 0;
 3062                 scsi_ulto2b(blk_desc_len, header10->blk_desc_len);
 3063 
 3064                 ccb->csio.dxfer_len = len;
 3065 
 3066                 scsi_ulto2b(len, ms10.length);
 3067                 ms10.control = ms6->control;
 3068                 bcopy(&ms10, cdb, 10);
 3069                 ccb->csio.cdb_len = 10;
 3070         }
 3071 
 3072         frozen = (ccb->ccb_h.status & CAM_DEV_QFRZN) != 0;
 3073         ccb->ccb_h.status = CAM_REQUEUE_REQ;
 3074         xpt_action(ccb);
 3075         if (frozen) {
 3076                 cam_release_devq(ccb->ccb_h.path,
 3077                                  /*relsim_flags*/0,
 3078                                  /*openings*/0,
 3079                                  /*timeout*/0,
 3080                                  /*getcount_only*/0);
 3081         }
 3082 
 3083         return (ERESTART);
 3084 }
 3085 
 3086 static int
 3087 cderror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
 3088 {
 3089         struct cd_softc *softc;
 3090         struct cam_periph *periph;
 3091         int error;
 3092 
 3093         periph = xpt_path_periph(ccb->ccb_h.path);
 3094         softc = (struct cd_softc *)periph->softc;
 3095 
 3096         error = 0;
 3097 
 3098         /*
 3099          * We use a status of CAM_REQ_INVALID as shorthand -- if a 6 byte
 3100          * CDB comes back with this particular error, try transforming it
 3101          * into the 10 byte version.
 3102          */
 3103         if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INVALID) {
 3104                 error = cd6byteworkaround(ccb);
 3105         } else if (((ccb->ccb_h.status & CAM_STATUS_MASK) ==
 3106                      CAM_SCSI_STATUS_ERROR)
 3107          && (ccb->ccb_h.status & CAM_AUTOSNS_VALID)
 3108          && (ccb->csio.scsi_status == SCSI_STATUS_CHECK_COND)
 3109          && ((ccb->ccb_h.flags & CAM_SENSE_PHYS) == 0)
 3110          && ((ccb->ccb_h.flags & CAM_SENSE_PTR) == 0)) {
 3111                 int sense_key, error_code, asc, ascq;
 3112 
 3113                 scsi_extract_sense(&ccb->csio.sense_data,
 3114                                    &error_code, &sense_key, &asc, &ascq);
 3115                 if (sense_key == SSD_KEY_ILLEGAL_REQUEST)
 3116                         error = cd6byteworkaround(ccb);
 3117         }
 3118 
 3119         if (error == ERESTART)
 3120                 return (error);
 3121 
 3122         /*
 3123          * XXX
 3124          * Until we have a better way of doing pack validation,
 3125          * don't treat UAs as errors.
 3126          */
 3127         sense_flags |= SF_RETRY_UA;
 3128         return (cam_periph_error(ccb, cam_flags, sense_flags, 
 3129                                  &softc->saved_ccb));
 3130 }
 3131 
 3132 /*
 3133  * Read table of contents
 3134  */
 3135 static int 
 3136 cdreadtoc(struct cam_periph *periph, u_int32_t mode, u_int32_t start, 
 3137           u_int8_t *data, u_int32_t len, u_int32_t sense_flags)
 3138 {
 3139         struct scsi_read_toc *scsi_cmd;
 3140         u_int32_t ntoc;
 3141         struct ccb_scsiio *csio;
 3142         union ccb *ccb;
 3143         int error;
 3144 
 3145         ntoc = len;
 3146         error = 0;
 3147 
 3148         ccb = cdgetccb(periph, /* priority */ 1);
 3149 
 3150         csio = &ccb->csio;
 3151 
 3152         cam_fill_csio(csio, 
 3153                       /* retries */ 1, 
 3154                       /* cbfcnp */ cddone, 
 3155                       /* flags */ CAM_DIR_IN,
 3156                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 3157                       /* data_ptr */ data,
 3158                       /* dxfer_len */ len,
 3159                       /* sense_len */ SSD_FULL_SIZE,
 3160                       sizeof(struct scsi_read_toc),
 3161                       /* timeout */ 50000);
 3162 
 3163         scsi_cmd = (struct scsi_read_toc *)&csio->cdb_io.cdb_bytes;
 3164         bzero (scsi_cmd, sizeof(*scsi_cmd));
 3165 
 3166         if (mode == CD_MSF_FORMAT)
 3167                 scsi_cmd->byte2 |= CD_MSF;
 3168         scsi_cmd->from_track = start;
 3169         /* scsi_ulto2b(ntoc, (u_int8_t *)scsi_cmd->data_len); */
 3170         scsi_cmd->data_len[0] = (ntoc) >> 8;
 3171         scsi_cmd->data_len[1] = (ntoc) & 0xff;
 3172 
 3173         scsi_cmd->op_code = READ_TOC;
 3174 
 3175         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3176                          /*sense_flags*/SF_RETRY_UA | sense_flags);
 3177 
 3178         xpt_release_ccb(ccb);
 3179 
 3180         return(error);
 3181 }
 3182 
 3183 static int
 3184 cdreadsubchannel(struct cam_periph *periph, u_int32_t mode, 
 3185                  u_int32_t format, int track, 
 3186                  struct cd_sub_channel_info *data, u_int32_t len) 
 3187 {
 3188         struct scsi_read_subchannel *scsi_cmd;
 3189         struct ccb_scsiio *csio;
 3190         union ccb *ccb;
 3191         int error;
 3192 
 3193         error = 0;
 3194 
 3195         ccb = cdgetccb(periph, /* priority */ 1);
 3196 
 3197         csio = &ccb->csio;
 3198 
 3199         cam_fill_csio(csio, 
 3200                       /* retries */ 1, 
 3201                       /* cbfcnp */ cddone, 
 3202                       /* flags */ CAM_DIR_IN,
 3203                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 3204                       /* data_ptr */ (u_int8_t *)data,
 3205                       /* dxfer_len */ len,
 3206                       /* sense_len */ SSD_FULL_SIZE,
 3207                       sizeof(struct scsi_read_subchannel),
 3208                       /* timeout */ 50000);
 3209 
 3210         scsi_cmd = (struct scsi_read_subchannel *)&csio->cdb_io.cdb_bytes;
 3211         bzero (scsi_cmd, sizeof(*scsi_cmd));
 3212 
 3213         scsi_cmd->op_code = READ_SUBCHANNEL;
 3214         if (mode == CD_MSF_FORMAT)
 3215                 scsi_cmd->byte1 |= CD_MSF;
 3216         scsi_cmd->byte2 = SRS_SUBQ;
 3217         scsi_cmd->subchan_format = format;
 3218         scsi_cmd->track = track;
 3219         scsi_ulto2b(len, (u_int8_t *)scsi_cmd->data_len);
 3220         scsi_cmd->control = 0;
 3221 
 3222         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3223                          /*sense_flags*/SF_RETRY_UA);
 3224 
 3225         xpt_release_ccb(ccb);
 3226 
 3227         return(error);
 3228 }
 3229 
 3230 
 3231 /*
 3232  * All MODE_SENSE requests in the cd(4) driver MUST go through this
 3233  * routine.  See comments in cd6byteworkaround() for details.
 3234  */
 3235 static int
 3236 cdgetmode(struct cam_periph *periph, struct cd_mode_params *data,
 3237           u_int32_t page)
 3238 {
 3239         struct ccb_scsiio *csio;
 3240         struct cd_softc *softc;
 3241         union ccb *ccb;
 3242         int param_len;
 3243         int error;
 3244 
 3245         softc = (struct cd_softc *)periph->softc;
 3246 
 3247         ccb = cdgetccb(periph, /* priority */ 1);
 3248 
 3249         csio = &ccb->csio;
 3250 
 3251         data->cdb_size = softc->minimum_command_size;
 3252         if (data->cdb_size < 10)
 3253                 param_len = sizeof(struct cd_mode_data);
 3254         else
 3255                 param_len = sizeof(struct cd_mode_data_10);
 3256 
 3257         /* Don't say we've got more room than we actually allocated */
 3258         param_len = min(param_len, data->alloc_len);
 3259 
 3260         scsi_mode_sense_len(csio,
 3261                             /* retries */ 1,
 3262                             /* cbfcnp */ cddone,
 3263                             /* tag_action */ MSG_SIMPLE_Q_TAG,
 3264                             /* dbd */ 0,
 3265                             /* page_code */ SMS_PAGE_CTRL_CURRENT,
 3266                             /* page */ page,
 3267                             /* param_buf */ data->mode_buf,
 3268                             /* param_len */ param_len,
 3269                             /* minimum_cmd_size */ softc->minimum_command_size,
 3270                             /* sense_len */ SSD_FULL_SIZE,
 3271                             /* timeout */ 50000);
 3272 
 3273         /*
 3274          * It would be nice not to have to do this, but there's no
 3275          * available pointer in the CCB that would allow us to stuff the
 3276          * mode params structure in there and retrieve it in
 3277          * cd6byteworkaround(), so we can set the cdb size.  The cdb size
 3278          * lets the caller know what CDB size we ended up using, so they
 3279          * can find the actual mode page offset.
 3280          */
 3281         STAILQ_INSERT_TAIL(&softc->mode_queue, data, links);
 3282 
 3283         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3284                          /*sense_flags*/SF_RETRY_UA);
 3285 
 3286         xpt_release_ccb(ccb);
 3287 
 3288         STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links);
 3289 
 3290         /*
 3291          * This is a bit of belt-and-suspenders checking, but if we run
 3292          * into a situation where the target sends back multiple block
 3293          * descriptors, we might not have enough space in the buffer to
 3294          * see the whole mode page.  Better to return an error than
 3295          * potentially access memory beyond our malloced region.
 3296          */
 3297         if (error == 0) {
 3298                 u_int32_t data_len;
 3299 
 3300                 if (data->cdb_size == 10) {
 3301                         struct scsi_mode_header_10 *hdr10;
 3302 
 3303                         hdr10 = (struct scsi_mode_header_10 *)data->mode_buf;
 3304                         data_len = scsi_2btoul(hdr10->data_length);
 3305                         data_len += sizeof(hdr10->data_length);
 3306                 } else {
 3307                         struct scsi_mode_header_6 *hdr6;
 3308 
 3309                         hdr6 = (struct scsi_mode_header_6 *)data->mode_buf;
 3310                         data_len = hdr6->data_length;
 3311                         data_len += sizeof(hdr6->data_length);
 3312                 }
 3313 
 3314                 /*
 3315                  * Complain if there is more mode data available than we
 3316                  * allocated space for.  This could potentially happen if
 3317                  * we miscalculated the page length for some reason, if the
 3318                  * drive returns multiple block descriptors, or if it sets
 3319                  * the data length incorrectly.
 3320                  */
 3321                 if (data_len > data->alloc_len) {
 3322                         xpt_print(periph->path, "allocated modepage %d length "
 3323                             "%d < returned length %d\n", page, data->alloc_len,
 3324                             data_len);
 3325                         error = ENOSPC;
 3326                 }
 3327         }
 3328         return (error);
 3329 }
 3330 
 3331 /*
 3332  * All MODE_SELECT requests in the cd(4) driver MUST go through this
 3333  * routine.  See comments in cd6byteworkaround() for details.
 3334  */
 3335 static int
 3336 cdsetmode(struct cam_periph *periph, struct cd_mode_params *data)
 3337 {
 3338         struct ccb_scsiio *csio;
 3339         struct cd_softc *softc;
 3340         union ccb *ccb;
 3341         int cdb_size, param_len;
 3342         int error;
 3343 
 3344         softc = (struct cd_softc *)periph->softc;
 3345 
 3346         ccb = cdgetccb(periph, /* priority */ 1);
 3347 
 3348         csio = &ccb->csio;
 3349 
 3350         error = 0;
 3351 
 3352         /*
 3353          * If the data is formatted for the 10 byte version of the mode
 3354          * select parameter list, we need to use the 10 byte CDB.
 3355          * Otherwise, we use whatever the stored minimum command size.
 3356          */
 3357         if (data->cdb_size == 10)
 3358                 cdb_size = data->cdb_size;
 3359         else
 3360                 cdb_size = softc->minimum_command_size;
 3361 
 3362         if (cdb_size >= 10) {
 3363                 struct scsi_mode_header_10 *mode_header;
 3364                 u_int32_t data_len;
 3365 
 3366                 mode_header = (struct scsi_mode_header_10 *)data->mode_buf;
 3367 
 3368                 data_len = scsi_2btoul(mode_header->data_length);
 3369 
 3370                 scsi_ulto2b(0, mode_header->data_length);
 3371                 /*
 3372                  * SONY drives do not allow a mode select with a medium_type
 3373                  * value that has just been returned by a mode sense; use a
 3374                  * medium_type of 0 (Default) instead.
 3375                  */
 3376                 mode_header->medium_type = 0;
 3377 
 3378                 /*
 3379                  * Pass back whatever the drive passed to us, plus the size
 3380                  * of the data length field.
 3381                  */
 3382                 param_len = data_len + sizeof(mode_header->data_length);
 3383 
 3384         } else {
 3385                 struct scsi_mode_header_6 *mode_header;
 3386 
 3387                 mode_header = (struct scsi_mode_header_6 *)data->mode_buf;
 3388 
 3389                 param_len = mode_header->data_length + 1;
 3390 
 3391                 mode_header->data_length = 0;
 3392                 /*
 3393                  * SONY drives do not allow a mode select with a medium_type
 3394                  * value that has just been returned by a mode sense; use a
 3395                  * medium_type of 0 (Default) instead.
 3396                  */
 3397                 mode_header->medium_type = 0;
 3398         }
 3399 
 3400         /* Don't say we've got more room than we actually allocated */
 3401         param_len = min(param_len, data->alloc_len);
 3402 
 3403         scsi_mode_select_len(csio,
 3404                              /* retries */ 1,
 3405                              /* cbfcnp */ cddone,
 3406                              /* tag_action */ MSG_SIMPLE_Q_TAG,
 3407                              /* scsi_page_fmt */ 1,
 3408                              /* save_pages */ 0,
 3409                              /* param_buf */ data->mode_buf,
 3410                              /* param_len */ param_len,
 3411                              /* minimum_cmd_size */ cdb_size,
 3412                              /* sense_len */ SSD_FULL_SIZE,
 3413                              /* timeout */ 50000);
 3414 
 3415         /* See comments in cdgetmode() and cd6byteworkaround(). */
 3416         STAILQ_INSERT_TAIL(&softc->mode_queue, data, links);
 3417 
 3418         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3419                          /*sense_flags*/SF_RETRY_UA);
 3420 
 3421         xpt_release_ccb(ccb);
 3422 
 3423         STAILQ_REMOVE(&softc->mode_queue, data, cd_mode_params, links);
 3424 
 3425         return (error);
 3426 }
 3427 
 3428 
 3429 static int 
 3430 cdplay(struct cam_periph *periph, u_int32_t blk, u_int32_t len)
 3431 {
 3432         struct ccb_scsiio *csio;
 3433         union ccb *ccb;
 3434         int error;
 3435         u_int8_t cdb_len;
 3436 
 3437         error = 0;
 3438         ccb = cdgetccb(periph, /* priority */ 1);
 3439         csio = &ccb->csio;
 3440         /*
 3441          * Use the smallest possible command to perform the operation.
 3442          */
 3443         if ((len & 0xffff0000) == 0) {
 3444                 /*
 3445                  * We can fit in a 10 byte cdb.
 3446                  */
 3447                 struct scsi_play_10 *scsi_cmd;
 3448 
 3449                 scsi_cmd = (struct scsi_play_10 *)&csio->cdb_io.cdb_bytes;
 3450                 bzero (scsi_cmd, sizeof(*scsi_cmd));
 3451                 scsi_cmd->op_code = PLAY_10;
 3452                 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
 3453                 scsi_ulto2b(len, (u_int8_t *)scsi_cmd->xfer_len);
 3454                 cdb_len = sizeof(*scsi_cmd);
 3455         } else  {
 3456                 struct scsi_play_12 *scsi_cmd;
 3457 
 3458                 scsi_cmd = (struct scsi_play_12 *)&csio->cdb_io.cdb_bytes;
 3459                 bzero (scsi_cmd, sizeof(*scsi_cmd));
 3460                 scsi_cmd->op_code = PLAY_12;
 3461                 scsi_ulto4b(blk, (u_int8_t *)scsi_cmd->blk_addr);
 3462                 scsi_ulto4b(len, (u_int8_t *)scsi_cmd->xfer_len);
 3463                 cdb_len = sizeof(*scsi_cmd);
 3464         }
 3465         cam_fill_csio(csio,
 3466                       /*retries*/2,
 3467                       cddone,
 3468                       /*flags*/CAM_DIR_NONE,
 3469                       MSG_SIMPLE_Q_TAG,
 3470                       /*dataptr*/NULL,
 3471                       /*datalen*/0,
 3472                       /*sense_len*/SSD_FULL_SIZE,
 3473                       cdb_len,
 3474                       /*timeout*/50 * 1000);
 3475 
 3476         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3477                          /*sense_flags*/SF_RETRY_UA);
 3478 
 3479         xpt_release_ccb(ccb);
 3480 
 3481         return(error);
 3482 }
 3483 
 3484 static int
 3485 cdplaymsf(struct cam_periph *periph, u_int32_t startm, u_int32_t starts,
 3486           u_int32_t startf, u_int32_t endm, u_int32_t ends, u_int32_t endf)
 3487 {
 3488         struct scsi_play_msf *scsi_cmd;
 3489         struct ccb_scsiio *csio;
 3490         union ccb *ccb;
 3491         int error;
 3492 
 3493         error = 0;
 3494 
 3495         ccb = cdgetccb(periph, /* priority */ 1);
 3496 
 3497         csio = &ccb->csio;
 3498 
 3499         cam_fill_csio(csio, 
 3500                       /* retries */ 1, 
 3501                       /* cbfcnp */ cddone, 
 3502                       /* flags */ CAM_DIR_NONE,
 3503                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 3504                       /* data_ptr */ NULL,
 3505                       /* dxfer_len */ 0,
 3506                       /* sense_len */ SSD_FULL_SIZE,
 3507                       sizeof(struct scsi_play_msf),
 3508                       /* timeout */ 50000);
 3509 
 3510         scsi_cmd = (struct scsi_play_msf *)&csio->cdb_io.cdb_bytes;
 3511         bzero (scsi_cmd, sizeof(*scsi_cmd));
 3512 
 3513         scsi_cmd->op_code = PLAY_MSF;
 3514         scsi_cmd->start_m = startm;
 3515         scsi_cmd->start_s = starts;
 3516         scsi_cmd->start_f = startf;
 3517         scsi_cmd->end_m = endm;
 3518         scsi_cmd->end_s = ends;
 3519         scsi_cmd->end_f = endf; 
 3520 
 3521         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3522                          /*sense_flags*/SF_RETRY_UA);
 3523         
 3524         xpt_release_ccb(ccb);
 3525 
 3526         return(error);
 3527 }
 3528 
 3529 
 3530 static int
 3531 cdplaytracks(struct cam_periph *periph, u_int32_t strack, u_int32_t sindex,
 3532              u_int32_t etrack, u_int32_t eindex)
 3533 {
 3534         struct scsi_play_track *scsi_cmd;
 3535         struct ccb_scsiio *csio;
 3536         union ccb *ccb;
 3537         int error;
 3538 
 3539         error = 0;
 3540 
 3541         ccb = cdgetccb(periph, /* priority */ 1);
 3542 
 3543         csio = &ccb->csio;
 3544 
 3545         cam_fill_csio(csio, 
 3546                       /* retries */ 1, 
 3547                       /* cbfcnp */ cddone, 
 3548                       /* flags */ CAM_DIR_NONE,
 3549                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 3550                       /* data_ptr */ NULL,
 3551                       /* dxfer_len */ 0,
 3552                       /* sense_len */ SSD_FULL_SIZE,
 3553                       sizeof(struct scsi_play_track),
 3554                       /* timeout */ 50000);
 3555 
 3556         scsi_cmd = (struct scsi_play_track *)&csio->cdb_io.cdb_bytes;
 3557         bzero (scsi_cmd, sizeof(*scsi_cmd));
 3558 
 3559         scsi_cmd->op_code = PLAY_TRACK;
 3560         scsi_cmd->start_track = strack;
 3561         scsi_cmd->start_index = sindex;
 3562         scsi_cmd->end_track = etrack;
 3563         scsi_cmd->end_index = eindex;
 3564 
 3565         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3566                          /*sense_flags*/SF_RETRY_UA);
 3567 
 3568         xpt_release_ccb(ccb);
 3569 
 3570         return(error);
 3571 }
 3572 
 3573 static int
 3574 cdpause(struct cam_periph *periph, u_int32_t go)
 3575 {
 3576         struct scsi_pause *scsi_cmd;
 3577         struct ccb_scsiio *csio;
 3578         union ccb *ccb;
 3579         int error;
 3580 
 3581         error = 0;
 3582 
 3583         ccb = cdgetccb(periph, /* priority */ 1);
 3584 
 3585         csio = &ccb->csio;
 3586 
 3587         cam_fill_csio(csio, 
 3588                       /* retries */ 1, 
 3589                       /* cbfcnp */ cddone, 
 3590                       /* flags */ CAM_DIR_NONE,
 3591                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 3592                       /* data_ptr */ NULL,
 3593                       /* dxfer_len */ 0,
 3594                       /* sense_len */ SSD_FULL_SIZE,
 3595                       sizeof(struct scsi_pause),
 3596                       /* timeout */ 50000);
 3597 
 3598         scsi_cmd = (struct scsi_pause *)&csio->cdb_io.cdb_bytes;
 3599         bzero (scsi_cmd, sizeof(*scsi_cmd));
 3600 
 3601         scsi_cmd->op_code = PAUSE;
 3602         scsi_cmd->resume = go;
 3603 
 3604         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3605                          /*sense_flags*/SF_RETRY_UA);
 3606 
 3607         xpt_release_ccb(ccb);
 3608 
 3609         return(error);
 3610 }
 3611 
 3612 static int
 3613 cdstartunit(struct cam_periph *periph, int load)
 3614 {
 3615         union ccb *ccb;
 3616         int error;
 3617 
 3618         error = 0;
 3619 
 3620         ccb = cdgetccb(periph, /* priority */ 1);
 3621 
 3622         scsi_start_stop(&ccb->csio,
 3623                         /* retries */ 1,
 3624                         /* cbfcnp */ cddone,
 3625                         /* tag_action */ MSG_SIMPLE_Q_TAG,
 3626                         /* start */ TRUE,
 3627                         /* load_eject */ load,
 3628                         /* immediate */ FALSE,
 3629                         /* sense_len */ SSD_FULL_SIZE,
 3630                         /* timeout */ 50000);
 3631 
 3632         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3633                          /*sense_flags*/SF_RETRY_UA);
 3634 
 3635         xpt_release_ccb(ccb);
 3636 
 3637         return(error);
 3638 }
 3639 
 3640 static int
 3641 cdstopunit(struct cam_periph *periph, u_int32_t eject)
 3642 {
 3643         union ccb *ccb;
 3644         int error;
 3645 
 3646         error = 0;
 3647 
 3648         ccb = cdgetccb(periph, /* priority */ 1);
 3649 
 3650         scsi_start_stop(&ccb->csio,
 3651                         /* retries */ 1,
 3652                         /* cbfcnp */ cddone,
 3653                         /* tag_action */ MSG_SIMPLE_Q_TAG,
 3654                         /* start */ FALSE,
 3655                         /* load_eject */ eject,
 3656                         /* immediate */ FALSE,
 3657                         /* sense_len */ SSD_FULL_SIZE,
 3658                         /* timeout */ 50000);
 3659 
 3660         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3661                          /*sense_flags*/SF_RETRY_UA);
 3662 
 3663         xpt_release_ccb(ccb);
 3664 
 3665         return(error);
 3666 }
 3667 
 3668 static int
 3669 cdsetspeed(struct cam_periph *periph, u_int32_t rdspeed, u_int32_t wrspeed)
 3670 {
 3671         struct scsi_set_speed *scsi_cmd;
 3672         struct ccb_scsiio *csio;
 3673         union ccb *ccb;
 3674         int error;
 3675 
 3676         error = 0;
 3677         ccb = cdgetccb(periph, /* priority */ 1);
 3678         csio = &ccb->csio;
 3679 
 3680         /* Preserve old behavior: units in multiples of CDROM speed */
 3681         if (rdspeed < 177)
 3682                 rdspeed *= 177;
 3683         if (wrspeed < 177)
 3684                 wrspeed *= 177;
 3685 
 3686         cam_fill_csio(csio,
 3687                       /* retries */ 1,
 3688                       /* cbfcnp */ cddone,
 3689                       /* flags */ CAM_DIR_NONE,
 3690                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 3691                       /* data_ptr */ NULL,
 3692                       /* dxfer_len */ 0,
 3693                       /* sense_len */ SSD_FULL_SIZE,
 3694                       sizeof(struct scsi_set_speed),
 3695                       /* timeout */ 50000);
 3696 
 3697         scsi_cmd = (struct scsi_set_speed *)&csio->cdb_io.cdb_bytes;
 3698         bzero(scsi_cmd, sizeof(*scsi_cmd));
 3699 
 3700         scsi_cmd->opcode = SET_CD_SPEED;
 3701         scsi_ulto2b(rdspeed, scsi_cmd->readspeed);
 3702         scsi_ulto2b(wrspeed, scsi_cmd->writespeed);
 3703 
 3704         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3705                          /*sense_flags*/SF_RETRY_UA);
 3706 
 3707         xpt_release_ccb(ccb);
 3708 
 3709         return(error);
 3710 }
 3711 
 3712 static int
 3713 cdreportkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
 3714 {
 3715         union ccb *ccb;
 3716         u_int8_t *databuf;
 3717         u_int32_t lba;
 3718         int error;
 3719         int length;
 3720 
 3721         error = 0;
 3722         databuf = NULL;
 3723         lba = 0;
 3724 
 3725         ccb = cdgetccb(periph, /* priority */ 1);
 3726 
 3727         switch (authinfo->format) {
 3728         case DVD_REPORT_AGID:
 3729                 length = sizeof(struct scsi_report_key_data_agid);
 3730                 break;
 3731         case DVD_REPORT_CHALLENGE:
 3732                 length = sizeof(struct scsi_report_key_data_challenge);
 3733                 break;
 3734         case DVD_REPORT_KEY1:
 3735                 length = sizeof(struct scsi_report_key_data_key1_key2);
 3736                 break;
 3737         case DVD_REPORT_TITLE_KEY:
 3738                 length = sizeof(struct scsi_report_key_data_title);
 3739                 /* The lba field is only set for the title key */
 3740                 lba = authinfo->lba;
 3741                 break;
 3742         case DVD_REPORT_ASF:
 3743                 length = sizeof(struct scsi_report_key_data_asf);
 3744                 break;
 3745         case DVD_REPORT_RPC:
 3746                 length = sizeof(struct scsi_report_key_data_rpc);
 3747                 break;
 3748         case DVD_INVALIDATE_AGID:
 3749                 length = 0;
 3750                 break;
 3751         default:
 3752                 error = EINVAL;
 3753                 goto bailout;
 3754                 break; /* NOTREACHED */
 3755         }
 3756 
 3757         if (length != 0) {
 3758                 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 3759         } else
 3760                 databuf = NULL;
 3761 
 3762 
 3763         scsi_report_key(&ccb->csio,
 3764                         /* retries */ 1,
 3765                         /* cbfcnp */ cddone,
 3766                         /* tag_action */ MSG_SIMPLE_Q_TAG,
 3767                         /* lba */ lba,
 3768                         /* agid */ authinfo->agid,
 3769                         /* key_format */ authinfo->format,
 3770                         /* data_ptr */ databuf,
 3771                         /* dxfer_len */ length,
 3772                         /* sense_len */ SSD_FULL_SIZE,
 3773                         /* timeout */ 50000);
 3774 
 3775         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3776                          /*sense_flags*/SF_RETRY_UA);
 3777 
 3778         if (error != 0)
 3779                 goto bailout;
 3780 
 3781         if (ccb->csio.resid != 0) {
 3782                 xpt_print(periph->path, "warning, residual for report key "
 3783                     "command is %d\n", ccb->csio.resid);
 3784         }
 3785 
 3786         switch(authinfo->format) {
 3787         case DVD_REPORT_AGID: {
 3788                 struct scsi_report_key_data_agid *agid_data;
 3789 
 3790                 agid_data = (struct scsi_report_key_data_agid *)databuf;
 3791 
 3792                 authinfo->agid = (agid_data->agid & RKD_AGID_MASK) >>
 3793                         RKD_AGID_SHIFT;
 3794                 break;
 3795         }
 3796         case DVD_REPORT_CHALLENGE: {
 3797                 struct scsi_report_key_data_challenge *chal_data;
 3798 
 3799                 chal_data = (struct scsi_report_key_data_challenge *)databuf;
 3800 
 3801                 bcopy(chal_data->challenge_key, authinfo->keychal,
 3802                       min(sizeof(chal_data->challenge_key),
 3803                           sizeof(authinfo->keychal)));
 3804                 break;
 3805         }
 3806         case DVD_REPORT_KEY1: {
 3807                 struct scsi_report_key_data_key1_key2 *key1_data;
 3808 
 3809                 key1_data = (struct scsi_report_key_data_key1_key2 *)databuf;
 3810 
 3811                 bcopy(key1_data->key1, authinfo->keychal,
 3812                       min(sizeof(key1_data->key1), sizeof(authinfo->keychal)));
 3813                 break;
 3814         }
 3815         case DVD_REPORT_TITLE_KEY: {
 3816                 struct scsi_report_key_data_title *title_data;
 3817 
 3818                 title_data = (struct scsi_report_key_data_title *)databuf;
 3819 
 3820                 authinfo->cpm = (title_data->byte0 & RKD_TITLE_CPM) >>
 3821                         RKD_TITLE_CPM_SHIFT;
 3822                 authinfo->cp_sec = (title_data->byte0 & RKD_TITLE_CP_SEC) >>
 3823                         RKD_TITLE_CP_SEC_SHIFT;
 3824                 authinfo->cgms = (title_data->byte0 & RKD_TITLE_CMGS_MASK) >>
 3825                         RKD_TITLE_CMGS_SHIFT;
 3826                 bcopy(title_data->title_key, authinfo->keychal,
 3827                       min(sizeof(title_data->title_key),
 3828                           sizeof(authinfo->keychal)));
 3829                 break;
 3830         }
 3831         case DVD_REPORT_ASF: {
 3832                 struct scsi_report_key_data_asf *asf_data;
 3833 
 3834                 asf_data = (struct scsi_report_key_data_asf *)databuf;
 3835 
 3836                 authinfo->asf = asf_data->success & RKD_ASF_SUCCESS;
 3837                 break;
 3838         }
 3839         case DVD_REPORT_RPC: {
 3840                 struct scsi_report_key_data_rpc *rpc_data;
 3841 
 3842                 rpc_data = (struct scsi_report_key_data_rpc *)databuf;
 3843 
 3844                 authinfo->reg_type = (rpc_data->byte4 & RKD_RPC_TYPE_MASK) >>
 3845                         RKD_RPC_TYPE_SHIFT;
 3846                 authinfo->vend_rsts =
 3847                         (rpc_data->byte4 & RKD_RPC_VENDOR_RESET_MASK) >>
 3848                         RKD_RPC_VENDOR_RESET_SHIFT;
 3849                 authinfo->user_rsts = rpc_data->byte4 & RKD_RPC_USER_RESET_MASK;
 3850                 authinfo->region = rpc_data->region_mask;
 3851                 authinfo->rpc_scheme = rpc_data->rpc_scheme1;
 3852                 break;
 3853         }
 3854         case DVD_INVALIDATE_AGID:
 3855                 break;
 3856         default:
 3857                 /* This should be impossible, since we checked above */
 3858                 error = EINVAL;
 3859                 goto bailout;
 3860                 break; /* NOTREACHED */
 3861         }
 3862 bailout:
 3863         if (databuf != NULL)
 3864                 free(databuf, M_DEVBUF);
 3865 
 3866         xpt_release_ccb(ccb);
 3867 
 3868         return(error);
 3869 }
 3870 
 3871 static int
 3872 cdsendkey(struct cam_periph *periph, struct dvd_authinfo *authinfo)
 3873 {
 3874         union ccb *ccb;
 3875         u_int8_t *databuf;
 3876         int length;
 3877         int error;
 3878 
 3879         error = 0;
 3880         databuf = NULL;
 3881 
 3882         ccb = cdgetccb(periph, /* priority */ 1);
 3883 
 3884         switch(authinfo->format) {
 3885         case DVD_SEND_CHALLENGE: {
 3886                 struct scsi_report_key_data_challenge *challenge_data;
 3887 
 3888                 length = sizeof(*challenge_data);
 3889 
 3890                 challenge_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 3891 
 3892                 databuf = (u_int8_t *)challenge_data;
 3893 
 3894                 scsi_ulto2b(length - sizeof(challenge_data->data_len),
 3895                             challenge_data->data_len);
 3896 
 3897                 bcopy(authinfo->keychal, challenge_data->challenge_key,
 3898                       min(sizeof(authinfo->keychal),
 3899                           sizeof(challenge_data->challenge_key)));
 3900                 break;
 3901         }
 3902         case DVD_SEND_KEY2: {
 3903                 struct scsi_report_key_data_key1_key2 *key2_data;
 3904 
 3905                 length = sizeof(*key2_data);
 3906 
 3907                 key2_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 3908 
 3909                 databuf = (u_int8_t *)key2_data;
 3910 
 3911                 scsi_ulto2b(length - sizeof(key2_data->data_len),
 3912                             key2_data->data_len);
 3913 
 3914                 bcopy(authinfo->keychal, key2_data->key1,
 3915                       min(sizeof(authinfo->keychal), sizeof(key2_data->key1)));
 3916 
 3917                 break;
 3918         }
 3919         case DVD_SEND_RPC: {
 3920                 struct scsi_send_key_data_rpc *rpc_data;
 3921 
 3922                 length = sizeof(*rpc_data);
 3923 
 3924                 rpc_data = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 3925 
 3926                 databuf = (u_int8_t *)rpc_data;
 3927 
 3928                 scsi_ulto2b(length - sizeof(rpc_data->data_len),
 3929                             rpc_data->data_len);
 3930 
 3931                 rpc_data->region_code = authinfo->region;
 3932                 break;
 3933         }
 3934         default:
 3935                 error = EINVAL;
 3936                 goto bailout;
 3937                 break; /* NOTREACHED */
 3938         }
 3939 
 3940         scsi_send_key(&ccb->csio,
 3941                       /* retries */ 1,
 3942                       /* cbfcnp */ cddone,
 3943                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 3944                       /* agid */ authinfo->agid,
 3945                       /* key_format */ authinfo->format,
 3946                       /* data_ptr */ databuf,
 3947                       /* dxfer_len */ length,
 3948                       /* sense_len */ SSD_FULL_SIZE,
 3949                       /* timeout */ 50000);
 3950 
 3951         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 3952                          /*sense_flags*/SF_RETRY_UA);
 3953 
 3954 bailout:
 3955 
 3956         if (databuf != NULL)
 3957                 free(databuf, M_DEVBUF);
 3958 
 3959         xpt_release_ccb(ccb);
 3960 
 3961         return(error);
 3962 }
 3963 
 3964 static int
 3965 cdreaddvdstructure(struct cam_periph *periph, struct dvd_struct *dvdstruct)
 3966 {
 3967         union ccb *ccb;
 3968         u_int8_t *databuf;
 3969         u_int32_t address;
 3970         int error;
 3971         int length;
 3972 
 3973         error = 0;
 3974         databuf = NULL;
 3975         /* The address is reserved for many of the formats */
 3976         address = 0;
 3977 
 3978         ccb = cdgetccb(periph, /* priority */ 1);
 3979 
 3980         switch(dvdstruct->format) {
 3981         case DVD_STRUCT_PHYSICAL:
 3982                 length = sizeof(struct scsi_read_dvd_struct_data_physical);
 3983                 break;
 3984         case DVD_STRUCT_COPYRIGHT:
 3985                 length = sizeof(struct scsi_read_dvd_struct_data_copyright);
 3986                 break;
 3987         case DVD_STRUCT_DISCKEY:
 3988                 length = sizeof(struct scsi_read_dvd_struct_data_disc_key);
 3989                 break;
 3990         case DVD_STRUCT_BCA:
 3991                 length = sizeof(struct scsi_read_dvd_struct_data_bca);
 3992                 break;
 3993         case DVD_STRUCT_MANUFACT:
 3994                 length = sizeof(struct scsi_read_dvd_struct_data_manufacturer);
 3995                 break;
 3996         case DVD_STRUCT_CMI:
 3997                 error = ENODEV;
 3998                 goto bailout;
 3999 #ifdef notyet
 4000                 length = sizeof(struct scsi_read_dvd_struct_data_copy_manage);
 4001                 address = dvdstruct->address;
 4002 #endif
 4003                 break; /* NOTREACHED */
 4004         case DVD_STRUCT_PROTDISCID:
 4005                 length = sizeof(struct scsi_read_dvd_struct_data_prot_discid);
 4006                 break;
 4007         case DVD_STRUCT_DISCKEYBLOCK:
 4008                 length = sizeof(struct scsi_read_dvd_struct_data_disc_key_blk);
 4009                 break;
 4010         case DVD_STRUCT_DDS:
 4011                 length = sizeof(struct scsi_read_dvd_struct_data_dds);
 4012                 break;
 4013         case DVD_STRUCT_MEDIUM_STAT:
 4014                 length = sizeof(struct scsi_read_dvd_struct_data_medium_status);
 4015                 break;
 4016         case DVD_STRUCT_SPARE_AREA:
 4017                 length = sizeof(struct scsi_read_dvd_struct_data_spare_area);
 4018                 break;
 4019         case DVD_STRUCT_RMD_LAST:
 4020                 error = ENODEV;
 4021                 goto bailout;
 4022 #ifdef notyet
 4023                 length = sizeof(struct scsi_read_dvd_struct_data_rmd_borderout);
 4024                 address = dvdstruct->address;
 4025 #endif
 4026                 break; /* NOTREACHED */
 4027         case DVD_STRUCT_RMD_RMA:
 4028                 error = ENODEV;
 4029                 goto bailout;
 4030 #ifdef notyet
 4031                 length = sizeof(struct scsi_read_dvd_struct_data_rmd);
 4032                 address = dvdstruct->address;
 4033 #endif
 4034                 break; /* NOTREACHED */
 4035         case DVD_STRUCT_PRERECORDED:
 4036                 length = sizeof(struct scsi_read_dvd_struct_data_leadin);
 4037                 break;
 4038         case DVD_STRUCT_UNIQUEID:
 4039                 length = sizeof(struct scsi_read_dvd_struct_data_disc_id);
 4040                 break;
 4041         case DVD_STRUCT_DCB:
 4042                 error = ENODEV;
 4043                 goto bailout;
 4044 #ifdef notyet
 4045                 length = sizeof(struct scsi_read_dvd_struct_data_dcb);
 4046                 address = dvdstruct->address;
 4047 #endif
 4048                 break; /* NOTREACHED */
 4049         case DVD_STRUCT_LIST:
 4050                 /*
 4051                  * This is the maximum allocation length for the READ DVD
 4052                  * STRUCTURE command.  There's nothing in the MMC3 spec
 4053                  * that indicates a limit in the amount of data that can
 4054                  * be returned from this call, other than the limits
 4055                  * imposed by the 2-byte length variables.
 4056                  */
 4057                 length = 65535;
 4058                 break;
 4059         default:
 4060                 error = EINVAL;
 4061                 goto bailout;
 4062                 break; /* NOTREACHED */
 4063         }
 4064 
 4065         if (length != 0) {
 4066                 databuf = malloc(length, M_DEVBUF, M_WAITOK | M_ZERO);
 4067         } else
 4068                 databuf = NULL;
 4069 
 4070         scsi_read_dvd_structure(&ccb->csio,
 4071                                 /* retries */ 1,
 4072                                 /* cbfcnp */ cddone,
 4073                                 /* tag_action */ MSG_SIMPLE_Q_TAG,
 4074                                 /* lba */ address,
 4075                                 /* layer_number */ dvdstruct->layer_num,
 4076                                 /* key_format */ dvdstruct->format,
 4077                                 /* agid */ dvdstruct->agid,
 4078                                 /* data_ptr */ databuf,
 4079                                 /* dxfer_len */ length,
 4080                                 /* sense_len */ SSD_FULL_SIZE,
 4081                                 /* timeout */ 50000);
 4082 
 4083         error = cdrunccb(ccb, cderror, /*cam_flags*/CAM_RETRY_SELTO,
 4084                          /*sense_flags*/SF_RETRY_UA);
 4085 
 4086         if (error != 0)
 4087                 goto bailout;
 4088 
 4089         switch(dvdstruct->format) {
 4090         case DVD_STRUCT_PHYSICAL: {
 4091                 struct scsi_read_dvd_struct_data_layer_desc *inlayer;
 4092                 struct dvd_layer *outlayer;
 4093                 struct scsi_read_dvd_struct_data_physical *phys_data;
 4094 
 4095                 phys_data =
 4096                         (struct scsi_read_dvd_struct_data_physical *)databuf;
 4097                 inlayer = &phys_data->layer_desc;
 4098                 outlayer = (struct dvd_layer *)&dvdstruct->data;
 4099 
 4100                 dvdstruct->length = sizeof(*inlayer);
 4101 
 4102                 outlayer->book_type = (inlayer->book_type_version &
 4103                         RDSD_BOOK_TYPE_MASK) >> RDSD_BOOK_TYPE_SHIFT;
 4104                 outlayer->book_version = (inlayer->book_type_version &
 4105                         RDSD_BOOK_VERSION_MASK);
 4106                 outlayer->disc_size = (inlayer->disc_size_max_rate &
 4107                         RDSD_DISC_SIZE_MASK) >> RDSD_DISC_SIZE_SHIFT;
 4108                 outlayer->max_rate = (inlayer->disc_size_max_rate &
 4109                         RDSD_MAX_RATE_MASK);
 4110                 outlayer->nlayers = (inlayer->layer_info &
 4111                         RDSD_NUM_LAYERS_MASK) >> RDSD_NUM_LAYERS_SHIFT;
 4112                 outlayer->track_path = (inlayer->layer_info &
 4113                         RDSD_TRACK_PATH_MASK) >> RDSD_TRACK_PATH_SHIFT;
 4114                 outlayer->layer_type = (inlayer->layer_info &
 4115                         RDSD_LAYER_TYPE_MASK);
 4116                 outlayer->linear_density = (inlayer->density &
 4117                         RDSD_LIN_DENSITY_MASK) >> RDSD_LIN_DENSITY_SHIFT;
 4118                 outlayer->track_density = (inlayer->density &
 4119                         RDSD_TRACK_DENSITY_MASK);
 4120                 outlayer->bca = (inlayer->bca & RDSD_BCA_MASK) >>
 4121                         RDSD_BCA_SHIFT;
 4122                 outlayer->start_sector = scsi_3btoul(inlayer->main_data_start);
 4123                 outlayer->end_sector = scsi_3btoul(inlayer->main_data_end);
 4124                 outlayer->end_sector_l0 =
 4125                         scsi_3btoul(inlayer->end_sector_layer0);
 4126                 break;
 4127         }
 4128         case DVD_STRUCT_COPYRIGHT: {
 4129                 struct scsi_read_dvd_struct_data_copyright *copy_data;
 4130 
 4131                 copy_data = (struct scsi_read_dvd_struct_data_copyright *)
 4132                         databuf;
 4133 
 4134                 dvdstruct->cpst = copy_data->cps_type;
 4135                 dvdstruct->rmi = copy_data->region_info;
 4136                 dvdstruct->length = 0;
 4137 
 4138                 break;
 4139         }
 4140         default:
 4141                 /*
 4142                  * Tell the user what the overall length is, no matter
 4143                  * what we can actually fit in the data buffer.
 4144                  */
 4145                 dvdstruct->length = length - ccb->csio.resid - 
 4146                         sizeof(struct scsi_read_dvd_struct_data_header);
 4147 
 4148                 /*
 4149                  * But only actually copy out the smaller of what we read
 4150                  * in or what the structure can take.
 4151                  */
 4152                 bcopy(databuf + sizeof(struct scsi_read_dvd_struct_data_header),
 4153                       dvdstruct->data,
 4154                       min(sizeof(dvdstruct->data), dvdstruct->length));
 4155                 break;
 4156         }
 4157 bailout:
 4158 
 4159         if (databuf != NULL)
 4160                 free(databuf, M_DEVBUF);
 4161 
 4162         xpt_release_ccb(ccb);
 4163 
 4164         return(error);
 4165 }
 4166 
 4167 void
 4168 scsi_report_key(struct ccb_scsiio *csio, u_int32_t retries,
 4169                 void (*cbfcnp)(struct cam_periph *, union ccb *),
 4170                 u_int8_t tag_action, u_int32_t lba, u_int8_t agid,
 4171                 u_int8_t key_format, u_int8_t *data_ptr, u_int32_t dxfer_len,
 4172                 u_int8_t sense_len, u_int32_t timeout)
 4173 {
 4174         struct scsi_report_key *scsi_cmd;
 4175 
 4176         scsi_cmd = (struct scsi_report_key *)&csio->cdb_io.cdb_bytes;
 4177         bzero(scsi_cmd, sizeof(*scsi_cmd));
 4178         scsi_cmd->opcode = REPORT_KEY;
 4179         scsi_ulto4b(lba, scsi_cmd->lba);
 4180         scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
 4181         scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
 4182                 (key_format & RK_KF_KEYFORMAT_MASK);
 4183 
 4184         cam_fill_csio(csio,
 4185                       retries,
 4186                       cbfcnp,
 4187                       /*flags*/ (dxfer_len == 0) ? CAM_DIR_NONE : CAM_DIR_IN,
 4188                       tag_action,
 4189                       /*data_ptr*/ data_ptr,
 4190                       /*dxfer_len*/ dxfer_len,
 4191                       sense_len,
 4192                       sizeof(*scsi_cmd),
 4193                       timeout);
 4194 }
 4195 
 4196 void
 4197 scsi_send_key(struct ccb_scsiio *csio, u_int32_t retries,
 4198               void (*cbfcnp)(struct cam_periph *, union ccb *),
 4199               u_int8_t tag_action, u_int8_t agid, u_int8_t key_format,
 4200               u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len,
 4201               u_int32_t timeout)
 4202 {
 4203         struct scsi_send_key *scsi_cmd;
 4204 
 4205         scsi_cmd = (struct scsi_send_key *)&csio->cdb_io.cdb_bytes;
 4206         bzero(scsi_cmd, sizeof(*scsi_cmd));
 4207         scsi_cmd->opcode = SEND_KEY;
 4208 
 4209         scsi_ulto2b(dxfer_len, scsi_cmd->param_len);
 4210         scsi_cmd->agid_keyformat = (agid << RK_KF_AGID_SHIFT) |
 4211                 (key_format & RK_KF_KEYFORMAT_MASK);
 4212 
 4213         cam_fill_csio(csio,
 4214                       retries,
 4215                       cbfcnp,
 4216                       /*flags*/ CAM_DIR_OUT,
 4217                       tag_action,
 4218                       /*data_ptr*/ data_ptr,
 4219                       /*dxfer_len*/ dxfer_len,
 4220                       sense_len,
 4221                       sizeof(*scsi_cmd),
 4222                       timeout);
 4223 }
 4224 
 4225 
 4226 void
 4227 scsi_read_dvd_structure(struct ccb_scsiio *csio, u_int32_t retries,
 4228                         void (*cbfcnp)(struct cam_periph *, union ccb *),
 4229                         u_int8_t tag_action, u_int32_t address,
 4230                         u_int8_t layer_number, u_int8_t format, u_int8_t agid,
 4231                         u_int8_t *data_ptr, u_int32_t dxfer_len,
 4232                         u_int8_t sense_len, u_int32_t timeout)
 4233 {
 4234         struct scsi_read_dvd_structure *scsi_cmd;
 4235 
 4236         scsi_cmd = (struct scsi_read_dvd_structure *)&csio->cdb_io.cdb_bytes;
 4237         bzero(scsi_cmd, sizeof(*scsi_cmd));
 4238         scsi_cmd->opcode = READ_DVD_STRUCTURE;
 4239 
 4240         scsi_ulto4b(address, scsi_cmd->address);
 4241         scsi_cmd->layer_number = layer_number;
 4242         scsi_cmd->format = format;
 4243         scsi_ulto2b(dxfer_len, scsi_cmd->alloc_len);
 4244         /* The AGID is the top two bits of this byte */
 4245         scsi_cmd->agid = agid << 6;
 4246 
 4247         cam_fill_csio(csio,
 4248                       retries,
 4249                       cbfcnp,
 4250                       /*flags*/ CAM_DIR_IN,
 4251                       tag_action,
 4252                       /*data_ptr*/ data_ptr,
 4253                       /*dxfer_len*/ dxfer_len,
 4254                       sense_len,
 4255                       sizeof(*scsi_cmd),
 4256                       timeout);
 4257 }

Cache object: 4b53f245c4286f4e1274c1e8964f9fd3


[ 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.