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/cam/scsi/scsi_enc.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) 2000 Matthew Jacob
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions, and the following disclaimer,
   10  *    without modification, immediately at the beginning of the file.
   11  * 2. The name of the author may not be used to endorse or promote products
   12  *    derived from this software without specific prior written permission.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.0/sys/cam/scsi/scsi_enc.c 257049 2013-10-24 10:33:31Z mav $");
   29 
   30 #include <sys/param.h>
   31 
   32 #include <sys/conf.h>
   33 #include <sys/errno.h>
   34 #include <sys/fcntl.h>
   35 #include <sys/kernel.h>
   36 #include <sys/kthread.h>
   37 #include <sys/lock.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mutex.h>
   40 #include <sys/queue.h>
   41 #include <sys/sx.h>
   42 #include <sys/systm.h>
   43 #include <sys/sysctl.h>
   44 #include <sys/types.h>
   45 
   46 #include <machine/stdarg.h>
   47 
   48 #include <cam/cam.h>
   49 #include <cam/cam_ccb.h>
   50 #include <cam/cam_debug.h>
   51 #include <cam/cam_periph.h>
   52 #include <cam/cam_xpt_periph.h>
   53 
   54 #include <cam/scsi/scsi_all.h>
   55 #include <cam/scsi/scsi_message.h>
   56 #include <cam/scsi/scsi_enc.h>
   57 #include <cam/scsi/scsi_enc_internal.h>
   58 
   59 #include <opt_ses.h>
   60 
   61 MALLOC_DEFINE(M_SCSIENC, "SCSI ENC", "SCSI ENC buffers");
   62 
   63 /* Enclosure type independent driver */
   64 
   65 static  d_open_t        enc_open;
   66 static  d_close_t       enc_close;
   67 static  d_ioctl_t       enc_ioctl;
   68 static  periph_init_t   enc_init;
   69 static  periph_ctor_t   enc_ctor;
   70 static  periph_oninv_t  enc_oninvalidate;
   71 static  periph_dtor_t   enc_dtor;
   72 static  periph_start_t  enc_start;
   73 
   74 static void enc_async(void *, uint32_t, struct cam_path *, void *);
   75 static enctyp enc_type(struct ccb_getdev *);
   76 
   77 SYSCTL_NODE(_kern_cam, OID_AUTO, enc, CTLFLAG_RD, 0,
   78             "CAM Enclosure Services driver");
   79 
   80 static struct periph_driver encdriver = {
   81         enc_init, "ses",
   82         TAILQ_HEAD_INITIALIZER(encdriver.units), /* generation */ 0
   83 };
   84 
   85 PERIPHDRIVER_DECLARE(enc, encdriver);
   86 
   87 static struct cdevsw enc_cdevsw = {
   88         .d_version =    D_VERSION,
   89         .d_open =       enc_open,
   90         .d_close =      enc_close,
   91         .d_ioctl =      enc_ioctl,
   92         .d_name =       "ses",
   93         .d_flags =      D_TRACKCLOSE,
   94 };
   95 
   96 static void
   97 enc_init(void)
   98 {
   99         cam_status status;
  100 
  101         /*
  102          * Install a global async callback.  This callback will
  103          * receive async callbacks like "new device found".
  104          */
  105         status = xpt_register_async(AC_FOUND_DEVICE, enc_async, NULL, NULL);
  106 
  107         if (status != CAM_REQ_CMP) {
  108                 printf("enc: Failed to attach master async callback "
  109                        "due to status 0x%x!\n", status);
  110         }
  111 }
  112 
  113 static void
  114 enc_devgonecb(void *arg)
  115 {
  116         struct cam_sim    *sim;
  117         struct cam_periph *periph;
  118         struct enc_softc  *enc;
  119         int i;
  120 
  121         periph = (struct cam_periph *)arg;
  122         sim = periph->sim;
  123         enc = (struct enc_softc *)periph->softc;
  124 
  125         mtx_lock(sim->mtx);
  126 
  127         /*
  128          * When we get this callback, we will get no more close calls from
  129          * devfs.  So if we have any dangling opens, we need to release the
  130          * reference held for that particular context.
  131          */
  132         for (i = 0; i < enc->open_count; i++)
  133                 cam_periph_release_locked(periph);
  134 
  135         enc->open_count = 0;
  136 
  137         /*
  138          * Release the reference held for the device node, it is gone now.
  139          */
  140         cam_periph_release_locked(periph);
  141 
  142         /*
  143          * We reference the SIM lock directly here, instead of using
  144          * cam_periph_unlock().  The reason is that the final call to
  145          * cam_periph_release_locked() above could result in the periph
  146          * getting freed.  If that is the case, dereferencing the periph
  147          * with a cam_periph_unlock() call would cause a page fault.
  148          */
  149         mtx_unlock(sim->mtx);
  150 }
  151 
  152 static void
  153 enc_oninvalidate(struct cam_periph *periph)
  154 {
  155         struct enc_softc *enc;
  156 
  157         enc = periph->softc;
  158 
  159         enc->enc_flags |= ENC_FLAG_INVALID;
  160 
  161         /* If the sub-driver has an invalidate routine, call it */
  162         if (enc->enc_vec.softc_invalidate != NULL)
  163                 enc->enc_vec.softc_invalidate(enc);
  164 
  165         /*
  166          * Unregister any async callbacks.
  167          */
  168         xpt_register_async(0, enc_async, periph, periph->path);
  169 
  170         /*
  171          * Shutdown our daemon.
  172          */
  173         enc->enc_flags |= ENC_FLAG_SHUTDOWN;
  174         if (enc->enc_daemon != NULL) {
  175                 /* Signal the ses daemon to terminate. */
  176                 wakeup(enc->enc_daemon);
  177         }
  178         callout_drain(&enc->status_updater);
  179 
  180         destroy_dev_sched_cb(enc->enc_dev, enc_devgonecb, periph);
  181 }
  182 
  183 static void
  184 enc_dtor(struct cam_periph *periph)
  185 {
  186         struct enc_softc *enc;
  187 
  188         enc = periph->softc;
  189 
  190         /* If the sub-driver has a cleanup routine, call it */
  191         if (enc->enc_vec.softc_cleanup != NULL)
  192                 enc->enc_vec.softc_cleanup(enc);
  193 
  194         if (enc->enc_boot_hold_ch.ich_func != NULL) {
  195                 config_intrhook_disestablish(&enc->enc_boot_hold_ch);
  196                 enc->enc_boot_hold_ch.ich_func = NULL;
  197         }
  198 
  199         ENC_FREE(enc);
  200 }
  201 
  202 static void
  203 enc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
  204 {
  205         struct cam_periph *periph;
  206 
  207         periph = (struct cam_periph *)callback_arg;
  208 
  209         switch(code) {
  210         case AC_FOUND_DEVICE:
  211         {
  212                 struct ccb_getdev *cgd;
  213                 cam_status status;
  214                 path_id_t path_id;
  215 
  216                 cgd = (struct ccb_getdev *)arg;
  217                 if (arg == NULL) {
  218                         break;
  219                 }
  220 
  221                 if (enc_type(cgd) == ENC_NONE) {
  222                         /*
  223                          * Schedule announcement of the ENC bindings for
  224                          * this device if it is managed by a SEP.
  225                          */
  226                         path_id = xpt_path_path_id(path);
  227                         xpt_lock_buses();
  228                         TAILQ_FOREACH(periph, &encdriver.units, unit_links) {
  229                                 struct enc_softc *softc;
  230 
  231                                 softc = (struct enc_softc *)periph->softc;
  232                                 if (xpt_path_path_id(periph->path) != path_id
  233                                  || softc == NULL
  234                                  || (softc->enc_flags & ENC_FLAG_INITIALIZED)
  235                                   == 0
  236                                  || softc->enc_vec.device_found == NULL)
  237                                         continue;
  238 
  239                                 softc->enc_vec.device_found(softc);
  240                         }
  241                         xpt_unlock_buses();
  242                         return;
  243                 }
  244 
  245                 status = cam_periph_alloc(enc_ctor, enc_oninvalidate,
  246                     enc_dtor, enc_start, "ses", CAM_PERIPH_BIO,
  247                     cgd->ccb_h.path, enc_async, AC_FOUND_DEVICE, cgd);
  248 
  249                 if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) {
  250                         printf("enc_async: Unable to probe new device due to "
  251                             "status 0x%x\n", status);
  252                 }
  253                 break;
  254         }
  255         default:
  256                 cam_periph_async(periph, code, path, arg);
  257                 break;
  258         }
  259 }
  260 
  261 static int
  262 enc_open(struct cdev *dev, int flags, int fmt, struct thread *td)
  263 {
  264         struct cam_periph *periph;
  265         struct enc_softc *softc;
  266         int error = 0;
  267 
  268         periph = (struct cam_periph *)dev->si_drv1;
  269         if (periph == NULL) {
  270                 return (ENXIO);
  271         }
  272 
  273         if (cam_periph_acquire(periph) != CAM_REQ_CMP)
  274                 return (ENXIO);
  275 
  276         cam_periph_lock(periph);
  277 
  278         softc = (struct enc_softc *)periph->softc;
  279 
  280         if ((softc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
  281                 error = ENXIO;
  282                 goto out;
  283         }
  284         if (softc->enc_flags & ENC_FLAG_INVALID) {
  285                 error = ENXIO;
  286                 goto out;
  287         }
  288 out:
  289         if (error != 0)
  290                 cam_periph_release_locked(periph);
  291         else
  292                 softc->open_count++;
  293 
  294         cam_periph_unlock(periph);
  295 
  296         return (error);
  297 }
  298 
  299 static int
  300 enc_close(struct cdev *dev, int flag, int fmt, struct thread *td)
  301 {
  302         struct cam_sim    *sim;
  303         struct cam_periph *periph;
  304         struct enc_softc  *enc;
  305 
  306         periph = (struct cam_periph *)dev->si_drv1;
  307         if (periph == NULL)
  308                 return (ENXIO);
  309 
  310         sim = periph->sim;
  311         enc = periph->softc;
  312 
  313         mtx_lock(sim->mtx);
  314 
  315         enc->open_count--;
  316 
  317         cam_periph_release_locked(periph);
  318 
  319         /*
  320          * We reference the SIM lock directly here, instead of using
  321          * cam_periph_unlock().  The reason is that the call to
  322          * cam_periph_release_locked() above could result in the periph
  323          * getting freed.  If that is the case, dereferencing the periph
  324          * with a cam_periph_unlock() call would cause a page fault.
  325          *
  326          * cam_periph_release() avoids this problem using the same method,
  327          * but we're manually acquiring and dropping the lock here to
  328          * protect the open count and avoid another lock acquisition and
  329          * release.
  330          */
  331         mtx_unlock(sim->mtx);
  332 
  333         return (0);
  334 }
  335 
  336 static void
  337 enc_start(struct cam_periph *p, union ccb *sccb)
  338 {
  339         struct enc_softc *enc;
  340 
  341         enc = p->softc;
  342         ENC_DLOG(enc, "%s enter imm=%d prio=%d\n",
  343             __func__, p->immediate_priority, p->pinfo.priority);
  344         if (p->immediate_priority <= p->pinfo.priority) {
  345                 SLIST_INSERT_HEAD(&p->ccb_list, &sccb->ccb_h, periph_links.sle);
  346                 p->immediate_priority = CAM_PRIORITY_NONE;
  347                 wakeup(&p->ccb_list);
  348         } else
  349                 xpt_release_ccb(sccb);
  350         ENC_DLOG(enc, "%s exit\n", __func__);
  351 }
  352 
  353 void
  354 enc_done(struct cam_periph *periph, union ccb *dccb)
  355 {
  356         wakeup(&dccb->ccb_h.cbfcnp);
  357 }
  358 
  359 int
  360 enc_error(union ccb *ccb, uint32_t cflags, uint32_t sflags)
  361 {
  362         struct enc_softc *softc;
  363         struct cam_periph *periph;
  364 
  365         periph = xpt_path_periph(ccb->ccb_h.path);
  366         softc = (struct enc_softc *)periph->softc;
  367 
  368         return (cam_periph_error(ccb, cflags, sflags, &softc->saved_ccb));
  369 }
  370 
  371 static int
  372 enc_ioctl(struct cdev *dev, u_long cmd, caddr_t arg_addr, int flag,
  373          struct thread *td)
  374 {
  375         struct cam_periph *periph;
  376         encioc_enc_status_t tmp;
  377         encioc_string_t sstr;
  378         encioc_elm_status_t elms;
  379         encioc_elm_desc_t elmd;
  380         encioc_elm_devnames_t elmdn;
  381         encioc_element_t *uelm;
  382         enc_softc_t *enc;
  383         enc_cache_t *cache;
  384         void *addr;
  385         int error, i;
  386 
  387 
  388         if (arg_addr)
  389                 addr = *((caddr_t *) arg_addr);
  390         else
  391                 addr = NULL;
  392 
  393         periph = (struct cam_periph *)dev->si_drv1;
  394         if (periph == NULL)
  395                 return (ENXIO);
  396 
  397         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("entering encioctl\n"));
  398 
  399         cam_periph_lock(periph);
  400         enc = (struct enc_softc *)periph->softc;
  401         cache = &enc->enc_cache;
  402 
  403         /*
  404          * Now check to see whether we're initialized or not.
  405          * This actually should never fail as we're not supposed
  406          * to get past enc_open w/o successfully initializing
  407          * things.
  408          */
  409         if ((enc->enc_flags & ENC_FLAG_INITIALIZED) == 0) {
  410                 cam_periph_unlock(periph);
  411                 return (ENXIO);
  412         }
  413         cam_periph_unlock(periph);
  414 
  415         error = 0;
  416 
  417         CAM_DEBUG(periph->path, CAM_DEBUG_TRACE,
  418             ("trying to do ioctl %#lx\n", cmd));
  419 
  420         /*
  421          * If this command can change the device's state,
  422          * we must have the device open for writing.
  423          *
  424          * For commands that get information about the
  425          * device- we don't need to lock the peripheral
  426          * if we aren't running a command.  The periph
  427          * also can't go away while a user process has
  428          * it open.
  429          */
  430         switch (cmd) {
  431         case ENCIOC_GETNELM:
  432         case ENCIOC_GETELMMAP:
  433         case ENCIOC_GETENCSTAT:
  434         case ENCIOC_GETELMSTAT:
  435         case ENCIOC_GETELMDESC:
  436         case ENCIOC_GETELMDEVNAMES:
  437                 break;
  438         default:
  439                 if ((flag & FWRITE) == 0) {
  440                         return (EBADF);
  441                 }
  442         }
  443  
  444         /*
  445          * XXX The values read here are only valid for the current
  446          *     configuration generation.  We need these ioctls
  447          *     to also pass in/out a generation number.
  448          */
  449         sx_slock(&enc->enc_cache_lock);
  450         switch (cmd) {
  451         case ENCIOC_GETNELM:
  452                 error = copyout(&cache->nelms, addr, sizeof (cache->nelms));
  453                 break;
  454                 
  455         case ENCIOC_GETELMMAP:
  456                 for (uelm = addr, i = 0; i != cache->nelms; i++) {
  457                         encioc_element_t kelm;
  458                         kelm.elm_idx = i;
  459                         kelm.elm_subenc_id = cache->elm_map[i].subenclosure;
  460                         kelm.elm_type = cache->elm_map[i].enctype;
  461                         error = copyout(&kelm, &uelm[i], sizeof(kelm));
  462                         if (error)
  463                                 break;
  464                 }
  465                 break;
  466 
  467         case ENCIOC_GETENCSTAT:
  468                 cam_periph_lock(periph);
  469                 error = enc->enc_vec.get_enc_status(enc, 1);
  470                 if (error) {
  471                         cam_periph_unlock(periph);
  472                         break;
  473                 }
  474                 tmp = cache->enc_status;
  475                 cam_periph_unlock(periph);
  476                 error = copyout(&tmp, addr, sizeof(tmp));
  477                 cache->enc_status = tmp;
  478                 break;
  479 
  480         case ENCIOC_SETENCSTAT:
  481                 error = copyin(addr, &tmp, sizeof(tmp));
  482                 if (error)
  483                         break;
  484                 cam_periph_lock(periph);
  485                 error = enc->enc_vec.set_enc_status(enc, tmp, 1);
  486                 cam_periph_unlock(periph);
  487                 break;
  488 
  489         case ENCIOC_GETSTRING:
  490         case ENCIOC_SETSTRING:
  491                 if (enc->enc_vec.handle_string == NULL) {
  492                         error = EINVAL;
  493                         break;
  494                 }
  495                 error = copyin(addr, &sstr, sizeof(sstr));
  496                 if (error)
  497                         break;
  498                 cam_periph_lock(periph);
  499                 error = enc->enc_vec.handle_string(enc, &sstr, cmd);
  500                 cam_periph_unlock(periph);
  501                 break;
  502 
  503         case ENCIOC_GETELMSTAT:
  504                 error = copyin(addr, &elms, sizeof(elms));
  505                 if (error)
  506                         break;
  507                 if (elms.elm_idx >= cache->nelms) {
  508                         error = EINVAL;
  509                         break;
  510                 }
  511                 cam_periph_lock(periph);
  512                 error = enc->enc_vec.get_elm_status(enc, &elms, 1);
  513                 cam_periph_unlock(periph);
  514                 if (error)
  515                         break;
  516                 error = copyout(&elms, addr, sizeof(elms));
  517                 break;
  518 
  519         case ENCIOC_GETELMDESC:
  520                 error = copyin(addr, &elmd, sizeof(elmd));
  521                 if (error)
  522                         break;
  523                 if (elmd.elm_idx >= cache->nelms) {
  524                         error = EINVAL;
  525                         break;
  526                 }
  527                 if (enc->enc_vec.get_elm_desc != NULL) {
  528                         error = enc->enc_vec.get_elm_desc(enc, &elmd);
  529                         if (error)
  530                                 break;
  531                 } else
  532                         elmd.elm_desc_len = 0;
  533                 error = copyout(&elmd, addr, sizeof(elmd));
  534                 break;
  535 
  536         case ENCIOC_GETELMDEVNAMES:
  537                 if (enc->enc_vec.get_elm_devnames == NULL) {
  538                         error = EINVAL;
  539                         break;
  540                 }
  541                 error = copyin(addr, &elmdn, sizeof(elmdn));
  542                 if (error)
  543                         break;
  544                 if (elmdn.elm_idx >= cache->nelms) {
  545                         error = EINVAL;
  546                         break;
  547                 }
  548                 cam_periph_lock(periph);
  549                 error = (*enc->enc_vec.get_elm_devnames)(enc, &elmdn);
  550                 cam_periph_unlock(periph);
  551                 if (error)
  552                         break;
  553                 error = copyout(&elmdn, addr, sizeof(elmdn));
  554                 break;
  555 
  556         case ENCIOC_SETELMSTAT:
  557                 error = copyin(addr, &elms, sizeof(elms));
  558                 if (error)
  559                         break;
  560 
  561                 if (elms.elm_idx >= cache->nelms) {
  562                         error = EINVAL;
  563                         break;
  564                 }
  565                 cam_periph_lock(periph);
  566                 error = enc->enc_vec.set_elm_status(enc, &elms, 1);
  567                 cam_periph_unlock(periph);
  568 
  569                 break;
  570 
  571         case ENCIOC_INIT:
  572 
  573                 cam_periph_lock(periph);
  574                 error = enc->enc_vec.init_enc(enc);
  575                 cam_periph_unlock(periph);
  576                 break;
  577 
  578         default:
  579                 cam_periph_lock(periph);
  580                 error = cam_periph_ioctl(periph, cmd, arg_addr, enc_error);
  581                 cam_periph_unlock(periph);
  582                 break;
  583         }
  584         sx_sunlock(&enc->enc_cache_lock);
  585         return (error);
  586 }
  587 
  588 int
  589 enc_runcmd(struct enc_softc *enc, char *cdb, int cdbl, char *dptr, int *dlenp)
  590 {
  591         int error, dlen, tdlen;
  592         ccb_flags ddf;
  593         union ccb *ccb;
  594 
  595         CAM_DEBUG(enc->periph->path, CAM_DEBUG_TRACE,
  596             ("entering enc_runcmd\n"));
  597         if (dptr) {
  598                 if ((dlen = *dlenp) < 0) {
  599                         dlen = -dlen;
  600                         ddf = CAM_DIR_OUT;
  601                 } else {
  602                         ddf = CAM_DIR_IN;
  603                 }
  604         } else {
  605                 dlen = 0;
  606                 ddf = CAM_DIR_NONE;
  607         }
  608 
  609         if (cdbl > IOCDBLEN) {
  610                 cdbl = IOCDBLEN;
  611         }
  612 
  613         ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL);
  614         if (enc->enc_type == ENC_SEMB_SES || enc->enc_type == ENC_SEMB_SAFT) {
  615                 tdlen = min(dlen, 1020);
  616                 tdlen = (tdlen + 3) & ~3;
  617                 cam_fill_ataio(&ccb->ataio, 0, enc_done, ddf, 0, dptr, tdlen,
  618                     30 * 1000);
  619                 if (cdb[0] == RECEIVE_DIAGNOSTIC)
  620                         ata_28bit_cmd(&ccb->ataio,
  621                             ATA_SEP_ATTN, cdb[2], 0x02, tdlen / 4);
  622                 else if (cdb[0] == SEND_DIAGNOSTIC)
  623                         ata_28bit_cmd(&ccb->ataio,
  624                             ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
  625                             0x82, tdlen / 4);
  626                 else if (cdb[0] == READ_BUFFER)
  627                         ata_28bit_cmd(&ccb->ataio,
  628                             ATA_SEP_ATTN, cdb[2], 0x00, tdlen / 4);
  629                 else
  630                         ata_28bit_cmd(&ccb->ataio,
  631                             ATA_SEP_ATTN, dlen > 0 ? dptr[0] : 0,
  632                             0x80, tdlen / 4);
  633         } else {
  634                 tdlen = dlen;
  635                 cam_fill_csio(&ccb->csio, 0, enc_done, ddf, MSG_SIMPLE_Q_TAG,
  636                     dptr, dlen, sizeof (struct scsi_sense_data), cdbl,
  637                     60 * 1000);
  638                 bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cdbl);
  639         }
  640 
  641         error = cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL);
  642         if (error) {
  643                 if (dptr) {
  644                         *dlenp = dlen;
  645                 }
  646         } else {
  647                 if (dptr) {
  648                         if (ccb->ccb_h.func_code == XPT_ATA_IO)
  649                                 *dlenp = ccb->ataio.resid;
  650                         else
  651                                 *dlenp = ccb->csio.resid;
  652                         *dlenp += tdlen - dlen;
  653                 }
  654         }
  655         xpt_release_ccb(ccb);
  656         CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
  657             ("exiting enc_runcmd: *dlenp = %d\n", *dlenp));
  658         return (error);
  659 }
  660 
  661 void
  662 enc_log(struct enc_softc *enc, const char *fmt, ...)
  663 {
  664         va_list ap;
  665 
  666         printf("%s%d: ", enc->periph->periph_name, enc->periph->unit_number);
  667         va_start(ap, fmt);
  668         vprintf(fmt, ap);
  669         va_end(ap);
  670 }
  671 
  672 /*
  673  * The code after this point runs on many platforms,
  674  * so forgive the slightly awkward and nonconforming
  675  * appearance.
  676  */
  677 
  678 /*
  679  * Is this a device that supports enclosure services?
  680  *
  681  * It's a pretty simple ruleset- if it is device type
  682  * 0x0D (13), it's an ENCLOSURE device.
  683  */
  684 
  685 #define SAFTE_START     44
  686 #define SAFTE_END       50
  687 #define SAFTE_LEN       SAFTE_END-SAFTE_START
  688 
  689 static enctyp
  690 enc_type(struct ccb_getdev *cgd)
  691 {
  692         int buflen;
  693         unsigned char *iqd;
  694 
  695         if (cgd->protocol == PROTO_SEMB) {
  696                 iqd = (unsigned char *)&cgd->ident_data;
  697                 if (STRNCMP(iqd + 43, "S-E-S", 5) == 0)
  698                         return (ENC_SEMB_SES);
  699                 else if (STRNCMP(iqd + 43, "SAF-TE", 6) == 0)
  700                         return (ENC_SEMB_SAFT);
  701                 return (ENC_NONE);
  702 
  703         } else if (cgd->protocol != PROTO_SCSI)
  704                 return (ENC_NONE);
  705 
  706         iqd = (unsigned char *)&cgd->inq_data;
  707         buflen = min(sizeof(cgd->inq_data),
  708             SID_ADDITIONAL_LENGTH(&cgd->inq_data));
  709 
  710         if ((iqd[0] & 0x1f) == T_ENCLOSURE) {
  711                 if ((iqd[2] & 0x7) > 2) {
  712                         return (ENC_SES);
  713                 } else {
  714                         return (ENC_SES_SCSI2);
  715                 }
  716                 return (ENC_NONE);
  717         }
  718 
  719 #ifdef  SES_ENABLE_PASSTHROUGH
  720         if ((iqd[6] & 0x40) && (iqd[2] & 0x7) >= 2) {
  721                 /*
  722                  * PassThrough Device.
  723                  */
  724                 return (ENC_SES_PASSTHROUGH);
  725         }
  726 #endif
  727 
  728         /*
  729          * The comparison is short for a reason-
  730          * some vendors were chopping it short.
  731          */
  732 
  733         if (buflen < SAFTE_END - 2) {
  734                 return (ENC_NONE);
  735         }
  736 
  737         if (STRNCMP((char *)&iqd[SAFTE_START], "SAF-TE", SAFTE_LEN - 2) == 0) {
  738                 return (ENC_SAFT);
  739         }
  740         return (ENC_NONE);
  741 }
  742 
  743 /*================== Enclosure Monitoring/Processing Daemon ==================*/
  744 /**
  745  * \brief Queue an update request for a given action, if needed.
  746  *
  747  * \param enc           SES softc to queue the request for.
  748  * \param action        Action requested.
  749  */
  750 void
  751 enc_update_request(enc_softc_t *enc, uint32_t action)
  752 {
  753         if ((enc->pending_actions & (0x1 << action)) == 0) {
  754                 enc->pending_actions |= (0x1 << action);
  755                 ENC_DLOG(enc, "%s: queing requested action %d\n",
  756                     __func__, action);
  757                 if (enc->current_action == ENC_UPDATE_NONE)
  758                         wakeup(enc->enc_daemon);
  759         } else {
  760                 ENC_DLOG(enc, "%s: ignoring requested action %d - "
  761                     "Already queued\n", __func__, action);
  762         }
  763 }
  764 
  765 /**
  766  * \brief Invoke the handler of the highest priority pending
  767  *        state in the SES state machine.
  768  *
  769  * \param enc  The SES instance invoking the state machine.
  770  */
  771 static void
  772 enc_fsm_step(enc_softc_t *enc)
  773 {
  774         union ccb            *ccb;
  775         uint8_t              *buf;
  776         struct enc_fsm_state *cur_state;
  777         int                   error;
  778         uint32_t              xfer_len;
  779         
  780         ENC_DLOG(enc, "%s enter %p\n", __func__, enc);
  781 
  782         enc->current_action   = ffs(enc->pending_actions) - 1;
  783         enc->pending_actions &= ~(0x1 << enc->current_action);
  784 
  785         cur_state = &enc->enc_fsm_states[enc->current_action];
  786 
  787         buf = NULL;
  788         if (cur_state->buf_size != 0) {
  789                 cam_periph_unlock(enc->periph);
  790                 buf = malloc(cur_state->buf_size, M_SCSIENC, M_WAITOK|M_ZERO);
  791                 cam_periph_lock(enc->periph);
  792         }
  793 
  794         error = 0;
  795         ccb   = NULL;
  796         if (cur_state->fill != NULL) {
  797                 ccb = cam_periph_getccb(enc->periph, CAM_PRIORITY_NORMAL);
  798 
  799                 error = cur_state->fill(enc, cur_state, ccb, buf);
  800                 if (error != 0)
  801                         goto done;
  802 
  803                 error = cam_periph_runccb(ccb, cur_state->error,
  804                                           ENC_CFLAGS,
  805                                           ENC_FLAGS|SF_QUIET_IR, NULL);
  806         }
  807 
  808         if (ccb != NULL) {
  809                 if (ccb->ccb_h.func_code == XPT_ATA_IO)
  810                         xfer_len = ccb->ataio.dxfer_len - ccb->ataio.resid;
  811                 else
  812                         xfer_len = ccb->csio.dxfer_len - ccb->csio.resid;
  813         } else
  814                 xfer_len = 0;
  815 
  816         cam_periph_unlock(enc->periph);
  817         cur_state->done(enc, cur_state, ccb, &buf, error, xfer_len);
  818         cam_periph_lock(enc->periph);
  819 
  820 done:
  821         ENC_DLOG(enc, "%s exit - result %d\n", __func__, error);
  822         ENC_FREE_AND_NULL(buf);
  823         if (ccb != NULL)
  824                 xpt_release_ccb(ccb);
  825 }
  826 
  827 /**
  828  * \invariant Called with cam_periph mutex held.
  829  */
  830 static void
  831 enc_status_updater(void *arg)
  832 {
  833         enc_softc_t *enc;
  834 
  835         enc = arg;
  836         if (enc->enc_vec.poll_status != NULL)
  837                 enc->enc_vec.poll_status(enc);
  838 }
  839 
  840 static void
  841 enc_daemon(void *arg)
  842 {
  843         enc_softc_t *enc;
  844 
  845         enc = arg;
  846 
  847         cam_periph_lock(enc->periph);
  848         while ((enc->enc_flags & ENC_FLAG_SHUTDOWN) == 0) {
  849                 if (enc->pending_actions == 0) {
  850                         struct intr_config_hook *hook;
  851 
  852                         /*
  853                          * Reset callout and msleep, or
  854                          * issue timed task completion
  855                          * status command.
  856                          */
  857                         enc->current_action = ENC_UPDATE_NONE;
  858 
  859                         /*
  860                          * We've been through our state machine at least
  861                          * once.  Allow the transition to userland.
  862                          */
  863                         hook = &enc->enc_boot_hold_ch;
  864                         if (hook->ich_func != NULL) {
  865                                 config_intrhook_disestablish(hook);
  866                                 hook->ich_func = NULL;
  867                         }
  868 
  869                         callout_reset(&enc->status_updater, 60*hz,
  870                                       enc_status_updater, enc);
  871 
  872                         cam_periph_sleep(enc->periph, enc->enc_daemon,
  873                                          PUSER, "idle", 0);
  874                 } else {
  875                         enc_fsm_step(enc);
  876                 }
  877         }
  878         enc->enc_daemon = NULL;
  879         cam_periph_unlock(enc->periph);
  880         cam_periph_release(enc->periph);
  881         kproc_exit(0);
  882 }
  883 
  884 static int
  885 enc_kproc_init(enc_softc_t *enc)
  886 {
  887         int result;
  888 
  889         callout_init_mtx(&enc->status_updater, enc->periph->sim->mtx, 0);
  890 
  891         if (cam_periph_acquire(enc->periph) != CAM_REQ_CMP)
  892                 return (ENXIO);
  893 
  894         result = kproc_create(enc_daemon, enc, &enc->enc_daemon, /*flags*/0,
  895                               /*stackpgs*/0, "enc_daemon%d",
  896                               enc->periph->unit_number);
  897         if (result == 0) {
  898                 /* Do an initial load of all page data. */
  899                 cam_periph_lock(enc->periph);
  900                 enc->enc_vec.poll_status(enc);
  901                 cam_periph_unlock(enc->periph);
  902         } else
  903                 cam_periph_release(enc->periph);
  904         return (result);
  905 }
  906  
  907 /**
  908  * \brief Interrupt configuration hook callback associated with
  909  *        enc_boot_hold_ch.
  910  *
  911  * Since interrupts are always functional at the time of enclosure
  912  * configuration, there is nothing to be done when the callback occurs.
  913  * This hook is only registered to hold up boot processing while initial
  914  * eclosure processing occurs.
  915  * 
  916  * \param arg  The enclosure softc, but currently unused in this callback.
  917  */
  918 static void
  919 enc_nop_confighook_cb(void *arg __unused)
  920 {
  921 }
  922 
  923 static cam_status
  924 enc_ctor(struct cam_periph *periph, void *arg)
  925 {
  926         cam_status status = CAM_REQ_CMP_ERR;
  927         int err;
  928         enc_softc_t *enc;
  929         struct ccb_getdev *cgd;
  930         char *tname;
  931 
  932         cgd = (struct ccb_getdev *)arg;
  933         if (cgd == NULL) {
  934                 printf("enc_ctor: no getdev CCB, can't register device\n");
  935                 goto out;
  936         }
  937 
  938         enc = ENC_MALLOCZ(sizeof(*enc));
  939         if (enc == NULL) {
  940                 printf("enc_ctor: Unable to probe new device. "
  941                        "Unable to allocate enc\n");                             
  942                 goto out;
  943         }
  944         enc->periph = periph;
  945         enc->current_action = ENC_UPDATE_INVALID;
  946 
  947         enc->enc_type = enc_type(cgd);
  948         sx_init(&enc->enc_cache_lock, "enccache");
  949 
  950         switch (enc->enc_type) {
  951         case ENC_SES:
  952         case ENC_SES_SCSI2:
  953         case ENC_SES_PASSTHROUGH:
  954         case ENC_SEMB_SES:
  955                 err = ses_softc_init(enc);
  956                 break;
  957         case ENC_SAFT:
  958         case ENC_SEMB_SAFT:
  959                 err = safte_softc_init(enc);
  960                 break;
  961         case ENC_NONE:
  962         default:
  963                 ENC_FREE(enc);
  964                 return (CAM_REQ_CMP_ERR);
  965         }
  966 
  967         if (err) {
  968                 xpt_print(periph->path, "error %d initializing\n", err);
  969                 goto out;
  970         }
  971 
  972         /*
  973          * Hold off userland until we have made at least one pass
  974          * through our state machine so that physical path data is
  975          * present.
  976          */
  977         if (enc->enc_vec.poll_status != NULL) {
  978                 enc->enc_boot_hold_ch.ich_func = enc_nop_confighook_cb;
  979                 enc->enc_boot_hold_ch.ich_arg = enc;
  980                 config_intrhook_establish(&enc->enc_boot_hold_ch);
  981         }
  982 
  983         /*
  984          * The softc field is set only once the enc is fully initialized
  985          * so that we can rely on this field to detect partially
  986          * initialized periph objects in the AC_FOUND_DEVICE handler.
  987          */
  988         periph->softc = enc;
  989 
  990         cam_periph_unlock(periph);
  991         if (enc->enc_vec.poll_status != NULL) {
  992                 err = enc_kproc_init(enc);
  993                 if (err) {
  994                         xpt_print(periph->path,
  995                                   "error %d starting enc_daemon\n", err);
  996                         goto out;
  997                 }
  998         }
  999 
 1000         /*
 1001          * Acquire a reference to the periph before we create the devfs
 1002          * instance for it.  We'll release this reference once the devfs
 1003          * instance has been freed.
 1004          */
 1005         if (cam_periph_acquire(periph) != CAM_REQ_CMP) {
 1006                 xpt_print(periph->path, "%s: lost periph during "
 1007                           "registration!\n", __func__);
 1008                 cam_periph_lock(periph);
 1009 
 1010                 return (CAM_REQ_CMP_ERR);
 1011         }
 1012 
 1013         enc->enc_dev = make_dev(&enc_cdevsw, periph->unit_number,
 1014             UID_ROOT, GID_OPERATOR, 0600, "%s%d",
 1015             periph->periph_name, periph->unit_number);
 1016 
 1017         cam_periph_lock(periph);
 1018         enc->enc_dev->si_drv1 = periph;
 1019 
 1020         enc->enc_flags |= ENC_FLAG_INITIALIZED;
 1021 
 1022         /*
 1023          * Add an async callback so that we get notified if this
 1024          * device goes away.
 1025          */
 1026         xpt_register_async(AC_LOST_DEVICE, enc_async, periph, periph->path);
 1027 
 1028         switch (enc->enc_type) {
 1029         default:
 1030         case ENC_NONE:
 1031                 tname = "No ENC device";
 1032                 break;
 1033         case ENC_SES_SCSI2:
 1034                 tname = "SCSI-2 ENC Device";
 1035                 break;
 1036         case ENC_SES:
 1037                 tname = "SCSI-3 ENC Device";
 1038                 break;
 1039         case ENC_SES_PASSTHROUGH:
 1040                 tname = "ENC Passthrough Device";
 1041                 break;
 1042         case ENC_SAFT:
 1043                 tname = "SAF-TE Compliant Device";
 1044                 break;
 1045         case ENC_SEMB_SES:
 1046                 tname = "SEMB SES Device";
 1047                 break;
 1048         case ENC_SEMB_SAFT:
 1049                 tname = "SEMB SAF-TE Device";
 1050                 break;
 1051         }
 1052         xpt_announce_periph(periph, tname);
 1053         status = CAM_REQ_CMP;
 1054 
 1055 out:
 1056         if (status != CAM_REQ_CMP)
 1057                 enc_dtor(periph);
 1058         return (status);
 1059 }
 1060 

Cache object: 38b6799e8897dac225c4073dcf091db5


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