LCOV - code coverage report
Current view: top level - scsi - ch.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 296 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13