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 /*
    2  * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
    3  * All rights reserved.
    4  *
    5  * Partially based on an autochanger driver written by Stefan Grefen
    6  * and on an autochanger driver written by the Systems Programming Group
    7  * at the University of Utah Computer Science Department.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgements:
   19  *      This product includes software developed by Jason R. Thorpe
   20  *      for And Communications, http://www.and.com/
   21  * 4. The name of the author may not be used to endorse or promote products
   22  *    derived from this software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  * $FreeBSD: src/sys/scsi/ch.c,v 1.34.2.3 1999/09/05 08:21:34 peter Exp $
   37  */
   38 
   39 #include "opt_scsi.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/errno.h>
   44 #include <sys/ioctl.h>
   45 #include <sys/buf.h>
   46 #include <sys/proc.h>
   47 #include <sys/chio.h>
   48 #include <sys/kernel.h>
   49 #include <sys/malloc.h>
   50 #ifdef DEVFS
   51 #include <sys/devfsext.h>
   52 #endif /*DEVFS*/
   53 
   54 #include <scsi/scsi_all.h>
   55 #include <scsi/scsi_changer.h>
   56 #include <scsi/scsiconf.h>
   57 
   58 #include "ch.h"
   59 
   60 #define CHRETRIES       2
   61 #define CHUNIT(x)       (minor((x)))
   62 #define CHSETUNIT(x, y) makedev(major(x), y)
   63 
   64 struct ch_softc {
   65         /*
   66          * Human-readable external name.  FreeBSD doesn't have a
   67          * generic hook for this, so we make it look NetBSD-like.  See
   68          * comment in chattach().
   69          */
   70         struct {
   71                 char    dv_xname[16];
   72         } sc_dev;
   73 
   74         /*
   75          * Pointer back to the scsi_link.  See comment in chattach().
   76          */
   77         struct scsi_link *sc_link;
   78 
   79         int             sc_picker;      /* current picker */
   80 
   81         /*
   82          * The following information is obtained from the
   83          * element address assignment page.
   84          */
   85         int             sc_firsts[4];   /* firsts, indexed by CHET_* */
   86         int             sc_counts[4];   /* counts, indexed by CHET_* */
   87 
   88         /*
   89          * The following mask defines the legal combinations
   90          * of elements for the MOVE MEDIUM command.
   91          */
   92         u_int8_t        sc_movemask[4];
   93 
   94         /*
   95          * As above, but for EXCHANGE MEDIUM.
   96          */
   97         u_int8_t        sc_exchangemask[4];
   98 
   99         int             flags;          /* misc. info */
  100 #ifdef  DEVFS
  101         void            *c_devfs_token;
  102         void            *ctl_devfs_token;
  103 #endif
  104 };
  105 
  106 /* sc_flags */
  107 #define CHF_ROTATE      0x01            /* picker can rotate */
  108 
  109 static  d_open_t        chopen;
  110 static  d_close_t       chclose;
  111 static  d_ioctl_t       chioctl;
  112 
  113 #define CDEV_MAJOR 17
  114 static struct cdevsw ch_cdevsw = 
  115         { chopen,       chclose,        noread,         nowrite,        /*17*/
  116           chioctl,      nostop,         nullreset,      nodevtotty,/* ch */
  117           noselect,     nommap,         nostrat,        "ch",   NULL,   -1 };
  118 
  119 /*
  120  * SCSI glue.
  121  */
  122 
  123 /*
  124  * Under FreeBSD, this macro sets up a bunch of trampoline
  125  * functions that indirect through the SCSI subsystem.
  126  */
  127 SCSI_DEVICE_ENTRIES(ch)
  128 
  129 static  int chunit __P((dev_t));
  130 static  dev_t chsetunit __P((dev_t, int));
  131 
  132 /* So, like, why not "int"? */
  133 static  errval  ch_devopen __P((dev_t, int, int, struct proc *,
  134                                 struct scsi_link *));
  135 static  errval  ch_devioctl __P((dev_t, int, caddr_t, int, struct proc *,
  136                                  struct scsi_link *));
  137 static  errval  ch_devclose __P((dev_t, int, int, struct proc *,
  138                                  struct scsi_link *));
  139 
  140 static struct scsi_device ch_switch = {
  141         NULL,                           /* (*err_handler) */
  142         NULL,                           /* (*start) */
  143         NULL,                           /* (*async) */
  144         NULL,                           /* (*done) */
  145         "ch",                           /* name */
  146         0,                              /* flags */
  147         { 0, 0 },                       /* spare[2] */
  148         0,                              /* link_flags */
  149         chattach,                       /* (*attach) */
  150         "Medium-Changer",               /* desc */
  151         chopen,                         /* (*open) */
  152         sizeof(struct ch_softc),        /* sizeof_scsi_data */
  153         T_CHANGER,                      /* type */
  154         chunit,                         /* (*getunit) */
  155         chsetunit,                      /* (*setunit) */
  156         ch_devopen,                     /* (*dev_open) */
  157         ch_devioctl,                    /* (*dev_ioctl) */
  158         ch_devclose,                    /* (*dev_close) */
  159 };
  160 
  161 static  int     ch_move __P((struct ch_softc *, struct changer_move *));
  162 static  int     ch_exchange __P((struct ch_softc *, struct changer_exchange *));
  163 static  int     ch_position __P((struct ch_softc *, struct changer_position *));
  164 static  int     ch_usergetelemstatus __P((struct ch_softc *, int, u_int8_t *));
  165 static  int     ch_getelemstatus __P((struct ch_softc *, int, int, caddr_t, size_t));
  166 static  int     ch_get_params __P((struct ch_softc *, int));
  167 
  168 static  errval
  169 chattach(link)
  170         struct scsi_link *link;
  171 {
  172         struct ch_softc *sc = (struct ch_softc *)(link->sd);
  173         u_int32_t unit = link->dev_unit;
  174 
  175         /*
  176          * FreeBSD doesn't have any common way of carrying
  177          * around a device's external name (i.e. <name><unit>),
  178          * so emulate the structure used by NetBSD to keep the
  179          * diffs lower.
  180          */
  181         bzero(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname));
  182         sprintf(sc->sc_dev.dv_xname, "%s%d", ch_switch.name, unit);
  183 
  184         /*
  185          * FreeBSD gets "softc" info for a device from the
  186          * scsi_link argument passed to indirect entry point functions.
  187          * NetBSD get scsi_link info from softcs that are
  188          * obtained from indexes passed to direct entry point functions.
  189          * We emulate the NetBSD behavior here to keep the diffs
  190          * lower.
  191          */
  192         sc->sc_link = link;
  193 
  194         /*
  195          * Get information about the device.  Note we can't use
  196          * interrupts yet.
  197          */
  198         if (ch_get_params(sc, SCSI_NOSLEEP|SCSI_NOMASK))
  199                 printf("offline");
  200         else {
  201                 printf("%d slot%s, %d drive%s, %d picker%s",
  202                     sc->sc_counts[CHET_ST], (sc->sc_counts[CHET_ST] > 1) ?
  203                     "s" : "",
  204                     sc->sc_counts[CHET_DT], (sc->sc_counts[CHET_DT] > 1) ?
  205                     "s" : "",
  206                     sc->sc_counts[CHET_MT], (sc->sc_counts[CHET_MT] > 1) ?
  207                     "s" : "");
  208                 if (sc->sc_counts[CHET_IE])
  209                         printf(", %d portal%s", sc->sc_counts[CHET_IE],
  210                             (sc->sc_counts[CHET_IE] > 1) ? "s" : "");
  211                 if (bootverbose) {
  212                         printf("\n");   /* This will probably look ugly ... bummer. */
  213                         printf("%s: move mask: 0x%x 0x%x 0x%x 0x%x\n",
  214                                sc->sc_dev.dv_xname,
  215                                sc->sc_movemask[CHET_MT], sc->sc_movemask[CHET_ST],
  216                                sc->sc_movemask[CHET_IE], sc->sc_movemask[CHET_DT]);
  217                         printf("%s: exchange mask: 0x%x 0x%x 0x%x 0x%x\n",
  218                                sc->sc_dev.dv_xname,
  219                                sc->sc_exchangemask[CHET_MT], sc->sc_exchangemask[CHET_ST],
  220                                sc->sc_exchangemask[CHET_IE], sc->sc_exchangemask[CHET_DT]);
  221                 }
  222         }
  223 
  224         /* Default the current picker. */
  225         sc->sc_picker = sc->sc_firsts[CHET_MT];
  226 
  227 #ifdef DEVFS
  228         sc->c_devfs_token = devfs_add_devswf(&ch_cdevsw, unit << 4, DV_CHR,
  229                                              UID_ROOT, GID_OPERATOR, 0600,
  230                                              "ch%d", unit);
  231         sc->ctl_devfs_token = devfs_add_devswf(&ch_cdevsw,
  232                                                (unit << 4) | SCSI_CONTROL_MASK,
  233                                                DV_CHR,
  234                                                UID_ROOT, GID_OPERATOR, 0600,
  235                                                "ch%d.ctl", unit);
  236 #endif
  237         return (0);
  238 }
  239 
  240 static  errval
  241 ch_devopen(dev, flags, fmt, p, link)
  242         dev_t dev;
  243         int flags, fmt;
  244         struct proc *p;
  245         struct scsi_link *link;
  246 {
  247         struct ch_softc *sc = (struct ch_softc *)(link->sd);
  248         errval error = 0;
  249         int unit;
  250 
  251         unit = CHUNIT(dev);
  252 
  253         /*
  254          * Only allow one open at a time.
  255          */
  256         if (link->flags & SDEV_OPEN)
  257                 return (EBUSY);
  258 
  259         link->flags |= SDEV_OPEN;
  260 
  261         /*
  262          * Absorb any unit attention errors.  Ignore "not ready"
  263          * since this might occur if e.g. a tape isn't actually
  264          * loaded in the drive.
  265          */
  266         (void)scsi_test_unit_ready(link, SCSI_SILENT);
  267 
  268         /*
  269          * Make sure our parameters are up to date.
  270          */
  271         if (error = ch_get_params(sc, 0))
  272                 goto bad;
  273 
  274         return (0);
  275 
  276  bad:
  277         link->flags &= ~SDEV_OPEN;
  278         return (error);
  279 }
  280 
  281 static  errval
  282 ch_devclose(dev, flags, fmt, p, link)
  283         dev_t dev;
  284         int flags, fmt;
  285         struct proc *p;
  286         struct scsi_link *link;
  287 {
  288 
  289         link->flags &= ~SDEV_OPEN;
  290         return (0);
  291 }
  292 
  293 static  errval
  294 ch_devioctl(dev, cmd, data, flags, p, link)
  295         dev_t dev;
  296         int cmd;
  297         caddr_t data;
  298         int flags;
  299         struct proc *p;
  300         struct scsi_link *link;
  301 {
  302         struct ch_softc *sc = (struct ch_softc *)(link->sd);
  303         caddr_t elemdata;
  304         int error = 0;
  305 
  306         switch (cmd) {
  307         case CHIOMOVE:
  308                 error = ch_move(sc, (struct changer_move *)data);
  309                 break;
  310 
  311         case CHIOEXCHANGE:
  312                 error = ch_exchange(sc, (struct changer_exchange *)data);
  313                 break;
  314 
  315         case CHIOPOSITION:
  316                 error = ch_position(sc, (struct changer_position *)data);
  317                 break;
  318 
  319         case CHIOGPICKER:
  320                 *(int *)data = sc->sc_picker - sc->sc_firsts[CHET_MT];
  321                 break;
  322 
  323         case CHIOSPICKER:       {
  324                 int new_picker = *(int *)data;
  325 
  326                 if (new_picker > (sc->sc_counts[CHET_MT] - 1))
  327                         return (EINVAL);
  328                 sc->sc_picker = sc->sc_firsts[CHET_MT] + new_picker;
  329                 break;          }
  330 
  331         case CHIOGPARAMS:       {
  332                 struct changer_params *cp = (struct changer_params *)data;
  333 
  334                 cp->cp_curpicker = sc->sc_picker - sc->sc_firsts[CHET_MT];
  335                 cp->cp_npickers = sc->sc_counts[CHET_MT];
  336                 cp->cp_nslots = sc->sc_counts[CHET_ST];
  337                 cp->cp_nportals = sc->sc_counts[CHET_IE];
  338                 cp->cp_ndrives = sc->sc_counts[CHET_DT];
  339                 break;          }
  340 
  341         case CHIOGSTATUS:       {
  342                 struct changer_element_status *ces =
  343                     (struct changer_element_status *)data;
  344 
  345                 error = ch_usergetelemstatus(sc, ces->ces_type, ces->ces_data);
  346                 break;          }
  347 
  348         /* Implement prevent/allow? */
  349 
  350         default:
  351                 error = scsi_do_ioctl(dev, cmd, data, flags, p, link);
  352                 break;
  353         }
  354 
  355         return (error);
  356 }
  357 
  358 static  int
  359 ch_move(sc, cm)
  360         struct ch_softc *sc;
  361         struct changer_move *cm;
  362 {
  363         struct scsi_move_medium cmd;
  364         u_int16_t fromelem, toelem;
  365 
  366         /*
  367          * Check arguments.
  368          */
  369         if ((cm->cm_fromtype > CHET_DT) || (cm->cm_totype > CHET_DT))
  370                 return (EINVAL);
  371         if ((cm->cm_fromunit > (sc->sc_counts[cm->cm_fromtype] - 1)) ||
  372             (cm->cm_tounit > (sc->sc_counts[cm->cm_totype] - 1)))
  373                 return (ENODEV);
  374 
  375         /*
  376          * Check the request against the changer's capabilities.
  377          */
  378         if ((sc->sc_movemask[cm->cm_fromtype] & (1 << cm->cm_totype)) == 0)
  379                 return (EINVAL);
  380 
  381         /*
  382          * Calculate the source and destination elements.
  383          */
  384         fromelem = sc->sc_firsts[cm->cm_fromtype] + cm->cm_fromunit;
  385         toelem = sc->sc_firsts[cm->cm_totype] + cm->cm_tounit;
  386 
  387         /*
  388          * Build the SCSI command.
  389          */
  390         bzero(&cmd, sizeof(cmd));
  391         cmd.opcode = MOVE_MEDIUM;
  392         scsi_uto2b(sc->sc_picker, cmd.tea);
  393         scsi_uto2b(fromelem, cmd.src);
  394         scsi_uto2b(toelem, cmd.dst);
  395         if (cm->cm_flags & CM_INVERT)
  396                 cmd.flags |= MOVE_MEDIUM_INVERT;
  397 
  398         /*
  399          * Send command to changer.
  400          */
  401         return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  402             sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
  403 }
  404 
  405 static  int
  406 ch_exchange(sc, ce)
  407         struct ch_softc *sc;
  408         struct changer_exchange *ce;
  409 {
  410         struct scsi_exchange_medium cmd;
  411         u_int16_t src, dst1, dst2;
  412 
  413         /*
  414          * Check arguments.
  415          */
  416         if ((ce->ce_srctype > CHET_DT) || (ce->ce_fdsttype > CHET_DT) ||
  417             (ce->ce_sdsttype > CHET_DT))
  418                 return (EINVAL);
  419         if ((ce->ce_srcunit > (sc->sc_counts[ce->ce_srctype] - 1)) ||
  420             (ce->ce_fdstunit > (sc->sc_counts[ce->ce_fdsttype] - 1)) ||
  421             (ce->ce_sdstunit > (sc->sc_counts[ce->ce_sdsttype] - 1)))
  422                 return (ENODEV);
  423 
  424         /*
  425          * Check the request against the changer's capabilities.
  426          */
  427         if (((sc->sc_exchangemask[ce->ce_srctype] &
  428              (1 << ce->ce_fdsttype)) == 0) ||
  429             ((sc->sc_exchangemask[ce->ce_fdsttype] &
  430              (1 << ce->ce_sdsttype)) == 0))
  431                 return (EINVAL);
  432 
  433         /*
  434          * Calculate the source and destination elements.
  435          */
  436         src = sc->sc_firsts[ce->ce_srctype] + ce->ce_srcunit;
  437         dst1 = sc->sc_firsts[ce->ce_fdsttype] + ce->ce_fdstunit;
  438         dst2 = sc->sc_firsts[ce->ce_sdsttype] + ce->ce_sdstunit;
  439 
  440         /*
  441          * Build the SCSI command.
  442          */
  443         bzero(&cmd, sizeof(cmd));
  444         cmd.opcode = EXCHANGE_MEDIUM;
  445         scsi_uto2b(sc->sc_picker, cmd.tea);
  446         scsi_uto2b(src, cmd.src);
  447         scsi_uto2b(dst1, cmd.fdst);
  448         scsi_uto2b(dst2, cmd.sdst);
  449         if (ce->ce_flags & CE_INVERT1)
  450                 cmd.flags |= EXCHANGE_MEDIUM_INV1;
  451         if (ce->ce_flags & CE_INVERT2)
  452                 cmd.flags |= EXCHANGE_MEDIUM_INV2;
  453 
  454         /*
  455          * Send command to changer.
  456          */
  457         return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  458             sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
  459 }
  460 
  461 static  int
  462 ch_position(sc, cp)
  463         struct ch_softc *sc;
  464         struct changer_position *cp;
  465 {
  466         struct scsi_position_to_element cmd;
  467         u_int16_t dst;
  468 
  469         /*
  470          * Check arguments.
  471          */
  472         if (cp->cp_type > CHET_DT)
  473                 return (EINVAL);
  474         if (cp->cp_unit > (sc->sc_counts[cp->cp_type] - 1))
  475                 return (ENODEV);
  476 
  477         /*
  478          * Calculate the destination element.
  479          */
  480         dst = sc->sc_firsts[cp->cp_type] + cp->cp_unit;
  481 
  482         /*
  483          * Build the SCSI command.
  484          */
  485         bzero(&cmd, sizeof(cmd));
  486         cmd.opcode = POSITION_TO_ELEMENT;
  487         scsi_uto2b(sc->sc_picker, cmd.tea);
  488         scsi_uto2b(dst, cmd.dst);
  489         if (cp->cp_flags & CP_INVERT)
  490                 cmd.flags |= POSITION_TO_ELEMENT_INVERT;
  491 
  492         /*
  493          * Send command to changer.
  494          */
  495         return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  496             sizeof(cmd), NULL, 0, CHRETRIES, 100000, NULL, 0));
  497 }
  498 
  499 /*
  500  * Perform a READ ELEMENT STATUS on behalf of the user, and return to
  501  * the user only the data the user is interested in (i.e. an array of
  502  * flags bytes).
  503  */
  504 static  int
  505 ch_usergetelemstatus(sc, chet, uptr)
  506         struct ch_softc *sc;
  507         int chet;
  508         u_int8_t *uptr;
  509 {
  510         struct read_element_status_header *st_hdr;
  511         struct read_element_status_page_header *pg_hdr;
  512         struct read_element_status_descriptor *desc;
  513         caddr_t data = NULL;
  514         size_t size, desclen;
  515         int avail, i, error = 0;
  516         u_int8_t *user_data = NULL;
  517 
  518         /*
  519          * If there are no elements of the requested type in the changer,
  520          * the request is invalid.
  521          */
  522         if (sc->sc_counts[chet] == 0)
  523                 return (EINVAL);
  524 
  525         /*
  526          * Request one descriptor for the given element type.  This
  527          * is used to determine the size of the descriptor so that
  528          * we can allocate enough storage for all of them.  We assume
  529          * that the first one can fit into 1k.
  530          */
  531         data = (caddr_t)malloc(1024, M_DEVBUF, M_WAITOK);
  532         if (error = ch_getelemstatus(sc, sc->sc_firsts[chet], 1, data, 1024))
  533                 goto done;
  534 
  535         st_hdr = (struct read_element_status_header *)data;
  536         pg_hdr = (struct read_element_status_page_header *)((u_long)st_hdr +
  537             sizeof(struct read_element_status_header));
  538         desclen = scsi_2btou(pg_hdr->edl);
  539 
  540         size = sizeof(struct read_element_status_header) +
  541             sizeof(struct read_element_status_page_header) +
  542             (desclen * sc->sc_counts[chet]);
  543 
  544         /*
  545          * Reallocate storage for descriptors and get them from the
  546          * device.
  547          */
  548         free(data, M_DEVBUF);
  549         data = (caddr_t)malloc(size, M_DEVBUF, M_WAITOK);
  550         if (error = ch_getelemstatus(sc, sc->sc_firsts[chet],
  551             sc->sc_counts[chet], data, size))
  552                 goto done;
  553 
  554         /*
  555          * Fill in the user status array.
  556          */
  557         st_hdr = (struct read_element_status_header *)data;
  558         avail = scsi_2btou(st_hdr->count);
  559         if (avail != sc->sc_counts[chet])
  560                 printf("%s: warning, READ ELEMENT STATUS avail != count\n",
  561                     sc->sc_dev.dv_xname);
  562 
  563         user_data = (u_int8_t *)malloc(avail, M_DEVBUF, M_WAITOK);
  564 
  565         desc = (struct read_element_status_descriptor *)((u_long)data +
  566             sizeof(struct read_element_status_header) +
  567             sizeof(struct read_element_status_page_header));
  568         for (i = 0; i < avail; ++i) {
  569                 user_data[i] = desc->flags1;
  570                 (u_long)desc += desclen;
  571         }
  572 
  573         /* Copy flags array out to userspace. */
  574         error = copyout(user_data, uptr, avail);
  575 
  576  done:
  577         if (data != NULL)
  578                 free(data, M_DEVBUF);
  579         if (user_data != NULL)
  580                 free(user_data, M_DEVBUF);
  581         return (error);
  582 }
  583 
  584 static  int
  585 ch_getelemstatus(sc, first, count, data, datalen)
  586         struct ch_softc *sc;
  587         int first, count;
  588         caddr_t data;
  589         size_t datalen;
  590 {
  591         struct scsi_read_element_status cmd;
  592 
  593         /*
  594          * Build SCSI command.
  595          */
  596         bzero(&cmd, sizeof(cmd));
  597         cmd.opcode = READ_ELEMENT_STATUS;
  598         scsi_uto2b(first, cmd.sea);
  599         scsi_uto2b(count, cmd.count);
  600         scsi_uto3b(datalen, cmd.len);
  601 
  602         /*
  603          * Send command to changer.
  604          */
  605         return (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  606             sizeof(cmd), (u_char *)data, datalen, CHRETRIES, 100000, NULL, SCSI_DATA_IN));
  607 }
  608 
  609 
  610 /*
  611  * Ask the device about itself and fill in the parameters in our
  612  * softc.
  613  */
  614 static  int
  615 ch_get_params(sc, scsiflags)
  616         struct ch_softc *sc;
  617         int scsiflags;
  618 {
  619         struct scsi_mode_sense cmd;
  620         struct scsi_mode_sense_data {
  621                 struct scsi_mode_header header;
  622                 union {
  623                         struct page_element_address_assignment ea;
  624                         struct page_transport_geometry_parameters tg;
  625                         struct page_device_capabilities cap;
  626                 } pages;
  627         } sense_data;
  628         int error, from;
  629         u_int8_t *moves, *exchanges;
  630 
  631         /*
  632          * Grab info from the element address assignment page.
  633          */
  634         bzero(&cmd, sizeof(cmd));
  635         bzero(&sense_data, sizeof(sense_data));
  636         cmd.op_code = MODE_SENSE;
  637         cmd.byte2 |= 0x08;      /* disable block descriptors */
  638         cmd.page = 0x1d;
  639         cmd.length = (sizeof(sense_data) & 0xff);
  640         error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  641             sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES,
  642             6000, NULL, scsiflags | SCSI_DATA_IN);
  643         if (error) {
  644                 printf("%s: could not sense element address page\n",
  645                     sc->sc_dev.dv_xname);
  646                 return (error);
  647         }
  648 
  649         sc->sc_firsts[CHET_MT] = scsi_2btou(sense_data.pages.ea.mtea);
  650         sc->sc_counts[CHET_MT] = scsi_2btou(sense_data.pages.ea.nmte);
  651         sc->sc_firsts[CHET_ST] = scsi_2btou(sense_data.pages.ea.fsea);
  652         sc->sc_counts[CHET_ST] = scsi_2btou(sense_data.pages.ea.nse);
  653         sc->sc_firsts[CHET_IE] = scsi_2btou(sense_data.pages.ea.fieea);
  654         sc->sc_counts[CHET_IE] = scsi_2btou(sense_data.pages.ea.niee);
  655         sc->sc_firsts[CHET_DT] = scsi_2btou(sense_data.pages.ea.fdtea);
  656         sc->sc_counts[CHET_DT] = scsi_2btou(sense_data.pages.ea.ndte);
  657 
  658         /* XXX ask for page trasport geom */
  659 
  660         /*
  661          * Grab info from the capabilities page.
  662          */
  663         bzero(&cmd, sizeof(cmd));
  664         bzero(&sense_data, sizeof(sense_data));
  665         cmd.op_code = MODE_SENSE;
  666         cmd.byte2 |= 0x08;      /* disable block descriptors */
  667         cmd.page = 0x1f;
  668         cmd.length = (sizeof(sense_data) & 0xff);
  669         error = scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
  670             sizeof(cmd), (u_char *)&sense_data, sizeof(sense_data), CHRETRIES,
  671             6000, NULL, scsiflags | SCSI_DATA_IN);
  672         if (error) {
  673                 printf("%s: could not sense capabilities page\n",
  674                     sc->sc_dev.dv_xname);
  675                 return (error);
  676         }
  677 
  678         bzero(sc->sc_movemask, sizeof(sc->sc_movemask));
  679         bzero(sc->sc_exchangemask, sizeof(sc->sc_exchangemask));
  680         moves = &sense_data.pages.cap.move_from_mt;
  681         exchanges = &sense_data.pages.cap.exchange_with_mt;
  682         for (from = CHET_MT; from <= CHET_DT; ++from) {
  683                 sc->sc_movemask[from] = moves[from];
  684                 sc->sc_exchangemask[from] = exchanges[from];
  685         }
  686 
  687         sc->sc_link->flags |= SDEV_MEDIA_LOADED;
  688         return (0);
  689 }
  690 
  691 static int
  692 chunit(dev)
  693         dev_t dev;
  694 {
  695 
  696         return (CHUNIT(dev));
  697 }
  698 
  699 static dev_t
  700 chsetunit(dev, unit)
  701         dev_t dev;
  702         int unit;
  703 {
  704 
  705         return (CHSETUNIT(dev, unit));
  706 }
  707 
  708 
  709 static ch_devsw_installed = 0;
  710 
  711 static void
  712 ch_drvinit(void *unused)
  713 {
  714         dev_t dev;
  715 
  716         if( ! ch_devsw_installed ) {
  717                 dev = makedev(CDEV_MAJOR, 0);
  718                 cdevsw_add(&dev,&ch_cdevsw, NULL);
  719                 ch_devsw_installed = 1;
  720         }
  721 }
  722 
  723 SYSINIT(chdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ch_drvinit,NULL)

Cache object: 616da992facc6e233bdfb7e63cc7d41a


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