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

Cache object: 4e10b8e81721ad788029f18f82d44ebb


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