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/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 /*      $OpenBSD: ch.c,v 1.71 2022/01/11 23:10:11 jsg Exp $     */
    2 /*      $NetBSD: ch.c,v 1.26 1997/02/21 22:06:52 thorpej Exp $  */
    3 
    4 /*
    5  * Copyright (c) 1996, 1997 Jason R. Thorpe <thorpej@and.com>
    6  * All rights reserved.
    7  *
    8  * Partially based on an autochanger driver written by Stefan Grefen
    9  * and on an autochanger driver written by the Systems Programming Group
   10  * at the University of Utah Computer Science Department.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgements:
   22  *      This product includes software developed by Jason R. Thorpe
   23  *      for And Communications, http://www.and.com/
   24  * 4. The name of the author may not be used to endorse or promote products
   25  *    derived from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   28  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   29  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   30  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   32  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   33  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   34  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   35  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   37  * SUCH DAMAGE.
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/errno.h>
   43 #include <sys/ioctl.h>
   44 #include <sys/chio.h>
   45 #include <sys/device.h>
   46 #include <sys/malloc.h>
   47 #include <sys/pool.h>
   48 #include <sys/conf.h>
   49 #include <sys/fcntl.h>
   50 
   51 #include <scsi/scsi_all.h>
   52 #include <scsi/scsi_changer.h>
   53 #include <scsi/scsi_debug.h>
   54 #include <scsi/scsiconf.h>
   55 
   56 #define CHRETRIES       2
   57 #define CHUNIT(x)       (minor((x)))
   58 
   59 struct ch_softc {
   60         struct device            sc_dev;        /* generic device info */
   61         struct scsi_link        *sc_link;       /* link in the SCSI bus */
   62 
   63         int                      sc_picker;     /* current picker */
   64 
   65         /*
   66          * The following information is obtained from the
   67          * element address assignment page.
   68          */
   69         int                      sc_firsts[4];  /* firsts, indexed by CHET_* */
   70         int                      sc_counts[4];  /* counts, indexed by CHET_* */
   71 
   72         /*
   73          * The following mask defines the legal combinations
   74          * of elements for the MOVE MEDIUM command.
   75          */
   76         u_int8_t                 sc_movemask[4];
   77 
   78         /*
   79          * As above, but for EXCHANGE MEDIUM.
   80          */
   81         u_int8_t                 sc_exchangemask[4];
   82 
   83         int                      flags;         /* misc. info */
   84 
   85         /*
   86          * Quirks; see below.
   87          */
   88         int                      sc_settledelay; /* delay for settle */
   89 
   90 };
   91 
   92 /* sc_flags */
   93 #define CHF_ROTATE      0x01            /* picker can rotate */
   94 
   95 /* Autoconfiguration glue */
   96 int     chmatch(struct device *, void *, void *);
   97 void    chattach(struct device *, struct device *, void *);
   98 
   99 const struct cfattach ch_ca = {
  100         sizeof(struct ch_softc), chmatch, chattach
  101 };
  102 
  103 struct cfdriver ch_cd = {
  104         NULL, "ch", DV_DULL
  105 };
  106 
  107 const struct scsi_inquiry_pattern ch_patterns[] = {
  108         {T_CHANGER, T_REMOV,
  109          "",            "",             ""},
  110 };
  111 
  112 int     ch_move(struct ch_softc *, struct changer_move *);
  113 int     ch_exchange(struct ch_softc *, struct changer_exchange *);
  114 int     ch_position(struct ch_softc *, struct changer_position *);
  115 int     ch_usergetelemstatus(struct ch_softc *,
  116             struct changer_element_status_request *);
  117 int     ch_getelemstatus(struct ch_softc *, int, int, caddr_t, size_t, int);
  118 int     ch_get_params(struct ch_softc *, int);
  119 int     ch_interpret_sense(struct scsi_xfer *xs);
  120 void    ch_get_quirks(struct ch_softc *, struct scsi_inquiry_data *);
  121 
  122 /*
  123  * SCSI changer quirks.
  124  */
  125 struct chquirk {
  126         struct  scsi_inquiry_pattern cq_match; /* device id pattern */
  127         int     cq_settledelay; /* settle delay, in seconds */
  128 };
  129 
  130 struct chquirk chquirks[] = {
  131         {{T_CHANGER, T_REMOV,
  132           "SPECTRA",    "9000",         "0200"},
  133          75},
  134 };
  135 
  136 int
  137 chmatch(struct device *parent, void *match, void *aux)
  138 {
  139         struct scsi_attach_args         *sa = aux;
  140         struct scsi_inquiry_data        *inq = &sa->sa_sc_link->inqdata;
  141         int                              priority;
  142 
  143         (void)scsi_inqmatch(inq, ch_patterns, nitems(ch_patterns),
  144             sizeof(ch_patterns[0]), &priority);
  145 
  146         return priority;
  147 }
  148 
  149 void
  150 chattach(struct device *parent, struct device *self, void *aux)
  151 {
  152         struct ch_softc                 *sc = (struct ch_softc *)self;
  153         struct scsi_attach_args         *sa = aux;
  154         struct scsi_link                *link = sa->sa_sc_link;
  155 
  156         /* Glue into the SCSI bus */
  157         sc->sc_link = link;
  158         link->interpret_sense = ch_interpret_sense;
  159         link->device_softc = sc;
  160         link->openings = 1;
  161 
  162         printf("\n");
  163 
  164         /*
  165          * Store our our device's quirks.
  166          */
  167         ch_get_quirks(sc, &link->inqdata);
  168 }
  169 
  170 int
  171 chopen(dev_t dev, int flags, int fmt, struct proc *p)
  172 {
  173         struct ch_softc         *sc;
  174         int                      oldcounts[4];
  175         int                      i, unit, error = 0;
  176 
  177         unit = CHUNIT(dev);
  178         if ((unit >= ch_cd.cd_ndevs) ||
  179             ((sc = ch_cd.cd_devs[unit]) == NULL))
  180                 return ENXIO;
  181 
  182         /*
  183          * Only allow one open at a time.
  184          */
  185         if (ISSET(sc->sc_link->flags, SDEV_OPEN))
  186                 return EBUSY;
  187 
  188         SET(sc->sc_link->flags, SDEV_OPEN);
  189 
  190         /*
  191          * Absorb any unit attention errors. We must notice
  192          * "Not ready" errors as a changer will report "In the
  193          * process of getting ready" any time it must rescan
  194          * itself to determine the state of the changer.
  195          */
  196         error = scsi_test_unit_ready(sc->sc_link, TEST_READY_RETRIES,
  197             SCSI_IGNORE_ILLEGAL_REQUEST | SCSI_IGNORE_MEDIA_CHANGE);
  198         if (error)
  199                 goto bad;
  200 
  201         /*
  202          * Get information about the device. Save old information
  203          * so we can decide whether to be verbose about new parameters.
  204          */
  205         for (i = 0; i < 4; i++) {
  206                 oldcounts[i] = sc->sc_counts[i];
  207         }
  208         error = ch_get_params(sc, scsi_autoconf);
  209         if (error)
  210                 goto bad;
  211 
  212         for (i = 0; i < 4; i++) {
  213                 if (oldcounts[i] != sc->sc_counts[i]) {
  214                         break;
  215                 }
  216         }
  217         if (i < 4) {
  218 #ifdef CHANGER_DEBUG
  219 #define PLURAL(c)       (c) == 1 ? "" : "s"
  220                 printf("%s: %d slot%s, %d drive%s, %d picker%s, %d portal%s\n",
  221                     sc->sc_dev.dv_xname,
  222                     sc->sc_counts[CHET_ST], PLURAL(sc->sc_counts[CHET_ST]),
  223                     sc->sc_counts[CHET_DT], PLURAL(sc->sc_counts[CHET_DT]),
  224                     sc->sc_counts[CHET_MT], PLURAL(sc->sc_counts[CHET_MT]),
  225                     sc->sc_counts[CHET_IE], PLURAL(sc->sc_counts[CHET_IE]));
  226 #undef PLURAL
  227                 printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
  228                     sc->sc_dev.dv_xname,
  229                     sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
  230                     sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
  231                 printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
  232                     sc->sc_dev.dv_xname,
  233                     sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
  234                     sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
  235 #endif /* CHANGER_DEBUG */
  236         }
  237 
  238         /* Default the current picker. */
  239         sc->sc_picker = sc->sc_firsts[CHET_MT];
  240 
  241         return 0;
  242 
  243 bad:
  244         CLR(sc->sc_link->flags, SDEV_OPEN);
  245         return error;
  246 }
  247 
  248 int
  249 chclose(dev_t dev, int flags, int fmt, struct proc *p)
  250 {
  251         struct ch_softc *sc = ch_cd.cd_devs[CHUNIT(dev)];
  252 
  253         CLR(sc->sc_link->flags, SDEV_OPEN);
  254         return 0;
  255 }
  256 
  257 int
  258 chioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  259 {
  260         struct ch_softc         *sc = ch_cd.cd_devs[CHUNIT(dev)];
  261         int                      error = 0;
  262 
  263         /*
  264          * If this command can change the device's state, we must
  265          * have the device open for writing.
  266          */
  267         switch (cmd) {
  268         case CHIOGPICKER:
  269         case CHIOGPARAMS:
  270         case CHIOGSTATUS:
  271                 break;
  272 
  273         default:
  274                 if (!ISSET(flags, FWRITE))
  275                         return EBADF;
  276         }
  277 
  278         switch (cmd) {
  279         case CHIOMOVE:
  280                 error = ch_move(sc, (struct changer_move *)data);
  281                 break;
  282 
  283         case CHIOEXCHANGE:
  284                 error = ch_exchange(sc, (struct changer_exchange *)data);
  285                 break;
  286 
  287         case CHIOPOSITION:
  288                 error = ch_position(sc, (struct changer_position *)data);
  289                 break;
  290 
  291         case CHIOGPICKER:
  292                 *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
  293                 break;
  294 
  295         case CHIOSPICKER:       {
  296                 int new_picker = *(int *)data;
  297 
  298                 if (new_picker > (sc->sc_counts[CHET_MT] - 1))
  299                         return EINVAL;
  300                 sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
  301                 break;          }
  302 
  303         case CHIOGPARAMS:       {
  304                 struct changer_params *cp = (struct changer_params *)data;
  305 
  306                 cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
  307                 cp->cp_npickers = sc->sc_counts[CHET_MT];
  308                 cp->cp_nslots = sc->sc_counts[CHET_ST];
  309                 cp->cp_nportals = sc->sc_counts[CHET_IE];
  310                 cp->cp_ndrives = sc->sc_counts[CHET_DT];
  311                 break;          }
  312 
  313         case CHIOGSTATUS:       {
  314                 struct changer_element_status_request *cesr =
  315                     (struct changer_element_status_request *)data;
  316 
  317                 error = ch_usergetelemstatus(sc, cesr);
  318                 break;          }
  319 
  320         /* Implement prevent/allow? */
  321 
  322         default:
  323                 error = scsi_do_ioctl(sc->sc_link, cmd, data, flags);
  324                 break;
  325         }
  326 
  327         return error;
  328 }
  329 
  330 int
  331 ch_move(struct ch_softc *sc, struct changer_move *cm)
  332 {
  333         struct scsi_move_medium         *cmd;
  334         struct scsi_xfer                *xs;
  335         int                              error;
  336         u_int16_t                        fromelem, toelem;
  337 
  338         /*
  339          * Check arguments.
  340          */
  341         if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
  342                 return EINVAL;
  343         if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
  344             (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
  345                 return ENODEV;
  346 
  347         /*
  348          * Check the request against the changer's capabilities.
  349          */
  350         if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
  351                 return EINVAL;
  352 
  353         /*
  354          * Calculate the source and destination elements.
  355          */
  356         fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
  357         toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
  358 
  359         /*
  360          * Build the SCSI command.
  361          */
  362         xs = scsi_xs_get(sc->sc_link, 0);
  363         if (xs == NULL)
  364                 return ENOMEM;
  365         xs->cmdlen = sizeof(*cmd);
  366         xs->retries = CHRETRIES;
  367         xs->timeout = 100000;
  368 
  369         cmd = (struct scsi_move_medium *)&xs->cmd;
  370         cmd->opcode = MOVE_MEDIUM;
  371         _lto2b(sc->sc_picker, cmd->tea);
  372         _lto2b(fromelem, cmd->src);
  373         _lto2b(toelem, cmd->dst);
  374         if (ISSET(cm->cm_flags, CM_INVERT))
  375                 SET(cmd->flags, MOVE_MEDIUM_INVERT);
  376 
  377         error = scsi_xs_sync(xs);
  378         scsi_xs_put(xs);
  379 
  380         return error;
  381 }
  382 
  383 int
  384 ch_exchange(struct ch_softc *sc, struct changer_exchange *ce)
  385 {
  386         struct scsi_exchange_medium     *cmd;
  387         struct scsi_xfer                *xs;
  388         int                              error;
  389         u_int16_t                        src, dst1, dst2;
  390 
  391         /*
  392          * Check arguments.
  393          */
  394         if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
  395             (ce->ce_sdsttype > CHET_DT))
  396                 return EINVAL;
  397         if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
  398             (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
  399             (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
  400                 return ENODEV;
  401 
  402         /*
  403          * Check the request against the changer's capabilities.
  404          */
  405         if (((sc->sc_exchangemask[ce->ce_srctype] &
  406             (1 << ce->ce_fdsttype)) == 0) ||
  407             ((sc->sc_exchangemask[ce->ce_fdsttype] &
  408             (1 << ce->ce_sdsttype)) == 0))
  409                 return EINVAL;
  410 
  411         /*
  412          * Calculate the source and destination elements.
  413          */
  414         src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
  415         dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
  416         dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
  417 
  418         /*
  419          * Build the SCSI command.
  420          */
  421         xs = scsi_xs_get(sc->sc_link, 0);
  422         if (xs == NULL)
  423                 return ENOMEM;
  424         xs->cmdlen = sizeof(*cmd);
  425         xs->retries = CHRETRIES;
  426         xs->timeout = 100000;
  427 
  428         cmd = (struct scsi_exchange_medium *)&xs->cmd;
  429         cmd->opcode = EXCHANGE_MEDIUM;
  430         _lto2b(sc->sc_picker, cmd->tea);
  431         _lto2b(src, cmd->src);
  432         _lto2b(dst1, cmd->fdst);
  433         _lto2b(dst2, cmd->sdst);
  434         if (ISSET(ce->ce_flags, CE_INVERT1))
  435                 SET(cmd->flags, EXCHANGE_MEDIUM_INV1);
  436         if (ISSET(ce->ce_flags, CE_INVERT2))
  437                 SET(cmd->flags, EXCHANGE_MEDIUM_INV2);
  438 
  439         error = scsi_xs_sync(xs);
  440         scsi_xs_put(xs);
  441 
  442         return error;
  443 }
  444 
  445 int
  446 ch_position(struct ch_softc *sc, struct changer_position *cp)
  447 {
  448         struct scsi_position_to_element         *cmd;
  449         struct scsi_xfer                        *xs;
  450         int                                      error;
  451         u_int16_t                                dst;
  452 
  453         /*
  454          * Check arguments.
  455          */
  456         if (cp->cp_type > CHET_DT)
  457                 return EINVAL;
  458         if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
  459                 return ENODEV;
  460 
  461         /*
  462          * Calculate the destination element.
  463          */
  464         dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
  465 
  466         /*
  467          * Build the SCSI command.
  468          */
  469         xs = scsi_xs_get(sc->sc_link, 0);
  470         if (xs == NULL)
  471                 return ENOMEM;
  472         xs->cmdlen = sizeof(*cmd);
  473         xs->retries = CHRETRIES;
  474         xs->timeout = 100000;
  475 
  476         cmd = (struct scsi_position_to_element *)&xs->cmd;
  477         cmd->opcode = POSITION_TO_ELEMENT;
  478         _lto2b(sc->sc_picker, cmd->tea);
  479         _lto2b(dst, cmd->dst);
  480         if (ISSET(cp->cp_flags, CP_INVERT))
  481                 SET(cmd->flags, POSITION_TO_ELEMENT_INVERT);
  482 
  483         error = scsi_xs_sync(xs);
  484         scsi_xs_put(xs);
  485 
  486         return error;
  487 }
  488 
  489 /*
  490  * Copy a volume tag to a volume_tag struct, converting SCSI byte order
  491  * to host native byte order in the volume serial number.  The volume
  492  * label as returned by the changer is transferred to user mode as
  493  * nul-terminated string.  Volume labels are truncated at the first
  494  * space, as suggested by SCSI-2.
  495  */
  496 static  void
  497 copy_voltag(struct changer_voltag *uvoltag, struct volume_tag *voltag)
  498 {
  499         int i;
  500 
  501         for (i=0; i<CH_VOLTAG_MAXLEN; i++) {
  502                 char c = voltag->vif[i];
  503                 if (c && c != ' ')
  504                         uvoltag->cv_volid[i] = c;
  505                 else
  506                         break;
  507         }
  508         uvoltag->cv_volid[i] = '\0';
  509         uvoltag->cv_serial = _2btol(voltag->vsn);
  510 }
  511 
  512 /*
  513  * Copy an an element status descriptor to a user-mode
  514  * changer_element_status structure.
  515  */
  516 static void
  517 copy_element_status(struct ch_softc *sc, int flags,
  518     struct read_element_status_descriptor *desc,
  519     struct changer_element_status *ces)
  520 {
  521         u_int16_t eaddr = _2btol(desc->eaddr);
  522         u_int16_t et;
  523 
  524         for (et = CHET_MT; et <= CHET_DT; et++) {
  525                 if ((sc->sc_firsts[et] <= eaddr)
  526                     && ((sc->sc_firsts[et] + sc->sc_counts[et])
  527                     > eaddr)) {
  528                         ces->ces_addr = eaddr - sc->sc_firsts[et];
  529                         ces->ces_type = et;
  530                         break;
  531                 }
  532         }
  533 
  534         ces->ces_flags = desc->flags1;
  535 
  536         ces->ces_sensecode = desc->sense_code;
  537         ces->ces_sensequal = desc->sense_qual;
  538 
  539         if (desc->flags2 & READ_ELEMENT_STATUS_INVERT)
  540                 ces->ces_flags |= READ_ELEMENT_STATUS_EXCEPT;
  541 
  542         if (desc->flags2 & READ_ELEMENT_STATUS_SVALID) {
  543                 eaddr = _2btol(desc->ssea);
  544 
  545                 /* convert source address to logical format */
  546                 for (et = CHET_MT; et <= CHET_DT; et++) {
  547                         if ((sc->sc_firsts[et] <= eaddr)
  548                             && ((sc->sc_firsts[et] + sc->sc_counts[et])
  549                                 > eaddr)) {
  550                                 ces->ces_source_addr =
  551                                         eaddr - sc->sc_firsts[et];
  552                                 ces->ces_source_type = et;
  553                                 ces->ces_flags |= READ_ELEMENT_STATUS_ACCESS;
  554                                 break;
  555                         }
  556                 }
  557 
  558                 if (!(ces->ces_flags & READ_ELEMENT_STATUS_ACCESS))
  559                         printf("ch: warning: could not map element source "
  560                                "address %ud to a valid element type\n",
  561                                eaddr);
  562         }
  563 
  564         if (ISSET(flags, READ_ELEMENT_STATUS_PVOLTAG))
  565                 copy_voltag(&ces->ces_pvoltag, &desc->pvoltag);
  566         if (ISSET(flags, READ_ELEMENT_STATUS_AVOLTAG))
  567                 copy_voltag(&ces->ces_avoltag, &desc->avoltag);
  568 }
  569 
  570 /*
  571  * Perform a READ ELEMENT STATUS on behalf of the user, and return to
  572  * the user only the data the user is interested in (i.e. an array of
  573  * changer_element_status structures)
  574  */
  575 int
  576 ch_usergetelemstatus(struct ch_softc *sc,
  577     struct changer_element_status_request *cesr)
  578 {
  579         struct changer_element_status           *user_data = NULL;
  580         struct read_element_status_header       *st_hdr;
  581         struct read_element_status_page_header  *pg_hdr;
  582         caddr_t                                  desc;
  583         caddr_t                                  data = NULL;
  584         size_t                                   size, desclen, udsize;
  585         int                                      avail, chet, i, want_voltags;
  586         int                                      error = 0;
  587 
  588         chet = cesr->cesr_type;
  589         want_voltags = (cesr->cesr_flags & CESR_VOLTAGS) ? 1 : 0;
  590 
  591         /*
  592          * If there are no elements of the requested type in the changer,
  593          * the request is invalid.
  594          */
  595         if (sc->sc_counts[chet] == 0)
  596                 return EINVAL;
  597 
  598         /*
  599          * Request one descriptor for the given element type.  This
  600          * is used to determine the size of the descriptor so that
  601          * we can allocate enough storage for all of them.  We assume
  602          * that the first one can fit into 1k.
  603          */
  604         size = 1024;
  605         data = dma_alloc(size, PR_WAITOK);
  606         error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, size,
  607             want_voltags);
  608         if (error)
  609                 goto done;
  610 
  611         st_hdr = (struct read_element_status_header *)data;
  612         pg_hdr = (struct read_element_status_page_header *) (st_hdr + 1);
  613         desclen = _2btol(pg_hdr->edl);
  614 
  615         dma_free(data, size);
  616 
  617         /*
  618          * Reallocate storage for descriptors and get them from the
  619          * device.
  620          */
  621         size = sizeof(struct read_element_status_header) +
  622             sizeof(struct read_element_status_page_header) +
  623             (desclen * sc->sc_counts[chet]);
  624         data = dma_alloc(size, PR_WAITOK);
  625         error = ch_getelemstatus(sc, sc->sc_firsts[chet],
  626             sc->sc_counts[chet], data, size, want_voltags);
  627         if (error)
  628                 goto done;
  629 
  630         /*
  631          * Fill in the user status array.
  632          */
  633         st_hdr = (struct read_element_status_header *)data;
  634         pg_hdr = (struct read_element_status_page_header *) (st_hdr + 1);
  635 
  636         avail = _2btol(st_hdr->count);
  637         if (avail != sc->sc_counts[chet]) {
  638                 error = EINVAL;
  639                 goto done;
  640         }
  641 
  642         user_data = mallocarray(avail, sizeof(struct changer_element_status),
  643             M_DEVBUF, M_WAITOK | M_ZERO);
  644         udsize = avail * sizeof(struct changer_element_status);
  645 
  646         desc = (caddr_t)(pg_hdr + 1);
  647         for (i = 0; i < avail; ++i) {
  648                 struct changer_element_status *ces = &(user_data[i]);
  649                 copy_element_status(sc, pg_hdr->flags,
  650                     (struct read_element_status_descriptor *)desc, ces);
  651                 desc += desclen;
  652         }
  653 
  654         /* Copy array out to userspace. */
  655         error = copyout(user_data, cesr->cesr_data, udsize);
  656 
  657 done:
  658         if (data != NULL)
  659                 dma_free(data, size);
  660         if (user_data != NULL)
  661                 free(user_data, M_DEVBUF, udsize);
  662         return error;
  663 }
  664 
  665 int
  666 ch_getelemstatus(struct ch_softc *sc, int first, int count, caddr_t data,
  667     size_t datalen, int voltag)
  668 {
  669         struct scsi_read_element_status         *cmd;
  670         struct scsi_xfer                        *xs;
  671         int                                      error;
  672 
  673         /*
  674          * Build SCSI command.
  675          */
  676         xs = scsi_xs_get(sc->sc_link, SCSI_DATA_IN);
  677         if (xs == NULL)
  678                 return ENOMEM;
  679         xs->cmdlen = sizeof(*cmd);
  680         xs->data = data;
  681         xs->datalen = datalen;
  682         xs->retries = CHRETRIES;
  683         xs->timeout = 100000;
  684 
  685         cmd = (struct scsi_read_element_status *)&xs->cmd;
  686         cmd->opcode = READ_ELEMENT_STATUS;
  687         _lto2b(first, cmd->sea);
  688         _lto2b(count, cmd->count);
  689         _lto3b(datalen, cmd->len);
  690         if (voltag)
  691                 SET(cmd->byte2, READ_ELEMENT_STATUS_VOLTAG);
  692 
  693         error = scsi_xs_sync(xs);
  694         scsi_xs_put(xs);
  695 
  696         return error;
  697 }
  698 
  699 /*
  700  * Ask the device about itself and fill in the parameters in our
  701  * softc.
  702  */
  703 int
  704 ch_get_params(struct ch_softc *sc, int flags)
  705 {
  706         union scsi_mode_sense_buf                       *data;
  707         struct page_element_address_assignment          *ea;
  708         struct page_device_capabilities                 *cap;
  709         u_int8_t                                        *moves, *exchanges;
  710         int                                              big, error, from;
  711 
  712         data = dma_alloc(sizeof(*data), PR_NOWAIT);
  713         if (data == NULL)
  714                 return ENOMEM;
  715 
  716         /*
  717          * Grab info from the element address assignment page (0x1d).
  718          */
  719         error = scsi_do_mode_sense(sc->sc_link, EA_PAGE, data,
  720             (void **)&ea, sizeof(*ea), flags, &big);
  721         if (error == 0 && ea == NULL)
  722                 error = EIO;
  723         if (error != 0) {
  724 #ifdef CHANGER_DEBUG
  725                 printf("%s: could not sense element address page\n",
  726                     sc->sc_dev.dv_xname);
  727 #endif /* CHANGER_DEBUG */
  728                 dma_free(data, sizeof(*data));
  729                 return error;
  730         }
  731 
  732         sc->sc_firsts[CHET_MT] = _2btol(ea->mtea);
  733         sc->sc_counts[CHET_MT] = _2btol(ea->nmte);
  734         sc->sc_firsts[CHET_ST] = _2btol(ea->fsea);
  735         sc->sc_counts[CHET_ST] = _2btol(ea->nse);
  736         sc->sc_firsts[CHET_IE] = _2btol(ea->fieea);
  737         sc->sc_counts[CHET_IE] = _2btol(ea->niee);
  738         sc->sc_firsts[CHET_DT] = _2btol(ea->fdtea);
  739         sc->sc_counts[CHET_DT] = _2btol(ea->ndte);
  740 
  741         /* XXX Ask for transport geometry page. */
  742 
  743         /*
  744          * Grab info from the capabilities page (0x1f).
  745          */
  746         error = scsi_do_mode_sense(sc->sc_link, CAP_PAGE, data,
  747             (void **)&cap, sizeof(*cap), flags, &big);
  748         if (error == 0 && cap == NULL)
  749                 error = EIO;
  750         if (error != 0) {
  751 #ifdef CHANGER_DEBUG
  752                 printf("%s: could not sense capabilities page\n",
  753                     sc->sc_dev.dv_xname);
  754 #endif /* CHANGER_DEBUG */
  755                 dma_free(data, sizeof(*data));
  756                 return error;
  757         }
  758 
  759         bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
  760         bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
  761         moves = &cap->move_from_mt;
  762         exchanges = &cap->exchange_with_mt;
  763         for (from = CHET_MT; from <= CHET_DT; ++from) {
  764                 sc->sc_movemask[from] = moves[from];
  765                 sc->sc_exchangemask[from] = exchanges[from];
  766         }
  767 
  768         SET(sc->sc_link->flags, SDEV_MEDIA_LOADED);
  769         dma_free(data, sizeof(*data));
  770         return 0;
  771 }
  772 
  773 void
  774 ch_get_quirks(struct ch_softc *sc, struct scsi_inquiry_data *inqbuf)
  775 {
  776         const struct chquirk            *match;
  777         int                              priority;
  778 
  779         sc->sc_settledelay = 0;
  780 
  781         match = (const struct chquirk *)scsi_inqmatch(inqbuf,
  782             (caddr_t)chquirks,
  783             sizeof(chquirks) / sizeof(chquirks[0]),
  784             sizeof(chquirks[0]), &priority);
  785         if (priority != 0) {
  786                 sc->sc_settledelay = match->cq_settledelay;
  787         }
  788 }
  789 
  790 /*
  791  * Look at the returned sense and act on the error to determine
  792  * the unix error number to pass back... (0 = report no error)
  793  *                            (-1 = continue processing)
  794  */
  795 int
  796 ch_interpret_sense(struct scsi_xfer *xs)
  797 {
  798         struct scsi_sense_data          *sense = &xs->sense;
  799         struct scsi_link                *link = xs->sc_link;
  800         u_int8_t                         serr, skey;
  801 
  802         serr = sense->error_code & SSD_ERRCODE;
  803         skey = sense->flags & SSD_KEY;
  804 
  805         if (!ISSET(link->flags, SDEV_OPEN) ||
  806             (serr != SSD_ERRCODE_CURRENT && serr != SSD_ERRCODE_DEFERRED))
  807                 return scsi_interpret_sense(xs);
  808 
  809         switch (skey) {
  810 
  811         /*
  812          * We do custom processing in ch for the unit becoming ready
  813          * case.  in this case we do not allow xs->retries to be
  814          * decremented only on the "Unit Becoming Ready" case. This is
  815          * because tape changers report "Unit Becoming Ready" when they
  816          * rescan their state (i.e. when the door got opened) and can
  817          * take a long time for large units. Rather than having a
  818          * massive timeout for all operations (which would cause other
  819          * problems) we allow changers to wait (but be interruptible
  820          * with Ctrl-C) forever as long as they are reporting that they
  821          * are becoming ready.  all other cases are handled as per the
  822          * default.
  823          */
  824         case SKEY_NOT_READY:
  825                 if (ISSET(xs->flags, SCSI_IGNORE_NOT_READY))
  826                         return 0;
  827                 switch (ASC_ASCQ(sense)) {
  828                 case SENSE_NOT_READY_BECOMING_READY:
  829                         SC_DEBUG(link, SDEV_DB1, ("not ready: busy (%#x)\n",
  830                             sense->add_sense_code_qual));
  831                         /* don't count this as a retry */
  832                         xs->retries++;
  833                         return scsi_delay(xs, 1);
  834                 default:
  835                         return scsi_interpret_sense(xs);
  836                 }
  837         default:
  838                 return scsi_interpret_sense(xs);
  839         }
  840 }

Cache object: b852517bfb3d2df67b63a42bb30f6120


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