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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/scsipi/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 /*      $NetBSD: ch.c,v 1.69 2005/02/27 00:27:48 perry Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 1996, 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 #include <sys/cdefs.h>
   41 __KERNEL_RCSID(0, "$NetBSD: ch.c,v 1.69 2005/02/27 00:27:48 perry Exp $");
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/kernel.h>
   46 #include <sys/errno.h>
   47 #include <sys/ioctl.h>
   48 #include <sys/buf.h>
   49 #include <sys/proc.h>
   50 #include <sys/user.h>
   51 #include <sys/chio.h>
   52 #include <sys/device.h>
   53 #include <sys/malloc.h>
   54 #include <sys/conf.h>
   55 #include <sys/fcntl.h>
   56 #include <sys/vnode.h>
   57 #include <sys/time.h>
   58 #include <sys/select.h>
   59 #include <sys/poll.h>
   60 
   61 #include <dev/scsipi/scsipi_all.h>
   62 #include <dev/scsipi/scsi_all.h>
   63 #include <dev/scsipi/scsi_changer.h>
   64 #include <dev/scsipi/scsiconf.h>
   65 
   66 #define CHRETRIES       2
   67 #define CHUNIT(x)       (minor((x)))
   68 
   69 struct ch_softc {
   70         struct device   sc_dev;         /* generic device info */
   71         struct scsipi_periph *sc_periph;/* our periph data */
   72 
   73         u_int           sc_events;      /* event bitmask */
   74         struct selinfo  sc_selq;        /* select/poll queue for events */
   75 
   76         int             sc_flags;       /* misc. info */
   77 
   78         int             sc_picker;      /* current picker */
   79 
   80         /*
   81          * The following information is obtained from the
   82          * element address assignment page.
   83          */
   84         int             sc_firsts[4];   /* firsts, indexed by CHET_* */
   85         int             sc_counts[4];   /* counts, indexed by CHET_* */
   86 
   87         /*
   88          * The following mask defines the legal combinations
   89          * of elements for the MOVE MEDIUM command.
   90          */
   91         u_int8_t        sc_movemask[4];
   92 
   93         /*
   94          * As above, but for EXCHANGE MEDIUM.
   95          */
   96         u_int8_t        sc_exchangemask[4];
   97 
   98         /*
   99          * Quirks; see below.
  100          */
  101         int             sc_settledelay; /* delay for settle */
  102 
  103 };
  104 
  105 /* sc_flags */
  106 #define CHF_ROTATE              0x01    /* picker can rotate */
  107 
  108 /* Autoconfiguration glue */
  109 static int      chmatch(struct device *, struct cfdata *, void *);
  110 static void     chattach(struct device *, struct device *, void *);
  111 
  112 CFATTACH_DECL(ch, sizeof(struct ch_softc),
  113     chmatch, chattach, NULL, NULL);
  114 
  115 extern struct cfdriver ch_cd;
  116 
  117 static struct scsipi_inquiry_pattern ch_patterns[] = {
  118         {T_CHANGER, T_REMOV,
  119          "",            "",             ""},
  120 };
  121 
  122 static dev_type_open(chopen);
  123 static dev_type_close(chclose);
  124 static dev_type_read(chread);
  125 static dev_type_ioctl(chioctl);
  126 static dev_type_poll(chpoll);
  127 static dev_type_kqfilter(chkqfilter);
  128 
  129 const struct cdevsw ch_cdevsw = {
  130         chopen, chclose, chread, nowrite, chioctl,
  131         nostop, notty, chpoll, nommap, chkqfilter,
  132 };
  133 
  134 /* SCSI glue */
  135 static int      ch_interpret_sense(struct scsipi_xfer *);
  136 
  137 static const struct scsipi_periphsw ch_switch = {
  138         ch_interpret_sense,     /* check our error handler first */
  139         NULL,                   /* no queue; our commands are synchronous */
  140         NULL,                   /* have no async handler */
  141         NULL,                   /* nothing to be done when xfer is done */
  142 };
  143 
  144 static int      ch_move(struct ch_softc *, struct changer_move_request *);
  145 static int      ch_exchange(struct ch_softc *,
  146                     struct changer_exchange_request *);
  147 static int      ch_position(struct ch_softc *,
  148                     struct changer_position_request *);
  149 static int      ch_ielem(struct ch_softc *);
  150 static int      ch_ousergetelemstatus(struct ch_softc *, int, u_int8_t *);
  151 static int      ch_usergetelemstatus(struct ch_softc *,
  152                     struct changer_element_status_request *);
  153 static int      ch_getelemstatus(struct ch_softc *, int, int, void *,
  154                     size_t, int, int);
  155 static int      ch_setvoltag(struct ch_softc *,
  156                     struct changer_set_voltag_request *);
  157 static int      ch_get_params(struct ch_softc *, int);
  158 static void     ch_get_quirks(struct ch_softc *,
  159                     struct scsipi_inquiry_pattern *);
  160 static void     ch_event(struct ch_softc *, u_int);
  161 static int      ch_map_element(struct ch_softc *, u_int16_t, int *, int *);
  162 
  163 static void     ch_voltag_convert_in(const struct changer_volume_tag *,
  164                     struct changer_voltag *);
  165 static int      ch_voltag_convert_out(const struct changer_voltag *,
  166                     struct changer_volume_tag *);
  167 
  168 /*
  169  * SCSI changer quirks.
  170  */
  171 struct chquirk {
  172         struct  scsipi_inquiry_pattern cq_match; /* device id pattern */
  173         int     cq_settledelay; /* settle delay, in seconds */
  174 };
  175 
  176 static const struct chquirk chquirks[] = {
  177         {{T_CHANGER, T_REMOV,
  178           "SPECTRA",    "9000",         "0200"},
  179          75},
  180 };
  181 
  182 static int
  183 chmatch(struct device *parent, struct cfdata *match, void *aux)
  184 {
  185         struct scsipibus_attach_args *sa = aux;
  186         int priority;
  187 
  188         (void)scsipi_inqmatch(&sa->sa_inqbuf,
  189             (caddr_t)ch_patterns, sizeof(ch_patterns) / sizeof(ch_patterns[0]),
  190             sizeof(ch_patterns[0]), &priority);
  191 
  192         return (priority);
  193 }
  194 
  195 static void
  196 chattach(struct device *parent, struct device *self, void *aux)
  197 {
  198         struct ch_softc *sc = (struct ch_softc *)self;
  199         struct scsipibus_attach_args *sa = aux;
  200         struct scsipi_periph *periph = sa->sa_periph;
  201 
  202         /* Glue into the SCSI bus */
  203         sc->sc_periph = periph;
  204         periph->periph_dev = &sc->sc_dev;
  205         periph->periph_switch = &ch_switch;
  206 
  207         printf("\n");
  208 
  209         /*
  210          * Find out our device's quirks.
  211          */
  212         ch_get_quirks(sc, &sa->sa_inqbuf);
  213 
  214         /*
  215          * Some changers require a long time to settle out, to do
  216          * tape inventory, for instance.
  217          */
  218         if (sc->sc_settledelay) {
  219                 printf("%s: waiting %d seconds for changer to settle...\n",
  220                     sc->sc_dev.dv_xname, sc->sc_settledelay);
  221                 delay(1000000 * sc->sc_settledelay);
  222         }
  223 
  224         /*
  225          * Get information about the device.  Note we can't use
  226          * interrupts yet.
  227          */
  228         if (ch_get_params(sc, XS_CTL_DISCOVERY|XS_CTL_IGNORE_MEDIA_CHANGE))
  229                 printf("%s: offline\n", sc->sc_dev.dv_xname);
  230         else {
  231 #define PLURAL(c)       (c) == 1 ? "" : "s"
  232                 printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n",
  233                     sc->sc_dev.dv_xname,
  234                     sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]),
  235                     sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]),
  236                     sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]),
  237                     sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE]));
  238 #undef PLURAL
  239 #ifdef CHANGER_DEBUG
  240                 printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
  241                     sc->sc_dev.dv_xname,
  242                     sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
  243                     sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
  244                 printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
  245                     sc->sc_dev.dv_xname,
  246                     sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
  247                     sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
  248 #endif /* CHANGER_DEBUG */
  249         }
  250 
  251         /* Default the current picker. */
  252         sc->sc_picker = sc->sc_firsts[CHET_MT];
  253 }
  254 
  255 static int
  256 chopen(dev_t dev, int flags, int fmt, struct proc *p)
  257 {
  258         struct ch_softc *sc;
  259         struct scsipi_periph *periph;
  260         struct scsipi_adapter *adapt;
  261         int unit, error;
  262 
  263         unit = CHUNIT(dev);
  264         if ((unit >= ch_cd.cd_ndevs) ||
  265             ((sc = ch_cd.cd_devs[unit]) == NULL))
  266                 return (ENXIO);
  267 
  268         periph = sc->sc_periph;
  269         adapt = periph->periph_channel->chan_adapter;
  270 
  271         /*
  272          * Only allow one open at a time.
  273          */
  274         if (periph->periph_flags & PERIPH_OPEN)
  275                 return (EBUSY);
  276 
  277         if ((error = scsipi_adapter_addref(adapt)) != 0)
  278                 return (error);
  279 
  280         /*
  281          * Make sure the unit is on-line.  If a UNIT ATTENTION
  282          * occurs, we will mark that an Init-Element-Status is
  283          * needed in ch_get_params().
  284          *
  285          * We ignore NOT READY in case e.g a magazine isn't actually
  286          * loaded into the changer or a tape isn't in the drive.
  287          */
  288         error = scsipi_test_unit_ready(periph, XS_CTL_IGNORE_NOT_READY);
  289         if (error)
  290                 goto bad;
  291 
  292         periph->periph_flags |= PERIPH_OPEN;
  293 
  294         /*
  295          * Make sure our parameters are up to date.
  296          */
  297         if ((error = ch_get_params(sc, 0)) != 0)
  298                 goto bad;
  299 
  300         return (0);
  301 
  302  bad:
  303         scsipi_adapter_delref(adapt);
  304         periph->periph_flags &= ~PERIPH_OPEN;
  305         return (error);
  306 }
  307 
  308 static int
  309 chclose(dev_t dev, int flags, int fmt, struct proc *p)
  310 {
  311         struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  312         struct scsipi_periph *periph = sc->sc_periph;
  313         struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
  314 
  315         scsipi_wait_drain(periph);
  316 
  317         scsipi_adapter_delref(adapt);
  318 
  319         sc->sc_events = 0;
  320 
  321         periph->periph_flags &= ~PERIPH_OPEN;
  322         return (0);
  323 }
  324 
  325 static int
  326 chread(dev_t dev, struct uio *uio, int flags)
  327 {
  328         struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  329         int error;
  330 
  331         if (uio->uio_resid != CHANGER_EVENT_SIZE)
  332                 return (EINVAL);
  333 
  334         /*
  335          * Read never blocks; if there are no events pending, we just
  336          * return an all-clear bitmask.
  337          */
  338         error = uiomove(&sc->sc_events, CHANGER_EVENT_SIZE, uio);
  339         if (error == 0)
  340                 sc->sc_events = 0;
  341         return (error);
  342 }
  343 
  344 static int
  345 chioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  346 {
  347         struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  348         int error = 0;
  349 
  350         /*
  351          * If this command can change the device's state, we must
  352          * have the device open for writing.
  353          */
  354         switch (cmd) {
  355         case CHIOGPICKER:
  356         case CHIOGPARAMS:
  357         case OCHIOGSTATUS:
  358                 break;
  359 
  360         default:
  361                 if ((flags & FWRITE) == 0)
  362                         return (EBADF);
  363         }
  364 
  365         switch (cmd) {
  366         case CHIOMOVE:
  367                 error = ch_move(sc, (struct changer_move_request *)data);
  368                 break;
  369 
  370         case CHIOEXCHANGE:
  371                 error = ch_exchange(sc,
  372                     (struct changer_exchange_request *)data);
  373                 break;
  374 
  375         case CHIOPOSITION:
  376                 error = ch_position(sc,
  377                     (struct changer_position_request *)data);
  378                 break;
  379 
  380         case CHIOGPICKER:
  381                 *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
  382                 break;
  383 
  384         case CHIOSPICKER:
  385             {
  386                 int new_picker = *(int *)data;
  387 
  388                 if (new_picker > (sc->sc_counts[CHET_MT] - 1))
  389                         return (EINVAL);
  390                 sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
  391                 break;
  392             }
  393 
  394         case CHIOGPARAMS:
  395             {
  396                 struct changer_params *cp = (struct changer_params *)data;
  397 
  398                 cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
  399                 cp->cp_npickers = sc->sc_counts[CHET_MT];
  400                 cp->cp_nslots = sc->sc_counts[CHET_ST];
  401                 cp->cp_nportals = sc->sc_counts[CHET_IE];
  402                 cp->cp_ndrives = sc->sc_counts[CHET_DT];
  403                 break;
  404             }
  405 
  406         case CHIOIELEM:
  407                 error = ch_ielem(sc);
  408                 if (error == 0) {
  409                         sc->sc_periph->periph_flags |= PERIPH_MEDIA_LOADED;
  410                 }
  411                 break;
  412 
  413         case OCHIOGSTATUS:
  414             {
  415                 struct ochanger_element_status_request *cesr =
  416                     (struct ochanger_element_status_request *)data;
  417 
  418                 error = ch_ousergetelemstatus(sc, cesr->cesr_type,
  419                     cesr->cesr_data);
  420                 break;
  421             }
  422 
  423         case CHIOGSTATUS:
  424                 error = ch_usergetelemstatus(sc,
  425                     (struct changer_element_status_request *)data);
  426                 break;
  427 
  428         case CHIOSVOLTAG:
  429                 error = ch_setvoltag(sc,
  430                     (struct changer_set_voltag_request *)data);
  431                 break;
  432 
  433         /* Implement prevent/allow? */
  434 
  435         default:
  436                 error = scsipi_do_ioctl(sc->sc_periph, dev, cmd, data,
  437                     flags, p);
  438                 break;
  439         }
  440 
  441         return (error);
  442 }
  443 
  444 static int
  445 chpoll(dev_t dev, int events, struct proc *p)
  446 {
  447         struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  448         int revents;
  449 
  450         revents = events & (POLLOUT | POLLWRNORM);
  451 
  452         if ((events & (POLLIN | POLLRDNORM)) == 0)
  453                 return (revents);
  454 
  455         if (sc->sc_events == 0)
  456                 revents |= events & (POLLIN | POLLRDNORM);
  457         else
  458                 selrecord(p, &sc->sc_selq);
  459 
  460         return (revents);
  461 }
  462 
  463 static void
  464 filt_chdetach(struct knote *kn)
  465 {
  466         struct ch_softc *sc = kn->kn_hook;
  467 
  468         SLIST_REMOVE(&sc->sc_selq.sel_klist, kn, knote, kn_selnext);
  469 }
  470 
  471 static int
  472 filt_chread(struct knote *kn, long hint)
  473 {
  474         struct ch_softc *sc = kn->kn_hook;
  475 
  476         if (sc->sc_events == 0)
  477                 return (0);
  478         kn->kn_data = CHANGER_EVENT_SIZE;
  479         return (1);
  480 }
  481 
  482 static const struct filterops chread_filtops =
  483         { 1, NULL, filt_chdetach, filt_chread };
  484 
  485 static const struct filterops chwrite_filtops =
  486         { 1, NULL, filt_chdetach, filt_seltrue };
  487 
  488 static int
  489 chkqfilter(dev_t dev, struct knote *kn)
  490 {
  491         struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  492         struct klist *klist;
  493 
  494         switch (kn->kn_filter) {
  495         case EVFILT_READ:
  496                 klist = &sc->sc_selq.sel_klist;
  497                 kn->kn_fop = &chread_filtops;
  498                 break;
  499 
  500         case EVFILT_WRITE:
  501                 klist = &sc->sc_selq.sel_klist;
  502                 kn->kn_fop = &chwrite_filtops;
  503                 break;
  504 
  505         default:
  506                 return (1);
  507         }
  508 
  509         kn->kn_hook = sc;
  510 
  511         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
  512 
  513         return (0);
  514 }
  515 
  516 static int
  517 ch_interpret_sense(struct scsipi_xfer *xs)
  518 {
  519         struct scsipi_periph *periph = xs->xs_periph;
  520         struct scsi_sense_data *sense = &xs->sense.scsi_sense;
  521         struct ch_softc *sc = (void *)periph->periph_dev;
  522         u_int16_t asc_ascq;
  523 
  524         /*
  525          * If the periph is already recovering, just do the
  526          * normal error recovering.
  527          */
  528         if (periph->periph_flags & PERIPH_RECOVERING)
  529                 return (EJUSTRETURN);
  530 
  531         /*
  532          * If it isn't an extended or extended/deferred error, let
  533          * the generic code handle it.
  534          */
  535         if ((sense->response_code & SSD_RCODE_VALID) == 0 ||
  536             (SSD_RCODE(sense->response_code) != SSD_RCODE_CURRENT &&
  537              SSD_RCODE(sense->response_code) != SSD_RCODE_DEFERRED))
  538                 return (EJUSTRETURN);
  539 
  540         /*
  541          * We're only interested in condtions that
  542          * indicate potential inventory violation.
  543          *
  544          * We use ASC/ASCQ codes for this.
  545          */
  546 
  547         asc_ascq = (((u_int16_t) sense->asc) << 8) |
  548             sense->ascq;
  549 
  550         switch (asc_ascq) {
  551         case 0x2800:
  552                 /* "Not Ready To Ready Transition (Medium May Have Changed)" */
  553         case 0x2900:
  554                 /* "Power On, Reset, or Bus Device Reset Occurred" */
  555                 sc->sc_periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
  556                 /*
  557                  * Enqueue an Element-Status-Changed event, and wake up
  558                  * any processes waiting for them.
  559                  */
  560                 if ((xs->xs_control & XS_CTL_IGNORE_MEDIA_CHANGE) == 0)
  561                         ch_event(sc, CHEV_ELEMENT_STATUS_CHANGED);
  562                 break;
  563         default:
  564                 break;
  565         }
  566 
  567         return (EJUSTRETURN);
  568 }
  569 
  570 static void
  571 ch_event(struct ch_softc *sc, u_int event)
  572 {
  573 
  574         sc->sc_events |= event;
  575         selnotify(&sc->sc_selq, 0);
  576 }
  577 
  578 static int
  579 ch_move(struct ch_softc *sc, struct changer_move_request *cm)
  580 {
  581         struct scsi_move_medium cmd;
  582         u_int16_t fromelem, toelem;
  583 
  584         /*
  585          * Check arguments.
  586          */
  587         if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
  588                 return (EINVAL);
  589         if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
  590             (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
  591                 return (ENODEV);
  592 
  593         /*
  594          * Check the request against the changer's capabilities.
  595          */
  596         if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
  597                 return (ENODEV);
  598 
  599         /*
  600          * Calculate the source and destination elements.
  601          */
  602         fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
  603         toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
  604 
  605         /*
  606          * Build the SCSI command.
  607          */
  608         memset(&cmd, 0, sizeof(cmd));
  609         cmd.opcode = MOVE_MEDIUM;
  610         _lto2b(sc->sc_picker, cmd.tea);
  611         _lto2b(fromelem, cmd.src);
  612         _lto2b(toelem, cmd.dst);
  613         if (cm->cm_flags & CM_INVERT)
  614                 cmd.flags |= MOVE_MEDIUM_INVERT;
  615 
  616         /*
  617          * Send command to changer.
  618          */
  619         return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
  620             CHRETRIES, 100000, NULL, 0));
  621 }
  622 
  623 static int
  624 ch_exchange(struct ch_softc *sc, struct changer_exchange_request *ce)
  625 {
  626         struct scsi_exchange_medium cmd;
  627         u_int16_t src, dst1, dst2;
  628 
  629         /*
  630          * Check arguments.
  631          */
  632         if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
  633             (ce->ce_sdsttype > CHET_DT))
  634                 return (EINVAL);
  635         if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
  636             (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
  637             (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
  638                 return (ENODEV);
  639 
  640         /*
  641          * Check the request against the changer's capabilities.
  642          */
  643         if (((sc->sc_exchangemask[ce->ce_srctype] &
  644              (1 << ce->ce_fdsttype)) == 0) ||
  645             ((sc->sc_exchangemask[ce->ce_fdsttype] &
  646              (1 << ce->ce_sdsttype)) == 0))
  647                 return (ENODEV);
  648 
  649         /*
  650          * Calculate the source and destination elements.
  651          */
  652         src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
  653         dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
  654         dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
  655 
  656         /*
  657          * Build the SCSI command.
  658          */
  659         memset(&cmd, 0, sizeof(cmd));
  660         cmd.opcode = EXCHANGE_MEDIUM;
  661         _lto2b(sc->sc_picker, cmd.tea);
  662         _lto2b(src, cmd.src);
  663         _lto2b(dst1, cmd.fdst);
  664         _lto2b(dst2, cmd.sdst);
  665         if (ce->ce_flags & CE_INVERT1)
  666                 cmd.flags |= EXCHANGE_MEDIUM_INV1;
  667         if (ce->ce_flags & CE_INVERT2)
  668                 cmd.flags |= EXCHANGE_MEDIUM_INV2;
  669 
  670         /*
  671          * Send command to changer.
  672          */
  673         return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
  674             CHRETRIES, 100000, NULL, 0));
  675 }
  676 
  677 static int
  678 ch_position(struct ch_softc *sc, struct changer_position_request *cp)
  679 {
  680         struct scsi_position_to_element cmd;
  681         u_int16_t dst;
  682 
  683         /*
  684          * Check arguments.
  685          */
  686         if (cp->cp_type > CHET_DT)
  687                 return (EINVAL);
  688         if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
  689                 return (ENODEV);
  690 
  691         /*
  692          * Calculate the destination element.
  693          */
  694         dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
  695 
  696         /*
  697          * Build the SCSI command.
  698          */
  699         memset(&cmd, 0, sizeof(cmd));
  700         cmd.opcode = POSITION_TO_ELEMENT;
  701         _lto2b(sc->sc_picker, cmd.tea);
  702         _lto2b(dst, cmd.dst);
  703         if (cp->cp_flags & CP_INVERT)
  704                 cmd.flags |= POSITION_TO_ELEMENT_INVERT;
  705 
  706         /*
  707          * Send command to changer.
  708          */
  709         return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
  710             CHRETRIES, 100000, NULL, 0));
  711 }
  712 
  713 /*
  714  * Perform a READ ELEMENT STATUS on behalf of the user, and return to
  715  * the user only the data the user is interested in.  This returns the
  716  * old data format.
  717  */
  718 static int
  719 ch_ousergetelemstatus(struct ch_softc *sc, int chet, u_int8_t *uptr)
  720 {
  721         struct read_element_status_header *st_hdrp, st_hdr;
  722         struct read_element_status_page_header *pg_hdrp;
  723         struct read_element_status_descriptor *desc;
  724         size_t size, desclen;
  725         caddr_t data;
  726         int avail, i, error = 0;
  727         u_int8_t user_data;
  728 
  729         /*
  730          * If there are no elements of the requested type in the changer,
  731          * the request is invalid.
  732          */
  733         if (sc->sc_counts[chet] == 0)
  734                 return (EINVAL);
  735 
  736         /*
  737          * Do the request the user wants, but only read the status header.
  738          * This will tell us the amount of storage we must allocate in
  739          * order to read all data.
  740          */
  741         error = ch_getelemstatus(sc, sc->sc_firsts[chet],
  742             sc->sc_counts[chet], &st_hdr, sizeof(st_hdr),
  743             XS_CTL_DATA_ONSTACK, 0);
  744         if (error)
  745                 return (error);
  746 
  747         size = sizeof(struct read_element_status_header) +
  748             _3btol(st_hdr.nbytes);
  749 
  750         /*
  751          * We must have at least room for the status header and
  752          * one page header (since we only ask for one element type
  753          * at a time).
  754          */
  755         if (size < (sizeof(struct read_element_status_header) +
  756             sizeof(struct read_element_status_page_header)))
  757                 return (EIO);
  758 
  759         /*
  760          * Allocate the storage and do the request again.
  761          */
  762         data = malloc(size, M_DEVBUF, M_WAITOK);
  763         error = ch_getelemstatus(sc, sc->sc_firsts[chet],
  764             sc->sc_counts[chet], data, size, 0, 0);
  765         if (error)
  766                 goto done;
  767 
  768         st_hdrp = (struct read_element_status_header *)data;
  769         pg_hdrp = (struct read_element_status_page_header *)((u_long)st_hdrp +
  770             sizeof(struct read_element_status_header));
  771         desclen = _2btol(pg_hdrp->edl);
  772 
  773         /*
  774          * Fill in the user status array.
  775          */
  776         avail = _2btol(st_hdrp->count);
  777 
  778         if (avail != sc->sc_counts[chet])
  779                 printf("%s: warning, READ ELEMENT STATUS avail != count\n",
  780                     sc->sc_dev.dv_xname);
  781 
  782         desc = (struct read_element_status_descriptor *)((u_long)data +
  783             sizeof(struct read_element_status_header) +
  784             sizeof(struct read_element_status_page_header));
  785         for (i = 0; i < avail; ++i) {
  786                 user_data = desc->flags1;
  787                 error = copyout(&user_data, &uptr[i], avail);
  788                 if (error)
  789                         break;
  790                 desc = (struct read_element_status_descriptor *)((u_long)desc
  791                     + desclen);
  792         }
  793 
  794  done:
  795         if (data != NULL)
  796                 free(data, M_DEVBUF);
  797         return (error);
  798 }
  799 
  800 /*
  801  * Perform a READ ELEMENT STATUS on behalf of the user.  This returns
  802  * the new (more complete) data format.
  803  */
  804 static int
  805 ch_usergetelemstatus(struct ch_softc *sc,
  806     struct changer_element_status_request *cesr)
  807 {
  808         struct scsipi_channel *chan = sc->sc_periph->periph_channel;
  809         struct scsipi_periph *dtperiph;
  810         struct read_element_status_header *st_hdrp, st_hdr;
  811         struct read_element_status_page_header *pg_hdrp;
  812         struct read_element_status_descriptor *desc;
  813         struct changer_volume_tag *avol, *pvol;
  814         size_t size, desclen, stddesclen, offset;
  815         int first, avail, i, error = 0;
  816         caddr_t data;
  817         void *uvendptr;
  818         struct changer_element_status ces;
  819 
  820         /*
  821          * Check arguments.
  822          */
  823         if (cesr->cesr_type > CHET_DT)
  824                 return (EINVAL);
  825         if (sc->sc_counts[cesr->cesr_type] == 0)
  826                 return (ENODEV);
  827         if (cesr->cesr_unit > (sc->sc_counts[cesr->cesr_type] - 1))
  828                 return (ENODEV);
  829         if (cesr->cesr_count >
  830             (sc->sc_counts[cesr->cesr_type] + cesr->cesr_unit))
  831                 return (EINVAL);
  832 
  833         /*
  834          * Do the request the user wants, but only read the status header.
  835          * This will tell us the amount of storage we must allocate
  836          * in order to read all the data.
  837          */
  838         error = ch_getelemstatus(sc, sc->sc_firsts[cesr->cesr_type] +
  839             cesr->cesr_unit, cesr->cesr_count, &st_hdr, sizeof(st_hdr), 0,
  840             cesr->cesr_flags);
  841         if (error)
  842                 return (error);
  843 
  844         size = sizeof(struct read_element_status_header) +
  845             _3btol(st_hdr.nbytes);
  846 
  847         /*
  848          * We must have at least room for the status header and
  849          * one page header (since we only ask for oen element type
  850          * at a time).
  851          */
  852         if (size < (sizeof(struct read_element_status_header) +
  853             sizeof(struct read_element_status_page_header)))
  854                 return (EIO);
  855 
  856         /*
  857          * Allocate the storage and do the request again.
  858          */
  859         data = malloc(size, M_DEVBUF, M_WAITOK);
  860         error = ch_getelemstatus(sc, sc->sc_firsts[cesr->cesr_type] +
  861             cesr->cesr_unit, cesr->cesr_count, data, size, 0,
  862             cesr->cesr_flags);
  863         if (error)
  864                 goto done;
  865 
  866         st_hdrp = (struct read_element_status_header *)data;
  867         pg_hdrp = (struct read_element_status_page_header *)((u_long)st_hdrp +
  868             sizeof(struct read_element_status_header));
  869         desclen = _2btol(pg_hdrp->edl);
  870 
  871         /*
  872          * Fill in the user status array.
  873          */
  874         first = _2btol(st_hdrp->fear);
  875         if (first <  (sc->sc_firsts[cesr->cesr_type] + cesr->cesr_unit) ||
  876             first >= (sc->sc_firsts[cesr->cesr_type] + cesr->cesr_unit +
  877                       cesr->cesr_count)) {
  878                 error = EIO;
  879                 goto done;
  880         }
  881         first -= sc->sc_firsts[cesr->cesr_type] + cesr->cesr_unit;
  882 
  883         avail = _2btol(st_hdrp->count);
  884         if (avail <= 0 || avail > cesr->cesr_count) {
  885                 error = EIO;
  886                 goto done;
  887         }
  888 
  889         offset = sizeof(struct read_element_status_header) +
  890                  sizeof(struct read_element_status_page_header);
  891 
  892         for (i = 0; i < cesr->cesr_count; i++) {
  893                 memset(&ces, 0, sizeof(ces));
  894                 if (i < first || i >= (first + avail)) {
  895                         error = copyout(&ces, &cesr->cesr_data[i],
  896                             sizeof(ces));
  897                         if (error)
  898                                 goto done;
  899                 }
  900 
  901                 desc = (struct read_element_status_descriptor *)
  902                     (data + offset);
  903                 stddesclen = sizeof(struct read_element_status_descriptor);
  904                 offset += desclen;
  905 
  906                 ces.ces_flags = CESTATUS_STATUS_VALID;
  907 
  908                 /*
  909                  * The SCSI flags conveniently map directly to the
  910                  * chio API flags.
  911                  */
  912                 ces.ces_flags |= (desc->flags1 & 0x3f);
  913 
  914                 ces.ces_asc = desc->sense_code;
  915                 ces.ces_ascq = desc->sense_qual;
  916 
  917                 /*
  918                  * For Data Transport elemenets, get the SCSI ID and LUN,
  919                  * and attempt to map them to a device name if they're
  920                  * on the same SCSI bus.
  921                  */
  922                 if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_IDVALID) {
  923                         ces.ces_target = desc->dt_scsi_addr;
  924                         ces.ces_flags |= CESTATUS_TARGET_VALID;
  925                 }
  926                 if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_LUVALID) {
  927                         ces.ces_lun = desc->dt_scsi_flags &
  928                             READ_ELEMENT_STATUS_DT_LUNMASK;
  929                         ces.ces_flags |= CESTATUS_LUN_VALID;
  930                 }
  931                 if (desc->dt_scsi_flags & READ_ELEMENT_STATUS_DT_NOTBUS)
  932                         ces.ces_flags |= CESTATUS_NOTBUS;
  933                 else if ((ces.ces_flags &
  934                           (CESTATUS_TARGET_VALID|CESTATUS_LUN_VALID)) ==
  935                          (CESTATUS_TARGET_VALID|CESTATUS_LUN_VALID)) {
  936                         if (ces.ces_target < chan->chan_ntargets &&
  937                             ces.ces_lun < chan->chan_nluns &&
  938                             (dtperiph = scsipi_lookup_periph(chan,
  939                              ces.ces_target, ces.ces_lun)) != NULL &&
  940                             dtperiph->periph_dev != NULL) {
  941                                 strlcpy(ces.ces_xname,
  942                                     dtperiph->periph_dev->dv_xname,
  943                                     sizeof(ces.ces_xname));
  944                                 ces.ces_flags |= CESTATUS_XNAME_VALID;
  945                         }
  946                 }
  947 
  948                 if (desc->flags2 & READ_ELEMENT_STATUS_INVERT)
  949                         ces.ces_flags |= CESTATUS_INVERTED;
  950 
  951                 if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) {
  952                         if (ch_map_element(sc, _2btol(desc->ssea),
  953                             &ces.ces_from_type, &ces.ces_from_unit))
  954                                 ces.ces_flags |= CESTATUS_FROM_VALID;
  955                 }
  956 
  957                 /*
  958                  * Extract volume tag information.
  959                  */
  960                 switch (pg_hdrp->flags &
  961                     (READ_ELEMENT_STATUS_PVOLTAG|READ_ELEMENT_STATUS_AVOLTAG)) {
  962                 case (READ_ELEMENT_STATUS_PVOLTAG|READ_ELEMENT_STATUS_AVOLTAG):
  963                         pvol = (struct changer_volume_tag *)(desc + 1);
  964                         avol = pvol + 1;
  965                         break;
  966 
  967                 case READ_ELEMENT_STATUS_PVOLTAG:
  968                         pvol = (struct changer_volume_tag *)(desc + 1);
  969                         avol = NULL;
  970                         break;
  971 
  972                 case READ_ELEMENT_STATUS_AVOLTAG:
  973                         pvol = NULL;
  974                         avol = (struct changer_volume_tag *)(desc + 1);
  975                         break;
  976 
  977                 default:
  978                         avol = pvol = NULL;
  979                         break;
  980                 }
  981 
  982                 if (pvol != NULL) {
  983                         ch_voltag_convert_in(pvol, &ces.ces_pvoltag);
  984                         ces.ces_flags |= CESTATUS_PVOL_VALID;
  985                         stddesclen += sizeof(struct changer_volume_tag);
  986                 }
  987                 if (avol != NULL) {
  988                         ch_voltag_convert_in(avol, &ces.ces_avoltag);
  989                         ces.ces_flags |= CESTATUS_AVOL_VALID;
  990                         stddesclen += sizeof(struct changer_volume_tag);
  991                 }
  992 
  993                 /*
  994                  * Compute vendor-specific length.  Note the 4 reserved
  995                  * bytes between the volume tags and the vendor-specific
  996                  * data.  Copy it out of the user wants it.
  997                  */
  998                 stddesclen += 4;
  999                 if (desclen > stddesclen)
 1000                         ces.ces_vendor_len = desclen - stddesclen;
 1001 
 1002                 if (ces.ces_vendor_len != 0 && cesr->cesr_vendor_data != NULL) {
 1003                         error = copyin(&cesr->cesr_vendor_data[i], &uvendptr,
 1004                             sizeof(uvendptr));
 1005                         if (error)
 1006                                 goto done;
 1007                         error = copyout((void *)((u_long)desc + stddesclen),
 1008                             uvendptr, ces.ces_vendor_len);
 1009                         if (error)
 1010                                 goto done;
 1011                 }
 1012 
 1013                 /*
 1014                  * Now copy out the status descriptor we've constructed.
 1015                  */
 1016                 error = copyout(&ces, &cesr->cesr_data[i], sizeof(ces));
 1017                 if (error)
 1018                         goto done;
 1019         }
 1020 
 1021  done:
 1022         if (data != NULL)
 1023                 free(data, M_DEVBUF);
 1024         return (error);
 1025 }
 1026 
 1027 static int
 1028 ch_getelemstatus(struct ch_softc *sc, int first, int count, void *data,
 1029     size_t datalen, int scsiflags, int flags)
 1030 {
 1031         struct scsi_read_element_status cmd;
 1032 
 1033         /*
 1034          * Build SCSI command.
 1035          */
 1036         memset(&cmd, 0, sizeof(cmd));
 1037         cmd.opcode = READ_ELEMENT_STATUS;
 1038         cmd.byte2 = ELEMENT_TYPE_ALL;
 1039         if (flags & CESR_VOLTAGS)
 1040                 cmd.byte2 |= READ_ELEMENT_STATUS_VOLTAG;
 1041         _lto2b(first, cmd.sea);
 1042         _lto2b(count, cmd.count);
 1043         _lto3b(datalen, cmd.len);
 1044 
 1045         /*
 1046          * Send command to changer.
 1047          */
 1048         return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd),
 1049             (void *)data, datalen,
 1050             CHRETRIES, 100000, NULL, scsiflags | XS_CTL_DATA_IN));
 1051 }
 1052 
 1053 static int
 1054 ch_setvoltag(struct ch_softc *sc, struct changer_set_voltag_request *csvr)
 1055 {
 1056         struct scsi_send_volume_tag cmd;
 1057         struct changer_volume_tag voltag;
 1058         void *data = NULL;
 1059         size_t datalen = 0;
 1060         int error;
 1061         u_int16_t dst;
 1062 
 1063         /*
 1064          * Check arguments.
 1065          */
 1066         if (csvr->csvr_type > CHET_DT)
 1067                 return (EINVAL);
 1068         if (csvr->csvr_unit > (sc->sc_counts[csvr->csvr_type] - 1))
 1069                 return (ENODEV);
 1070 
 1071         dst = sc->sc_firsts[csvr->csvr_type] + csvr->csvr_unit;
 1072 
 1073         /*
 1074          * Build the SCSI command.
 1075          */
 1076         memset(&cmd, 0, sizeof(cmd));
 1077         cmd.opcode = SEND_VOLUME_TAG;
 1078         _lto2b(dst, cmd.eaddr);
 1079 
 1080 #define ALTERNATE       (csvr->csvr_flags & CSVR_ALTERNATE)
 1081 
 1082         switch (csvr->csvr_flags & CSVR_MODE_MASK) {
 1083         case CSVR_MODE_SET:
 1084                 cmd.sac = ALTERNATE ? SAC_ASSERT_ALT : SAC_ASSERT_PRIMARY;
 1085                 break;
 1086 
 1087         case CSVR_MODE_REPLACE:
 1088                 cmd.sac = ALTERNATE ? SAC_REPLACE_ALT : SAC_REPLACE_PRIMARY;
 1089                 break;
 1090 
 1091         case CSVR_MODE_CLEAR:
 1092                 cmd.sac = ALTERNATE ? SAC_UNDEFINED_ALT : SAC_UNDEFINED_PRIMARY;
 1093                 break;
 1094 
 1095         default:
 1096                 return (EINVAL);
 1097         }
 1098 
 1099 #undef ALTERNATE
 1100 
 1101         if (cmd.sac < SAC_UNDEFINED_PRIMARY) {
 1102                 error = ch_voltag_convert_out(&csvr->csvr_voltag, &voltag);
 1103                 if (error)
 1104                         return (error);
 1105                 data = &voltag;
 1106                 datalen = sizeof(voltag);
 1107                 _lto2b(datalen, cmd.length);
 1108         }
 1109 
 1110         /*
 1111          * Send command to changer.
 1112          */
 1113         return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd),
 1114             (void *)data, datalen, CHRETRIES, 100000, NULL,
 1115             datalen ? XS_CTL_DATA_OUT | XS_CTL_DATA_ONSTACK : 0));
 1116 }
 1117 
 1118 static int
 1119 ch_ielem(struct ch_softc *sc)
 1120 {
 1121         int tmo;
 1122         struct scsi_initialize_element_status cmd;
 1123 
 1124         /*
 1125          * Build SCSI command.
 1126          */
 1127         memset(&cmd, 0, sizeof(cmd));
 1128         cmd.opcode = INITIALIZE_ELEMENT_STATUS;
 1129 
 1130         /*
 1131          * Send command to changer.
 1132          *
 1133          * The problem is, how long to allow for the command?
 1134          * It can take a *really* long time, and also depends
 1135          * on unknowable factors such as whether there are
 1136          * *almost* readable labels on tapes that a barcode
 1137          * reader is trying to decipher.
 1138          *
 1139          * I'm going to make this long enough to allow 5 minutes
 1140          * per element plus an initial 10 minute wait.
 1141          */
 1142         tmo =   sc->sc_counts[CHET_MT] +
 1143                 sc->sc_counts[CHET_ST] +
 1144                 sc->sc_counts[CHET_IE] +
 1145                 sc->sc_counts[CHET_DT];
 1146         tmo *= 5 * 60 * 1000;
 1147         tmo += (10 * 60 * 1000);
 1148 
 1149         return (scsipi_command(sc->sc_periph, (void *)&cmd, sizeof(cmd), 0, 0,
 1150             CHRETRIES, tmo, NULL, XS_CTL_IGNORE_ILLEGAL_REQUEST));
 1151 }
 1152 
 1153 /*
 1154  * Ask the device about itself and fill in the parameters in our
 1155  * softc.
 1156  */
 1157 static int
 1158 ch_get_params(struct ch_softc *sc, int scsiflags)
 1159 {
 1160         struct scsi_mode_sense_data {
 1161                 struct scsi_mode_parameter_header_6 header;
 1162                 union {
 1163                         struct page_element_address_assignment ea;
 1164                         struct page_transport_geometry_parameters tg;
 1165                         struct page_device_capabilities cap;
 1166                 } pages;
 1167         } sense_data;
 1168         int error, from;
 1169         u_int8_t *moves, *exchanges;
 1170 
 1171         /*
 1172          * Grab info from the element address assignment page.
 1173          */
 1174         memset(&sense_data, 0, sizeof(sense_data));
 1175         error = scsipi_mode_sense(sc->sc_periph, SMS_DBD, 0x1d,
 1176             &sense_data.header, sizeof(sense_data),
 1177             scsiflags | XS_CTL_DATA_ONSTACK, CHRETRIES, 6000);
 1178         if (error) {
 1179                 printf("%s: could not sense element address page\n",
 1180                     sc->sc_dev.dv_xname);
 1181                 return (error);
 1182         }
 1183 
 1184         sc->sc_firsts[CHET_MT] = _2btol(sense_data.pages.ea.mtea);
 1185         sc->sc_counts[CHET_MT] = _2btol(sense_data.pages.ea.nmte);
 1186         sc->sc_firsts[CHET_ST] = _2btol(sense_data.pages.ea.fsea);
 1187         sc->sc_counts[CHET_ST] = _2btol(sense_data.pages.ea.nse);
 1188         sc->sc_firsts[CHET_IE] = _2btol(sense_data.pages.ea.fieea);
 1189         sc->sc_counts[CHET_IE] = _2btol(sense_data.pages.ea.niee);
 1190         sc->sc_firsts[CHET_DT] = _2btol(sense_data.pages.ea.fdtea);
 1191         sc->sc_counts[CHET_DT] = _2btol(sense_data.pages.ea.ndte);
 1192 
 1193         /* XXX ask for transport geometry page XXX */
 1194 
 1195         /*
 1196          * Grab info from the capabilities page.
 1197          */
 1198         memset(&sense_data, 0, sizeof(sense_data));
 1199         /*
 1200          * XXX: Note: not all changers can deal with disabled block descriptors
 1201          */
 1202         error = scsipi_mode_sense(sc->sc_periph, SMS_DBD, 0x1f,
 1203             &sense_data.header, sizeof(sense_data),
 1204             scsiflags | XS_CTL_DATA_ONSTACK, CHRETRIES, 6000);
 1205         if (error) {
 1206                 printf("%s: could not sense capabilities page\n",
 1207                     sc->sc_dev.dv_xname);
 1208                 return (error);
 1209         }
 1210 
 1211         memset(sc->sc_movemask, 0, sizeof(sc->sc_movemask));
 1212         memset(sc->sc_exchangemask, 0, sizeof(sc->sc_exchangemask));
 1213         moves = &sense_data.pages.cap.move_from_mt;
 1214         exchanges = &sense_data.pages.cap.exchange_with_mt;
 1215         for (from = CHET_MT; from <= CHET_DT; ++from) {
 1216                 sc->sc_movemask[from] = moves[from];
 1217                 sc->sc_exchangemask[from] = exchanges[from];
 1218         }
 1219 
 1220 #ifdef CH_AUTOMATIC_IELEM_POLICY
 1221         /*
 1222          * If we need to do an Init-Element-Status,
 1223          * do that now that we know what's in the changer.
 1224          */
 1225         if ((scsiflags & XS_CTL_IGNORE_MEDIA_CHANGE) == 0) {
 1226                 if ((sc->sc_periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)
 1227                         error = ch_ielem(sc);
 1228                 if (error == 0)
 1229                         sc->sc_periph->periph_flags |= PERIPH_MEDIA_LOADED;
 1230                 else
 1231                         sc->sc_periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
 1232         }
 1233 #endif
 1234         return (error);
 1235 }
 1236 
 1237 static void
 1238 ch_get_quirks(struct ch_softc *sc, struct scsipi_inquiry_pattern *inqbuf)
 1239 {
 1240         struct chquirk *match;
 1241         int priority;
 1242 
 1243         sc->sc_settledelay = 0;
 1244 
 1245         match = (struct chquirk *)scsipi_inqmatch(inqbuf,
 1246             (caddr_t)chquirks,
 1247             sizeof(chquirks) / sizeof(chquirks[0]),
 1248             sizeof(chquirks[0]), &priority);
 1249         if (priority != 0)
 1250                 sc->sc_settledelay = match->cq_settledelay;
 1251 }
 1252 
 1253 static int
 1254 ch_map_element(struct ch_softc *sc, u_int16_t elem, int *typep, int *unitp)
 1255 {
 1256         int chet;
 1257 
 1258         for (chet = CHET_MT; chet <= CHET_DT; chet++) {
 1259                 if (elem >= sc->sc_firsts[chet] &&
 1260                     elem < (sc->sc_firsts[chet] + sc->sc_counts[chet])) {
 1261                         *typep = chet;
 1262                         *unitp = elem - sc->sc_firsts[chet];
 1263                         return (1);
 1264                 }
 1265         }
 1266         return (0);
 1267 }
 1268 
 1269 static void
 1270 ch_voltag_convert_in(const struct changer_volume_tag *sv,
 1271     struct changer_voltag *cv)
 1272 {
 1273         int i;
 1274 
 1275         memset(cv, 0, sizeof(struct changer_voltag));
 1276 
 1277         /*
 1278          * Copy the volume tag string from the SCSI representation.
 1279          * Per the SCSI-2 spec, we stop at the first blank character.
 1280          */
 1281         for (i = 0; i < sizeof(sv->volid); i++) {
 1282                 if (sv->volid[i] == ' ')
 1283                         break;
 1284                 cv->cv_tag[i] = sv->volid[i];
 1285         }
 1286         cv->cv_tag[i] = '\0';
 1287 
 1288         cv->cv_serial = _2btol(sv->volseq);
 1289 }
 1290 
 1291 static int
 1292 ch_voltag_convert_out(const struct changer_voltag *cv,
 1293     struct changer_volume_tag *sv)
 1294 {
 1295         int i;
 1296 
 1297         memset(sv, ' ', sizeof(struct changer_volume_tag));
 1298 
 1299         for (i = 0; i < sizeof(sv->volid); i++) {
 1300                 if (cv->cv_tag[i] == '\0')
 1301                         break;
 1302                 /*
 1303                  * Limit the character set to what is suggested in
 1304                  * the SCSI-2 spec.
 1305                  */
 1306                 if ((cv->cv_tag[i] < '' || cv->cv_tag[i] > '9') &&
 1307                     (cv->cv_tag[i] < 'A' || cv->cv_tag[i] > 'Z') &&
 1308                     (cv->cv_tag[i] != '_'))
 1309                         return (EINVAL);
 1310                 sv->volid[i] = cv->cv_tag[i];
 1311         }
 1312 
 1313         _lto2b(cv->cv_serial, sv->volseq);
 1314 
 1315         return (0);
 1316 }

Cache object: 100d5718ee28c2b766e9157bb5feb69e


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