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_ch.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 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  * Derived from the NetBSD SCSI changer driver.
   30  *
   31  *      $NetBSD: ch.c,v 1.32 1998/01/12 09:49:12 thorpej Exp $
   32  *
   33  */
   34 /*-
   35  * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com>
   36  * All rights reserved.
   37  *
   38  * Partially based on an autochanger driver written by Stefan Grefen
   39  * and on an autochanger driver written by the Systems Programming Group
   40  * at the University of Utah Computer Science Department.
   41  *
   42  * Redistribution and use in source and binary forms, with or without
   43  * modification, are permitted provided that the following conditions
   44  * are met:
   45  * 1. Redistributions of source code must retain the above copyright
   46  *    notice, this list of conditions and the following disclaimer.
   47  * 2. Redistributions in binary form must reproduce the above copyright
   48  *    notice, this list of conditions and the following disclaimer in the
   49  *    documentation and/or other materials provided with the distribution.
   50  * 3. All advertising materials mentioning features or use of this software
   51  *    must display the following acknowledgements:
   52  *      This product includes software developed by Jason R. Thorpe
   53  *      for And Communications, http://www.and.com/
   54  * 4. The name of the author may not be used to endorse or promote products
   55  *    derived from this software without specific prior written permission.
   56  *
   57  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   58  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   59  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   60  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   61  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   62  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   63  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   64  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   65  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   67  * SUCH DAMAGE.
   68  */
   69 
   70 #include <sys/cdefs.h>
   71 __FBSDID("$FreeBSD: releng/10.4/sys/cam/scsi/scsi_ch.c 316791 2017-04-13 20:36:40Z bdrewery $");
   72 
   73 #include <sys/param.h>
   74 #include <sys/queue.h>
   75 #include <sys/systm.h>
   76 #include <sys/kernel.h>
   77 #include <sys/types.h>
   78 #include <sys/malloc.h>
   79 #include <sys/fcntl.h>
   80 #include <sys/conf.h>
   81 #include <sys/chio.h>
   82 #include <sys/errno.h>
   83 #include <sys/devicestat.h>
   84 
   85 #include <cam/cam.h>
   86 #include <cam/cam_ccb.h>
   87 #include <cam/cam_periph.h>
   88 #include <cam/cam_xpt_periph.h>
   89 #include <cam/cam_debug.h>
   90 
   91 #include <cam/scsi/scsi_all.h>
   92 #include <cam/scsi/scsi_message.h>
   93 #include <cam/scsi/scsi_ch.h>
   94 
   95 /*
   96  * Timeout definitions for various changer related commands.  They may
   97  * be too short for some devices (especially the timeout for INITIALIZE
   98  * ELEMENT STATUS).
   99  */
  100 
  101 static const u_int32_t  CH_TIMEOUT_MODE_SENSE                = 6000;
  102 static const u_int32_t  CH_TIMEOUT_MOVE_MEDIUM               = 15 * 60 * 1000;
  103 static const u_int32_t  CH_TIMEOUT_EXCHANGE_MEDIUM           = 15 * 60 * 1000;
  104 static const u_int32_t  CH_TIMEOUT_POSITION_TO_ELEMENT       = 15 * 60 * 1000;
  105 static const u_int32_t  CH_TIMEOUT_READ_ELEMENT_STATUS       = 5 * 60 * 1000;
  106 static const u_int32_t  CH_TIMEOUT_SEND_VOLTAG               = 10000;
  107 static const u_int32_t  CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS = 500000;
  108 
  109 typedef enum {
  110         CH_FLAG_INVALID         = 0x001
  111 } ch_flags;
  112 
  113 typedef enum {
  114         CH_STATE_PROBE,
  115         CH_STATE_NORMAL
  116 } ch_state;
  117 
  118 typedef enum {
  119         CH_CCB_PROBE
  120 } ch_ccb_types;
  121 
  122 typedef enum {
  123         CH_Q_NONE       = 0x00,
  124         CH_Q_NO_DBD     = 0x01,
  125         CH_Q_NO_DVCID   = 0x02
  126 } ch_quirks;
  127 
  128 #define CH_Q_BIT_STRING \
  129         "\020"          \
  130         "\001NO_DBD"    \
  131         "\002NO_DVCID"
  132 
  133 #define ccb_state       ppriv_field0
  134 #define ccb_bp          ppriv_ptr1
  135 
  136 struct scsi_mode_sense_data {
  137         struct scsi_mode_header_6 header;
  138         struct scsi_mode_blk_desc blk_desc;
  139         union {
  140                 struct page_element_address_assignment ea;
  141                 struct page_transport_geometry_parameters tg;
  142                 struct page_device_capabilities cap;
  143         } pages;
  144 };
  145 
  146 struct ch_softc {
  147         ch_flags        flags;
  148         ch_state        state;
  149         ch_quirks       quirks;
  150         union ccb       saved_ccb;
  151         struct devstat  *device_stats;
  152         struct cdev     *dev;
  153         int             open_count;
  154 
  155         int             sc_picker;      /* current picker */
  156 
  157         /*
  158          * The following information is obtained from the
  159          * element address assignment page.
  160          */
  161         int             sc_firsts[CHET_MAX + 1];        /* firsts */
  162         int             sc_counts[CHET_MAX + 1];        /* counts */
  163 
  164         /*
  165          * The following mask defines the legal combinations
  166          * of elements for the MOVE MEDIUM command.
  167          */
  168         u_int8_t        sc_movemask[CHET_MAX + 1];
  169 
  170         /*
  171          * As above, but for EXCHANGE MEDIUM.
  172          */
  173         u_int8_t        sc_exchangemask[CHET_MAX + 1];
  174 
  175         /*
  176          * Quirks; see below.  XXX KDM not implemented yet
  177          */
  178         int             sc_settledelay; /* delay for settle */
  179 };
  180 
  181 static  d_open_t        chopen;
  182 static  d_close_t       chclose;
  183 static  d_ioctl_t       chioctl;
  184 static  periph_init_t   chinit;
  185 static  periph_ctor_t   chregister;
  186 static  periph_oninv_t  choninvalidate;
  187 static  periph_dtor_t   chcleanup;
  188 static  periph_start_t  chstart;
  189 static  void            chasync(void *callback_arg, u_int32_t code,
  190                                 struct cam_path *path, void *arg);
  191 static  void            chdone(struct cam_periph *periph,
  192                                union ccb *done_ccb);
  193 static  int             cherror(union ccb *ccb, u_int32_t cam_flags,
  194                                 u_int32_t sense_flags);
  195 static  int             chmove(struct cam_periph *periph,
  196                                struct changer_move *cm);
  197 static  int             chexchange(struct cam_periph *periph,
  198                                    struct changer_exchange *ce);
  199 static  int             chposition(struct cam_periph *periph,
  200                                    struct changer_position *cp);
  201 static  int             chgetelemstatus(struct cam_periph *periph,
  202                                 int scsi_version, u_long cmd,
  203                                 struct changer_element_status_request *csr);
  204 static  int             chsetvoltag(struct cam_periph *periph,
  205                                     struct changer_set_voltag_request *csvr);
  206 static  int             chielem(struct cam_periph *periph, 
  207                                 unsigned int timeout);
  208 static  int             chgetparams(struct cam_periph *periph);
  209 static  int             chscsiversion(struct cam_periph *periph);
  210 
  211 static struct periph_driver chdriver =
  212 {
  213         chinit, "ch",
  214         TAILQ_HEAD_INITIALIZER(chdriver.units), /* generation */ 0
  215 };
  216 
  217 PERIPHDRIVER_DECLARE(ch, chdriver);
  218 
  219 static struct cdevsw ch_cdevsw = {
  220         .d_version =    D_VERSION,
  221         .d_flags =      D_TRACKCLOSE,
  222         .d_open =       chopen,
  223         .d_close =      chclose,
  224         .d_ioctl =      chioctl,
  225         .d_name =       "ch",
  226 };
  227 
  228 static MALLOC_DEFINE(M_SCSICH, "scsi_ch", "scsi_ch buffers");
  229 
  230 static void
  231 chinit(void)
  232 {
  233         cam_status status;
  234 
  235         /*
  236          * Install a global async callback.  This callback will
  237          * receive async callbacks like "new device found".
  238          */
  239         status = xpt_register_async(AC_FOUND_DEVICE, chasync, NULL, NULL);
  240 
  241         if (status != CAM_REQ_CMP) {
  242                 printf("ch: Failed to attach master async callback "
  243                        "due to status 0x%x!\n", status);
  244         }
  245 }
  246 
  247 static void
  248 chdevgonecb(void *arg)
  249 {
  250         struct ch_softc   *softc;
  251         struct cam_periph *periph;
  252         struct mtx *mtx;
  253         int i;
  254 
  255         periph = (struct cam_periph *)arg;
  256         mtx = cam_periph_mtx(periph);
  257         mtx_lock(mtx);
  258 
  259         softc = (struct ch_softc *)periph->softc;
  260         KASSERT(softc->open_count >= 0, ("Negative open count %d",
  261                 softc->open_count));
  262 
  263         /*
  264          * When we get this callback, we will get no more close calls from
  265          * devfs.  So if we have any dangling opens, we need to release the
  266          * reference held for that particular context.
  267          */
  268         for (i = 0; i < softc->open_count; i++)
  269                 cam_periph_release_locked(periph);
  270 
  271         softc->open_count = 0;
  272 
  273         /*
  274          * Release the reference held for the device node, it is gone now.
  275          */
  276         cam_periph_release_locked(periph);
  277 
  278         /*
  279          * We reference the lock directly here, instead of using
  280          * cam_periph_unlock().  The reason is that the final call to
  281          * cam_periph_release_locked() above could result in the periph
  282          * getting freed.  If that is the case, dereferencing the periph
  283          * with a cam_periph_unlock() call would cause a page fault.
  284          */
  285         mtx_unlock(mtx);
  286 }
  287 
  288 static void
  289 choninvalidate(struct cam_periph *periph)
  290 {
  291         struct ch_softc *softc;
  292 
  293         softc = (struct ch_softc *)periph->softc;
  294 
  295         /*
  296          * De-register any async callbacks.
  297          */
  298         xpt_register_async(0, chasync, periph, periph->path);
  299 
  300         softc->flags |= CH_FLAG_INVALID;
  301 
  302         /*
  303          * Tell devfs this device has gone away, and ask for a callback
  304          * when it has cleaned up its state.
  305          */
  306         destroy_dev_sched_cb(softc->dev, chdevgonecb, periph);
  307 }
  308 
  309 static void
  310 chcleanup(struct cam_periph *periph)
  311 {
  312         struct ch_softc *softc;
  313 
  314         softc = (struct ch_softc *)periph->softc;
  315 
  316         devstat_remove_entry(softc->device_stats);
  317 
  318         free(softc, M_DEVBUF);
  319 }
  320 
  321 static void
  322 chasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
  323 {
  324         struct cam_periph *periph;
  325 
  326         periph = (struct cam_periph *)callback_arg;
  327 
  328         switch(code) {
  329         case AC_FOUND_DEVICE:
  330         {
  331                 struct ccb_getdev *cgd;
  332                 cam_status status;
  333 
  334                 cgd = (struct ccb_getdev *)arg;
  335                 if (cgd == NULL)
  336                         break;
  337 
  338                 if (cgd->protocol != PROTO_SCSI)
  339                         break;
  340                 if (SID_QUAL(&cgd->inq_data) != SID_QUAL_LU_CONNECTED)
  341                         break;
  342                 if (SID_TYPE(&cgd->inq_data)!= T_CHANGER)
  343                         break;
  344 
  345                 /*
  346                  * Allocate a peripheral instance for
  347                  * this device and start the probe
  348                  * process.
  349                  */
  350                 status = cam_periph_alloc(chregister, choninvalidate,
  351                                           chcleanup, chstart, "ch",
  352                                           CAM_PERIPH_BIO, path,
  353                                           chasync, AC_FOUND_DEVICE, cgd);
  354 
  355                 if (status != CAM_REQ_CMP
  356                  && status != CAM_REQ_INPROG)
  357                         printf("chasync: Unable to probe new device "
  358                                "due to status 0x%x\n", status);
  359 
  360                 break;
  361 
  362         }
  363         default:
  364                 cam_periph_async(periph, code, path, arg);
  365                 break;
  366         }
  367 }
  368 
  369 static cam_status
  370 chregister(struct cam_periph *periph, void *arg)
  371 {
  372         struct ch_softc *softc;
  373         struct ccb_getdev *cgd;
  374         struct ccb_pathinq cpi;
  375         struct make_dev_args args;
  376         int error;
  377 
  378         cgd = (struct ccb_getdev *)arg;
  379         if (cgd == NULL) {
  380                 printf("chregister: no getdev CCB, can't register device\n");
  381                 return(CAM_REQ_CMP_ERR);
  382         }
  383 
  384         softc = (struct ch_softc *)malloc(sizeof(*softc),M_DEVBUF,M_NOWAIT);
  385 
  386         if (softc == NULL) {
  387                 printf("chregister: Unable to probe new device. "
  388                        "Unable to allocate softc\n");                           
  389                 return(CAM_REQ_CMP_ERR);
  390         }
  391 
  392         bzero(softc, sizeof(*softc));
  393         softc->state = CH_STATE_PROBE;
  394         periph->softc = softc;
  395         softc->quirks = CH_Q_NONE;
  396 
  397         /*
  398          * The DVCID and CURDATA bits were not introduced until the SMC
  399          * spec.  If this device claims SCSI-2 or earlier support, then it
  400          * very likely does not support these bits.
  401          */
  402         if (cgd->inq_data.version <= SCSI_REV_2)
  403                 softc->quirks |= CH_Q_NO_DVCID;
  404 
  405         bzero(&cpi, sizeof(cpi));
  406         xpt_setup_ccb(&cpi.ccb_h, periph->path, CAM_PRIORITY_NORMAL);
  407         cpi.ccb_h.func_code = XPT_PATH_INQ;
  408         xpt_action((union ccb *)&cpi);
  409 
  410         /*
  411          * Changers don't have a blocksize, and obviously don't support
  412          * tagged queueing.
  413          */
  414         cam_periph_unlock(periph);
  415         softc->device_stats = devstat_new_entry("ch",
  416                           periph->unit_number, 0,
  417                           DEVSTAT_NO_BLOCKSIZE | DEVSTAT_NO_ORDERED_TAGS,
  418                           SID_TYPE(&cgd->inq_data) |
  419                           XPORT_DEVSTAT_TYPE(cpi.transport),
  420                           DEVSTAT_PRIORITY_OTHER);
  421 
  422         /*
  423          * Acquire a reference to the periph before we create the devfs
  424          * instance for it.  We'll release this reference once the devfs
  425          * instance has been freed.
  426          */
  427         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
  428                 xpt_print(periph->path, "%s: lost periph during "
  429                           "registration!\n", __func__);
  430                 cam_periph_lock(periph);
  431                 return (CAM_REQ_CMP_ERR);
  432         }
  433 
  434 
  435         /* Register the device */
  436         make_dev_args_init(&args);
  437         args.mda_devsw = &ch_cdevsw;
  438         args.mda_unit = periph->unit_number;
  439         args.mda_uid = UID_ROOT;
  440         args.mda_gid = GID_OPERATOR;
  441         args.mda_mode = 0600;
  442         args.mda_si_drv1 = periph;
  443         error = make_dev_s(&args, &softc->dev, "%s%d", periph->periph_name,
  444             periph->unit_number);
  445         cam_periph_lock(periph);
  446         if (error != 0) {
  447                 cam_periph_release_locked(periph);
  448                 return (CAM_REQ_CMP_ERR);
  449         }
  450 
  451         /*
  452          * Add an async callback so that we get
  453          * notified if this device goes away.
  454          */
  455         xpt_register_async(AC_LOST_DEVICE, chasync, periph, periph->path);
  456 
  457         /*
  458          * Lock this periph until we are setup.
  459          * This first call can't block
  460          */
  461         (void)cam_periph_hold(periph, PRIBIO);
  462         xpt_schedule(periph, CAM_PRIORITY_DEV);
  463 
  464         return(CAM_REQ_CMP);
  465 }
  466 
  467 static int
  468 chopen(struct cdev *dev, int flags, int fmt, struct thread *td)
  469 {
  470         struct cam_periph *periph;
  471         struct ch_softc *softc;
  472         int error;
  473 
  474         periph = (struct cam_periph *)dev->si_drv1;
  475         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  476                 return (ENXIO);
  477 
  478         softc = (struct ch_softc *)periph->softc;
  479 
  480         cam_periph_lock(periph);
  481         
  482         if (softc->flags & CH_FLAG_INVALID) {
  483                 cam_periph_release_locked(periph);
  484                 cam_periph_unlock(periph);
  485                 return(ENXIO);
  486         }
  487 
  488         if ((error = cam_periph_hold(periph, PRIBIO | PCATCH)) != 0) {
  489                 cam_periph_unlock(periph);
  490                 cam_periph_release(periph);
  491                 return (error);
  492         }
  493 
  494         /*
  495          * Load information about this changer device into the softc.
  496          */
  497         if ((error = chgetparams(periph)) != 0) {
  498                 cam_periph_unhold(periph);
  499                 cam_periph_release_locked(periph);
  500                 cam_periph_unlock(periph);
  501                 return(error);
  502         }
  503 
  504         cam_periph_unhold(periph);
  505 
  506         softc->open_count++;
  507 
  508         cam_periph_unlock(periph);
  509 
  510         return(error);
  511 }
  512 
  513 static int
  514 chclose(struct cdev *dev, int flag, int fmt, struct thread *td)
  515 {
  516         struct  cam_periph *periph;
  517         struct  ch_softc *softc;
  518         struct mtx *mtx;
  519 
  520         periph = (struct cam_periph *)dev->si_drv1;
  521         mtx = cam_periph_mtx(periph);
  522         mtx_lock(mtx);
  523 
  524         softc = (struct ch_softc *)periph->softc;
  525         softc->open_count--;
  526 
  527         cam_periph_release_locked(periph);
  528 
  529         /*
  530          * We reference the lock directly here, instead of using
  531          * cam_periph_unlock().  The reason is that the call to
  532          * cam_periph_release_locked() above could result in the periph
  533          * getting freed.  If that is the case, dereferencing the periph
  534          * with a cam_periph_unlock() call would cause a page fault.
  535          *
  536          * cam_periph_release() avoids this problem using the same method,
  537          * but we're manually acquiring and dropping the lock here to
  538          * protect the open count and avoid another lock acquisition and
  539          * release.
  540          */
  541         mtx_unlock(mtx);
  542 
  543         return(0);
  544 }
  545 
  546 static void
  547 chstart(struct cam_periph *periph, union ccb *start_ccb)
  548 {
  549         struct ch_softc *softc;
  550 
  551         softc = (struct ch_softc *)periph->softc;
  552 
  553         switch (softc->state) {
  554         case CH_STATE_NORMAL:
  555         {
  556                 xpt_release_ccb(start_ccb);
  557                 break;
  558         }
  559         case CH_STATE_PROBE:
  560         {
  561                 int mode_buffer_len;
  562                 void *mode_buffer;
  563 
  564                 /*
  565                  * Include the block descriptor when calculating the mode
  566                  * buffer length,
  567                  */
  568                 mode_buffer_len = sizeof(struct scsi_mode_header_6) +
  569                                   sizeof(struct scsi_mode_blk_desc) +
  570                                  sizeof(struct page_element_address_assignment);
  571 
  572                 mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
  573 
  574                 if (mode_buffer == NULL) {
  575                         printf("chstart: couldn't malloc mode sense data\n");
  576                         break;
  577                 }
  578                 bzero(mode_buffer, mode_buffer_len);
  579 
  580                 /*
  581                  * Get the element address assignment page.
  582                  */
  583                 scsi_mode_sense(&start_ccb->csio,
  584                                 /* retries */ 1,
  585                                 /* cbfcnp */ chdone,
  586                                 /* tag_action */ MSG_SIMPLE_Q_TAG,
  587                                 /* dbd */ (softc->quirks & CH_Q_NO_DBD) ?
  588                                         FALSE : TRUE,
  589                                 /* pc */ SMS_PAGE_CTRL_CURRENT,
  590                                 /* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
  591                                 /* param_buf */ (u_int8_t *)mode_buffer,
  592                                 /* param_len */ mode_buffer_len,
  593                                 /* sense_len */ SSD_FULL_SIZE,
  594                                 /* timeout */ CH_TIMEOUT_MODE_SENSE);
  595 
  596                 start_ccb->ccb_h.ccb_bp = NULL;
  597                 start_ccb->ccb_h.ccb_state = CH_CCB_PROBE;
  598                 xpt_action(start_ccb);
  599                 break;
  600         }
  601         }
  602 }
  603 
  604 static void
  605 chdone(struct cam_periph *periph, union ccb *done_ccb)
  606 {
  607         struct ch_softc *softc;
  608         struct ccb_scsiio *csio;
  609 
  610         softc = (struct ch_softc *)periph->softc;
  611         csio = &done_ccb->csio;
  612 
  613         switch(done_ccb->ccb_h.ccb_state) {
  614         case CH_CCB_PROBE:
  615         {
  616                 struct scsi_mode_header_6 *mode_header;
  617                 struct page_element_address_assignment *ea;
  618                 char announce_buf[80];
  619 
  620 
  621                 mode_header = (struct scsi_mode_header_6 *)csio->data_ptr;
  622 
  623                 ea = (struct page_element_address_assignment *)
  624                         find_mode_page_6(mode_header);
  625 
  626                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP){
  627                         
  628                         softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
  629                         softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
  630                         softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
  631                         softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
  632                         softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
  633                         softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
  634                         softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
  635                         softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
  636                         softc->sc_picker = softc->sc_firsts[CHET_MT];
  637 
  638 #define PLURAL(c)       (c) == 1 ? "" : "s"
  639                         snprintf(announce_buf, sizeof(announce_buf),
  640                                 "%d slot%s, %d drive%s, "
  641                                 "%d picker%s, %d portal%s",
  642                                 softc->sc_counts[CHET_ST],
  643                                 PLURAL(softc->sc_counts[CHET_ST]),
  644                                 softc->sc_counts[CHET_DT],
  645                                 PLURAL(softc->sc_counts[CHET_DT]),
  646                                 softc->sc_counts[CHET_MT],
  647                                 PLURAL(softc->sc_counts[CHET_MT]),
  648                                 softc->sc_counts[CHET_IE],
  649                                 PLURAL(softc->sc_counts[CHET_IE]));
  650 #undef PLURAL
  651                         if (announce_buf[0] != '\0') {
  652                                 xpt_announce_periph(periph, announce_buf);
  653                                 xpt_announce_quirks(periph, softc->quirks,
  654                                     CH_Q_BIT_STRING);
  655                         }
  656                 } else {
  657                         int error;
  658 
  659                         error = cherror(done_ccb, CAM_RETRY_SELTO,
  660                                         SF_RETRY_UA | SF_NO_PRINT);
  661                         /*
  662                          * Retry any UNIT ATTENTION type errors.  They
  663                          * are expected at boot.
  664                          */
  665                         if (error == ERESTART) {
  666                                 /*
  667                                  * A retry was scheuled, so
  668                                  * just return.
  669                                  */
  670                                 return;
  671                         } else if (error != 0) {
  672                                 struct scsi_mode_sense_6 *sms;
  673                                 int frozen, retry_scheduled;
  674 
  675                                 sms = (struct scsi_mode_sense_6 *)
  676                                         done_ccb->csio.cdb_io.cdb_bytes;
  677                                 frozen = (done_ccb->ccb_h.status &
  678                                     CAM_DEV_QFRZN) != 0;
  679 
  680                                 /*
  681                                  * Check to see if block descriptors were
  682                                  * disabled.  Some devices don't like that.
  683                                  * We're taking advantage of the fact that
  684                                  * the first few bytes of the 6 and 10 byte
  685                                  * mode sense commands are the same.  If
  686                                  * block descriptors were disabled, enable
  687                                  * them and re-send the command.
  688                                  */
  689                                 if ((sms->byte2 & SMS_DBD) != 0 &&
  690                                     (periph->flags & CAM_PERIPH_INVALID) == 0) {
  691                                         sms->byte2 &= ~SMS_DBD;
  692                                         xpt_action(done_ccb);
  693                                         softc->quirks |= CH_Q_NO_DBD;
  694                                         retry_scheduled = 1;
  695                                 } else
  696                                         retry_scheduled = 0;
  697 
  698                                 /* Don't wedge this device's queue */
  699                                 if (frozen)
  700                                         cam_release_devq(done_ccb->ccb_h.path,
  701                                                  /*relsim_flags*/0,
  702                                                  /*reduction*/0,
  703                                                  /*timeout*/0,
  704                                                  /*getcount_only*/0);
  705 
  706                                 if (retry_scheduled)
  707                                         return;
  708 
  709                                 if ((done_ccb->ccb_h.status & CAM_STATUS_MASK)
  710                                     == CAM_SCSI_STATUS_ERROR) 
  711                                         scsi_sense_print(&done_ccb->csio);
  712                                 else {
  713                                         xpt_print(periph->path,
  714                                             "got CAM status %#x\n",
  715                                             done_ccb->ccb_h.status);
  716                                 }
  717                                 xpt_print(periph->path, "fatal error, failed "
  718                                     "to attach to device\n");
  719 
  720                                 cam_periph_invalidate(periph);
  721 
  722                         }
  723                 }
  724                 softc->state = CH_STATE_NORMAL;
  725                 free(mode_header, M_SCSICH);
  726                 /*
  727                  * Since our peripheral may be invalidated by an error
  728                  * above or an external event, we must release our CCB
  729                  * before releasing the probe lock on the peripheral.
  730                  * The peripheral will only go away once the last lock
  731                  * is removed, and we need it around for the CCB release
  732                  * operation.
  733                  */
  734                 xpt_release_ccb(done_ccb);
  735                 cam_periph_unhold(periph);
  736                 return;
  737         }
  738         default:
  739                 break;
  740         }
  741         xpt_release_ccb(done_ccb);
  742 }
  743 
  744 static int
  745 cherror(union ccb *ccb, u_int32_t cam_flags, u_int32_t sense_flags)
  746 {
  747         struct ch_softc *softc;
  748         struct cam_periph *periph;
  749 
  750         periph = xpt_path_periph(ccb->ccb_h.path);
  751         softc = (struct ch_softc *)periph->softc;
  752 
  753         return (cam_periph_error(ccb, cam_flags, sense_flags,
  754                                  &softc->saved_ccb));
  755 }
  756 
  757 static int
  758 chioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  759 {
  760         struct cam_periph *periph;
  761         struct ch_softc *softc;
  762         int error;
  763 
  764         periph = (struct cam_periph *)dev->si_drv1;
  765         cam_periph_lock(periph);
  766         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering chioctl\n"));
  767 
  768         softc = (struct ch_softc *)periph->softc;
  769 
  770         error = 0;
  771 
  772         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, 
  773                   ("trying to do ioctl %#lx\n", cmd));
  774 
  775         /*
  776          * If this command can change the device's state, we must
  777          * have the device open for writing.
  778          */
  779         switch (cmd) {
  780         case CHIOGPICKER:
  781         case CHIOGPARAMS:
  782         case OCHIOGSTATUS:
  783         case CHIOGSTATUS:
  784                 break;
  785 
  786         default:
  787                 if ((flag & FWRITE) == 0) {
  788                         cam_periph_unlock(periph);
  789                         return (EBADF);
  790                 }
  791         }
  792 
  793         switch (cmd) {
  794         case CHIOMOVE:
  795                 error = chmove(periph, (struct changer_move *)addr);
  796                 break;
  797 
  798         case CHIOEXCHANGE:
  799                 error = chexchange(periph, (struct changer_exchange *)addr);
  800                 break;
  801 
  802         case CHIOPOSITION:
  803                 error = chposition(periph, (struct changer_position *)addr);
  804                 break;
  805 
  806         case CHIOGPICKER:
  807                 *(int *)addr = softc->sc_picker - softc->sc_firsts[CHET_MT];
  808                 break;
  809 
  810         case CHIOSPICKER:
  811         {
  812                 int new_picker = *(int *)addr;
  813 
  814                 if (new_picker > (softc->sc_counts[CHET_MT] - 1)) {
  815                         error = EINVAL;
  816                         break;
  817                 }
  818                 softc->sc_picker = softc->sc_firsts[CHET_MT] + new_picker;
  819                 break;
  820         }
  821         case CHIOGPARAMS:
  822         {
  823                 struct changer_params *cp = (struct changer_params *)addr;
  824 
  825                 cp->cp_npickers = softc->sc_counts[CHET_MT];
  826                 cp->cp_nslots = softc->sc_counts[CHET_ST];
  827                 cp->cp_nportals = softc->sc_counts[CHET_IE];
  828                 cp->cp_ndrives = softc->sc_counts[CHET_DT];
  829                 break;
  830         }
  831         case CHIOIELEM:
  832                 error = chielem(periph, *(unsigned int *)addr);
  833                 break;
  834 
  835         case OCHIOGSTATUS:
  836         {
  837                 error = chgetelemstatus(periph, SCSI_REV_2, cmd,
  838                     (struct changer_element_status_request *)addr);
  839                 break;
  840         }
  841 
  842         case CHIOGSTATUS:
  843         {
  844                 int scsi_version;
  845 
  846                 scsi_version = chscsiversion(periph);
  847                 if (scsi_version >= SCSI_REV_0) {
  848                         error = chgetelemstatus(periph, scsi_version, cmd,
  849                             (struct changer_element_status_request *)addr);
  850                 }
  851                 else { /* unable to determine the SCSI version */
  852                         cam_periph_unlock(periph);
  853                         return (ENXIO);
  854                 }
  855                 break;
  856         }
  857 
  858         case CHIOSETVOLTAG:
  859         {
  860                 error = chsetvoltag(periph,
  861                                     (struct changer_set_voltag_request *) addr);
  862                 break;
  863         }
  864 
  865         /* Implement prevent/allow? */
  866 
  867         default:
  868                 error = cam_periph_ioctl(periph, cmd, addr, cherror);
  869                 break;
  870         }
  871 
  872         cam_periph_unlock(periph);
  873         return (error);
  874 }
  875 
  876 static int
  877 chmove(struct cam_periph *periph, struct changer_move *cm)
  878 {
  879         struct ch_softc *softc;
  880         u_int16_t fromelem, toelem;
  881         union ccb *ccb;
  882         int error;
  883 
  884         error = 0;
  885         softc = (struct ch_softc *)periph->softc;
  886 
  887         /*
  888          * Check arguments.
  889          */
  890         if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
  891                 return (EINVAL);
  892         if ((cm->cm_fromunit > (softc->sc_counts[cm->cm_fromtype] - 1)) ||
  893             (cm->cm_tounit > (softc->sc_counts[cm->cm_totype] - 1)))
  894                 return (ENODEV);
  895 
  896         /*
  897          * Check the request against the changer's capabilities.
  898          */
  899         if ((softc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
  900                 return (ENODEV);
  901 
  902         /*
  903          * Calculate the source and destination elements.
  904          */
  905         fromelem = softc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
  906         toelem = softc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
  907 
  908         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
  909 
  910         scsi_move_medium(&ccb->csio,
  911                          /* retries */ 1,
  912                          /* cbfcnp */ chdone,
  913                          /* tag_action */ MSG_SIMPLE_Q_TAG,
  914                          /* tea */ softc->sc_picker,
  915                          /* src */ fromelem,
  916                          /* dst */ toelem,
  917                          /* invert */ (cm->cm_flags & CM_INVERT) ? TRUE : FALSE,
  918                          /* sense_len */ SSD_FULL_SIZE,
  919                          /* timeout */ CH_TIMEOUT_MOVE_MEDIUM);
  920 
  921         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO,
  922                                   /*sense_flags*/ SF_RETRY_UA,
  923                                   softc->device_stats);
  924 
  925         xpt_release_ccb(ccb);
  926 
  927         return(error);
  928 }
  929 
  930 static int
  931 chexchange(struct cam_periph *periph, struct changer_exchange *ce)
  932 {
  933         struct ch_softc *softc;
  934         u_int16_t src, dst1, dst2;
  935         union ccb *ccb;
  936         int error;
  937 
  938         error = 0;
  939         softc = (struct ch_softc *)periph->softc;
  940         /*
  941          * Check arguments.
  942          */
  943         if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
  944             (ce->ce_sdsttype > CHET_DT))
  945                 return (EINVAL);
  946         if ((ce->ce_srcunit > (softc->sc_counts[ce->ce_srctype] - 1)) ||
  947             (ce->ce_fdstunit > (softc->sc_counts[ce->ce_fdsttype] - 1)) ||
  948             (ce->ce_sdstunit > (softc->sc_counts[ce->ce_sdsttype] - 1)))
  949                 return (ENODEV);
  950 
  951         /*
  952          * Check the request against the changer's capabilities.
  953          */
  954         if (((softc->sc_exchangemask[ce->ce_srctype] &
  955              (1 << ce->ce_fdsttype)) == 0) ||
  956             ((softc->sc_exchangemask[ce->ce_fdsttype] &
  957              (1 << ce->ce_sdsttype)) == 0))
  958                 return (ENODEV);
  959 
  960         /*
  961          * Calculate the source and destination elements.
  962          */
  963         src = softc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
  964         dst1 = softc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
  965         dst2 = softc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
  966 
  967         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
  968 
  969         scsi_exchange_medium(&ccb->csio,
  970                              /* retries */ 1,
  971                              /* cbfcnp */ chdone,
  972                              /* tag_action */ MSG_SIMPLE_Q_TAG,
  973                              /* tea */ softc->sc_picker,
  974                              /* src */ src,
  975                              /* dst1 */ dst1,
  976                              /* dst2 */ dst2,
  977                              /* invert1 */ (ce->ce_flags & CE_INVERT1) ?
  978                                            TRUE : FALSE,
  979                              /* invert2 */ (ce->ce_flags & CE_INVERT2) ?
  980                                            TRUE : FALSE,
  981                              /* sense_len */ SSD_FULL_SIZE,
  982                              /* timeout */ CH_TIMEOUT_EXCHANGE_MEDIUM);
  983 
  984         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/CAM_RETRY_SELTO,
  985                                   /*sense_flags*/ SF_RETRY_UA,
  986                                   softc->device_stats);
  987 
  988         xpt_release_ccb(ccb);
  989 
  990         return(error);
  991 }
  992 
  993 static int
  994 chposition(struct cam_periph *periph, struct changer_position *cp)
  995 {
  996         struct ch_softc *softc;
  997         u_int16_t dst;
  998         union ccb *ccb;
  999         int error;
 1000 
 1001         error = 0;
 1002         softc = (struct ch_softc *)periph->softc;
 1003 
 1004         /*
 1005          * Check arguments.
 1006          */
 1007         if (cp->cp_type > CHET_DT)
 1008                 return (EINVAL);
 1009         if (cp->cp_unit > (softc->sc_counts[cp->cp_type] - 1))
 1010                 return (ENODEV);
 1011 
 1012         /*
 1013          * Calculate the destination element.
 1014          */
 1015         dst = softc->sc_firsts[cp->cp_type] + cp->cp_unit;
 1016 
 1017         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 1018 
 1019         scsi_position_to_element(&ccb->csio,
 1020                                  /* retries */ 1,
 1021                                  /* cbfcnp */ chdone,
 1022                                  /* tag_action */ MSG_SIMPLE_Q_TAG,
 1023                                  /* tea */ softc->sc_picker,
 1024                                  /* dst */ dst,
 1025                                  /* invert */ (cp->cp_flags & CP_INVERT) ?
 1026                                               TRUE : FALSE,
 1027                                  /* sense_len */ SSD_FULL_SIZE,
 1028                                  /* timeout */ CH_TIMEOUT_POSITION_TO_ELEMENT);
 1029 
 1030         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 1031                                   /*sense_flags*/ SF_RETRY_UA,
 1032                                   softc->device_stats);
 1033 
 1034         xpt_release_ccb(ccb);
 1035 
 1036         return(error);
 1037 }
 1038 
 1039 /*
 1040  * Copy a volume tag to a volume_tag struct, converting SCSI byte order
 1041  * to host native byte order in the volume serial number.  The volume
 1042  * label as returned by the changer is transferred to user mode as
 1043  * nul-terminated string.  Volume labels are truncated at the first
 1044  * space, as suggested by SCSI-2.
 1045  */
 1046 static  void
 1047 copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
 1048 {
 1049         int i;
 1050         for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
 1051                 char c = voltag->vif[i];
 1052                 if (c && c != ' ')
 1053                         uvoltag->cv_volid[i] = c;
 1054                 else
 1055                         break;
 1056         }
 1057         uvoltag->cv_serial = scsi_2btoul(voltag->vsn);
 1058 }
 1059 
 1060 /*
 1061  * Copy an element status descriptor to a user-mode
 1062  * changer_element_status structure.
 1063  */
 1064 static void
 1065 copy_element_status(struct ch_softc *softc,
 1066                     u_int16_t flags,
 1067                     struct read_element_status_descriptor *desc,
 1068                     struct changer_element_status *ces,
 1069                     int scsi_version)
 1070 {
 1071         u_int16_t eaddr = scsi_2btoul(desc->eaddr);
 1072         u_int16_t et;
 1073         struct volume_tag *pvol_tag = NULL, *avol_tag = NULL;
 1074         struct read_element_status_device_id *devid = NULL;
 1075 
 1076         ces->ces_int_addr = eaddr;
 1077         /* set up logical address in element status */
 1078         for (et = CHET_MT; et <= CHET_DT; et++) {
 1079                 if ((softc->sc_firsts[et] <= eaddr)
 1080                     && ((softc->sc_firsts[et] + softc->sc_counts[et])
 1081                         > eaddr)) {
 1082                         ces->ces_addr = eaddr - softc->sc_firsts[et];
 1083                         ces->ces_type = et;
 1084                         break;
 1085                 }
 1086         }
 1087 
 1088         ces->ces_flags = desc->flags1;
 1089 
 1090         ces->ces_sensecode = desc->sense_code;
 1091         ces->ces_sensequal = desc->sense_qual;
 1092 
 1093         if (desc->flags2 & READ_ELEMENT_STATUS_INVERT)
 1094                 ces->ces_flags |= CES_INVERT;
 1095 
 1096         if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) {
 1097 
 1098                 eaddr = scsi_2btoul(desc->ssea);
 1099 
 1100                 /* convert source address to logical format */
 1101                 for (et = CHET_MT; et <= CHET_DT; et++) {
 1102                         if ((softc->sc_firsts[et] <= eaddr)
 1103                             && ((softc->sc_firsts[et] + softc->sc_counts[et])
 1104                                 > eaddr)) {
 1105                                 ces->ces_source_addr =
 1106                                         eaddr - softc->sc_firsts[et];
 1107                                 ces->ces_source_type = et;
 1108                                 ces->ces_flags |= CES_SOURCE_VALID;
 1109                                 break;
 1110                         }
 1111                 }
 1112 
 1113                 if (!(ces->ces_flags & CES_SOURCE_VALID))
 1114                         printf("ch: warning: could not map element source "
 1115                                "address %ud to a valid element type\n",
 1116                                eaddr);
 1117         }
 1118 
 1119         /*
 1120          * pvoltag and avoltag are common between SCSI-2 and later versions
 1121          */
 1122         if (flags & READ_ELEMENT_STATUS_PVOLTAG)
 1123                 pvol_tag = &desc->voltag_devid.pvoltag;
 1124         if (flags & READ_ELEMENT_STATUS_AVOLTAG)
 1125                 avol_tag = (flags & READ_ELEMENT_STATUS_PVOLTAG) ?
 1126                     &desc->voltag_devid.voltag[1] :&desc->voltag_devid.pvoltag;
 1127         /*
 1128          * For SCSI-3 and later, element status can carry designator and
 1129          * other information.
 1130          */
 1131         if (scsi_version >= SCSI_REV_SPC) {
 1132                 if ((flags & READ_ELEMENT_STATUS_PVOLTAG) ^
 1133                     (flags & READ_ELEMENT_STATUS_AVOLTAG))
 1134                         devid = &desc->voltag_devid.pvol_and_devid.devid;
 1135                 else if (!(flags & READ_ELEMENT_STATUS_PVOLTAG) &&
 1136                          !(flags & READ_ELEMENT_STATUS_AVOLTAG))
 1137                         devid = &desc->voltag_devid.devid;
 1138                 else /* Have both PVOLTAG and AVOLTAG */
 1139                         devid = &desc->voltag_devid.vol_tags_and_devid.devid;
 1140         }
 1141 
 1142         if (pvol_tag)
 1143                 copy_voltag(&(ces->ces_pvoltag), pvol_tag);
 1144         if (avol_tag)
 1145                 copy_voltag(&(ces->ces_pvoltag), avol_tag);
 1146         if (devid != NULL) {
 1147                 if (devid->designator_length > 0) {
 1148                         bcopy((void *)devid->designator,
 1149                               (void *)ces->ces_designator,
 1150                               devid->designator_length);
 1151                         ces->ces_designator_length = devid->designator_length;
 1152                         /*
 1153                          * Make sure we are always NUL terminated.  The
 1154                          * This won't matter for the binary code set,
 1155                          * since the user will only pay attention to the
 1156                          * length field.
 1157                          */
 1158                         ces->ces_designator[devid->designator_length]= '\0';
 1159                 }
 1160                 if (devid->piv_assoc_designator_type &
 1161                     READ_ELEMENT_STATUS_PIV_SET) {
 1162                         ces->ces_flags |= CES_PIV;
 1163                         ces->ces_protocol_id =
 1164                             READ_ELEMENT_STATUS_PROTOCOL_ID(
 1165                             devid->prot_code_set);
 1166                 }
 1167                 ces->ces_code_set =
 1168                     READ_ELEMENT_STATUS_CODE_SET(devid->prot_code_set);
 1169                 ces->ces_assoc = READ_ELEMENT_STATUS_ASSOCIATION(
 1170                     devid->piv_assoc_designator_type);
 1171                 ces->ces_designator_type = READ_ELEMENT_STATUS_DESIGNATOR_TYPE(
 1172                     devid->piv_assoc_designator_type);
 1173         } else if (scsi_version > SCSI_REV_2) {
 1174                 /* SCSI-SPC and No devid, no designator */
 1175                 ces->ces_designator_length = 0;
 1176                 ces->ces_designator[0] = '\0';
 1177                 ces->ces_protocol_id = CES_PROTOCOL_ID_FCP_4;
 1178         }
 1179 
 1180         if (scsi_version <= SCSI_REV_2) {
 1181                 if (desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
 1182                     READ_ELEMENT_STATUS_DT_IDVALID) {
 1183                         ces->ces_flags |= CES_SCSIID_VALID;
 1184                         ces->ces_scsi_id =
 1185                             desc->dt_or_obsolete.scsi_2.dt_scsi_addr;
 1186                 }
 1187 
 1188                 if (desc->dt_or_obsolete.scsi_2.dt_scsi_addr &
 1189                     READ_ELEMENT_STATUS_DT_LUVALID) {
 1190                         ces->ces_flags |= CES_LUN_VALID;
 1191                         ces->ces_scsi_lun =
 1192                             desc->dt_or_obsolete.scsi_2.dt_scsi_flags &
 1193                             READ_ELEMENT_STATUS_DT_LUNMASK;
 1194                 }
 1195         }
 1196 }
 1197 
 1198 static int
 1199 chgetelemstatus(struct cam_periph *periph, int scsi_version, u_long cmd,
 1200                 struct changer_element_status_request *cesr)
 1201 {
 1202         struct read_element_status_header *st_hdr;
 1203         struct read_element_status_page_header *pg_hdr;
 1204         struct read_element_status_descriptor *desc;
 1205         caddr_t data = NULL;
 1206         size_t size, desclen;
 1207         int avail, i, error = 0;
 1208         int curdata, dvcid, sense_flags;
 1209         int try_no_dvcid = 0;
 1210         struct changer_element_status *user_data = NULL;
 1211         struct ch_softc *softc;
 1212         union ccb *ccb;
 1213         int chet = cesr->cesr_element_type;
 1214         int want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
 1215 
 1216         softc = (struct ch_softc *)periph->softc;
 1217 
 1218         /* perform argument checking */
 1219 
 1220         /*
 1221          * Perform a range check on the cesr_element_{base,count}
 1222          * request argument fields.
 1223          */
 1224         if ((softc->sc_counts[chet] - cesr->cesr_element_base) <= 0
 1225             || (cesr->cesr_element_base + cesr->cesr_element_count)
 1226                 > softc->sc_counts[chet])
 1227                 return (EINVAL);
 1228 
 1229         /*
 1230          * Request one descriptor for the given element type.  This
 1231          * is used to determine the size of the descriptor so that
 1232          * we can allocate enough storage for all of them.  We assume
 1233          * that the first one can fit into 1k.
 1234          */
 1235         cam_periph_unlock(periph);
 1236         data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
 1237 
 1238         cam_periph_lock(periph);
 1239         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 1240 
 1241         sense_flags = SF_RETRY_UA;
 1242         if (softc->quirks & CH_Q_NO_DVCID) {
 1243                 dvcid = 0;
 1244                 curdata = 0;
 1245         } else {
 1246                 dvcid = 1;
 1247                 curdata = 1;
 1248                 /*
 1249                  * Don't print anything for an Illegal Request, because
 1250                  * these flags can cause some changers to complain.  We'll
 1251                  * retry without them if we get an error.
 1252                  */
 1253                 sense_flags |= SF_QUIET_IR;
 1254         }
 1255 
 1256 retry_einval:
 1257 
 1258         scsi_read_element_status(&ccb->csio,
 1259                                  /* retries */ 1,
 1260                                  /* cbfcnp */ chdone,
 1261                                  /* tag_action */ MSG_SIMPLE_Q_TAG,
 1262                                  /* voltag */ want_voltags,
 1263                                  /* sea */ softc->sc_firsts[chet],
 1264                                  /* curdata */ curdata,
 1265                                  /* dvcid */ dvcid,
 1266                                  /* count */ 1,
 1267                                  /* data_ptr */ data,
 1268                                  /* dxfer_len */ 1024,
 1269                                  /* sense_len */ SSD_FULL_SIZE,
 1270                                  /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
 1271 
 1272         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 1273                                   /*sense_flags*/ sense_flags,
 1274                                   softc->device_stats);
 1275 
 1276         /*
 1277          * An Illegal Request sense key (only used if there is no asc/ascq)
 1278          * or 0x24,0x00 for an ASC/ASCQ both map to EINVAL.  If dvcid or
 1279          * curdata are set (we set both or neither), try turning them off
 1280          * and see if the command is successful.
 1281          */
 1282         if ((error == EINVAL)
 1283          && (dvcid || curdata))  {
 1284                 dvcid = 0;
 1285                 curdata = 0;
 1286                 error = 0;
 1287                 /* At this point we want to report any Illegal Request */
 1288                 sense_flags &= ~SF_QUIET_IR;
 1289                 try_no_dvcid = 1;
 1290                 goto retry_einval;
 1291         }
 1292 
 1293         /*
 1294          * In this case, we tried a read element status with dvcid and
 1295          * curdata set, and it failed.  We retried without those bits, and
 1296          * it succeeded.  Suggest to the user that he set a quirk, so we
 1297          * don't go through the retry process the first time in the future.
 1298          * This should only happen on changers that claim SCSI-3 or higher,
 1299          * but don't support these bits.
 1300          */
 1301         if ((try_no_dvcid != 0)
 1302          && (error == 0))
 1303                 softc->quirks |= CH_Q_NO_DVCID;
 1304 
 1305         if (error)
 1306                 goto done;
 1307         cam_periph_unlock(periph);
 1308 
 1309         st_hdr = (struct read_element_status_header *)data;
 1310         pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
 1311                   sizeof(struct read_element_status_header));
 1312         desclen = scsi_2btoul(pg_hdr->edl);
 1313 
 1314         size = sizeof(struct read_element_status_header) +
 1315                sizeof(struct read_element_status_page_header) +
 1316                (desclen * cesr->cesr_element_count);
 1317         /*
 1318          * Reallocate storage for descriptors and get them from the
 1319          * device.
 1320          */
 1321         free(data, M_DEVBUF);
 1322         data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
 1323 
 1324         cam_periph_lock(periph);
 1325         scsi_read_element_status(&ccb->csio,
 1326                                  /* retries */ 1,
 1327                                  /* cbfcnp */ chdone,
 1328                                  /* tag_action */ MSG_SIMPLE_Q_TAG,
 1329                                  /* voltag */ want_voltags,
 1330                                  /* sea */ softc->sc_firsts[chet]
 1331                                  + cesr->cesr_element_base,
 1332                                  /* curdata */ curdata,
 1333                                  /* dvcid */ dvcid,
 1334                                  /* count */ cesr->cesr_element_count,
 1335                                  /* data_ptr */ data,
 1336                                  /* dxfer_len */ size,
 1337                                  /* sense_len */ SSD_FULL_SIZE,
 1338                                  /* timeout */ CH_TIMEOUT_READ_ELEMENT_STATUS);
 1339 
 1340         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 1341                                   /*sense_flags*/ SF_RETRY_UA,
 1342                                   softc->device_stats);
 1343 
 1344         if (error)
 1345                 goto done;
 1346         cam_periph_unlock(periph);
 1347 
 1348         /*
 1349          * Fill in the user status array.
 1350          */
 1351         st_hdr = (struct read_element_status_header *)data;
 1352         pg_hdr = (struct read_element_status_page_header *)((uintptr_t)st_hdr +
 1353                   sizeof(struct read_element_status_header));
 1354         avail = scsi_2btoul(st_hdr->count);
 1355 
 1356         if (avail != cesr->cesr_element_count) {
 1357                 xpt_print(periph->path,
 1358                     "warning, READ ELEMENT STATUS avail != count\n");
 1359         }
 1360 
 1361         user_data = (struct changer_element_status *)
 1362                 malloc(avail * sizeof(struct changer_element_status),
 1363                        M_DEVBUF, M_WAITOK | M_ZERO);
 1364 
 1365         desc = (struct read_element_status_descriptor *)((uintptr_t)data +
 1366                 sizeof(struct read_element_status_header) +
 1367                 sizeof(struct read_element_status_page_header));
 1368         /*
 1369          * Set up the individual element status structures
 1370          */
 1371         for (i = 0; i < avail; ++i) {
 1372                 struct changer_element_status *ces;
 1373 
 1374                 /*
 1375                  * In the changer_element_status structure, fields from
 1376                  * the beginning to the field of ces_scsi_lun are common
 1377                  * between SCSI-2 and SCSI-3, while all the rest are new
 1378                  * from SCSI-3. In order to maintain backward compatibility
 1379                  * of the chio command, the ces pointer, below, is computed
 1380                  * such that it lines up with the structure boundary
 1381                  * corresponding to the SCSI version.
 1382                  */
 1383                 ces = cmd == OCHIOGSTATUS ?
 1384                     (struct changer_element_status *)
 1385                     ((unsigned char *)user_data + i *
 1386                      (offsetof(struct changer_element_status,ces_scsi_lun)+1)):
 1387                     &user_data[i];
 1388 
 1389                 copy_element_status(softc, pg_hdr->flags, desc,
 1390                                     ces, scsi_version);
 1391 
 1392                 desc = (struct read_element_status_descriptor *)
 1393                        ((unsigned char *)desc + desclen);
 1394         }
 1395 
 1396         /* Copy element status structures out to userspace. */
 1397         if (cmd == OCHIOGSTATUS)
 1398                 error = copyout(user_data,
 1399                                 cesr->cesr_element_status,
 1400                                 avail* (offsetof(struct changer_element_status,
 1401                                 ces_scsi_lun) + 1));
 1402         else
 1403                 error = copyout(user_data,
 1404                                 cesr->cesr_element_status,
 1405                                 avail * sizeof(struct changer_element_status));
 1406 
 1407         cam_periph_lock(periph);
 1408 
 1409  done:
 1410         xpt_release_ccb(ccb);
 1411 
 1412         if (data != NULL)
 1413                 free(data, M_DEVBUF);
 1414         if (user_data != NULL)
 1415                 free(user_data, M_DEVBUF);
 1416 
 1417         return (error);
 1418 }
 1419 
 1420 static int
 1421 chielem(struct cam_periph *periph,
 1422         unsigned int timeout)
 1423 {
 1424         union ccb *ccb;
 1425         struct ch_softc *softc;
 1426         int error;
 1427 
 1428         if (!timeout) {
 1429                 timeout = CH_TIMEOUT_INITIALIZE_ELEMENT_STATUS;
 1430         } else {
 1431                 timeout *= 1000;
 1432         }
 1433 
 1434         error = 0;
 1435         softc = (struct ch_softc *)periph->softc;
 1436 
 1437         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 1438 
 1439         scsi_initialize_element_status(&ccb->csio,
 1440                                       /* retries */ 1,
 1441                                       /* cbfcnp */ chdone,
 1442                                       /* tag_action */ MSG_SIMPLE_Q_TAG,
 1443                                       /* sense_len */ SSD_FULL_SIZE,
 1444                                       /* timeout */ timeout);
 1445 
 1446         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 1447                                   /*sense_flags*/ SF_RETRY_UA,
 1448                                   softc->device_stats);
 1449 
 1450         xpt_release_ccb(ccb);
 1451 
 1452         return(error);
 1453 }
 1454 
 1455 static int
 1456 chsetvoltag(struct cam_periph *periph,
 1457             struct changer_set_voltag_request *csvr)
 1458 {
 1459         union ccb *ccb;
 1460         struct ch_softc *softc;
 1461         u_int16_t ea;
 1462         u_int8_t sac;
 1463         struct scsi_send_volume_tag_parameters ssvtp;
 1464         int error;
 1465         int i;
 1466 
 1467         error = 0;
 1468         softc = (struct ch_softc *)periph->softc;
 1469 
 1470         bzero(&ssvtp, sizeof(ssvtp));
 1471         for (i=0; i<sizeof(ssvtp.vitf); i++) {
 1472                 ssvtp.vitf[i] = ' ';
 1473         }
 1474 
 1475         /*
 1476          * Check arguments.
 1477          */
 1478         if (csvr->csvr_type > CHET_DT)
 1479                 return EINVAL;
 1480         if (csvr->csvr_addr > (softc->sc_counts[csvr->csvr_type] - 1))
 1481                 return ENODEV;
 1482 
 1483         ea = softc->sc_firsts[csvr->csvr_type] + csvr->csvr_addr;
 1484 
 1485         if (csvr->csvr_flags & CSVR_ALTERNATE) {
 1486                 switch (csvr->csvr_flags & CSVR_MODE_MASK) {
 1487                 case CSVR_MODE_SET:
 1488                         sac = SEND_VOLUME_TAG_ASSERT_ALTERNATE;
 1489                         break;
 1490                 case CSVR_MODE_REPLACE:
 1491                         sac = SEND_VOLUME_TAG_REPLACE_ALTERNATE;
 1492                         break;
 1493                 case CSVR_MODE_CLEAR:
 1494                         sac = SEND_VOLUME_TAG_UNDEFINED_ALTERNATE;
 1495                         break;
 1496                 default:
 1497                         error = EINVAL;
 1498                         goto out;
 1499                 }
 1500         } else {
 1501                 switch (csvr->csvr_flags & CSVR_MODE_MASK) {
 1502                 case CSVR_MODE_SET:
 1503                         sac = SEND_VOLUME_TAG_ASSERT_PRIMARY;
 1504                         break;
 1505                 case CSVR_MODE_REPLACE:
 1506                         sac = SEND_VOLUME_TAG_REPLACE_PRIMARY;
 1507                         break;
 1508                 case CSVR_MODE_CLEAR:
 1509                         sac = SEND_VOLUME_TAG_UNDEFINED_PRIMARY;
 1510                         break;
 1511                 default:
 1512                         error = EINVAL;
 1513                         goto out;
 1514                 }
 1515         }
 1516 
 1517         memcpy(ssvtp.vitf, csvr->csvr_voltag.cv_volid,
 1518                min(strlen(csvr->csvr_voltag.cv_volid), sizeof(ssvtp.vitf)));
 1519         scsi_ulto2b(csvr->csvr_voltag.cv_serial, ssvtp.minvsn);
 1520 
 1521         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 1522 
 1523         scsi_send_volume_tag(&ccb->csio,
 1524                              /* retries */ 1,
 1525                              /* cbfcnp */ chdone,
 1526                              /* tag_action */ MSG_SIMPLE_Q_TAG,
 1527                              /* element_address */ ea,
 1528                              /* send_action_code */ sac,
 1529                              /* parameters */ &ssvtp,
 1530                              /* sense_len */ SSD_FULL_SIZE,
 1531                              /* timeout */ CH_TIMEOUT_SEND_VOLTAG);
 1532         
 1533         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 1534                                   /*sense_flags*/ SF_RETRY_UA,
 1535                                   softc->device_stats);
 1536 
 1537         xpt_release_ccb(ccb);
 1538 
 1539  out:
 1540         return error;
 1541 }
 1542 
 1543 static int
 1544 chgetparams(struct cam_periph *periph)
 1545 {
 1546         union ccb *ccb;
 1547         struct ch_softc *softc;
 1548         void *mode_buffer;
 1549         int mode_buffer_len;
 1550         struct page_element_address_assignment *ea;
 1551         struct page_device_capabilities *cap;
 1552         int error, from, dbd;
 1553         u_int8_t *moves, *exchanges;
 1554 
 1555         error = 0;
 1556 
 1557         softc = (struct ch_softc *)periph->softc;
 1558 
 1559         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 1560 
 1561         /*
 1562          * The scsi_mode_sense_data structure is just a convenience
 1563          * structure that allows us to easily calculate the worst-case
 1564          * storage size of the mode sense buffer.
 1565          */
 1566         mode_buffer_len = sizeof(struct scsi_mode_sense_data);
 1567 
 1568         mode_buffer = malloc(mode_buffer_len, M_SCSICH, M_NOWAIT);
 1569 
 1570         if (mode_buffer == NULL) {
 1571                 printf("chgetparams: couldn't malloc mode sense data\n");
 1572                 xpt_release_ccb(ccb);
 1573                 return(ENOSPC);
 1574         }
 1575 
 1576         bzero(mode_buffer, mode_buffer_len);
 1577 
 1578         if (softc->quirks & CH_Q_NO_DBD)
 1579                 dbd = FALSE;
 1580         else
 1581                 dbd = TRUE;
 1582 
 1583         /*
 1584          * Get the element address assignment page.
 1585          */
 1586         scsi_mode_sense(&ccb->csio,
 1587                         /* retries */ 1,
 1588                         /* cbfcnp */ chdone,
 1589                         /* tag_action */ MSG_SIMPLE_Q_TAG,
 1590                         /* dbd */ dbd,
 1591                         /* pc */ SMS_PAGE_CTRL_CURRENT,
 1592                         /* page */ CH_ELEMENT_ADDR_ASSIGN_PAGE,
 1593                         /* param_buf */ (u_int8_t *)mode_buffer,
 1594                         /* param_len */ mode_buffer_len,
 1595                         /* sense_len */ SSD_FULL_SIZE,
 1596                         /* timeout */ CH_TIMEOUT_MODE_SENSE);
 1597 
 1598         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 1599                                   /* sense_flags */ SF_RETRY_UA|SF_NO_PRINT,
 1600                                   softc->device_stats);
 1601 
 1602         if (error) {
 1603                 if (dbd) {
 1604                         struct scsi_mode_sense_6 *sms;
 1605 
 1606                         sms = (struct scsi_mode_sense_6 *)
 1607                                 ccb->csio.cdb_io.cdb_bytes;
 1608 
 1609                         sms->byte2 &= ~SMS_DBD;
 1610                         error = cam_periph_runccb(ccb, cherror,
 1611                                                   /*cam_flags*/ CAM_RETRY_SELTO,
 1612                                                   /*sense_flags*/ SF_RETRY_UA,
 1613                                                   softc->device_stats);
 1614                 } else {
 1615                         /*
 1616                          * Since we disabled sense printing above, print
 1617                          * out the sense here since we got an error.
 1618                          */
 1619                         scsi_sense_print(&ccb->csio);
 1620                 }
 1621 
 1622                 if (error) {
 1623                         xpt_print(periph->path,
 1624                             "chgetparams: error getting element "
 1625                             "address page\n");
 1626                         xpt_release_ccb(ccb);
 1627                         free(mode_buffer, M_SCSICH);
 1628                         return(error);
 1629                 }
 1630         }
 1631 
 1632         ea = (struct page_element_address_assignment *)
 1633                 find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
 1634 
 1635         softc->sc_firsts[CHET_MT] = scsi_2btoul(ea->mtea);
 1636         softc->sc_counts[CHET_MT] = scsi_2btoul(ea->nmte);
 1637         softc->sc_firsts[CHET_ST] = scsi_2btoul(ea->fsea);
 1638         softc->sc_counts[CHET_ST] = scsi_2btoul(ea->nse);
 1639         softc->sc_firsts[CHET_IE] = scsi_2btoul(ea->fieea);
 1640         softc->sc_counts[CHET_IE] = scsi_2btoul(ea->niee);
 1641         softc->sc_firsts[CHET_DT] = scsi_2btoul(ea->fdtea);
 1642         softc->sc_counts[CHET_DT] = scsi_2btoul(ea->ndte);
 1643 
 1644         bzero(mode_buffer, mode_buffer_len);
 1645 
 1646         /*
 1647          * Now get the device capabilities page.
 1648          */
 1649         scsi_mode_sense(&ccb->csio,
 1650                         /* retries */ 1,
 1651                         /* cbfcnp */ chdone,
 1652                         /* tag_action */ MSG_SIMPLE_Q_TAG,
 1653                         /* dbd */ dbd,
 1654                         /* pc */ SMS_PAGE_CTRL_CURRENT,
 1655                         /* page */ CH_DEVICE_CAP_PAGE,
 1656                         /* param_buf */ (u_int8_t *)mode_buffer,
 1657                         /* param_len */ mode_buffer_len,
 1658                         /* sense_len */ SSD_FULL_SIZE,
 1659                         /* timeout */ CH_TIMEOUT_MODE_SENSE);
 1660         
 1661         error = cam_periph_runccb(ccb, cherror, /*cam_flags*/ CAM_RETRY_SELTO,
 1662                                   /* sense_flags */ SF_RETRY_UA | SF_NO_PRINT,
 1663                                   softc->device_stats);
 1664 
 1665         if (error) {
 1666                 if (dbd) {
 1667                         struct scsi_mode_sense_6 *sms;
 1668 
 1669                         sms = (struct scsi_mode_sense_6 *)
 1670                                 ccb->csio.cdb_io.cdb_bytes;
 1671 
 1672                         sms->byte2 &= ~SMS_DBD;
 1673                         error = cam_periph_runccb(ccb, cherror,
 1674                                                   /*cam_flags*/ CAM_RETRY_SELTO,
 1675                                                   /*sense_flags*/ SF_RETRY_UA,
 1676                                                   softc->device_stats);
 1677                 } else {
 1678                         /*
 1679                          * Since we disabled sense printing above, print
 1680                          * out the sense here since we got an error.
 1681                          */
 1682                         scsi_sense_print(&ccb->csio);
 1683                 }
 1684 
 1685                 if (error) {
 1686                         xpt_print(periph->path,
 1687                             "chgetparams: error getting device "
 1688                             "capabilities page\n");
 1689                         xpt_release_ccb(ccb);
 1690                         free(mode_buffer, M_SCSICH);
 1691                         return(error);
 1692                 }
 1693         }
 1694 
 1695         xpt_release_ccb(ccb);
 1696 
 1697         cap = (struct page_device_capabilities *)
 1698                 find_mode_page_6((struct scsi_mode_header_6 *)mode_buffer);
 1699 
 1700         bzero(softc->sc_movemask, sizeof(softc->sc_movemask));
 1701         bzero(softc->sc_exchangemask, sizeof(softc->sc_exchangemask));
 1702         moves = cap->move_from;
 1703         exchanges = cap->exchange_with;
 1704         for (from = CHET_MT; from <= CHET_MAX; ++from) {
 1705                 softc->sc_movemask[from] = moves[from];
 1706                 softc->sc_exchangemask[from] = exchanges[from];
 1707         }
 1708 
 1709         free(mode_buffer, M_SCSICH);
 1710 
 1711         return(error);
 1712 }
 1713 
 1714 static int
 1715 chscsiversion(struct cam_periph *periph)
 1716 {
 1717         struct scsi_inquiry_data *inq_data;
 1718         struct ccb_getdev *cgd;
 1719         int dev_scsi_version;
 1720 
 1721         cam_periph_assert(periph, MA_OWNED);
 1722         if ((cgd = (struct ccb_getdev *)xpt_alloc_ccb_nowait()) == NULL)
 1723                 return (-1);
 1724         /*
 1725          * Get the device information.
 1726          */
 1727         xpt_setup_ccb(&cgd->ccb_h,
 1728                       periph->path,
 1729                       CAM_PRIORITY_NORMAL);
 1730         cgd->ccb_h.func_code = XPT_GDEV_TYPE;
 1731         xpt_action((union ccb *)cgd);
 1732 
 1733         if (cgd->ccb_h.status != CAM_REQ_CMP) {
 1734                 xpt_free_ccb((union ccb *)cgd);
 1735                 return -1;
 1736         }
 1737 
 1738         inq_data = &cgd->inq_data;
 1739         dev_scsi_version = inq_data->version;
 1740         xpt_free_ccb((union ccb *)cgd);
 1741 
 1742         return dev_scsi_version;
 1743 }
 1744 
 1745 void
 1746 scsi_move_medium(struct ccb_scsiio *csio, u_int32_t retries,
 1747                  void (*cbfcnp)(struct cam_periph *, union ccb *),
 1748                  u_int8_t tag_action, u_int32_t tea, u_int32_t src,
 1749                  u_int32_t dst, int invert, u_int8_t sense_len,
 1750                  u_int32_t timeout)
 1751 {
 1752         struct scsi_move_medium *scsi_cmd;
 1753 
 1754         scsi_cmd = (struct scsi_move_medium *)&csio->cdb_io.cdb_bytes;
 1755         bzero(scsi_cmd, sizeof(*scsi_cmd));
 1756 
 1757         scsi_cmd->opcode = MOVE_MEDIUM;
 1758 
 1759         scsi_ulto2b(tea, scsi_cmd->tea);
 1760         scsi_ulto2b(src, scsi_cmd->src);
 1761         scsi_ulto2b(dst, scsi_cmd->dst);
 1762 
 1763         if (invert)
 1764                 scsi_cmd->invert |= MOVE_MEDIUM_INVERT;
 1765 
 1766         cam_fill_csio(csio,
 1767                       retries,
 1768                       cbfcnp,
 1769                       /*flags*/ CAM_DIR_NONE,
 1770                       tag_action,
 1771                       /*data_ptr*/ NULL,
 1772                       /*dxfer_len*/ 0,
 1773                       sense_len,
 1774                       sizeof(*scsi_cmd),
 1775                       timeout);
 1776 }
 1777 
 1778 void
 1779 scsi_exchange_medium(struct ccb_scsiio *csio, u_int32_t retries,
 1780                      void (*cbfcnp)(struct cam_periph *, union ccb *),
 1781                      u_int8_t tag_action, u_int32_t tea, u_int32_t src,
 1782                      u_int32_t dst1, u_int32_t dst2, int invert1,
 1783                      int invert2, u_int8_t sense_len, u_int32_t timeout)
 1784 {
 1785         struct scsi_exchange_medium *scsi_cmd;
 1786 
 1787         scsi_cmd = (struct scsi_exchange_medium *)&csio->cdb_io.cdb_bytes;
 1788         bzero(scsi_cmd, sizeof(*scsi_cmd));
 1789 
 1790         scsi_cmd->opcode = EXCHANGE_MEDIUM;
 1791 
 1792         scsi_ulto2b(tea, scsi_cmd->tea);
 1793         scsi_ulto2b(src, scsi_cmd->src);
 1794         scsi_ulto2b(dst1, scsi_cmd->fdst);
 1795         scsi_ulto2b(dst2, scsi_cmd->sdst);
 1796 
 1797         if (invert1)
 1798                 scsi_cmd->invert |= EXCHANGE_MEDIUM_INV1;
 1799 
 1800         if (invert2)
 1801                 scsi_cmd->invert |= EXCHANGE_MEDIUM_INV2;
 1802 
 1803         cam_fill_csio(csio,
 1804                       retries,
 1805                       cbfcnp,
 1806                       /*flags*/ CAM_DIR_NONE,
 1807                       tag_action,
 1808                       /*data_ptr*/ NULL,
 1809                       /*dxfer_len*/ 0,
 1810                       sense_len,
 1811                       sizeof(*scsi_cmd),
 1812                       timeout);
 1813 }
 1814 
 1815 void
 1816 scsi_position_to_element(struct ccb_scsiio *csio, u_int32_t retries,
 1817                          void (*cbfcnp)(struct cam_periph *, union ccb *),
 1818                          u_int8_t tag_action, u_int32_t tea, u_int32_t dst,
 1819                          int invert, u_int8_t sense_len, u_int32_t timeout)
 1820 {
 1821         struct scsi_position_to_element *scsi_cmd;
 1822 
 1823         scsi_cmd = (struct scsi_position_to_element *)&csio->cdb_io.cdb_bytes;
 1824         bzero(scsi_cmd, sizeof(*scsi_cmd));
 1825 
 1826         scsi_cmd->opcode = POSITION_TO_ELEMENT;
 1827 
 1828         scsi_ulto2b(tea, scsi_cmd->tea);
 1829         scsi_ulto2b(dst, scsi_cmd->dst);
 1830 
 1831         if (invert)
 1832                 scsi_cmd->invert |= POSITION_TO_ELEMENT_INVERT;
 1833 
 1834         cam_fill_csio(csio,
 1835                       retries,
 1836                       cbfcnp,
 1837                       /*flags*/ CAM_DIR_NONE,
 1838                       tag_action,
 1839                       /*data_ptr*/ NULL,
 1840                       /*dxfer_len*/ 0,
 1841                       sense_len,
 1842                       sizeof(*scsi_cmd),
 1843                       timeout);
 1844 }
 1845 
 1846 void
 1847 scsi_read_element_status(struct ccb_scsiio *csio, u_int32_t retries,
 1848                          void (*cbfcnp)(struct cam_periph *, union ccb *),
 1849                          u_int8_t tag_action, int voltag, u_int32_t sea,
 1850                          int curdata, int dvcid,
 1851                          u_int32_t count, u_int8_t *data_ptr,
 1852                          u_int32_t dxfer_len, u_int8_t sense_len,
 1853                          u_int32_t timeout)
 1854 {
 1855         struct scsi_read_element_status *scsi_cmd;
 1856 
 1857         scsi_cmd = (struct scsi_read_element_status *)&csio->cdb_io.cdb_bytes;
 1858         bzero(scsi_cmd, sizeof(*scsi_cmd));
 1859 
 1860         scsi_cmd->opcode = READ_ELEMENT_STATUS;
 1861 
 1862         scsi_ulto2b(sea, scsi_cmd->sea);
 1863         scsi_ulto2b(count, scsi_cmd->count);
 1864         scsi_ulto3b(dxfer_len, scsi_cmd->len);
 1865         if (dvcid)
 1866                 scsi_cmd->flags |= READ_ELEMENT_STATUS_DVCID;
 1867         if (curdata)
 1868                 scsi_cmd->flags |= READ_ELEMENT_STATUS_CURDATA;
 1869 
 1870         if (voltag)
 1871                 scsi_cmd->byte2 |= READ_ELEMENT_STATUS_VOLTAG;
 1872 
 1873         cam_fill_csio(csio,
 1874                       retries,
 1875                       cbfcnp,
 1876                       /*flags*/ CAM_DIR_IN,
 1877                       tag_action,
 1878                       data_ptr,
 1879                       dxfer_len,
 1880                       sense_len,
 1881                       sizeof(*scsi_cmd),
 1882                       timeout);
 1883 }
 1884 
 1885 void
 1886 scsi_initialize_element_status(struct ccb_scsiio *csio, u_int32_t retries,
 1887                                void (*cbfcnp)(struct cam_periph *, union ccb *),
 1888                                u_int8_t tag_action, u_int8_t sense_len,
 1889                                u_int32_t timeout)
 1890 {
 1891         struct scsi_initialize_element_status *scsi_cmd;
 1892 
 1893         scsi_cmd = (struct scsi_initialize_element_status *)
 1894                     &csio->cdb_io.cdb_bytes;
 1895         bzero(scsi_cmd, sizeof(*scsi_cmd));
 1896 
 1897         scsi_cmd->opcode = INITIALIZE_ELEMENT_STATUS;
 1898 
 1899         cam_fill_csio(csio,
 1900                       retries,
 1901                       cbfcnp,
 1902                       /*flags*/ CAM_DIR_NONE,
 1903                       tag_action,
 1904                       /* data_ptr */ NULL,
 1905                       /* dxfer_len */ 0,
 1906                       sense_len,
 1907                       sizeof(*scsi_cmd),
 1908                       timeout);
 1909 }
 1910 
 1911 void
 1912 scsi_send_volume_tag(struct ccb_scsiio *csio, u_int32_t retries,
 1913                      void (*cbfcnp)(struct cam_periph *, union ccb *),
 1914                      u_int8_t tag_action, 
 1915                      u_int16_t element_address,
 1916                      u_int8_t send_action_code,
 1917                      struct scsi_send_volume_tag_parameters *parameters,
 1918                      u_int8_t sense_len, u_int32_t timeout)
 1919 {
 1920         struct scsi_send_volume_tag *scsi_cmd;
 1921 
 1922         scsi_cmd = (struct scsi_send_volume_tag *) &csio->cdb_io.cdb_bytes;
 1923         bzero(scsi_cmd, sizeof(*scsi_cmd));
 1924 
 1925         scsi_cmd->opcode = SEND_VOLUME_TAG;
 1926         scsi_ulto2b(element_address, scsi_cmd->ea);
 1927         scsi_cmd->sac = send_action_code;
 1928         scsi_ulto2b(sizeof(*parameters), scsi_cmd->pll);
 1929 
 1930         cam_fill_csio(csio,
 1931                       retries,
 1932                       cbfcnp,
 1933                       /*flags*/ CAM_DIR_OUT,
 1934                       tag_action,
 1935                       /* data_ptr */ (u_int8_t *) parameters,
 1936                       sizeof(*parameters),
 1937                       sense_len,
 1938                       sizeof(*scsi_cmd),
 1939                       timeout);
 1940 }

Cache object: 83962d8db6a3110a7eb42acf3b240a0f


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