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_ses.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2000 Matthew Jacob
    5  * Copyright (c) 2010 Spectra Logic Corporation
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions, and the following disclaimer,
   13  *    without modification, immediately at the beginning of the file.
   14  * 2. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 /**
   31  * \file scsi_enc_ses.c
   32  *
   33  * Structures and routines specific && private to SES only
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include <sys/param.h>
   40 
   41 #include <sys/ctype.h>
   42 #include <sys/errno.h>
   43 #include <sys/kernel.h>
   44 #include <sys/lock.h>
   45 #include <sys/malloc.h>
   46 #include <sys/mutex.h>
   47 #include <sys/queue.h>
   48 #include <sys/sbuf.h>
   49 #include <sys/sx.h>
   50 #include <sys/systm.h>
   51 #include <sys/types.h>
   52 
   53 #include <cam/cam.h>
   54 #include <cam/cam_ccb.h>
   55 #include <cam/cam_xpt_periph.h>
   56 #include <cam/cam_periph.h>
   57 
   58 #include <cam/scsi/scsi_message.h>
   59 #include <cam/scsi/scsi_enc.h>
   60 #include <cam/scsi/scsi_enc_internal.h>
   61 
   62 /* SES Native Type Device Support */
   63 
   64 /* SES Diagnostic Page Codes */
   65 typedef enum {
   66         SesSupportedPages       = 0x0,
   67         SesConfigPage           = 0x1,
   68         SesControlPage          = 0x2,
   69         SesStatusPage           = SesControlPage,
   70         SesHelpTxt              = 0x3,
   71         SesStringOut            = 0x4,
   72         SesStringIn             = SesStringOut,
   73         SesThresholdOut         = 0x5,
   74         SesThresholdIn          = SesThresholdOut,
   75         SesArrayControl         = 0x6,  /* Obsolete in SES v2 */
   76         SesArrayStatus          = SesArrayControl,
   77         SesElementDescriptor    = 0x7,
   78         SesShortStatus          = 0x8,
   79         SesEnclosureBusy        = 0x9,
   80         SesAddlElementStatus    = 0xa
   81 } SesDiagPageCodes;
   82 
   83 typedef struct ses_type {
   84         const struct ses_elm_type_desc  *hdr;
   85         const char                      *text;
   86 } ses_type_t;
   87 
   88 typedef struct ses_comstat {
   89         uint8_t comstatus;
   90         uint8_t comstat[3];
   91 } ses_comstat_t;
   92 
   93 typedef union ses_addl_data {
   94         struct ses_elm_sas_device_phy *sasdev_phys;
   95         struct ses_elm_sas_expander_phy *sasexp_phys;
   96         struct ses_elm_sas_port_phy *sasport_phys;
   97         struct ses_fcobj_port *fc_ports;
   98 } ses_add_data_t;
   99 
  100 typedef struct ses_addl_status {
  101         struct ses_elm_addlstatus_base_hdr *hdr;
  102         union {
  103                 union ses_fcobj_hdr *fc;
  104                 union ses_elm_sas_hdr *sas;
  105                 struct ses_elm_ata_hdr *ata;
  106         } proto_hdr;
  107         union ses_addl_data proto_data; /* array sizes stored in header */
  108 } ses_add_status_t;
  109 
  110 typedef struct ses_element {
  111         uint8_t eip;                    /* eip bit is set */
  112         uint16_t descr_len;             /* length of the descriptor */
  113         const char *descr;              /* descriptor for this object */
  114         struct ses_addl_status addl;    /* additional status info */
  115 } ses_element_t;
  116 
  117 typedef struct ses_control_request {
  118         int           elm_idx;
  119         ses_comstat_t elm_stat;
  120         int           result;
  121         TAILQ_ENTRY(ses_control_request) links;
  122 } ses_control_request_t;
  123 TAILQ_HEAD(ses_control_reqlist, ses_control_request);
  124 typedef struct ses_control_reqlist ses_control_reqlist_t;
  125 enum {
  126         SES_SETSTATUS_ENC_IDX = -1
  127 };
  128 
  129 static void
  130 ses_terminate_control_requests(ses_control_reqlist_t *reqlist, int result)
  131 {
  132         ses_control_request_t *req;
  133 
  134         while ((req = TAILQ_FIRST(reqlist)) != NULL) {
  135                 TAILQ_REMOVE(reqlist, req, links);
  136                 req->result = result;
  137                 wakeup(req);
  138         }
  139 }
  140 
  141 enum ses_iter_index_values {
  142         /**
  143          * \brief  Value of an initialized but invalid index
  144          *         in a ses_iterator object.
  145          *
  146          * This value is used for the  individual_element_index of
  147          * overal status elements and for all index types when
  148          * an iterator is first initialized.
  149          */
  150         ITERATOR_INDEX_INVALID = -1,
  151 
  152         /**
  153          * \brief  Value of an index in a ses_iterator object
  154          *         when the iterator has traversed past the last
  155          *         valid element..
  156          */
  157         ITERATOR_INDEX_END     = INT_MAX
  158 };
  159 
  160 /**
  161  * \brief Structure encapsulating all data necessary to traverse the
  162  *        elements of a SES configuration.
  163  *
  164  * The ses_iterator object simplifies the task of iterating through all
  165  * elements detected via the SES configuration page by tracking the numerous
  166  * element indexes that, instead of memoizing in the softc, we calculate
  167  * on the fly during the traversal of the element objects.  The various
  168  * indexes are necessary due to the varying needs of matching objects in
  169  * the different SES pages.  Some pages (e.g. Status/Control) contain all
  170  * elements, while others (e.g. Additional Element Status) only contain
  171  * individual elements (no overal status elements) of particular types.
  172  *
  173  * To use an iterator, initialize it with ses_iter_init(), and then
  174  * use ses_iter_next() to traverse the elements (including the first) in
  175  * the configuration.  Once an iterator is initiailized with ses_iter_init(),
  176  * you may also seek to any particular element by either it's global or
  177  * individual element index via the ses_iter_seek_to() function.  You may
  178  * also return an iterator to the position just before the first element
  179  * (i.e. the same state as after an ses_iter_init()), with ses_iter_reset().
  180  */
  181 struct ses_iterator {
  182         /**
  183          * \brief Backlink to the overal software configuration structure.
  184          *
  185          * This is included for convenience so the iteration functions
  186          * need only take a single, struct ses_iterator *, argument.
  187          */
  188         enc_softc_t *enc;
  189 
  190         enc_cache_t *cache;
  191 
  192         /**
  193          * \brief Index of the type of the current element within the
  194          *        ses_cache's ses_types array.
  195          */
  196         int               type_index;
  197 
  198         /**
  199          * \brief The position (0 based) of this element relative to all other
  200          *        elements of this type.
  201          *
  202          * This index resets to zero every time the iterator transitions
  203          * to elements of a new type in the configuration.
  204          */
  205         int               type_element_index;
  206 
  207         /**
  208          * \brief The position (0 based) of this element relative to all
  209          *        other individual status elements in the configuration.
  210          *
  211          * This index ranges from 0 through the number of individual
  212          * elements in the configuration.  When the iterator returns
  213          * an overall status element, individual_element_index is
  214          * set to ITERATOR_INDEX_INVALID, to indicate that it does
  215          * not apply to the current element.
  216          */
  217         int               individual_element_index;
  218 
  219         /**
  220          * \brief The position (0 based) of this element relative to
  221          *        all elements in the configration.
  222          *
  223          * This index is appropriate for indexing into enc->ses_elm_map.
  224          */
  225         int               global_element_index;
  226 
  227         /**
  228          * \brief The last valid individual element index of this
  229          *        iterator.
  230          *
  231          * When an iterator traverses an overal status element, the
  232          * individual element index is reset to ITERATOR_INDEX_INVALID
  233          * to prevent unintential use of the individual_element_index
  234          * field.  The saved_individual_element_index allows the iterator
  235          * to restore it's position in the individual elements upon
  236          * reaching the next individual element.
  237          */
  238         int               saved_individual_element_index;
  239 };
  240 
  241 typedef enum {
  242         SES_UPDATE_NONE,
  243         SES_UPDATE_PAGES,
  244         SES_UPDATE_GETCONFIG,
  245         SES_UPDATE_GETSTATUS,
  246         SES_UPDATE_GETELMDESCS,
  247         SES_UPDATE_GETELMADDLSTATUS,
  248         SES_PROCESS_CONTROL_REQS,
  249         SES_PUBLISH_PHYSPATHS,
  250         SES_PUBLISH_CACHE,
  251         SES_NUM_UPDATE_STATES
  252 } ses_update_action;
  253 
  254 static enc_softc_cleanup_t ses_softc_cleanup;
  255 
  256 #define SCSZ    0x8000
  257 
  258 static fsm_fill_handler_t ses_fill_rcv_diag_io;
  259 static fsm_fill_handler_t ses_fill_control_request;
  260 static fsm_done_handler_t ses_process_pages;
  261 static fsm_done_handler_t ses_process_config;
  262 static fsm_done_handler_t ses_process_status;
  263 static fsm_done_handler_t ses_process_elm_descs;
  264 static fsm_done_handler_t ses_process_elm_addlstatus;
  265 static fsm_done_handler_t ses_process_control_request;
  266 static fsm_done_handler_t ses_publish_physpaths;
  267 static fsm_done_handler_t ses_publish_cache;
  268 
  269 static struct enc_fsm_state enc_fsm_states[SES_NUM_UPDATE_STATES] =
  270 {
  271         { "SES_UPDATE_NONE", 0, 0, 0, NULL, NULL, NULL },
  272         {
  273                 "SES_UPDATE_PAGES",
  274                 SesSupportedPages,
  275                 SCSZ,
  276                 60 * 1000,
  277                 ses_fill_rcv_diag_io,
  278                 ses_process_pages,
  279                 enc_error
  280         },
  281         {
  282                 "SES_UPDATE_GETCONFIG",
  283                 SesConfigPage,
  284                 SCSZ,
  285                 60 * 1000,
  286                 ses_fill_rcv_diag_io,
  287                 ses_process_config,
  288                 enc_error
  289         },
  290         {
  291                 "SES_UPDATE_GETSTATUS",
  292                 SesStatusPage,
  293                 SCSZ,
  294                 60 * 1000,
  295                 ses_fill_rcv_diag_io,
  296                 ses_process_status,
  297                 enc_error
  298         },
  299         {
  300                 "SES_UPDATE_GETELMDESCS",
  301                 SesElementDescriptor,
  302                 SCSZ,
  303                 60 * 1000,
  304                 ses_fill_rcv_diag_io,
  305                 ses_process_elm_descs,
  306                 enc_error
  307         },
  308         {
  309                 "SES_UPDATE_GETELMADDLSTATUS",
  310                 SesAddlElementStatus,
  311                 SCSZ,
  312                 60 * 1000,
  313                 ses_fill_rcv_diag_io,
  314                 ses_process_elm_addlstatus,
  315                 enc_error
  316         },
  317         {
  318                 "SES_PROCESS_CONTROL_REQS",
  319                 SesControlPage,
  320                 SCSZ,
  321                 60 * 1000,
  322                 ses_fill_control_request,
  323                 ses_process_control_request,
  324                 enc_error
  325         },
  326         {
  327                 "SES_PUBLISH_PHYSPATHS",
  328                 0,
  329                 0,
  330                 0,
  331                 NULL,
  332                 ses_publish_physpaths,
  333                 NULL
  334         },
  335         {
  336                 "SES_PUBLISH_CACHE",
  337                 0,
  338                 0,
  339                 0,
  340                 NULL,
  341                 ses_publish_cache,
  342                 NULL
  343         }
  344 };
  345 
  346 typedef struct ses_cache {
  347         /* Source for all the configuration data pointers */
  348         const struct ses_cfg_page               *cfg_page;
  349 
  350         /* References into the config page. */
  351         int                                      ses_nsubencs;
  352         const struct ses_enc_desc * const       *subencs;
  353         int                                      ses_ntypes;
  354         const ses_type_t                        *ses_types;
  355 
  356         /* Source for all the status pointers */
  357         const struct ses_status_page            *status_page;
  358 
  359         /* Source for all the object descriptor pointers */
  360         const struct ses_elem_descr_page        *elm_descs_page;
  361 
  362         /* Source for all the additional object status pointers */
  363         const struct ses_addl_elem_status_page  *elm_addlstatus_page;
  364 
  365 } ses_cache_t;
  366 
  367 typedef struct ses_softc {
  368         uint32_t                ses_flags;
  369 #define SES_FLAG_TIMEDCOMP      0x01
  370 #define SES_FLAG_ADDLSTATUS     0x02
  371 #define SES_FLAG_DESC           0x04
  372 
  373         ses_control_reqlist_t   ses_requests;
  374         ses_control_reqlist_t   ses_pending_requests;
  375 } ses_softc_t;
  376 
  377 static int ses_search_globally = 0;
  378 SYSCTL_INT(_kern_cam_enc, OID_AUTO, search_globally, CTLFLAG_RWTUN,
  379            &ses_search_globally, 0, "Search for disks on other buses");
  380 
  381 /**
  382  * \brief Reset a SES iterator to just before the first element
  383  *        in the configuration.
  384  *
  385  * \param iter  The iterator object to reset.
  386  *
  387  * The indexes within a reset iterator are invalid and will only
  388  * become valid upon completion of a ses_iter_seek_to() or a
  389  * ses_iter_next().
  390  */
  391 static void
  392 ses_iter_reset(struct ses_iterator *iter)
  393 {
  394         /*
  395          * Set our indexes to just before the first valid element
  396          * of the first type (ITERATOR_INDEX_INVALID == -1).  This
  397          * simplifies the implementation of ses_iter_next().
  398          */
  399         iter->type_index                     = 0;
  400         iter->type_element_index             = ITERATOR_INDEX_INVALID;
  401         iter->global_element_index           = ITERATOR_INDEX_INVALID;
  402         iter->individual_element_index       = ITERATOR_INDEX_INVALID;
  403         iter->saved_individual_element_index = ITERATOR_INDEX_INVALID;
  404 }
  405 
  406 /**
  407  * \brief Initialize the storage of a SES iterator and reset it to
  408  *        the position just before the first element of the
  409  *        configuration.
  410  *
  411  * \param enc   The SES softc for the SES instance whose configuration
  412  *              will be enumerated by this iterator.
  413  * \param iter  The iterator object to initialize.
  414  */
  415 static void
  416 ses_iter_init(enc_softc_t *enc, enc_cache_t *cache, struct ses_iterator *iter)
  417 {
  418         iter->enc = enc;
  419         iter->cache = cache;
  420         ses_iter_reset(iter);
  421 }
  422 
  423 /**
  424  * \brief Traverse the provided SES iterator to the next element
  425  *        within the configuration.
  426  *
  427  * \param iter  The iterator to move.
  428  *
  429  * \return  If a valid next element exists, a pointer to it's enc_element_t.
  430  *          Otherwise NULL.
  431  */
  432 static enc_element_t *
  433 ses_iter_next(struct ses_iterator *iter)
  434 {
  435         ses_cache_t      *ses_cache;
  436         const ses_type_t *element_type;
  437 
  438         ses_cache = iter->cache->private;
  439 
  440         /*
  441          * Note: Treat nelms as signed, so we will hit this case
  442          *       and immediately terminate the iteration if the
  443          *       configuration has 0 objects.
  444          */
  445         if (iter->global_element_index >= (int)iter->cache->nelms - 1) {
  446                 /* Elements exhausted. */
  447                 iter->type_index               = ITERATOR_INDEX_END;
  448                 iter->type_element_index       = ITERATOR_INDEX_END;
  449                 iter->global_element_index     = ITERATOR_INDEX_END;
  450                 iter->individual_element_index = ITERATOR_INDEX_END;
  451                 iter->saved_individual_element_index = ITERATOR_INDEX_END;
  452                 return (NULL);
  453         }
  454 
  455         KASSERT((iter->type_index < ses_cache->ses_ntypes),
  456                 ("Corrupted element iterator. %d not less than %d",
  457                  iter->type_index, ses_cache->ses_ntypes));
  458 
  459         element_type = &ses_cache->ses_types[iter->type_index];
  460         iter->global_element_index++;
  461         iter->type_element_index++;
  462 
  463         /*
  464          * There is an object for overal type status in addition
  465          * to one for each allowed element, but only if the element
  466          * count is non-zero.
  467          */
  468         if (iter->type_element_index > element_type->hdr->etype_maxelt) {
  469                 /*
  470                  * We've exhausted the elements of this type.
  471                  * This next element belongs to the next type.
  472                  */
  473                 iter->type_index++;
  474                 iter->type_element_index = 0;
  475                 iter->individual_element_index = ITERATOR_INDEX_INVALID;
  476         }
  477 
  478         if (iter->type_element_index > 0) {
  479                 iter->individual_element_index =
  480                     ++iter->saved_individual_element_index;
  481         }
  482 
  483         return (&iter->cache->elm_map[iter->global_element_index]);
  484 }
  485 
  486 /**
  487  * Element index types tracked by a SES iterator.
  488  */
  489 typedef enum {
  490         /**
  491          * Index relative to all elements (overall and individual)
  492          * in the system.
  493          */
  494         SES_ELEM_INDEX_GLOBAL,
  495 
  496         /**
  497          * \brief Index relative to all individual elements in the system.
  498          *
  499          * This index counts only individual elements, skipping overall
  500          * status elements.  This is the index space of the additional
  501          * element status page (page 0xa).
  502          */
  503         SES_ELEM_INDEX_INDIVIDUAL
  504 } ses_elem_index_type_t;
  505 
  506 /**
  507  * \brief Move the provided iterator forwards or backwards to the object 
  508  *        having the give index.
  509  *
  510  * \param iter           The iterator on which to perform the seek.
  511  * \param element_index  The index of the element to find.
  512  * \param index_type     The type (global or individual) of element_index.
  513  *
  514  * \return  If the element is found, a pointer to it's enc_element_t.
  515  *          Otherwise NULL.
  516  */
  517 static enc_element_t *
  518 ses_iter_seek_to(struct ses_iterator *iter, int element_index,
  519                  ses_elem_index_type_t index_type)
  520 {
  521         enc_element_t   *element;
  522         int             *cur_index;
  523 
  524         if (index_type == SES_ELEM_INDEX_GLOBAL)
  525                 cur_index = &iter->global_element_index;
  526         else
  527                 cur_index = &iter->individual_element_index;
  528 
  529         if (*cur_index == element_index) {
  530                 /* Already there. */
  531                 return (&iter->cache->elm_map[iter->global_element_index]);
  532         }
  533 
  534         ses_iter_reset(iter);
  535         while ((element = ses_iter_next(iter)) != NULL
  536             && *cur_index != element_index)
  537                 ;
  538 
  539         if (*cur_index != element_index)
  540                 return (NULL);
  541 
  542         return (element);
  543 }
  544 
  545 #if 0
  546 static int ses_encode(enc_softc_t *, uint8_t *, int, int,
  547     struct ses_comstat *);
  548 #endif
  549 static int ses_set_timed_completion(enc_softc_t *, uint8_t);
  550 #if 0
  551 static int ses_putstatus(enc_softc_t *, int, struct ses_comstat *);
  552 #endif
  553 
  554 static void ses_poll_status(enc_softc_t *);
  555 static void ses_print_addl_data(enc_softc_t *, enc_element_t *);
  556 
  557 /*=========================== SES cleanup routines ===========================*/
  558 
  559 static void
  560 ses_cache_free_elm_addlstatus(enc_softc_t *enc, enc_cache_t *cache)
  561 {
  562         ses_cache_t   *ses_cache;
  563         ses_cache_t   *other_ses_cache;
  564         enc_element_t *cur_elm;
  565         enc_element_t *last_elm;
  566 
  567         ENC_DLOG(enc, "%s: enter\n", __func__);
  568         ses_cache = cache->private;
  569         if (ses_cache->elm_addlstatus_page == NULL)
  570                 return;
  571 
  572         for (cur_elm = cache->elm_map,
  573              last_elm = &cache->elm_map[cache->nelms];
  574              cur_elm != last_elm; cur_elm++) {
  575                 ses_element_t *elmpriv;
  576 
  577                 elmpriv = cur_elm->elm_private;
  578 
  579                 /* Clear references to the additional status page. */
  580                 bzero(&elmpriv->addl, sizeof(elmpriv->addl));
  581         }
  582 
  583         other_ses_cache = enc_other_cache(enc, cache)->private;
  584         if (other_ses_cache->elm_addlstatus_page
  585          != ses_cache->elm_addlstatus_page)
  586                 ENC_FREE(ses_cache->elm_addlstatus_page);
  587         ses_cache->elm_addlstatus_page = NULL;
  588 }
  589 
  590 static void
  591 ses_cache_free_elm_descs(enc_softc_t *enc, enc_cache_t *cache)
  592 {
  593         ses_cache_t   *ses_cache;
  594         ses_cache_t   *other_ses_cache;
  595         enc_element_t *cur_elm;
  596         enc_element_t *last_elm;
  597 
  598         ENC_DLOG(enc, "%s: enter\n", __func__);
  599         ses_cache = cache->private;
  600         if (ses_cache->elm_descs_page == NULL)
  601                 return;
  602 
  603         for (cur_elm = cache->elm_map,
  604              last_elm = &cache->elm_map[cache->nelms];
  605              cur_elm != last_elm; cur_elm++) {
  606                 ses_element_t *elmpriv;
  607 
  608                 elmpriv = cur_elm->elm_private;
  609                 elmpriv->descr_len = 0;
  610                 elmpriv->descr = NULL;
  611         }
  612 
  613         other_ses_cache = enc_other_cache(enc, cache)->private;
  614         if (other_ses_cache->elm_descs_page
  615          != ses_cache->elm_descs_page)
  616                 ENC_FREE(ses_cache->elm_descs_page);
  617         ses_cache->elm_descs_page = NULL;
  618 }
  619 
  620 static void
  621 ses_cache_free_status(enc_softc_t *enc, enc_cache_t *cache)
  622 {
  623         ses_cache_t *ses_cache;
  624         ses_cache_t *other_ses_cache;
  625 
  626         ENC_DLOG(enc, "%s: enter\n", __func__);
  627         ses_cache   = cache->private;
  628         if (ses_cache->status_page == NULL)
  629                 return;
  630 
  631         other_ses_cache = enc_other_cache(enc, cache)->private;
  632         if (other_ses_cache->status_page != ses_cache->status_page)
  633                 ENC_FREE(ses_cache->status_page);
  634         ses_cache->status_page = NULL;
  635 }
  636 
  637 static void
  638 ses_cache_free_elm_map(enc_softc_t *enc, enc_cache_t *cache)
  639 {
  640         enc_element_t *cur_elm;
  641         enc_element_t *last_elm;
  642 
  643         ENC_DLOG(enc, "%s: enter\n", __func__);
  644         if (cache->elm_map == NULL)
  645                 return;
  646 
  647         ses_cache_free_elm_descs(enc, cache);
  648         ses_cache_free_elm_addlstatus(enc, cache);
  649         for (cur_elm = cache->elm_map,
  650              last_elm = &cache->elm_map[cache->nelms];
  651              cur_elm != last_elm; cur_elm++) {
  652                 ENC_FREE_AND_NULL(cur_elm->elm_private);
  653         }
  654         ENC_FREE_AND_NULL(cache->elm_map);
  655         cache->nelms = 0;
  656         ENC_DLOG(enc, "%s: exit\n", __func__);
  657 }
  658 
  659 static void
  660 ses_cache_free(enc_softc_t *enc, enc_cache_t *cache)
  661 {
  662         ses_cache_t *other_ses_cache;
  663         ses_cache_t *ses_cache;
  664 
  665         ENC_DLOG(enc, "%s: enter\n", __func__);
  666         ses_cache_free_elm_addlstatus(enc, cache);
  667         ses_cache_free_status(enc, cache);
  668         ses_cache_free_elm_map(enc, cache);
  669 
  670         ses_cache = cache->private;
  671         ses_cache->ses_ntypes = 0;
  672 
  673         other_ses_cache = enc_other_cache(enc, cache)->private;
  674         if (other_ses_cache->subencs != ses_cache->subencs)
  675                 ENC_FREE(ses_cache->subencs);
  676         ses_cache->subencs = NULL;
  677 
  678         if (other_ses_cache->ses_types != ses_cache->ses_types)
  679                 ENC_FREE(ses_cache->ses_types);
  680         ses_cache->ses_types = NULL;
  681 
  682         if (other_ses_cache->cfg_page != ses_cache->cfg_page)
  683                 ENC_FREE(ses_cache->cfg_page);
  684         ses_cache->cfg_page = NULL;
  685 
  686         ENC_DLOG(enc, "%s: exit\n", __func__);
  687 }
  688 
  689 static void
  690 ses_cache_clone(enc_softc_t *enc, enc_cache_t *src, enc_cache_t *dst)
  691 {
  692         ses_cache_t   *dst_ses_cache;
  693         ses_cache_t   *src_ses_cache;
  694         enc_element_t *src_elm;
  695         enc_element_t *dst_elm;
  696         enc_element_t *last_elm;
  697 
  698         ses_cache_free(enc, dst);
  699         src_ses_cache = src->private;
  700         dst_ses_cache = dst->private;
  701 
  702         /*
  703          * The cloned enclosure cache and ses specific cache are
  704          * mostly identical to the source.
  705          */
  706         *dst = *src;
  707         *dst_ses_cache = *src_ses_cache;
  708 
  709         /*
  710          * But the ses cache storage is still independent.  Restore
  711          * the pointer that was clobbered by the structure copy above.
  712          */
  713         dst->private = dst_ses_cache;
  714 
  715         /*
  716          * The element map is independent even though it starts out
  717          * pointing to the same constant page data.
  718          */
  719         dst->elm_map = malloc(dst->nelms * sizeof(enc_element_t),
  720             M_SCSIENC, M_WAITOK);
  721         memcpy(dst->elm_map, src->elm_map, dst->nelms * sizeof(enc_element_t));
  722         for (dst_elm = dst->elm_map, src_elm = src->elm_map,
  723              last_elm = &src->elm_map[src->nelms];
  724              src_elm != last_elm; src_elm++, dst_elm++) {
  725                 dst_elm->elm_private = malloc(sizeof(ses_element_t),
  726                     M_SCSIENC, M_WAITOK);
  727                 memcpy(dst_elm->elm_private, src_elm->elm_private,
  728                        sizeof(ses_element_t));
  729         }
  730 }
  731 
  732 /* Structure accessors.  These are strongly typed to avoid errors. */
  733 
  734 int
  735 ses_elm_sas_descr_type(union ses_elm_sas_hdr *obj)
  736 {
  737         return ((obj)->base_hdr.byte1 >> 6);
  738 }
  739 int
  740 ses_elm_addlstatus_proto(struct ses_elm_addlstatus_base_hdr *hdr)
  741 {
  742         return ((hdr)->byte0 & 0xf);
  743 }
  744 int
  745 ses_elm_addlstatus_eip(struct ses_elm_addlstatus_base_hdr *hdr)
  746 {
  747         return ((hdr)->byte0 >> 4 & 0x1);
  748 }
  749 int
  750 ses_elm_addlstatus_invalid(struct ses_elm_addlstatus_base_hdr *hdr)
  751 {
  752         return ((hdr)->byte0 >> 7);
  753 }
  754 int
  755 ses_elm_sas_type0_not_all_phys(union ses_elm_sas_hdr *hdr)
  756 {
  757         return ((hdr)->type0_noneip.byte1 & 0x1);
  758 }
  759 int
  760 ses_elm_sas_dev_phy_sata_dev(struct ses_elm_sas_device_phy *phy)
  761 {
  762         return ((phy)->target_ports & 0x1);
  763 }
  764 int
  765 ses_elm_sas_dev_phy_sata_port(struct ses_elm_sas_device_phy *phy)
  766 {
  767         return ((phy)->target_ports >> 7);
  768 }
  769 int
  770 ses_elm_sas_dev_phy_dev_type(struct ses_elm_sas_device_phy *phy)
  771 {
  772         return (((phy)->byte0 >> 4) & 0x7);
  773 }
  774 
  775 /**
  776  * \brief Verify that the cached configuration data in our softc
  777  *        is valid for processing the page data corresponding to
  778  *        the provided page header.
  779  *
  780  * \param ses_cache The SES cache to validate.
  781  * \param gen_code  The 4 byte generation code from a SES diagnostic
  782  *                  page header.
  783  *
  784  * \return  non-zero if true, 0 if false.
  785  */
  786 static int
  787 ses_config_cache_valid(ses_cache_t *ses_cache, const uint8_t *gen_code)
  788 {
  789         uint32_t cache_gc;
  790         uint32_t cur_gc;
  791 
  792         if (ses_cache->cfg_page == NULL)
  793                 return (0);
  794 
  795         cache_gc = scsi_4btoul(ses_cache->cfg_page->hdr.gen_code);
  796         cur_gc   = scsi_4btoul(gen_code);
  797         return (cache_gc == cur_gc);
  798 }
  799 
  800 /**
  801  * Function signature for consumers of the ses_devids_iter() interface.
  802  */
  803 typedef void ses_devid_callback_t(enc_softc_t *, enc_element_t *,
  804                                   struct scsi_vpd_id_descriptor *, void *);
  805 
  806 /**
  807  * \brief Iterate over and create vpd device id records from the
  808  *        additional element status data for elm, passing that data
  809  *        to the provided callback.
  810  *
  811  * \param enc           SES instance containing elm
  812  * \param elm           Element for which to extract device ID data.
  813  * \param callback      The callback function to invoke on each generated
  814  *                      device id descriptor for elm.
  815  * \param callback_arg  Argument passed through to callback on each invocation.
  816  */
  817 static void
  818 ses_devids_iter(enc_softc_t *enc, enc_element_t *elm,
  819                 ses_devid_callback_t *callback, void *callback_arg)
  820 {
  821         ses_element_t           *elmpriv;
  822         struct ses_addl_status *addl;
  823         u_int                   i;
  824         size_t                  devid_record_size;
  825 
  826         elmpriv = elm->elm_private;
  827         addl = &(elmpriv->addl);
  828 
  829         devid_record_size = SVPD_DEVICE_ID_DESC_HDR_LEN
  830                           + sizeof(struct scsi_vpd_id_naa_ieee_reg);
  831         for (i = 0; i < addl->proto_hdr.sas->base_hdr.num_phys; i++) {
  832                 uint8_t                        devid_buf[devid_record_size];
  833                 struct scsi_vpd_id_descriptor *devid;
  834                 uint8_t                       *phy_addr;
  835 
  836                 devid = (struct scsi_vpd_id_descriptor *)devid_buf;
  837                 phy_addr = addl->proto_data.sasdev_phys[i].phy_addr;
  838                 devid->proto_codeset = (SCSI_PROTO_SAS << SVPD_ID_PROTO_SHIFT)
  839                                      | SVPD_ID_CODESET_BINARY;
  840                 devid->id_type       = SVPD_ID_PIV
  841                                      | SVPD_ID_ASSOC_PORT
  842                                      | SVPD_ID_TYPE_NAA;
  843                 devid->reserved      = 0;
  844                 devid->length        = sizeof(struct scsi_vpd_id_naa_ieee_reg);
  845                 memcpy(devid->identifier, phy_addr, devid->length);
  846 
  847                 callback(enc, elm, devid, callback_arg);
  848         }
  849 }
  850 
  851 /**
  852  * Function signature for consumers of the ses_paths_iter() interface.
  853  */
  854 typedef void ses_path_callback_t(enc_softc_t *, enc_element_t *,
  855                                  struct cam_path *, void *);
  856 
  857 /**
  858  * Argument package passed through ses_devids_iter() by
  859  * ses_paths_iter() to ses_path_iter_devid_callback().
  860  */
  861 typedef struct ses_path_iter_args {
  862         ses_path_callback_t *callback;
  863         void                *callback_arg;
  864 } ses_path_iter_args_t;
  865 
  866 /**
  867  * ses_devids_iter() callback function used by ses_paths_iter()
  868  * to map device ids to peripheral driver instances.
  869  *
  870  * \param enc     SES instance containing elm
  871  * \param elm     Element on which device ID matching is active.
  872  * \param periph  A device ID corresponding to elm.
  873  * \param arg     Argument passed through to callback on each invocation.
  874  */
  875 static void
  876 ses_path_iter_devid_callback(enc_softc_t *enc, enc_element_t *elem,
  877                                struct scsi_vpd_id_descriptor *devid,
  878                                void *arg)
  879 {
  880         struct ccb_dev_match         cdm;
  881         struct dev_match_pattern     match_pattern;
  882         struct dev_match_result      match_result;
  883         struct device_match_result  *device_match;
  884         struct device_match_pattern *device_pattern;
  885         ses_path_iter_args_t        *args;
  886         struct cam_path             *path;
  887 
  888         args = (ses_path_iter_args_t *)arg;
  889         match_pattern.type = DEV_MATCH_DEVICE;
  890         device_pattern = &match_pattern.pattern.device_pattern;
  891         device_pattern->flags = DEV_MATCH_DEVID;
  892         device_pattern->data.devid_pat.id_len = 
  893             offsetof(struct scsi_vpd_id_descriptor, identifier)
  894           + devid->length;
  895         memcpy(device_pattern->data.devid_pat.id, devid,
  896                device_pattern->data.devid_pat.id_len);
  897         if (!ses_search_globally) {
  898                 device_pattern->flags |= DEV_MATCH_PATH;
  899                 device_pattern->path_id = xpt_path_path_id(enc->periph->path);
  900         }
  901 
  902         memset(&cdm, 0, sizeof(cdm));
  903         if (xpt_create_path(&cdm.ccb_h.path, /*periph*/NULL,
  904                              CAM_XPT_PATH_ID,
  905                              CAM_TARGET_WILDCARD,
  906                              CAM_LUN_WILDCARD) != CAM_REQ_CMP)
  907                 return;
  908 
  909         cdm.ccb_h.func_code = XPT_DEV_MATCH;
  910         cdm.num_patterns    = 1;
  911         cdm.patterns        = &match_pattern;
  912         cdm.pattern_buf_len = sizeof(match_pattern);
  913         cdm.match_buf_len   = sizeof(match_result);
  914         cdm.matches         = &match_result;
  915 
  916         do {
  917                 xpt_action((union ccb *)&cdm);
  918 
  919                 if ((cdm.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP ||
  920                     (cdm.status != CAM_DEV_MATCH_LAST &&
  921                      cdm.status != CAM_DEV_MATCH_MORE) ||
  922                     cdm.num_matches == 0)
  923                         break;
  924 
  925                 device_match = &match_result.result.device_result;
  926                 if (xpt_create_path(&path, /*periph*/NULL,
  927                                     device_match->path_id,
  928                                     device_match->target_id,
  929                                     device_match->target_lun) == CAM_REQ_CMP) {
  930                         args->callback(enc, elem, path, args->callback_arg);
  931 
  932                         xpt_free_path(path);
  933                 }
  934         } while (cdm.status == CAM_DEV_MATCH_MORE);
  935 
  936         xpt_free_path(cdm.ccb_h.path);
  937 }
  938 
  939 /**
  940  * \brief Iterate over and find the matching periph objects for the
  941  *        specified element.
  942  *
  943  * \param enc           SES instance containing elm
  944  * \param elm           Element for which to perform periph object matching.
  945  * \param callback      The callback function to invoke with each matching
  946  *                      periph object.
  947  * \param callback_arg  Argument passed through to callback on each invocation.
  948  */
  949 static void
  950 ses_paths_iter(enc_softc_t *enc, enc_element_t *elm,
  951                ses_path_callback_t *callback, void *callback_arg)
  952 {
  953         ses_element_t *elmpriv;
  954         struct ses_addl_status *addl;
  955 
  956         elmpriv = elm->elm_private;
  957         addl = &(elmpriv->addl);
  958 
  959         if (addl->hdr == NULL)
  960                 return;
  961 
  962         switch(ses_elm_addlstatus_proto(addl->hdr)) {
  963         case SPSP_PROTO_SAS:
  964                 if (addl->proto_hdr.sas != NULL &&
  965                     addl->proto_data.sasdev_phys != NULL) {
  966                         ses_path_iter_args_t args;
  967 
  968                         args.callback     = callback;
  969                         args.callback_arg = callback_arg;
  970                         ses_devids_iter(enc, elm, ses_path_iter_devid_callback,
  971                             &args);
  972                 }
  973                 break;
  974         case SPSP_PROTO_ATA:
  975                 if (addl->proto_hdr.ata != NULL) {
  976                         struct cam_path *path;
  977                         struct ccb_getdev cgd;
  978 
  979                         if (xpt_create_path(&path, /*periph*/NULL,
  980                             scsi_4btoul(addl->proto_hdr.ata->bus),
  981                             scsi_4btoul(addl->proto_hdr.ata->target), 0)
  982                              != CAM_REQ_CMP)
  983                                 return;
  984 
  985                         memset(&cgd, 0, sizeof(cgd));
  986                         xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL);
  987                         cgd.ccb_h.func_code = XPT_GDEV_TYPE;
  988                         xpt_action((union ccb *)&cgd);
  989                         if (cgd.ccb_h.status == CAM_REQ_CMP)
  990                                 callback(enc, elm, path, callback_arg);
  991 
  992                         xpt_free_path(path);
  993                 }
  994                 break;
  995         }
  996 }
  997 
  998 /**
  999  * ses_paths_iter() callback function used by ses_get_elmdevname()
 1000  * to record periph driver instance strings corresponding to a SES
 1001  * element.
 1002  *
 1003  * \param enc     SES instance containing elm
 1004  * \param elm     Element on which periph matching is active.
 1005  * \param periph  A periph instance that matches elm.
 1006  * \param arg     Argument passed through to callback on each invocation.
 1007  */
 1008 static void
 1009 ses_elmdevname_callback(enc_softc_t *enc, enc_element_t *elem,
 1010                         struct cam_path *path, void *arg)
 1011 {
 1012         struct sbuf *sb;
 1013 
 1014         sb = (struct sbuf *)arg;
 1015         cam_periph_list(path, sb);
 1016 }
 1017 
 1018 /**
 1019  * Argument package passed through ses_paths_iter() to
 1020  * ses_getcampath_callback.
 1021  */
 1022 typedef struct ses_setphyspath_callback_args {
 1023         struct sbuf *physpath;
 1024         int          num_set;
 1025 } ses_setphyspath_callback_args_t;
 1026 
 1027 /**
 1028  * \brief ses_paths_iter() callback to set the physical path on the
 1029  *        CAM EDT entries corresponding to a given SES element.
 1030  *
 1031  * \param enc     SES instance containing elm
 1032  * \param elm     Element on which periph matching is active.
 1033  * \param periph  A periph instance that matches elm.
 1034  * \param arg     Argument passed through to callback on each invocation.
 1035  */
 1036 static void
 1037 ses_setphyspath_callback(enc_softc_t *enc, enc_element_t *elm,
 1038                          struct cam_path *path, void *arg)
 1039 {
 1040         struct ccb_dev_advinfo cdai;
 1041         ses_setphyspath_callback_args_t *args;
 1042         char *old_physpath;
 1043 
 1044         args = (ses_setphyspath_callback_args_t *)arg;
 1045         old_physpath = malloc(MAXPATHLEN, M_SCSIENC, M_WAITOK|M_ZERO);
 1046         xpt_path_lock(path);
 1047         memset(&cdai, 0, sizeof(cdai));
 1048         xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
 1049         cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
 1050         cdai.buftype = CDAI_TYPE_PHYS_PATH;
 1051         cdai.flags = CDAI_FLAG_NONE;
 1052         cdai.bufsiz = MAXPATHLEN;
 1053         cdai.buf = old_physpath;
 1054         xpt_action((union ccb *)&cdai);
 1055         if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
 1056                 cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
 1057 
 1058         if (strcmp(old_physpath, sbuf_data(args->physpath)) != 0) {
 1059                 xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL);
 1060                 cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
 1061                 cdai.buftype = CDAI_TYPE_PHYS_PATH;
 1062                 cdai.flags = CDAI_FLAG_STORE;
 1063                 cdai.bufsiz = sbuf_len(args->physpath);
 1064                 cdai.buf = sbuf_data(args->physpath);
 1065                 xpt_action((union ccb *)&cdai);
 1066                 if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
 1067                         cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
 1068                 if (cdai.ccb_h.status == CAM_REQ_CMP)
 1069                         args->num_set++;
 1070         }
 1071         xpt_path_unlock(path);
 1072         free(old_physpath, M_SCSIENC);
 1073 }
 1074 
 1075 /**
 1076  * \brief Set a device's physical path string in CAM XPT.
 1077  *
 1078  * \param enc   SES instance containing elm
 1079  * \param elm   Element to publish physical path string for
 1080  * \param iter  Iterator whose state corresponds to elm
 1081  *
 1082  * \return      0 on success, errno otherwise.
 1083  */
 1084 static int
 1085 ses_set_physpath(enc_softc_t *enc, enc_element_t *elm,
 1086                  struct ses_iterator *iter)
 1087 {
 1088         struct ccb_dev_advinfo cdai;
 1089         ses_setphyspath_callback_args_t args;
 1090         int i, ret;
 1091         struct sbuf sb;
 1092         struct scsi_vpd_id_descriptor *idd;
 1093         uint8_t *devid;
 1094         ses_element_t *elmpriv;
 1095         const char *c;
 1096 
 1097         ret = EIO;
 1098         devid = NULL;
 1099 
 1100         elmpriv = elm->elm_private;
 1101         if (elmpriv->addl.hdr == NULL)
 1102                 goto out;
 1103 
 1104         /*
 1105          * Assemble the components of the physical path starting with
 1106          * the device ID of the enclosure itself.
 1107          */
 1108         memset(&cdai, 0, sizeof(cdai));
 1109         xpt_setup_ccb(&cdai.ccb_h, enc->periph->path, CAM_PRIORITY_NORMAL);
 1110         cdai.ccb_h.func_code = XPT_DEV_ADVINFO;
 1111         cdai.flags = CDAI_FLAG_NONE;
 1112         cdai.buftype = CDAI_TYPE_SCSI_DEVID;
 1113         cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN;
 1114         cdai.buf = devid = malloc(cdai.bufsiz, M_SCSIENC, M_WAITOK|M_ZERO);
 1115         cam_periph_lock(enc->periph);
 1116         xpt_action((union ccb *)&cdai);
 1117         if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0)
 1118                 cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE);
 1119         cam_periph_unlock(enc->periph);
 1120         if (cdai.ccb_h.status != CAM_REQ_CMP)
 1121                 goto out;
 1122 
 1123         idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf,
 1124             cdai.provsiz, scsi_devid_is_naa_ieee_reg);
 1125         if (idd == NULL)
 1126                 goto out;
 1127 
 1128         if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL) {
 1129                 ret = ENOMEM;
 1130                 goto out;
 1131         }
 1132         /* Next, generate the physical path string */
 1133         sbuf_printf(&sb, "id1,enc@n%jx/type@%x/slot@%x",
 1134             scsi_8btou64(idd->identifier), iter->type_index,
 1135             iter->type_element_index);
 1136         /* Append the element descriptor if one exists */
 1137         if (elmpriv->descr != NULL && elmpriv->descr_len > 0) {
 1138                 sbuf_cat(&sb, "/elmdesc@");
 1139                 for (i = 0, c = elmpriv->descr; i < elmpriv->descr_len;
 1140                     i++, c++) {
 1141                         if (!isprint(*c) || isspace(*c) || *c == '/')
 1142                                 sbuf_putc(&sb, '_');
 1143                         else
 1144                                 sbuf_putc(&sb, *c);
 1145                 }
 1146         }
 1147         sbuf_finish(&sb);
 1148 
 1149         /*
 1150          * Set this physical path on any CAM devices with a device ID
 1151          * descriptor that matches one created from the SES additional
 1152          * status data for this element.
 1153          */
 1154         args.physpath= &sb;
 1155         args.num_set = 0;
 1156         ses_paths_iter(enc, elm, ses_setphyspath_callback, &args);
 1157         sbuf_delete(&sb);
 1158 
 1159         ret = args.num_set == 0 ? ENOENT : 0;
 1160 
 1161 out:
 1162         if (devid != NULL)
 1163                 ENC_FREE(devid);
 1164         return (ret);
 1165 }
 1166 
 1167 /**
 1168  * \brief Helper to set the CDB fields appropriately.
 1169  *
 1170  * \param cdb           Buffer containing the cdb.
 1171  * \param pagenum       SES diagnostic page to query for.
 1172  * \param dir           Direction of query.
 1173  */
 1174 static void
 1175 ses_page_cdb(char *cdb, int bufsiz, SesDiagPageCodes pagenum, int dir)
 1176 {
 1177 
 1178         /* Ref: SPC-4 r25 Section 6.20 Table 223 */
 1179         if (dir == CAM_DIR_IN) {
 1180                 cdb[0] = RECEIVE_DIAGNOSTIC;
 1181                 cdb[1] = 1; /* Set page code valid bit */
 1182                 cdb[2] = pagenum;
 1183         } else {
 1184                 cdb[0] = SEND_DIAGNOSTIC;
 1185                 cdb[1] = 0x10;
 1186                 cdb[2] = pagenum;
 1187         }
 1188         cdb[3] = bufsiz >> 8;   /* high bits */
 1189         cdb[4] = bufsiz & 0xff; /* low bits */
 1190         cdb[5] = 0;
 1191 }
 1192 
 1193 /**
 1194  * \brief Discover whether this instance supports timed completion of a
 1195  *        RECEIVE DIAGNOSTIC RESULTS command requesting the Enclosure Status
 1196  *        page, and store the result in the softc, updating if necessary.
 1197  *
 1198  * \param enc   SES instance to query and update.
 1199  * \param tc_en Value of timed completion to set (see \return).
 1200  *
 1201  * \return      1 if timed completion enabled, 0 otherwise.
 1202  */
 1203 static int
 1204 ses_set_timed_completion(enc_softc_t *enc, uint8_t tc_en)
 1205 {
 1206         union ccb *ccb;
 1207         struct cam_periph *periph;
 1208         struct ses_mgmt_mode_page *mgmt;
 1209         uint8_t *mode_buf;
 1210         size_t mode_buf_len;
 1211         ses_softc_t *ses;
 1212 
 1213         periph = enc->periph;
 1214         ses = enc->enc_private;
 1215         ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 1216 
 1217         mode_buf_len = sizeof(struct ses_mgmt_mode_page);
 1218         mode_buf = ENC_MALLOCZ(mode_buf_len);
 1219         if (mode_buf == NULL)
 1220                 goto out;
 1221 
 1222         scsi_mode_sense(&ccb->csio, /*retries*/4, NULL, MSG_SIMPLE_Q_TAG,
 1223             /*dbd*/FALSE, SMS_PAGE_CTRL_CURRENT, SES_MGMT_MODE_PAGE_CODE,
 1224             mode_buf, mode_buf_len, SSD_FULL_SIZE, /*timeout*/60 * 1000);
 1225 
 1226         /*
 1227          * Ignore illegal request errors, as they are quite common and we
 1228          * will print something out in that case anyway.
 1229          */
 1230         cam_periph_runccb(ccb, enc_error, ENC_CFLAGS,
 1231             ENC_FLAGS|SF_QUIET_IR, NULL);
 1232         if (ccb->ccb_h.status != CAM_REQ_CMP) {
 1233                 ENC_VLOG(enc, "Timed Completion Unsupported\n");
 1234                 goto release;
 1235         }
 1236 
 1237         /* Skip the mode select if the desired value is already set */
 1238         mgmt = (struct ses_mgmt_mode_page *)mode_buf;
 1239         if ((mgmt->byte5 & SES_MGMT_TIMED_COMP_EN) == tc_en)
 1240                 goto done;
 1241 
 1242         /* Value is not what we wanted, set it */
 1243         if (tc_en)
 1244                 mgmt->byte5 |= SES_MGMT_TIMED_COMP_EN;
 1245         else
 1246                 mgmt->byte5 &= ~SES_MGMT_TIMED_COMP_EN;
 1247         /* SES2r20: a completion time of zero means as long as possible */
 1248         bzero(&mgmt->max_comp_time, sizeof(mgmt->max_comp_time));
 1249 
 1250         scsi_mode_select(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG,
 1251             /*page_fmt*/FALSE, /*save_pages*/TRUE, mode_buf, mode_buf_len,
 1252             SSD_FULL_SIZE, /*timeout*/60 * 1000);
 1253 
 1254         cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL);
 1255         if (ccb->ccb_h.status != CAM_REQ_CMP) {
 1256                 ENC_VLOG(enc, "Timed Completion Set Failed\n");
 1257                 goto release;
 1258         }
 1259 
 1260 done:
 1261         if ((mgmt->byte5 & SES_MGMT_TIMED_COMP_EN) != 0) {
 1262                 ENC_LOG(enc, "Timed Completion Enabled\n");
 1263                 ses->ses_flags |= SES_FLAG_TIMEDCOMP;
 1264         } else {
 1265                 ENC_LOG(enc, "Timed Completion Disabled\n");
 1266                 ses->ses_flags &= ~SES_FLAG_TIMEDCOMP;
 1267         }
 1268 release:
 1269         ENC_FREE(mode_buf);
 1270         xpt_release_ccb(ccb);
 1271 out:
 1272         return (ses->ses_flags & SES_FLAG_TIMEDCOMP);
 1273 }
 1274 
 1275 /**
 1276  * \brief Process the list of supported pages and update flags.
 1277  *
 1278  * \param enc       SES device to query.
 1279  * \param buf       Buffer containing the config page.
 1280  * \param xfer_len  Length of the config page in the buffer.
 1281  *
 1282  * \return  0 on success, errno otherwise.
 1283  */
 1284 static int
 1285 ses_process_pages(enc_softc_t *enc, struct enc_fsm_state *state,
 1286     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 1287 {
 1288         ses_softc_t *ses;
 1289         struct scsi_diag_page *page;
 1290         int err, i, length;
 1291 
 1292         CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
 1293             ("entering %s(%p, %d)\n", __func__, bufp, xfer_len));
 1294         ses = enc->enc_private;
 1295         err = -1;
 1296 
 1297         if (error != 0) {
 1298                 err = error;
 1299                 goto out;
 1300         }
 1301         if (xfer_len < sizeof(*page)) {
 1302                 ENC_VLOG(enc, "Unable to parse Diag Pages List Header\n");
 1303                 err = EIO;
 1304                 goto out;
 1305         }
 1306         page = (struct scsi_diag_page *)*bufp;
 1307         length = scsi_2btoul(page->length);
 1308         if (length + offsetof(struct scsi_diag_page, params) > xfer_len) {
 1309                 ENC_VLOG(enc, "Diag Pages List Too Long\n");
 1310                 goto out;
 1311         }
 1312         ENC_DLOG(enc, "%s: page length %d, xfer_len %d\n",
 1313                  __func__, length, xfer_len);
 1314 
 1315         err = 0;
 1316         for (i = 0; i < length; i++) {
 1317                 if (page->params[i] == SesElementDescriptor)
 1318                         ses->ses_flags |= SES_FLAG_DESC;
 1319                 else if (page->params[i] == SesAddlElementStatus)
 1320                         ses->ses_flags |= SES_FLAG_ADDLSTATUS;
 1321         }
 1322 
 1323 out:
 1324         ENC_DLOG(enc, "%s: exiting with err %d\n", __func__, err);
 1325         return (err);
 1326 }
 1327 
 1328 /**
 1329  * \brief Process the config page and update associated structures.
 1330  *
 1331  * \param enc       SES device to query.
 1332  * \param buf       Buffer containing the config page.
 1333  * \param xfer_len  Length of the config page in the buffer.
 1334  *
 1335  * \return  0 on success, errno otherwise.
 1336  */
 1337 static int
 1338 ses_process_config(enc_softc_t *enc, struct enc_fsm_state *state,
 1339     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 1340 {
 1341         struct ses_iterator iter;
 1342         enc_cache_t *enc_cache;
 1343         ses_cache_t *ses_cache;
 1344         uint8_t *buf;
 1345         int length;
 1346         int err;
 1347         int nelm;
 1348         int ntype;
 1349         struct ses_cfg_page *cfg_page;
 1350         struct ses_enc_desc *buf_subenc;
 1351         const struct ses_enc_desc **subencs;
 1352         const struct ses_enc_desc **cur_subenc;
 1353         const struct ses_enc_desc **last_subenc;
 1354         ses_type_t *ses_types;
 1355         ses_type_t *sestype;
 1356         const struct ses_elm_type_desc *cur_buf_type;
 1357         const struct ses_elm_type_desc *last_buf_type;
 1358         uint8_t *last_valid_byte;
 1359         enc_element_t *element;
 1360         const char *type_text;
 1361 
 1362         CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
 1363             ("entering %s(%p, %d)\n", __func__, bufp, xfer_len));
 1364         enc_cache = &enc->enc_daemon_cache;
 1365         ses_cache = enc_cache->private;
 1366         buf = *bufp;
 1367         err = -1;
 1368 
 1369         if (error != 0) {
 1370                 err = error;
 1371                 goto out;
 1372         }
 1373         if (xfer_len < sizeof(cfg_page->hdr)) {
 1374                 ENC_VLOG(enc, "Unable to parse SES Config Header\n");
 1375                 err = EIO;
 1376                 goto out;
 1377         }
 1378 
 1379         cfg_page = (struct ses_cfg_page *)buf;
 1380         length = ses_page_length(&cfg_page->hdr);
 1381         if (length > xfer_len) {
 1382                 ENC_VLOG(enc, "Enclosure Config Page Too Long\n");
 1383                 goto out;
 1384         }
 1385         last_valid_byte = &buf[length - 1];
 1386 
 1387         ENC_DLOG(enc, "%s: total page length %d, xfer_len %d\n",
 1388                  __func__, length, xfer_len);
 1389 
 1390         err = 0;
 1391         if (ses_config_cache_valid(ses_cache, cfg_page->hdr.gen_code)) {
 1392                 /* Our cache is still valid.  Proceed to fetching status. */
 1393                 goto out;
 1394         }
 1395 
 1396         /* Cache is no longer valid.  Free old data to make way for new. */
 1397         ses_cache_free(enc, enc_cache);
 1398         ENC_VLOG(enc, "Generation Code 0x%x has %d SubEnclosures\n",
 1399             scsi_4btoul(cfg_page->hdr.gen_code),
 1400             ses_cfg_page_get_num_subenc(cfg_page));
 1401 
 1402         /* Take ownership of the buffer. */
 1403         ses_cache->cfg_page = cfg_page;
 1404         *bufp = NULL;
 1405 
 1406         /*
 1407          * Now waltz through all the subenclosures summing the number of
 1408          * types available in each.
 1409          */
 1410         subencs = malloc(ses_cfg_page_get_num_subenc(cfg_page)
 1411             * sizeof(*subencs), M_SCSIENC, M_WAITOK|M_ZERO);
 1412         /*
 1413          * Sub-enclosure data is const after construction (i.e. when
 1414          * accessed via our cache object.
 1415          *
 1416          * The cast here is not required in C++ but C99 is not so
 1417          * sophisticated (see C99 6.5.16.1(1)).
 1418          */
 1419         ses_cache->ses_nsubencs = ses_cfg_page_get_num_subenc(cfg_page);
 1420         ses_cache->subencs = subencs;
 1421 
 1422         buf_subenc = cfg_page->subencs;
 1423         cur_subenc = subencs;
 1424         last_subenc = &subencs[ses_cache->ses_nsubencs - 1];
 1425         ntype = 0;
 1426         while (cur_subenc <= last_subenc) {
 1427                 if (!ses_enc_desc_is_complete(buf_subenc, last_valid_byte)) {
 1428                         ENC_VLOG(enc, "Enclosure %d Beyond End of "
 1429                             "Descriptors\n", cur_subenc - subencs);
 1430                         err = EIO;
 1431                         goto out;
 1432                 }
 1433 
 1434                 ENC_VLOG(enc, " SubEnclosure ID %d, %d Types With this ID, "
 1435                     "Descriptor Length %d, offset %d\n", buf_subenc->subenc_id,
 1436                     buf_subenc->num_types, buf_subenc->length,
 1437                     &buf_subenc->byte0 - buf);
 1438                 ENC_VLOG(enc, "WWN: %jx\n",
 1439                     (uintmax_t)scsi_8btou64(buf_subenc->logical_id));
 1440 
 1441                 ntype += buf_subenc->num_types;
 1442                 *cur_subenc = buf_subenc;
 1443                 cur_subenc++;
 1444                 buf_subenc = ses_enc_desc_next(buf_subenc);
 1445         }
 1446 
 1447         /* Process the type headers. */
 1448         ses_types = malloc(ntype * sizeof(*ses_types),
 1449             M_SCSIENC, M_WAITOK|M_ZERO);
 1450         /*
 1451          * Type data is const after construction (i.e. when accessed via
 1452          * our cache object.
 1453          */
 1454         ses_cache->ses_ntypes = ntype;
 1455         ses_cache->ses_types = ses_types;
 1456 
 1457         cur_buf_type = (const struct ses_elm_type_desc *)
 1458             (&(*last_subenc)->length + (*last_subenc)->length + 1);
 1459         last_buf_type = cur_buf_type + ntype - 1;
 1460         type_text = (const uint8_t *)(last_buf_type + 1);
 1461         nelm = 0;
 1462         sestype = ses_types;
 1463         while (cur_buf_type <= last_buf_type) {
 1464                 if (&cur_buf_type->etype_txt_len > last_valid_byte) {
 1465                         ENC_VLOG(enc, "Runt Enclosure Type Header %d\n",
 1466                             sestype - ses_types);
 1467                         err = EIO;
 1468                         goto out;
 1469                 }
 1470                 sestype->hdr  = cur_buf_type;
 1471                 sestype->text = type_text;
 1472                 type_text += cur_buf_type->etype_txt_len;
 1473                 ENC_VLOG(enc, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc "
 1474                     "%d, Text Length %d: %.*s\n", sestype - ses_types,
 1475                     sestype->hdr->etype_elm_type, sestype->hdr->etype_maxelt,
 1476                     sestype->hdr->etype_subenc, sestype->hdr->etype_txt_len,
 1477                     sestype->hdr->etype_txt_len, sestype->text);
 1478 
 1479                 nelm += sestype->hdr->etype_maxelt
 1480                       + /*overall status element*/1;
 1481                 sestype++;
 1482                 cur_buf_type++;
 1483         }
 1484 
 1485         /* Create the object map. */
 1486         enc_cache->elm_map = malloc(nelm * sizeof(enc_element_t),
 1487             M_SCSIENC, M_WAITOK|M_ZERO);
 1488         enc_cache->nelms = nelm;
 1489 
 1490         ses_iter_init(enc, enc_cache, &iter);
 1491         while ((element = ses_iter_next(&iter)) != NULL) {
 1492                 const struct ses_elm_type_desc *thdr;
 1493 
 1494                 ENC_DLOG(enc, "%s: checking obj %d(%d,%d)\n", __func__,
 1495                     iter.global_element_index, iter.type_index, nelm,
 1496                     iter.type_element_index);
 1497                 thdr = ses_cache->ses_types[iter.type_index].hdr;
 1498                 element->elm_idx = iter.global_element_index;
 1499                 element->elm_type = thdr->etype_elm_type;
 1500                 element->subenclosure = thdr->etype_subenc;
 1501                 element->type_elm_idx = iter.type_element_index;
 1502                 element->elm_private = malloc(sizeof(ses_element_t),
 1503                     M_SCSIENC, M_WAITOK|M_ZERO);
 1504                 ENC_DLOG(enc, "%s: creating elmpriv %d(%d,%d) subenc %d "
 1505                     "type 0x%x\n", __func__, iter.global_element_index,
 1506                     iter.type_index, iter.type_element_index,
 1507                     thdr->etype_subenc, thdr->etype_elm_type);
 1508         }
 1509 
 1510         err = 0;
 1511 
 1512 out:
 1513         if (err)
 1514                 ses_cache_free(enc, enc_cache);
 1515         else {
 1516                 ses_poll_status(enc);
 1517                 enc_update_request(enc, SES_PUBLISH_CACHE);
 1518         }
 1519         ENC_DLOG(enc, "%s: exiting with err %d\n", __func__, err);
 1520         return (err);
 1521 }
 1522 
 1523 /**
 1524  * \brief Update the status page and associated structures.
 1525  * 
 1526  * \param enc   SES softc to update for.
 1527  * \param buf   Buffer containing the status page.
 1528  * \param bufsz Amount of data in the buffer.
 1529  *
 1530  * \return      0 on success, errno otherwise.
 1531  */
 1532 static int
 1533 ses_process_status(enc_softc_t *enc, struct enc_fsm_state *state,
 1534     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 1535 {
 1536         struct ses_iterator iter;
 1537         enc_element_t *element;
 1538         ses_softc_t *ses;
 1539         enc_cache_t *enc_cache;
 1540         ses_cache_t *ses_cache;
 1541         uint8_t *buf;
 1542         int err = -1;
 1543         int length;
 1544         struct ses_status_page *page;
 1545         union ses_status_element *cur_stat;
 1546         union ses_status_element *last_stat;
 1547 
 1548         ses = enc->enc_private;
 1549         enc_cache = &enc->enc_daemon_cache;
 1550         ses_cache = enc_cache->private;
 1551         buf = *bufp;
 1552 
 1553         ENC_DLOG(enc, "%s: enter (%p, %p, %d)\n", __func__, enc, buf, xfer_len);
 1554         page = (struct ses_status_page *)buf;
 1555         length = ses_page_length(&page->hdr);
 1556 
 1557         if (error != 0) {
 1558                 err = error;
 1559                 goto out;
 1560         }
 1561         /*
 1562          * Make sure the length fits in the buffer.
 1563          *
 1564          * XXX all this means is that the page is larger than the space
 1565          * we allocated.  Since we use a statically sized buffer, this
 1566          * could happen... Need to use dynamic discovery of the size.
 1567          */
 1568         if (length > xfer_len) {
 1569                 ENC_VLOG(enc, "Enclosure Status Page Too Long\n");
 1570                 goto out;
 1571         }
 1572 
 1573         /* Check for simple enclosure reporting short enclosure status. */
 1574         if (length >= 4 && page->hdr.page_code == SesShortStatus) {
 1575                 ENC_DLOG(enc, "Got Short Enclosure Status page\n");
 1576                 ses->ses_flags &= ~(SES_FLAG_ADDLSTATUS | SES_FLAG_DESC);
 1577                 ses_cache_free(enc, enc_cache);
 1578                 enc_cache->enc_status = page->hdr.page_specific_flags;
 1579                 enc_update_request(enc, SES_PUBLISH_CACHE);
 1580                 err = 0;
 1581                 goto out;
 1582         }
 1583 
 1584         /* Make sure the length contains at least one header and status */
 1585         if (length < (sizeof(*page) + sizeof(*page->elements))) {
 1586                 ENC_VLOG(enc, "Enclosure Status Page Too Short\n");
 1587                 goto out;
 1588         }
 1589 
 1590         if (!ses_config_cache_valid(ses_cache, page->hdr.gen_code)) {
 1591                 ENC_DLOG(enc, "%s: Generation count change detected\n",
 1592                     __func__);
 1593                 enc_update_request(enc, SES_UPDATE_GETCONFIG);
 1594                 goto out;
 1595         }
 1596 
 1597         ses_cache_free_status(enc, enc_cache);
 1598         ses_cache->status_page = page;
 1599         *bufp = NULL;
 1600 
 1601         enc_cache->enc_status = page->hdr.page_specific_flags;
 1602 
 1603         /*
 1604          * Read in individual element status.  The element order
 1605          * matches the order reported in the config page (i.e. the
 1606          * order of an unfiltered iteration of the config objects)..
 1607          */
 1608         ses_iter_init(enc, enc_cache, &iter);
 1609         cur_stat  = page->elements;
 1610         last_stat = (union ses_status_element *)
 1611             &buf[length - sizeof(*last_stat)];
 1612         ENC_DLOG(enc, "%s: total page length %d, xfer_len %d\n",
 1613                 __func__, length, xfer_len);
 1614         while (cur_stat <= last_stat
 1615             && (element = ses_iter_next(&iter)) != NULL) {
 1616                 ENC_DLOG(enc, "%s: obj %d(%d,%d) off=0x%tx status=%jx\n",
 1617                     __func__, iter.global_element_index, iter.type_index,
 1618                     iter.type_element_index, (uint8_t *)cur_stat - buf,
 1619                     scsi_4btoul(cur_stat->bytes));
 1620 
 1621                 memcpy(&element->encstat, cur_stat, sizeof(element->encstat));
 1622                 element->svalid = 1;
 1623                 cur_stat++;
 1624         }
 1625 
 1626         if (ses_iter_next(&iter) != NULL) {
 1627                 ENC_VLOG(enc, "Status page, length insufficient for "
 1628                         "expected number of objects\n");
 1629         } else {
 1630                 if (cur_stat <= last_stat)
 1631                         ENC_VLOG(enc, "Status page, exhausted objects before "
 1632                                 "exhausing page\n");
 1633                 enc_update_request(enc, SES_PUBLISH_CACHE);
 1634                 err = 0;
 1635         }
 1636 out:
 1637         ENC_DLOG(enc, "%s: exiting with error %d\n", __func__, err);
 1638         return (err);
 1639 }
 1640 
 1641 typedef enum {
 1642         /**
 1643          * The enclosure should not provide additional element
 1644          * status for this element type in page 0x0A.
 1645          *
 1646          * \note  This status is returned for any types not
 1647          *        listed SES3r02.  Further types added in a
 1648          *        future specification will be incorrectly
 1649          *        classified.
 1650          */
 1651         TYPE_ADDLSTATUS_NONE,
 1652 
 1653         /**
 1654          * The element type provides additional element status
 1655          * in page 0x0A.
 1656          */
 1657         TYPE_ADDLSTATUS_MANDATORY,
 1658 
 1659         /**
 1660          * The element type may provide additional element status
 1661          * in page 0x0A, but i
 1662          */
 1663         TYPE_ADDLSTATUS_OPTIONAL
 1664 } ses_addlstatus_avail_t;
 1665 
 1666 /**
 1667  * \brief Check to see whether a given type (as obtained via type headers) is
 1668  *        supported by the additional status command.
 1669  *
 1670  * \param enc     SES softc to check.
 1671  * \param typidx  Type index to check for.
 1672  *
 1673  * \return  An enumeration indicating if additional status is mandatory,
 1674  *          optional, or not required for this type.
 1675  */
 1676 static ses_addlstatus_avail_t
 1677 ses_typehasaddlstatus(enc_softc_t *enc, uint8_t typidx)
 1678 {
 1679         enc_cache_t *enc_cache;
 1680         ses_cache_t *ses_cache;
 1681 
 1682         enc_cache = &enc->enc_daemon_cache;
 1683         ses_cache = enc_cache->private;
 1684         switch(ses_cache->ses_types[typidx].hdr->etype_elm_type) {
 1685         case ELMTYP_DEVICE:
 1686         case ELMTYP_ARRAY_DEV:
 1687         case ELMTYP_SAS_EXP:
 1688                 return (TYPE_ADDLSTATUS_MANDATORY);
 1689         case ELMTYP_SCSI_INI:
 1690         case ELMTYP_SCSI_TGT:
 1691         case ELMTYP_ESCC:
 1692                 return (TYPE_ADDLSTATUS_OPTIONAL);
 1693         default:
 1694                 /* No additional status information available. */
 1695                 break;
 1696         }
 1697         return (TYPE_ADDLSTATUS_NONE);
 1698 }
 1699 
 1700 static int ses_get_elm_addlstatus_fc(enc_softc_t *, enc_cache_t *,
 1701                                      uint8_t *, int);
 1702 static int ses_get_elm_addlstatus_sas(enc_softc_t *, enc_cache_t *, uint8_t *,
 1703                                       int, int, int, int);
 1704 static int ses_get_elm_addlstatus_ata(enc_softc_t *, enc_cache_t *, uint8_t *,
 1705                                       int, int, int, int);
 1706 
 1707 /**
 1708  * \brief Parse the additional status element data for each object.
 1709  *
 1710  * \param enc       The SES softc to update.
 1711  * \param buf       The buffer containing the additional status
 1712  *                  element response.
 1713  * \param xfer_len  Size of the buffer.
 1714  *
 1715  * \return  0 on success, errno otherwise.
 1716  */
 1717 static int
 1718 ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state,
 1719     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 1720 {
 1721         struct ses_iterator iter, titer;
 1722         int eip;
 1723         int err;
 1724         int length;
 1725         int offset;
 1726         enc_cache_t *enc_cache;
 1727         ses_cache_t *ses_cache;
 1728         uint8_t *buf;
 1729         ses_element_t *elmpriv;
 1730         const struct ses_page_hdr *hdr;
 1731         enc_element_t *element, *telement;
 1732 
 1733         enc_cache = &enc->enc_daemon_cache;
 1734         ses_cache = enc_cache->private;
 1735         buf = *bufp;
 1736         err = -1;
 1737 
 1738         if (error != 0) {
 1739                 err = error;
 1740                 goto out;
 1741         }
 1742         ses_cache_free_elm_addlstatus(enc, enc_cache);
 1743         ses_cache->elm_addlstatus_page =
 1744             (struct ses_addl_elem_status_page *)buf;
 1745         *bufp = NULL;
 1746 
 1747         /*
 1748          * The objects appear in the same order here as in Enclosure Status,
 1749          * which itself is ordered by the Type Descriptors from the Config
 1750          * page.  However, it is necessary to skip elements that are not
 1751          * supported by this page when counting them.
 1752          */
 1753         hdr = &ses_cache->elm_addlstatus_page->hdr;
 1754         length = ses_page_length(hdr);
 1755         ENC_DLOG(enc, "Additional Element Status Page Length 0x%x\n", length);
 1756         /* Make sure the length includes at least one header. */
 1757         if (length < sizeof(*hdr)+sizeof(struct ses_elm_addlstatus_base_hdr)) {
 1758                 ENC_VLOG(enc, "Runt Additional Element Status Page\n");
 1759                 goto out;
 1760         }
 1761         if (length > xfer_len) {
 1762                 ENC_VLOG(enc, "Additional Element Status Page Too Long\n");
 1763                 goto out;
 1764         }
 1765 
 1766         if (!ses_config_cache_valid(ses_cache, hdr->gen_code)) {
 1767                 ENC_DLOG(enc, "%s: Generation count change detected\n",
 1768                     __func__);
 1769                 enc_update_request(enc, SES_UPDATE_GETCONFIG);
 1770                 goto out;
 1771         }
 1772 
 1773         offset = sizeof(struct ses_page_hdr);
 1774         ses_iter_init(enc, enc_cache, &iter);
 1775         while (offset < length
 1776             && (element = ses_iter_next(&iter)) != NULL) {
 1777                 struct ses_elm_addlstatus_base_hdr *elm_hdr;
 1778                 int proto_info_len;
 1779                 ses_addlstatus_avail_t status_type;
 1780 
 1781                 /*
 1782                  * Additional element status is only provided for
 1783                  * individual elements (i.e. overal status elements
 1784                  * are excluded) and those of the types specified
 1785                  * in the SES spec.
 1786                  */
 1787                 status_type = ses_typehasaddlstatus(enc, iter.type_index);
 1788                 if (iter.individual_element_index == ITERATOR_INDEX_INVALID
 1789                  || status_type == TYPE_ADDLSTATUS_NONE)
 1790                         continue;
 1791 
 1792                 elm_hdr = (struct ses_elm_addlstatus_base_hdr *)&buf[offset];
 1793                 eip = ses_elm_addlstatus_eip(elm_hdr);
 1794                 if (eip) {
 1795                         struct ses_elm_addlstatus_eip_hdr *eip_hdr;
 1796                         int expected_index, index;
 1797                         ses_elem_index_type_t index_type;
 1798 
 1799                         eip_hdr = (struct ses_elm_addlstatus_eip_hdr *)elm_hdr;
 1800                         if (SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2)) {
 1801                                 index_type = SES_ELEM_INDEX_GLOBAL;
 1802                                 expected_index = iter.global_element_index;
 1803                         } else {
 1804                                 index_type = SES_ELEM_INDEX_INDIVIDUAL;
 1805                                 expected_index = iter.individual_element_index;
 1806                         }
 1807                         if (eip_hdr->element_index < expected_index) {
 1808                                 ENC_VLOG(enc, "%s: provided %selement index "
 1809                                     "%d is lower then expected %d\n",
 1810                                     __func__, SES_ADDL_EIP_EIIOE_EI_GLOB(
 1811                                     eip_hdr->byte2) ? "global " : "",
 1812                                     eip_hdr->element_index, expected_index);
 1813                                 goto badindex;
 1814                         }
 1815                         titer = iter;
 1816                         telement = ses_iter_seek_to(&titer,
 1817                             eip_hdr->element_index, index_type);
 1818                         if (telement == NULL) {
 1819                                 ENC_VLOG(enc, "%s: provided %selement index "
 1820                                     "%d does not exist\n", __func__,
 1821                                     SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2) ?
 1822                                     "global " : "", eip_hdr->element_index);
 1823                                 goto badindex;
 1824                         }
 1825                         if (ses_typehasaddlstatus(enc, titer.type_index) ==
 1826                             TYPE_ADDLSTATUS_NONE) {
 1827                                 ENC_VLOG(enc, "%s: provided %selement index "
 1828                                     "%d can't have additional status\n",
 1829                                     __func__,
 1830                                     SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2) ?
 1831                                     "global " : "", eip_hdr->element_index);
 1832 badindex:
 1833                                 /*
 1834                                  * If we expected mandatory element, we may
 1835                                  * guess it was just a wrong index and we may
 1836                                  * use the status.  If element was optional,
 1837                                  * then we have no idea where status belongs.
 1838                                  */
 1839                                 if (status_type == TYPE_ADDLSTATUS_OPTIONAL)
 1840                                         break;
 1841                         } else {
 1842                                 iter = titer;
 1843                                 element = telement;
 1844                         }
 1845 
 1846                         if (SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2))
 1847                                 index = iter.global_element_index;
 1848                         else
 1849                                 index = iter.individual_element_index;
 1850                         if (index > expected_index
 1851                          && status_type == TYPE_ADDLSTATUS_MANDATORY) {
 1852                                 ENC_VLOG(enc, "%s: provided %s element"
 1853                                         "index %d skips mandatory status "
 1854                                         " element at index %d\n",
 1855                                         __func__, SES_ADDL_EIP_EIIOE_EI_GLOB(
 1856                                         eip_hdr->byte2) ? "global " : "",
 1857                                         index, expected_index);
 1858                         }
 1859                 }
 1860                 elmpriv = element->elm_private;
 1861                 ENC_DLOG(enc, "%s: global element index=%d, type index=%d "
 1862                     "type element index=%d, offset=0x%x, "
 1863                     "byte0=0x%x, length=0x%x\n", __func__,
 1864                     iter.global_element_index, iter.type_index,
 1865                     iter.type_element_index, offset, elm_hdr->byte0,
 1866                     elm_hdr->length);
 1867 
 1868                 /* Skip to after the length field */
 1869                 offset += sizeof(struct ses_elm_addlstatus_base_hdr);
 1870 
 1871                 /* Make sure the descriptor is within bounds */
 1872                 if ((offset + elm_hdr->length) > length) {
 1873                         ENC_VLOG(enc, "Element %d Beyond End "
 1874                             "of Additional Element Status Descriptors\n",
 1875                             iter.global_element_index);
 1876                         break;
 1877                 }
 1878 
 1879                 /* Skip elements marked as invalid. */
 1880                 if (ses_elm_addlstatus_invalid(elm_hdr)) {
 1881                         offset += elm_hdr->length;
 1882                         continue;
 1883                 }
 1884                 elmpriv->addl.hdr = elm_hdr;
 1885 
 1886                 /* Advance to the protocol data, skipping eip bytes if needed */
 1887                 offset += (eip * SES_EIP_HDR_EXTRA_LEN);
 1888                 proto_info_len = elm_hdr->length
 1889                                - (eip * SES_EIP_HDR_EXTRA_LEN);
 1890 
 1891                 /* Errors in this block are ignored as they are non-fatal */
 1892                 switch(ses_elm_addlstatus_proto(elm_hdr)) {
 1893                 case SPSP_PROTO_FC:
 1894                         if (elm_hdr->length == 0)
 1895                                 break;
 1896                         ses_get_elm_addlstatus_fc(enc, enc_cache,
 1897                                                   &buf[offset], proto_info_len);
 1898                         break;
 1899                 case SPSP_PROTO_SAS:
 1900                         if (elm_hdr->length <= 2)
 1901                                 break;
 1902                         ses_get_elm_addlstatus_sas(enc, enc_cache,
 1903                                                    &buf[offset],
 1904                                                    proto_info_len,
 1905                                                    eip, iter.type_index,
 1906                                                    iter.global_element_index);
 1907                         break;
 1908                 case SPSP_PROTO_ATA:
 1909                         ses_get_elm_addlstatus_ata(enc, enc_cache,
 1910                                                    &buf[offset],
 1911                                                    proto_info_len,
 1912                                                    eip, iter.type_index,
 1913                                                    iter.global_element_index);
 1914                         break;
 1915                 default:
 1916                         ENC_VLOG(enc, "Element %d: Unknown Additional Element "
 1917                             "Protocol 0x%x\n", iter.global_element_index,
 1918                             ses_elm_addlstatus_proto(elm_hdr));
 1919                         break;
 1920                 }
 1921 
 1922                 offset += proto_info_len;
 1923         }
 1924         err = 0;
 1925 out:
 1926         if (err)
 1927                 ses_cache_free_elm_addlstatus(enc, enc_cache);
 1928         enc_update_request(enc, SES_PUBLISH_PHYSPATHS);
 1929         enc_update_request(enc, SES_PUBLISH_CACHE);
 1930         return (err);
 1931 }
 1932 
 1933 static int
 1934 ses_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
 1935     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 1936 {
 1937         ses_softc_t *ses;
 1938 
 1939         ses = enc->enc_private;
 1940         /*
 1941          * Possible errors:
 1942          *  o Generation count wrong.
 1943          *  o Some SCSI status error.
 1944          */
 1945         ses_terminate_control_requests(&ses->ses_pending_requests, error);
 1946         ses_poll_status(enc);
 1947         return (0);
 1948 }
 1949 
 1950 static int
 1951 ses_publish_physpaths(enc_softc_t *enc, struct enc_fsm_state *state,
 1952     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 1953 {
 1954         struct ses_iterator iter;
 1955         enc_cache_t *enc_cache;
 1956         enc_element_t *element;
 1957 
 1958         enc_cache = &enc->enc_daemon_cache;
 1959 
 1960         ses_iter_init(enc, enc_cache, &iter);
 1961         while ((element = ses_iter_next(&iter)) != NULL) {
 1962                 /*
 1963                  * ses_set_physpath() returns success if we changed
 1964                  * the physpath of any element.  This allows us to
 1965                  * only announce devices once regardless of how
 1966                  * many times we process additional element status.
 1967                  */
 1968                 if (ses_set_physpath(enc, element, &iter) == 0)
 1969                         ses_print_addl_data(enc, element);
 1970         }
 1971 
 1972         return (0);
 1973 }
 1974 
 1975 static int
 1976 ses_publish_cache(enc_softc_t *enc, struct enc_fsm_state *state,
 1977     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 1978 {
 1979 
 1980         sx_xlock(&enc->enc_cache_lock);
 1981         ses_cache_clone(enc, /*src*/&enc->enc_daemon_cache,
 1982                         /*dst*/&enc->enc_cache);
 1983         sx_xunlock(&enc->enc_cache_lock);
 1984 
 1985         return (0);
 1986 }
 1987 
 1988 /*
 1989  * \brief Sanitize an element descriptor
 1990  *
 1991  * The SES4r3 standard, sections 3.1.2 and 6.1.10, specifies that element
 1992  * descriptors may only contain ASCII characters in the range 0x20 to 0x7e.
 1993  * But some vendors violate that rule.  Ensure that we only expose compliant
 1994  * descriptors to userland.
 1995  *
 1996  * \param desc          SES element descriptor as reported by the hardware
 1997  * \param len           Length of desc in bytes, not necessarily including
 1998  *                      trailing NUL.  It will be modified if desc is invalid.
 1999  */
 2000 static const char*
 2001 ses_sanitize_elm_desc(const char *desc, uint16_t *len)
 2002 {
 2003         const char *invalid = "<invalid>";
 2004         int i;
 2005 
 2006         for (i = 0; i < *len; i++) {
 2007                 if (desc[i] == 0) {
 2008                         break;
 2009                 } else if (desc[i] < 0x20 || desc[i] > 0x7e) {
 2010                         *len = strlen(invalid);
 2011                         return (invalid);
 2012                 }
 2013         }
 2014         return (desc);
 2015 }
 2016 
 2017 /**
 2018  * \brief Parse the descriptors for each object.
 2019  *
 2020  * \param enc       The SES softc to update.
 2021  * \param buf       The buffer containing the descriptor list response.
 2022  * \param xfer_len  Size of the buffer.
 2023  * 
 2024  * \return      0 on success, errno otherwise.
 2025  */
 2026 static int
 2027 ses_process_elm_descs(enc_softc_t *enc, struct enc_fsm_state *state,
 2028     union ccb *ccb, uint8_t **bufp, int error, int xfer_len)
 2029 {
 2030         ses_softc_t *ses;
 2031         struct ses_iterator iter;
 2032         enc_element_t *element;
 2033         int err;
 2034         int offset;
 2035         u_long length, plength;
 2036         enc_cache_t *enc_cache;
 2037         ses_cache_t *ses_cache;
 2038         uint8_t *buf;
 2039         ses_element_t *elmpriv;
 2040         const struct ses_page_hdr *phdr;
 2041         const struct ses_elm_desc_hdr *hdr;
 2042 
 2043         ses = enc->enc_private;
 2044         enc_cache = &enc->enc_daemon_cache;
 2045         ses_cache = enc_cache->private;
 2046         buf = *bufp;
 2047         err = -1;
 2048 
 2049         if (error != 0) {
 2050                 err = error;
 2051                 goto out;
 2052         }
 2053         ses_cache_free_elm_descs(enc, enc_cache);
 2054         ses_cache->elm_descs_page = (struct ses_elem_descr_page *)buf;
 2055         *bufp = NULL;
 2056 
 2057         phdr = &ses_cache->elm_descs_page->hdr;
 2058         plength = ses_page_length(phdr);
 2059         if (xfer_len < sizeof(struct ses_page_hdr)) {
 2060                 ENC_VLOG(enc, "Runt Element Descriptor Page\n");
 2061                 goto out;
 2062         }
 2063         if (plength > xfer_len) {
 2064                 ENC_VLOG(enc, "Element Descriptor Page Too Long\n");
 2065                 goto out;
 2066         }
 2067 
 2068         if (!ses_config_cache_valid(ses_cache, phdr->gen_code)) {
 2069                 ENC_VLOG(enc, "%s: Generation count change detected\n",
 2070                     __func__);
 2071                 enc_update_request(enc, SES_UPDATE_GETCONFIG);
 2072                 goto out;
 2073         }
 2074 
 2075         offset = sizeof(struct ses_page_hdr);
 2076 
 2077         ses_iter_init(enc, enc_cache, &iter);
 2078         while (offset < plength
 2079             && (element = ses_iter_next(&iter)) != NULL) {
 2080                 if ((offset + sizeof(struct ses_elm_desc_hdr)) > plength) {
 2081                         ENC_VLOG(enc, "Element %d Descriptor Header Past "
 2082                             "End of Buffer\n", iter.global_element_index);
 2083                         goto out;
 2084                 }
 2085                 hdr = (struct ses_elm_desc_hdr *)&buf[offset];
 2086                 length = scsi_2btoul(hdr->length);
 2087                 ENC_DLOG(enc, "%s: obj %d(%d,%d) length=%d off=%d\n", __func__,
 2088                     iter.global_element_index, iter.type_index,
 2089                     iter.type_element_index, length, offset);
 2090                 if ((offset + sizeof(*hdr) + length) > plength) {
 2091                         ENC_VLOG(enc, "Element%d Descriptor Past "
 2092                             "End of Buffer\n", iter.global_element_index);
 2093                         goto out;
 2094                 }
 2095                 offset += sizeof(*hdr);
 2096 
 2097                 if (length > 0) {
 2098                         elmpriv = element->elm_private;
 2099                         elmpriv->descr_len = length;
 2100                         elmpriv->descr = ses_sanitize_elm_desc(&buf[offset],
 2101                             &elmpriv->descr_len);
 2102                 }
 2103 
 2104                 /* skip over the descriptor itself */
 2105                 offset += length;
 2106         }
 2107 
 2108         err = 0;
 2109 out:
 2110         if (err == 0) {
 2111                 if (ses->ses_flags & SES_FLAG_ADDLSTATUS)
 2112                         enc_update_request(enc, SES_UPDATE_GETELMADDLSTATUS);
 2113         }
 2114         enc_update_request(enc, SES_PUBLISH_CACHE);
 2115         return (err);
 2116 }
 2117 
 2118 static int
 2119 ses_fill_rcv_diag_io(enc_softc_t *enc, struct enc_fsm_state *state,
 2120                        union ccb *ccb, uint8_t *buf)
 2121 {
 2122 
 2123         if (enc->enc_type == ENC_SEMB_SES) {
 2124                 semb_receive_diagnostic_results(&ccb->ataio, /*retries*/5,
 2125                                         NULL, MSG_SIMPLE_Q_TAG, /*pcv*/1,
 2126                                         state->page_code, buf, state->buf_size,
 2127                                         state->timeout);
 2128         } else {
 2129                 scsi_receive_diagnostic_results(&ccb->csio, /*retries*/5,
 2130                                         NULL, MSG_SIMPLE_Q_TAG, /*pcv*/1,
 2131                                         state->page_code, buf, state->buf_size,
 2132                                         SSD_FULL_SIZE, state->timeout);
 2133         }
 2134         return (0);
 2135 }
 2136 
 2137 /**
 2138  * \brief Encode the object status into the response buffer, which is
 2139  *        expected to contain the current enclosure status.  This function
 2140  *        turns off all the 'select' bits for the objects except for the
 2141  *        object specified, then sends it back to the enclosure.
 2142  *
 2143  * \param enc   SES enclosure the change is being applied to.
 2144  * \param buf   Buffer containing the current enclosure status response.
 2145  * \param amt   Length of the response in the buffer.
 2146  * \param req   The control request to be applied to buf.
 2147  *
 2148  * \return      0 on success, errno otherwise.
 2149  */
 2150 static int
 2151 ses_encode(enc_softc_t *enc, uint8_t *buf, int amt, ses_control_request_t *req)
 2152 {
 2153         struct ses_iterator iter;
 2154         enc_element_t *element;
 2155         int offset;
 2156         struct ses_control_page_hdr *hdr;
 2157 
 2158         ses_iter_init(enc, &enc->enc_cache, &iter);
 2159         hdr = (struct ses_control_page_hdr *)buf;
 2160         if (req->elm_idx == -1) {
 2161                 /* for enclosure status, at least 2 bytes are needed */
 2162                 if (amt < 2)
 2163                         return EIO;
 2164                 hdr->control_flags =
 2165                     req->elm_stat.comstatus & SES_SET_STATUS_MASK;
 2166                 ENC_DLOG(enc, "Set EncStat %x\n", hdr->control_flags);
 2167                 return (0);
 2168         }
 2169 
 2170         element = ses_iter_seek_to(&iter, req->elm_idx, SES_ELEM_INDEX_GLOBAL);
 2171         if (element == NULL)
 2172                 return (ENXIO);
 2173 
 2174         /*
 2175          * Seek to the type set that corresponds to the requested object.
 2176          * The +1 is for the overall status element for the type.
 2177          */
 2178         offset = sizeof(struct ses_control_page_hdr)
 2179                + (iter.global_element_index * sizeof(struct ses_comstat));
 2180 
 2181         /* Check for buffer overflow. */
 2182         if (offset + sizeof(struct ses_comstat) > amt)
 2183                 return (EIO);
 2184 
 2185         /* Set the status. */
 2186         memcpy(&buf[offset], &req->elm_stat, sizeof(struct ses_comstat));
 2187 
 2188         ENC_DLOG(enc, "Set Type 0x%x Obj 0x%x (offset %d) with %x %x %x %x\n",
 2189             iter.type_index, iter.global_element_index, offset,
 2190             req->elm_stat.comstatus, req->elm_stat.comstat[0],
 2191             req->elm_stat.comstat[1], req->elm_stat.comstat[2]);
 2192 
 2193         return (0);
 2194 }
 2195 
 2196 static int
 2197 ses_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state,
 2198                          union ccb *ccb, uint8_t *buf)
 2199 {
 2200         ses_softc_t                     *ses;
 2201         enc_cache_t                     *enc_cache;
 2202         ses_cache_t                     *ses_cache;
 2203         struct ses_control_page_hdr     *hdr;
 2204         ses_control_request_t           *req;
 2205         size_t                           plength;
 2206         size_t                           offset;
 2207 
 2208         ses = enc->enc_private;
 2209         enc_cache = &enc->enc_daemon_cache;
 2210         ses_cache = enc_cache->private;
 2211         hdr = (struct ses_control_page_hdr *)buf;
 2212 
 2213         if (ses_cache->status_page == NULL) {
 2214                 ses_terminate_control_requests(&ses->ses_requests, EIO);
 2215                 return (EIO);
 2216         }
 2217 
 2218         plength = ses_page_length(&ses_cache->status_page->hdr);
 2219         memcpy(buf, ses_cache->status_page, plength);
 2220 
 2221         /* Disable the select bits in all status entries.  */
 2222         offset = sizeof(struct ses_control_page_hdr);
 2223         for (offset = sizeof(struct ses_control_page_hdr);
 2224              offset < plength; offset += sizeof(struct ses_comstat)) {
 2225                 buf[offset] &= ~SESCTL_CSEL;
 2226         }
 2227 
 2228         /* And make sure the INVOP bit is clear.  */
 2229         hdr->control_flags &= ~SES_ENCSTAT_INVOP;
 2230 
 2231         /* Apply incoming requests. */
 2232         while ((req = TAILQ_FIRST(&ses->ses_requests)) != NULL) {
 2233                 TAILQ_REMOVE(&ses->ses_requests, req, links);
 2234                 req->result = ses_encode(enc, buf, plength, req);
 2235                 if (req->result != 0) {
 2236                         wakeup(req);
 2237                         continue;
 2238                 }
 2239                 TAILQ_INSERT_TAIL(&ses->ses_pending_requests, req, links);
 2240         }
 2241 
 2242         if (TAILQ_EMPTY(&ses->ses_pending_requests) != 0)
 2243                 return (ENOENT);
 2244 
 2245         /* Fill out the ccb */
 2246         if (enc->enc_type == ENC_SEMB_SES) {
 2247                 semb_send_diagnostic(&ccb->ataio, /*retries*/5, NULL,
 2248                              MSG_SIMPLE_Q_TAG,
 2249                              buf, ses_page_length(&ses_cache->status_page->hdr),
 2250                              state->timeout);
 2251         } else {
 2252                 scsi_send_diagnostic(&ccb->csio, /*retries*/5, NULL,
 2253                              MSG_SIMPLE_Q_TAG, /*unit_offline*/0,
 2254                              /*device_offline*/0, /*self_test*/0,
 2255                              /*page_format*/1, /*self_test_code*/0,
 2256                              buf, ses_page_length(&ses_cache->status_page->hdr),
 2257                              SSD_FULL_SIZE, state->timeout);
 2258         }
 2259         return (0);
 2260 }
 2261 
 2262 static int
 2263 ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache,
 2264                           uint8_t *buf, int bufsiz)
 2265 {
 2266         ENC_VLOG(enc, "FC Device Support Stubbed in Additional Status Page\n");
 2267         return (ENODEV);
 2268 }
 2269 
 2270 #define SES_PRINT_PORTS(p, type) do {                                   \
 2271         if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) != 0) {                \
 2272                 sbuf_printf(sbp, " %s (", type);                        \
 2273                 if ((p) & SES_SASOBJ_DEV_PHY_SMP)                       \
 2274                         sbuf_printf(sbp, " SMP");                       \
 2275                 if ((p) & SES_SASOBJ_DEV_PHY_STP)                       \
 2276                         sbuf_printf(sbp, " STP");                       \
 2277                 if ((p) & SES_SASOBJ_DEV_PHY_SSP)                       \
 2278                         sbuf_printf(sbp, " SSP");                       \
 2279                 sbuf_printf(sbp, " )");                                 \
 2280         }                                                               \
 2281 } while(0)
 2282 
 2283 /**
 2284  * \brief Print the additional element status data for this object, for SAS
 2285  *        type 0 objects.  See SES2 r20 Section 6.1.13.3.2.
 2286  *
 2287  * \param sesname       SES device name associated with the object.
 2288  * \param sbp           Sbuf to print to.
 2289  * \param obj           The object to print the data for.
 2290  */
 2291 static void
 2292 ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp,
 2293                               enc_element_t *obj)
 2294 {
 2295         int i;
 2296         ses_element_t *elmpriv;
 2297         struct ses_addl_status *addl;
 2298         struct ses_elm_sas_device_phy *phy;
 2299 
 2300         elmpriv = obj->elm_private;
 2301         addl = &(elmpriv->addl);
 2302         sbuf_printf(sbp, ", SAS Slot: %d%s phys",
 2303             addl->proto_hdr.sas->base_hdr.num_phys,
 2304             ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas) ? "+" : "");
 2305         if (ses_elm_addlstatus_eip(addl->hdr))
 2306                 sbuf_printf(sbp, " at slot %d",
 2307                     addl->proto_hdr.sas->type0_eip.dev_slot_num);
 2308         sbuf_printf(sbp, "\n");
 2309         if (addl->proto_data.sasdev_phys == NULL)
 2310                 return;
 2311         for (i = 0;i < addl->proto_hdr.sas->base_hdr.num_phys;i++) {
 2312                 phy = &addl->proto_data.sasdev_phys[i];
 2313                 sbuf_printf(sbp, "%s:  phy %d:", sesname, i);
 2314                 if (ses_elm_sas_dev_phy_sata_dev(phy))
 2315                         /* Spec says all other fields are specific values */
 2316                         sbuf_printf(sbp, " SATA device\n");
 2317                 else {
 2318                         sbuf_printf(sbp, " SAS device type %d phy %d",
 2319                             ses_elm_sas_dev_phy_dev_type(phy), phy->phy_id);
 2320                         SES_PRINT_PORTS(phy->initiator_ports, "Initiator");
 2321                         SES_PRINT_PORTS(phy->target_ports, "Target");
 2322                         sbuf_printf(sbp, "\n");
 2323                 }
 2324                 sbuf_printf(sbp, "%s:  phy %d: parent %jx addr %jx\n",
 2325                     sesname, i,
 2326                     (uintmax_t)scsi_8btou64(phy->parent_addr),
 2327                     (uintmax_t)scsi_8btou64(phy->phy_addr));
 2328         }
 2329 }
 2330 #undef SES_PRINT_PORTS
 2331 
 2332 /**
 2333  * \brief Print the additional element status data for this object, for SAS
 2334  *        type 1 objects.  See SES2 r20 Sections 6.1.13.3.3 and 6.1.13.3.4.
 2335  *
 2336  * \param sesname       SES device name associated with the object.
 2337  * \param sbp           Sbuf to print to.
 2338  * \param obj           The object to print the data for.
 2339  */
 2340 static void
 2341 ses_print_addl_data_sas_type1(char *sesname, struct sbuf *sbp,
 2342                               enc_element_t *obj)
 2343 {
 2344         int i, num_phys;
 2345         ses_element_t *elmpriv;
 2346         struct ses_addl_status *addl;
 2347         struct ses_elm_sas_expander_phy *exp_phy;
 2348         struct ses_elm_sas_port_phy *port_phy;
 2349 
 2350         elmpriv = obj->elm_private;
 2351         addl = &(elmpriv->addl);
 2352         sbuf_printf(sbp, ", SAS ");
 2353         if (obj->elm_type == ELMTYP_SAS_EXP) {
 2354                 num_phys = addl->proto_hdr.sas->base_hdr.num_phys;
 2355                 sbuf_printf(sbp, "Expander: %d phys", num_phys);
 2356                 if (addl->proto_data.sasexp_phys == NULL)
 2357                         return;
 2358                 for (i = 0;i < num_phys;i++) {
 2359                         exp_phy = &addl->proto_data.sasexp_phys[i];
 2360                         sbuf_printf(sbp, "%s:  phy %d: connector %d other %d\n",
 2361                             sesname, i, exp_phy->connector_index,
 2362                             exp_phy->other_index);
 2363                 }
 2364         } else {
 2365                 num_phys = addl->proto_hdr.sas->base_hdr.num_phys;
 2366                 sbuf_printf(sbp, "Port: %d phys", num_phys);
 2367                 if (addl->proto_data.sasport_phys == NULL)
 2368                         return;
 2369                 for (i = 0;i < num_phys;i++) {
 2370                         port_phy = &addl->proto_data.sasport_phys[i];
 2371                         sbuf_printf(sbp,
 2372                             "%s:  phy %d: id %d connector %d other %d\n",
 2373                             sesname, i, port_phy->phy_id,
 2374                             port_phy->connector_index, port_phy->other_index);
 2375                         sbuf_printf(sbp, "%s:  phy %d: addr %jx\n", sesname, i,
 2376                             (uintmax_t)scsi_8btou64(port_phy->phy_addr));
 2377                 }
 2378         }
 2379 }
 2380 
 2381 /**
 2382  * \brief Print the additional element status data for this object, for
 2383  *        ATA objects.
 2384  *
 2385  * \param sbp           Sbuf to print to.
 2386  * \param obj           The object to print the data for.
 2387  */
 2388 static void
 2389 ses_print_addl_data_ata(struct sbuf *sbp, enc_element_t *obj)
 2390 {
 2391         ses_element_t *elmpriv = obj->elm_private;
 2392         struct ses_addl_status *addl = &elmpriv->addl;
 2393         struct ses_elm_ata_hdr *ata = addl->proto_hdr.ata;
 2394 
 2395         sbuf_printf(sbp, ", SATA Slot: scbus%d target %d\n",
 2396             scsi_4btoul(ata->bus), scsi_4btoul(ata->target));
 2397 }
 2398 
 2399 /**
 2400  * \brief Print the additional element status data for this object.
 2401  *
 2402  * \param enc           SES softc associated with the object.
 2403  * \param obj           The object to print the data for.
 2404  */
 2405 static void
 2406 ses_print_addl_data(enc_softc_t *enc, enc_element_t *obj)
 2407 {
 2408         ses_element_t *elmpriv;
 2409         struct ses_addl_status *addl;
 2410         struct sbuf sesname, name, out;
 2411 
 2412         elmpriv = obj->elm_private;
 2413         if (elmpriv == NULL)
 2414                 return;
 2415 
 2416         addl = &(elmpriv->addl);
 2417         if (addl->hdr == NULL)
 2418                 return;
 2419 
 2420         sbuf_new(&sesname, NULL, 16, SBUF_AUTOEXTEND);
 2421         sbuf_new(&name, NULL, 16, SBUF_AUTOEXTEND);
 2422         sbuf_new(&out, NULL, 512, SBUF_AUTOEXTEND);
 2423         ses_paths_iter(enc, obj, ses_elmdevname_callback, &name);
 2424         if (sbuf_len(&name) == 0)
 2425                 sbuf_printf(&name, "(none)");
 2426         sbuf_finish(&name);
 2427         sbuf_printf(&sesname, "%s%d", enc->periph->periph_name,
 2428             enc->periph->unit_number);
 2429         sbuf_finish(&sesname);
 2430         sbuf_printf(&out, "%s: %s in ", sbuf_data(&sesname), sbuf_data(&name));
 2431         if (elmpriv->descr != NULL)
 2432                 sbuf_printf(&out, "'%s'", elmpriv->descr);
 2433         else {
 2434                 if (obj->elm_type <= ELMTYP_LAST)
 2435                         sbuf_cat(&out, elm_type_names[obj->elm_type]);
 2436                 else
 2437                         sbuf_printf(&out, "<Type 0x%02x>", obj->elm_type);
 2438                 sbuf_printf(&out, " %d", obj->type_elm_idx);
 2439                 if (obj->subenclosure != 0)
 2440                         sbuf_printf(&out, " of subenc %d", obj->subenclosure);
 2441         }
 2442         switch(ses_elm_addlstatus_proto(addl->hdr)) {
 2443         case SPSP_PROTO_FC:
 2444                 goto noaddl;    /* stubbed for now */
 2445         case SPSP_PROTO_SAS:
 2446                 if (addl->proto_hdr.sas == NULL)
 2447                         goto noaddl;
 2448                 switch(ses_elm_sas_descr_type(addl->proto_hdr.sas)) {
 2449                 case SES_SASOBJ_TYPE_SLOT:
 2450                         ses_print_addl_data_sas_type0(sbuf_data(&sesname),
 2451                             &out, obj);
 2452                         break;
 2453                 case SES_SASOBJ_TYPE_OTHER:
 2454                         ses_print_addl_data_sas_type1(sbuf_data(&sesname),
 2455                             &out, obj);
 2456                         break;
 2457                 default:
 2458                         goto noaddl;
 2459                 }
 2460                 break;
 2461         case SPSP_PROTO_ATA:
 2462                 if (addl->proto_hdr.ata == NULL)
 2463                         goto noaddl;
 2464                 ses_print_addl_data_ata(&out, obj);
 2465                 break;
 2466         default:
 2467 noaddl:
 2468                 sbuf_cat(&out, "\n");
 2469                 break;
 2470         }
 2471         sbuf_finish(&out);
 2472         printf("%s", sbuf_data(&out));
 2473         sbuf_delete(&out);
 2474         sbuf_delete(&name);
 2475         sbuf_delete(&sesname);
 2476 }
 2477 
 2478 /**
 2479  * \brief Update the softc with the additional element status data for this
 2480  *        object, for SAS type 0 objects.
 2481  *
 2482  * \param enc           SES softc to be updated.
 2483  * \param buf           The additional element status response buffer.
 2484  * \param bufsiz        Size of the response buffer.
 2485  * \param eip           The EIP bit value.
 2486  * \param nobj          Number of objects attached to the SES softc.
 2487  * 
 2488  * \return              0 on success, errno otherwise.
 2489  */
 2490 static int
 2491 ses_get_elm_addlstatus_sas_type0(enc_softc_t *enc, enc_cache_t *enc_cache,
 2492                                  uint8_t *buf, int bufsiz, int eip, int nobj)
 2493 {
 2494         int err, offset, physz;
 2495         enc_element_t *obj;
 2496         ses_element_t *elmpriv;
 2497         struct ses_addl_status *addl;
 2498 
 2499         err = offset = 0;
 2500 
 2501         /* basic object setup */
 2502         obj = &(enc_cache->elm_map[nobj]);
 2503         elmpriv = obj->elm_private;
 2504         addl = &(elmpriv->addl);
 2505 
 2506         addl->proto_hdr.sas = (union ses_elm_sas_hdr *)&buf[offset];
 2507 
 2508         /* Don't assume this object has any phys */
 2509         bzero(&addl->proto_data, sizeof(addl->proto_data));
 2510         if (addl->proto_hdr.sas->base_hdr.num_phys == 0)
 2511                 goto out;
 2512 
 2513         /* Skip forward to the phy list */
 2514         if (eip)
 2515                 offset += sizeof(struct ses_elm_sas_type0_eip_hdr);
 2516         else
 2517                 offset += sizeof(struct ses_elm_sas_type0_base_hdr);
 2518 
 2519         /* Make sure the phy list fits in the buffer */
 2520         physz = addl->proto_hdr.sas->base_hdr.num_phys;
 2521         physz *= sizeof(struct ses_elm_sas_device_phy);
 2522         if (physz > (bufsiz - offset + 4)) {
 2523                 ENC_VLOG(enc, "Element %d Device Phy List Beyond End Of Buffer\n",
 2524                     nobj);
 2525                 err = EIO;
 2526                 goto out;
 2527         }
 2528 
 2529         /* Point to the phy list */
 2530         addl->proto_data.sasdev_phys =
 2531             (struct ses_elm_sas_device_phy *)&buf[offset];
 2532 
 2533 out:
 2534         return (err);
 2535 }
 2536 
 2537 /**
 2538  * \brief Update the softc with the additional element status data for this
 2539  *        object, for SAS type 1 objects.
 2540  *
 2541  * \param enc           SES softc to be updated.
 2542  * \param buf           The additional element status response buffer.
 2543  * \param bufsiz        Size of the response buffer.
 2544  * \param eip           The EIP bit value.
 2545  * \param nobj          Number of objects attached to the SES softc.
 2546  * 
 2547  * \return              0 on success, errno otherwise.
 2548  */
 2549 static int
 2550 ses_get_elm_addlstatus_sas_type1(enc_softc_t *enc, enc_cache_t *enc_cache,
 2551                                  uint8_t *buf, int bufsiz, int eip, int nobj)
 2552 {
 2553         int err, offset, physz;
 2554         enc_element_t *obj;
 2555         ses_element_t *elmpriv;
 2556         struct ses_addl_status *addl;
 2557 
 2558         err = offset = 0;
 2559 
 2560         /* basic object setup */
 2561         obj = &(enc_cache->elm_map[nobj]);
 2562         elmpriv = obj->elm_private;
 2563         addl = &(elmpriv->addl);
 2564 
 2565         addl->proto_hdr.sas = (union ses_elm_sas_hdr *)&buf[offset];
 2566 
 2567         /* Don't assume this object has any phys */
 2568         bzero(&addl->proto_data, sizeof(addl->proto_data));
 2569         if (addl->proto_hdr.sas->base_hdr.num_phys == 0)
 2570                 goto out;
 2571 
 2572         /* Process expanders differently from other type1 cases */
 2573         if (obj->elm_type == ELMTYP_SAS_EXP) {
 2574                 offset += sizeof(struct ses_elm_sas_type1_expander_hdr);
 2575                 physz = addl->proto_hdr.sas->base_hdr.num_phys *
 2576                     sizeof(struct ses_elm_sas_expander_phy);
 2577                 if (physz > (bufsiz - offset)) {
 2578                         ENC_VLOG(enc, "Element %d: Expander Phy List Beyond "
 2579                             "End Of Buffer\n", nobj);
 2580                         err = EIO;
 2581                         goto out;
 2582                 }
 2583                 addl->proto_data.sasexp_phys =
 2584                     (struct ses_elm_sas_expander_phy *)&buf[offset];
 2585         } else {
 2586                 offset += sizeof(struct ses_elm_sas_type1_nonexpander_hdr);
 2587                 physz = addl->proto_hdr.sas->base_hdr.num_phys *
 2588                     sizeof(struct ses_elm_sas_port_phy);
 2589                 if (physz > (bufsiz - offset + 4)) {
 2590                         ENC_VLOG(enc, "Element %d: Port Phy List Beyond End "
 2591                             "Of Buffer\n", nobj);
 2592                         err = EIO;
 2593                         goto out;
 2594                 }
 2595                 addl->proto_data.sasport_phys =
 2596                     (struct ses_elm_sas_port_phy *)&buf[offset];
 2597         }
 2598 
 2599 out:
 2600         return (err);
 2601 }
 2602 
 2603 /**
 2604  * \brief Update the softc with the additional element status data for this
 2605  *        object, for SAS objects.
 2606  *
 2607  * \param enc           SES softc to be updated.
 2608  * \param buf           The additional element status response buffer.
 2609  * \param bufsiz        Size of the response buffer.
 2610  * \param eip           The EIP bit value.
 2611  * \param tidx          Type index for this object.
 2612  * \param nobj          Number of objects attached to the SES softc.
 2613  * 
 2614  * \return              0 on success, errno otherwise.
 2615  */
 2616 static int
 2617 ses_get_elm_addlstatus_sas(enc_softc_t *enc, enc_cache_t *enc_cache,
 2618                            uint8_t *buf, int bufsiz, int eip, int tidx,
 2619                            int nobj)
 2620 {
 2621         int dtype, err;
 2622         ses_cache_t *ses_cache;
 2623         union ses_elm_sas_hdr *hdr;
 2624 
 2625         /* Need to be able to read the descriptor type! */
 2626         if (bufsiz < sizeof(union ses_elm_sas_hdr)) {
 2627                 err = EIO;
 2628                 goto out;
 2629         }
 2630 
 2631         ses_cache = enc_cache->private;
 2632 
 2633         hdr = (union ses_elm_sas_hdr *)buf;
 2634         dtype = ses_elm_sas_descr_type(hdr);
 2635         switch(dtype) {
 2636         case SES_SASOBJ_TYPE_SLOT:
 2637                 switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) {
 2638                 case ELMTYP_DEVICE:
 2639                 case ELMTYP_ARRAY_DEV:
 2640                         break;
 2641                 default:
 2642                         ENC_VLOG(enc, "Element %d has Additional Status type 0, "
 2643                             "invalid for SES element type 0x%x\n", nobj,
 2644                             ses_cache->ses_types[tidx].hdr->etype_elm_type);
 2645                         err = ENODEV;
 2646                         goto out;
 2647                 }
 2648                 err = ses_get_elm_addlstatus_sas_type0(enc, enc_cache,
 2649                                                        buf, bufsiz, eip,
 2650                     nobj);
 2651                 break;
 2652         case SES_SASOBJ_TYPE_OTHER:
 2653                 switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) {
 2654                 case ELMTYP_SAS_EXP:
 2655                 case ELMTYP_SCSI_INI:
 2656                 case ELMTYP_SCSI_TGT:
 2657                 case ELMTYP_ESCC:
 2658                         break;
 2659                 default:
 2660                         ENC_VLOG(enc, "Element %d has Additional Status type 1, "
 2661                             "invalid for SES element type 0x%x\n", nobj,
 2662                             ses_cache->ses_types[tidx].hdr->etype_elm_type);
 2663                         err = ENODEV;
 2664                         goto out;
 2665                 }
 2666                 err = ses_get_elm_addlstatus_sas_type1(enc, enc_cache, buf,
 2667                                                        bufsiz, eip, nobj);
 2668                 break;
 2669         default:
 2670                 ENC_VLOG(enc, "Element %d of type 0x%x has Additional Status "
 2671                     "of unknown type 0x%x\n", nobj,
 2672                     ses_cache->ses_types[tidx].hdr->etype_elm_type, dtype);
 2673                 err = ENODEV;
 2674                 break;
 2675         }
 2676 
 2677 out:
 2678         return (err);
 2679 }
 2680 
 2681 /**
 2682  * \brief Update the softc with the additional element status data for this
 2683  *        object, for ATA objects.
 2684  *
 2685  * \param enc           SES softc to be updated.
 2686  * \param buf           The additional element status response buffer.
 2687  * \param bufsiz        Size of the response buffer.
 2688  * \param eip           The EIP bit value.
 2689  * \param tidx          Type index for this object.
 2690  * \param nobj          Number of objects attached to the SES softc.
 2691  * 
 2692  * \return              0 on success, errno otherwise.
 2693  */
 2694 static int
 2695 ses_get_elm_addlstatus_ata(enc_softc_t *enc, enc_cache_t *enc_cache,
 2696                            uint8_t *buf, int bufsiz, int eip, int tidx,
 2697                            int nobj)
 2698 {
 2699         int err;
 2700         ses_cache_t *ses_cache;
 2701 
 2702         if (bufsiz < sizeof(struct ses_elm_ata_hdr)) {
 2703                 err = EIO;
 2704                 goto out;
 2705         }
 2706 
 2707         ses_cache = enc_cache->private;
 2708         switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) {
 2709         case ELMTYP_DEVICE:
 2710         case ELMTYP_ARRAY_DEV:
 2711                 break;
 2712         default:
 2713                 ENC_VLOG(enc, "Element %d has Additional Status, "
 2714                     "invalid for SES element type 0x%x\n", nobj,
 2715                     ses_cache->ses_types[tidx].hdr->etype_elm_type);
 2716                 err = ENODEV;
 2717                 goto out;
 2718         }
 2719 
 2720         ((ses_element_t *)enc_cache->elm_map[nobj].elm_private)
 2721             ->addl.proto_hdr.ata = (struct ses_elm_ata_hdr *)buf;
 2722         err = 0;
 2723 
 2724 out:
 2725         return (err);
 2726 }
 2727 
 2728 static void
 2729 ses_softc_invalidate(enc_softc_t *enc)
 2730 {
 2731         ses_softc_t *ses;
 2732 
 2733         ses = enc->enc_private;
 2734         ses_terminate_control_requests(&ses->ses_requests, ENXIO);
 2735 }
 2736 
 2737 static void
 2738 ses_softc_cleanup(enc_softc_t *enc)
 2739 {
 2740 
 2741         ses_cache_free(enc, &enc->enc_cache);
 2742         ses_cache_free(enc, &enc->enc_daemon_cache);
 2743         ENC_FREE_AND_NULL(enc->enc_private);
 2744         ENC_FREE_AND_NULL(enc->enc_cache.private);
 2745         ENC_FREE_AND_NULL(enc->enc_daemon_cache.private);
 2746 }
 2747 
 2748 static int
 2749 ses_init_enc(enc_softc_t *enc)
 2750 {
 2751         return (0);
 2752 }
 2753 
 2754 static int
 2755 ses_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag)
 2756 {
 2757         ses_control_request_t req;
 2758         ses_softc_t          *ses;
 2759 
 2760         ses = enc->enc_private;
 2761         req.elm_idx = SES_SETSTATUS_ENC_IDX;
 2762         req.elm_stat.comstatus = encstat & 0xf;
 2763 
 2764         TAILQ_INSERT_TAIL(&ses->ses_requests, &req, links);
 2765         enc_update_request(enc, SES_PROCESS_CONTROL_REQS);
 2766         cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
 2767 
 2768         return (req.result);
 2769 }
 2770 
 2771 static int
 2772 ses_get_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag)
 2773 {
 2774         unsigned int i = elms->elm_idx;
 2775 
 2776         memcpy(elms->cstat, &enc->enc_cache.elm_map[i].encstat, 4);
 2777         return (0);
 2778 }
 2779 
 2780 static int
 2781 ses_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag)
 2782 {
 2783         ses_control_request_t req;
 2784         ses_softc_t          *ses;
 2785 
 2786         /* If this is clear, we don't do diddly.  */
 2787         if ((elms->cstat[0] & SESCTL_CSEL) == 0)
 2788                 return (0);
 2789 
 2790         ses = enc->enc_private;
 2791         req.elm_idx = elms->elm_idx;
 2792         memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat));
 2793 
 2794         TAILQ_INSERT_TAIL(&ses->ses_requests, &req, links);
 2795         enc_update_request(enc, SES_PROCESS_CONTROL_REQS);
 2796         cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0);
 2797 
 2798         return (req.result);
 2799 }
 2800 
 2801 static int
 2802 ses_get_elm_desc(enc_softc_t *enc, encioc_elm_desc_t *elmd)
 2803 {
 2804         int i = (int)elmd->elm_idx;
 2805         ses_element_t *elmpriv;
 2806 
 2807         /* Assume caller has already checked obj_id validity */
 2808         elmpriv = enc->enc_cache.elm_map[i].elm_private;
 2809         /* object might not have a descriptor */
 2810         if (elmpriv == NULL || elmpriv->descr == NULL) {
 2811                 elmd->elm_desc_len = 0;
 2812                 return (0);
 2813         }
 2814         if (elmd->elm_desc_len > elmpriv->descr_len)
 2815                 elmd->elm_desc_len = elmpriv->descr_len;
 2816         copyout(elmpriv->descr, elmd->elm_desc_str, elmd->elm_desc_len);
 2817         return (0);
 2818 }
 2819 
 2820 /**
 2821  * \brief Respond to ENCIOC_GETELMDEVNAME, providing a device name for the
 2822  *        given object id if one is available.
 2823  *
 2824  * \param enc   SES softc to examine.
 2825  * \param objdn ioctl structure to read/write device name info.
 2826  *
 2827  * \return      0 on success, errno otherwise.
 2828  */
 2829 static int
 2830 ses_get_elm_devnames(enc_softc_t *enc, encioc_elm_devnames_t *elmdn)
 2831 {
 2832         struct sbuf sb;
 2833         int len;
 2834 
 2835         len = elmdn->elm_names_size;
 2836         if (len < 0)
 2837                 return (EINVAL);
 2838 
 2839         cam_periph_unlock(enc->periph);
 2840         sbuf_new(&sb, NULL, len, SBUF_FIXEDLEN);
 2841         ses_paths_iter(enc, &enc->enc_cache.elm_map[elmdn->elm_idx],
 2842             ses_elmdevname_callback, &sb);
 2843         sbuf_finish(&sb);
 2844         elmdn->elm_names_len = sbuf_len(&sb);
 2845         copyout(sbuf_data(&sb), elmdn->elm_devnames, elmdn->elm_names_len + 1);
 2846         sbuf_delete(&sb);
 2847         cam_periph_lock(enc->periph);
 2848         return (elmdn->elm_names_len > 0 ? 0 : ENODEV);
 2849 }
 2850 
 2851 /**
 2852  * \brief Send a string to the primary subenclosure using the String Out
 2853  *        SES diagnostic page.
 2854  *
 2855  * \param enc   SES enclosure to run the command on.
 2856  * \param sstr  SES string structure to operate on
 2857  * \param ioc   Ioctl being performed
 2858  *
 2859  * \return      0 on success, errno otherwise.
 2860  */
 2861 static int
 2862 ses_handle_string(enc_softc_t *enc, encioc_string_t *sstr, unsigned long ioc)
 2863 {
 2864         enc_cache_t *enc_cache;
 2865         ses_cache_t *ses_cache;
 2866         const struct ses_enc_desc *enc_desc;
 2867         int amt, payload, ret;
 2868         char cdb[6];
 2869         char str[32];
 2870         char vendor[9];
 2871         char product[17];
 2872         char rev[5];
 2873         uint8_t *buf;
 2874         size_t size, rsize;
 2875 
 2876         enc_cache = &enc->enc_daemon_cache;
 2877         ses_cache = enc_cache->private;
 2878 
 2879         /* Implement SES2r20 6.1.6 */
 2880         if (sstr->bufsiz > ENC_STRING_MAX)
 2881                 return (EINVAL); /* buffer size too large */
 2882 
 2883         switch (ioc) {
 2884         case ENCIOC_SETSTRING:
 2885                 payload = sstr->bufsiz + 4; /* header for SEND DIAGNOSTIC */
 2886                 amt = 0 - payload;
 2887                 buf = ENC_MALLOC(payload);
 2888                 if (buf == NULL)
 2889                         return (ENOMEM);
 2890                 ses_page_cdb(cdb, payload, 0, CAM_DIR_OUT);
 2891                 /* Construct the page request */
 2892                 buf[0] = SesStringOut;
 2893                 buf[1] = 0;
 2894                 buf[2] = sstr->bufsiz >> 8;
 2895                 buf[3] = sstr->bufsiz & 0xff;
 2896                 ret = copyin(sstr->buf, &buf[4], sstr->bufsiz);
 2897                 if (ret != 0) {
 2898                         ENC_FREE(buf);
 2899                         return (ret);
 2900                 }
 2901                 break;
 2902         case ENCIOC_GETSTRING:
 2903                 payload = sstr->bufsiz;
 2904                 amt = payload;
 2905                 buf = ENC_MALLOC(payload);
 2906                 if (buf == NULL)
 2907                         return (ENOMEM);
 2908                 ses_page_cdb(cdb, payload, SesStringIn, CAM_DIR_IN);
 2909                 break;
 2910         case ENCIOC_GETENCNAME:
 2911                 if (ses_cache->ses_nsubencs < 1)
 2912                         return (ENODEV);
 2913                 enc_desc = ses_cache->subencs[0];
 2914                 cam_strvis(vendor, enc_desc->vendor_id,
 2915                     sizeof(enc_desc->vendor_id), sizeof(vendor));
 2916                 cam_strvis(product, enc_desc->product_id,
 2917                     sizeof(enc_desc->product_id), sizeof(product));
 2918                 cam_strvis(rev, enc_desc->product_rev,
 2919                     sizeof(enc_desc->product_rev), sizeof(rev));
 2920                 rsize = snprintf(str, sizeof(str), "%s %s %s",
 2921                     vendor, product, rev) + 1;
 2922                 if (rsize > sizeof(str))
 2923                         rsize = sizeof(str);
 2924                 size = rsize;
 2925                 if (size > sstr->bufsiz)
 2926                         size = sstr->bufsiz;
 2927                 copyout(str, sstr->buf, size);
 2928                 sstr->bufsiz = rsize;
 2929                 return (size == rsize ? 0 : ENOMEM);
 2930         case ENCIOC_GETENCID:
 2931                 if (ses_cache->ses_nsubencs < 1)
 2932                         return (ENODEV);
 2933                 enc_desc = ses_cache->subencs[0];
 2934                 rsize = snprintf(str, sizeof(str), "%16jx",
 2935                     scsi_8btou64(enc_desc->logical_id)) + 1;
 2936                 if (rsize > sizeof(str))
 2937                         rsize = sizeof(str);
 2938                 size = rsize;
 2939                 if (size > sstr->bufsiz)
 2940                         size = sstr->bufsiz;
 2941                 copyout(str, sstr->buf, size);
 2942                 sstr->bufsiz = rsize;
 2943                 return (size == rsize ? 0 : ENOMEM);
 2944         default:
 2945                 return (EINVAL);
 2946         }
 2947         ret = enc_runcmd(enc, cdb, 6, buf, &amt);
 2948         if (ret == 0 && ioc == ENCIOC_GETSTRING)
 2949                 ret = copyout(buf, sstr->buf, sstr->bufsiz);
 2950         if (ioc == ENCIOC_SETSTRING || ioc == ENCIOC_GETSTRING)
 2951                 ENC_FREE(buf);
 2952         return (ret);
 2953 }
 2954 
 2955 /**
 2956  * \invariant Called with cam_periph mutex held.
 2957  */
 2958 static void
 2959 ses_poll_status(enc_softc_t *enc)
 2960 {
 2961         ses_softc_t *ses;
 2962 
 2963         ses = enc->enc_private;
 2964         enc_update_request(enc, SES_UPDATE_GETSTATUS);
 2965         if (ses->ses_flags & SES_FLAG_DESC)
 2966                 enc_update_request(enc, SES_UPDATE_GETELMDESCS);
 2967         if (ses->ses_flags & SES_FLAG_ADDLSTATUS)
 2968                 enc_update_request(enc, SES_UPDATE_GETELMADDLSTATUS);
 2969 }
 2970 
 2971 /**
 2972  * \brief Notification received when CAM detects a new device in the
 2973  *        SCSI domain in which this SEP resides.
 2974  *
 2975  * \param enc   SES enclosure instance.
 2976  */
 2977 static void
 2978 ses_device_found(enc_softc_t *enc)
 2979 {
 2980         ses_poll_status(enc);
 2981         enc_update_request(enc, SES_PUBLISH_PHYSPATHS);
 2982 }
 2983 
 2984 static struct enc_vec ses_enc_vec =
 2985 {
 2986         .softc_invalidate       = ses_softc_invalidate,
 2987         .softc_cleanup          = ses_softc_cleanup,
 2988         .init_enc               = ses_init_enc,
 2989         .set_enc_status         = ses_set_enc_status,
 2990         .get_elm_status         = ses_get_elm_status,
 2991         .set_elm_status         = ses_set_elm_status,
 2992         .get_elm_desc           = ses_get_elm_desc,
 2993         .get_elm_devnames       = ses_get_elm_devnames,
 2994         .handle_string          = ses_handle_string,
 2995         .device_found           = ses_device_found,
 2996         .poll_status            = ses_poll_status
 2997 };
 2998 
 2999 /**
 3000  * \brief Initialize a new SES instance.
 3001  *
 3002  * \param enc           SES softc structure to set up the instance in.
 3003  * \param doinit        Do the initialization (see main driver).
 3004  *
 3005  * \return              0 on success, errno otherwise.
 3006  */
 3007 int
 3008 ses_softc_init(enc_softc_t *enc)
 3009 {
 3010         ses_softc_t *ses_softc;
 3011 
 3012         CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE,
 3013             ("entering enc_softc_init(%p)\n", enc));
 3014 
 3015         enc->enc_vec = ses_enc_vec;
 3016         enc->enc_fsm_states = enc_fsm_states;
 3017 
 3018         if (enc->enc_private == NULL)
 3019                 enc->enc_private = ENC_MALLOCZ(sizeof(ses_softc_t));
 3020         if (enc->enc_cache.private == NULL)
 3021                 enc->enc_cache.private = ENC_MALLOCZ(sizeof(ses_cache_t));
 3022         if (enc->enc_daemon_cache.private == NULL)
 3023                 enc->enc_daemon_cache.private =
 3024                      ENC_MALLOCZ(sizeof(ses_cache_t));
 3025 
 3026         if (enc->enc_private == NULL
 3027          || enc->enc_cache.private == NULL
 3028          || enc->enc_daemon_cache.private == NULL) {
 3029                 ENC_FREE_AND_NULL(enc->enc_private);
 3030                 ENC_FREE_AND_NULL(enc->enc_cache.private);
 3031                 ENC_FREE_AND_NULL(enc->enc_daemon_cache.private);
 3032                 return (ENOMEM);
 3033         }
 3034 
 3035         ses_softc = enc->enc_private;
 3036         TAILQ_INIT(&ses_softc->ses_requests);
 3037         TAILQ_INIT(&ses_softc->ses_pending_requests);
 3038 
 3039         enc_update_request(enc, SES_UPDATE_PAGES);
 3040 
 3041         // XXX: Move this to the FSM so it doesn't hang init
 3042         if (0) (void) ses_set_timed_completion(enc, 1);
 3043 
 3044         return (0);
 3045 }

Cache object: 390ad1b00a6fdd2a0d0ac625c989ca31


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