root/scsi/ch.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. chmatch
  2. chattach
  3. chopen
  4. chclose
  5. chioctl
  6. ch_move
  7. ch_exchange
  8. ch_position
  9. copy_voltag
  10. copy_element_status
  11. ch_usergetelemstatus
  12. ch_getelemstatus
  13. ch_get_params
  14. ch_get_quirks
  15. ch_interpret_sense

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

/* [<][>][^][v][top][bottom][index][help] */