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/dev/sfxge/common/efx_vpd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2009-2016 Solarflare Communications Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions are met:
    9  *
   10  * 1. Redistributions of source code must retain the above copyright notice,
   11  *    this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright notice,
   13  *    this list of conditions and the following disclaimer in the documentation
   14  *    and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
   18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
   26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * The views and conclusions contained in the software and documentation are
   29  * those of the authors and should not be interpreted as representing official
   30  * policies, either expressed or implied, of the FreeBSD Project.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include "efx.h"
   37 #include "efx_impl.h"
   38 
   39 #if EFSYS_OPT_VPD
   40 
   41 #define TAG_TYPE_LBN 7
   42 #define TAG_TYPE_WIDTH 1
   43 #define TAG_TYPE_LARGE_ITEM_DECODE 1
   44 #define TAG_TYPE_SMALL_ITEM_DECODE 0
   45 
   46 #define TAG_SMALL_ITEM_NAME_LBN 3
   47 #define TAG_SMALL_ITEM_NAME_WIDTH 4
   48 #define TAG_SMALL_ITEM_SIZE_LBN 0
   49 #define TAG_SMALL_ITEM_SIZE_WIDTH 3
   50 
   51 #define TAG_LARGE_ITEM_NAME_LBN 0
   52 #define TAG_LARGE_ITEM_NAME_WIDTH 7
   53 
   54 #define TAG_NAME_END_DECODE 0x0f
   55 #define TAG_NAME_ID_STRING_DECODE 0x02
   56 #define TAG_NAME_VPD_R_DECODE 0x10
   57 #define TAG_NAME_VPD_W_DECODE 0x11
   58 
   59 #if EFSYS_OPT_SIENA
   60 
   61 static const efx_vpd_ops_t      __efx_vpd_siena_ops = {
   62         siena_vpd_init,         /* evpdo_init */
   63         siena_vpd_size,         /* evpdo_size */
   64         siena_vpd_read,         /* evpdo_read */
   65         siena_vpd_verify,       /* evpdo_verify */
   66         siena_vpd_reinit,       /* evpdo_reinit */
   67         siena_vpd_get,          /* evpdo_get */
   68         siena_vpd_set,          /* evpdo_set */
   69         siena_vpd_next,         /* evpdo_next */
   70         siena_vpd_write,        /* evpdo_write */
   71         siena_vpd_fini,         /* evpdo_fini */
   72 };
   73 
   74 #endif  /* EFSYS_OPT_SIENA */
   75 
   76 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
   77 
   78 static const efx_vpd_ops_t      __efx_vpd_ef10_ops = {
   79         ef10_vpd_init,          /* evpdo_init */
   80         ef10_vpd_size,          /* evpdo_size */
   81         ef10_vpd_read,          /* evpdo_read */
   82         ef10_vpd_verify,        /* evpdo_verify */
   83         ef10_vpd_reinit,        /* evpdo_reinit */
   84         ef10_vpd_get,           /* evpdo_get */
   85         ef10_vpd_set,           /* evpdo_set */
   86         ef10_vpd_next,          /* evpdo_next */
   87         ef10_vpd_write,         /* evpdo_write */
   88         ef10_vpd_fini,          /* evpdo_fini */
   89 };
   90 
   91 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
   92 
   93         __checkReturn           efx_rc_t
   94 efx_vpd_init(
   95         __in                    efx_nic_t *enp)
   96 {
   97         const efx_vpd_ops_t *evpdop;
   98         efx_rc_t rc;
   99 
  100         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  101         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
  102         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
  103 
  104         switch (enp->en_family) {
  105 #if EFSYS_OPT_SIENA
  106         case EFX_FAMILY_SIENA:
  107                 evpdop = &__efx_vpd_siena_ops;
  108                 break;
  109 #endif  /* EFSYS_OPT_SIENA */
  110 
  111 #if EFSYS_OPT_HUNTINGTON
  112         case EFX_FAMILY_HUNTINGTON:
  113                 evpdop = &__efx_vpd_ef10_ops;
  114                 break;
  115 #endif  /* EFSYS_OPT_HUNTINGTON */
  116 
  117 #if EFSYS_OPT_MEDFORD
  118         case EFX_FAMILY_MEDFORD:
  119                 evpdop = &__efx_vpd_ef10_ops;
  120                 break;
  121 #endif  /* EFSYS_OPT_MEDFORD */
  122 
  123 #if EFSYS_OPT_MEDFORD2
  124         case EFX_FAMILY_MEDFORD2:
  125                 evpdop = &__efx_vpd_ef10_ops;
  126                 break;
  127 #endif  /* EFSYS_OPT_MEDFORD2 */
  128 
  129         default:
  130                 EFSYS_ASSERT(0);
  131                 rc = ENOTSUP;
  132                 goto fail1;
  133         }
  134 
  135         if (evpdop->evpdo_init != NULL) {
  136                 if ((rc = evpdop->evpdo_init(enp)) != 0)
  137                         goto fail2;
  138         }
  139 
  140         enp->en_evpdop = evpdop;
  141         enp->en_mod_flags |= EFX_MOD_VPD;
  142 
  143         return (0);
  144 
  145 fail2:
  146         EFSYS_PROBE(fail2);
  147 fail1:
  148         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  149 
  150         return (rc);
  151 }
  152 
  153         __checkReturn           efx_rc_t
  154 efx_vpd_size(
  155         __in                    efx_nic_t *enp,
  156         __out                   size_t *sizep)
  157 {
  158         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  159         efx_rc_t rc;
  160 
  161         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  162         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  163 
  164         if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
  165                 goto fail1;
  166 
  167         return (0);
  168 
  169 fail1:
  170         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  171 
  172         return (rc);
  173 }
  174 
  175         __checkReturn           efx_rc_t
  176 efx_vpd_read(
  177         __in                    efx_nic_t *enp,
  178         __out_bcount(size)      caddr_t data,
  179         __in                    size_t size)
  180 {
  181         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  182         efx_rc_t rc;
  183 
  184         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  185         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  186 
  187         if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
  188                 goto fail1;
  189 
  190         return (0);
  191 
  192 fail1:
  193         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  194 
  195         return (rc);
  196 }
  197 
  198         __checkReturn           efx_rc_t
  199 efx_vpd_verify(
  200         __in                    efx_nic_t *enp,
  201         __in_bcount(size)       caddr_t data,
  202         __in                    size_t size)
  203 {
  204         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  205         efx_rc_t rc;
  206 
  207         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  208         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  209 
  210         if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
  211                 goto fail1;
  212 
  213         return (0);
  214 
  215 fail1:
  216         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  217 
  218         return (rc);
  219 }
  220 
  221         __checkReturn           efx_rc_t
  222 efx_vpd_reinit(
  223         __in                    efx_nic_t *enp,
  224         __in_bcount(size)       caddr_t data,
  225         __in                    size_t size)
  226 {
  227         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  228         efx_rc_t rc;
  229 
  230         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  231         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  232 
  233         if (evpdop->evpdo_reinit == NULL) {
  234                 rc = ENOTSUP;
  235                 goto fail1;
  236         }
  237 
  238         if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
  239                 goto fail2;
  240 
  241         return (0);
  242 
  243 fail2:
  244         EFSYS_PROBE(fail2);
  245 fail1:
  246         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  247 
  248         return (rc);
  249 }
  250 
  251         __checkReturn           efx_rc_t
  252 efx_vpd_get(
  253         __in                    efx_nic_t *enp,
  254         __in_bcount(size)       caddr_t data,
  255         __in                    size_t size,
  256         __inout                 efx_vpd_value_t *evvp)
  257 {
  258         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  259         efx_rc_t rc;
  260 
  261         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  262         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  263 
  264         if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
  265                 if (rc == ENOENT)
  266                         return (rc);
  267 
  268                 goto fail1;
  269         }
  270 
  271         return (0);
  272 
  273 fail1:
  274         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  275 
  276         return (rc);
  277 }
  278 
  279         __checkReturn           efx_rc_t
  280 efx_vpd_set(
  281         __in                    efx_nic_t *enp,
  282         __inout_bcount(size)    caddr_t data,
  283         __in                    size_t size,
  284         __in                    efx_vpd_value_t *evvp)
  285 {
  286         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  287         efx_rc_t rc;
  288 
  289         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  290         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  291 
  292         if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
  293                 goto fail1;
  294 
  295         return (0);
  296 
  297 fail1:
  298         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  299 
  300         return (rc);
  301 }
  302 
  303         __checkReturn           efx_rc_t
  304 efx_vpd_next(
  305         __in                    efx_nic_t *enp,
  306         __inout_bcount(size)    caddr_t data,
  307         __in                    size_t size,
  308         __out                   efx_vpd_value_t *evvp,
  309         __inout                 unsigned int *contp)
  310 {
  311         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  312         efx_rc_t rc;
  313 
  314         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  315         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  316 
  317         if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
  318                 goto fail1;
  319 
  320         return (0);
  321 
  322 fail1:
  323         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  324 
  325         return (rc);
  326 }
  327 
  328         __checkReturn           efx_rc_t
  329 efx_vpd_write(
  330         __in                    efx_nic_t *enp,
  331         __in_bcount(size)       caddr_t data,
  332         __in                    size_t size)
  333 {
  334         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
  335         efx_rc_t rc;
  336 
  337         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  338         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
  339 
  340         if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
  341                 goto fail1;
  342 
  343         return (0);
  344 
  345 fail1:
  346         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  347 
  348         return (rc);
  349 }
  350 
  351 static  __checkReturn           efx_rc_t
  352 efx_vpd_next_tag(
  353         __in                    caddr_t data,
  354         __in                    size_t size,
  355         __inout                 unsigned int *offsetp,
  356         __out                   efx_vpd_tag_t *tagp,
  357         __out                   uint16_t *lengthp)
  358 {
  359         efx_byte_t byte;
  360         efx_word_t word;
  361         uint8_t name;
  362         uint16_t length;
  363         size_t headlen;
  364         efx_rc_t rc;
  365 
  366         if (*offsetp >= size) {
  367                 rc = EFAULT;
  368                 goto fail1;
  369         }
  370 
  371         EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
  372 
  373         switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
  374         case TAG_TYPE_SMALL_ITEM_DECODE:
  375                 headlen = 1;
  376 
  377                 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
  378                 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
  379 
  380                 break;
  381 
  382         case TAG_TYPE_LARGE_ITEM_DECODE:
  383                 headlen = 3;
  384 
  385                 if (*offsetp + headlen > size) {
  386                         rc = EFAULT;
  387                         goto fail2;
  388                 }
  389 
  390                 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
  391                 EFX_POPULATE_WORD_2(word,
  392                                     EFX_BYTE_0, data[*offsetp + 1],
  393                                     EFX_BYTE_1, data[*offsetp + 2]);
  394                 length = EFX_WORD_FIELD(word, EFX_WORD_0);
  395 
  396                 break;
  397 
  398         default:
  399                 rc = EFAULT;
  400                 goto fail2;
  401         }
  402 
  403         if (*offsetp + headlen + length > size) {
  404                 rc = EFAULT;
  405                 goto fail3;
  406         }
  407 
  408         EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
  409         EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
  410         EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
  411         EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
  412         if (name != EFX_VPD_END && name != EFX_VPD_ID &&
  413             name != EFX_VPD_RO) {
  414                 rc = EFAULT;
  415                 goto fail4;
  416         }
  417 
  418         *tagp = name;
  419         *lengthp = length;
  420         *offsetp += headlen;
  421 
  422         return (0);
  423 
  424 fail4:
  425         EFSYS_PROBE(fail4);
  426 fail3:
  427         EFSYS_PROBE(fail3);
  428 fail2:
  429         EFSYS_PROBE(fail2);
  430 fail1:
  431         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  432 
  433         return (rc);
  434 }
  435 
  436 static  __checkReturn           efx_rc_t
  437 efx_vpd_next_keyword(
  438         __in_bcount(size)       caddr_t tag,
  439         __in                    size_t size,
  440         __in                    unsigned int pos,
  441         __out                   efx_vpd_keyword_t *keywordp,
  442         __out                   uint8_t *lengthp)
  443 {
  444         efx_vpd_keyword_t keyword;
  445         uint8_t length;
  446         efx_rc_t rc;
  447 
  448         if (pos + 3U > size) {
  449                 rc = EFAULT;
  450                 goto fail1;
  451         }
  452 
  453         keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
  454         length = tag[pos + 2];
  455 
  456         if (length == 0 || pos + 3U + length > size) {
  457                 rc = EFAULT;
  458                 goto fail2;
  459         }
  460 
  461         *keywordp = keyword;
  462         *lengthp = length;
  463 
  464         return (0);
  465 
  466 fail2:
  467         EFSYS_PROBE(fail2);
  468 fail1:
  469         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  470 
  471         return (rc);
  472 }
  473 
  474         __checkReturn           efx_rc_t
  475 efx_vpd_hunk_length(
  476         __in_bcount(size)       caddr_t data,
  477         __in                    size_t size,
  478         __out                   size_t *lengthp)
  479 {
  480         efx_vpd_tag_t tag;
  481         unsigned int offset;
  482         uint16_t taglen;
  483         efx_rc_t rc;
  484 
  485         offset = 0;
  486         _NOTE(CONSTANTCONDITION)
  487         while (1) {
  488                 if ((rc = efx_vpd_next_tag(data, size, &offset,
  489                     &tag, &taglen)) != 0)
  490                         goto fail1;
  491                 offset += taglen;
  492                 if (tag == EFX_VPD_END)
  493                         break;
  494         }
  495 
  496         *lengthp = offset;
  497 
  498         return (0);
  499 
  500 fail1:
  501         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  502 
  503         return (rc);
  504 }
  505 
  506         __checkReturn           efx_rc_t
  507 efx_vpd_hunk_verify(
  508         __in_bcount(size)       caddr_t data,
  509         __in                    size_t size,
  510         __out_opt               boolean_t *cksummedp)
  511 {
  512         efx_vpd_tag_t tag;
  513         efx_vpd_keyword_t keyword;
  514         unsigned int offset;
  515         unsigned int pos;
  516         unsigned int i;
  517         uint16_t taglen;
  518         uint8_t keylen;
  519         uint8_t cksum;
  520         boolean_t cksummed = B_FALSE;
  521         efx_rc_t rc;
  522 
  523         /*
  524          * Parse every tag,keyword in the existing VPD. If the csum is present,
  525          * the assert it is correct, and is the final keyword in the RO block.
  526          */
  527         offset = 0;
  528         _NOTE(CONSTANTCONDITION)
  529         while (1) {
  530                 if ((rc = efx_vpd_next_tag(data, size, &offset,
  531                     &tag, &taglen)) != 0)
  532                         goto fail1;
  533                 if (tag == EFX_VPD_END)
  534                         break;
  535                 else if (tag == EFX_VPD_ID)
  536                         goto done;
  537 
  538                 for (pos = 0; pos != taglen; pos += 3 + keylen) {
  539                         /* RV keyword must be the last in the block */
  540                         if (cksummed) {
  541                                 rc = EFAULT;
  542                                 goto fail2;
  543                         }
  544 
  545                         if ((rc = efx_vpd_next_keyword(data + offset,
  546                             taglen, pos, &keyword, &keylen)) != 0)
  547                                 goto fail3;
  548 
  549                         if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
  550                                 cksum = 0;
  551                                 for (i = 0; i < offset + pos + 4; i++)
  552                                         cksum += data[i];
  553 
  554                                 if (cksum != 0) {
  555                                         rc = EFAULT;
  556                                         goto fail4;
  557                                 }
  558 
  559                                 cksummed = B_TRUE;
  560                         }
  561                 }
  562 
  563         done:
  564                 offset += taglen;
  565         }
  566 
  567         if (!cksummed) {
  568                 rc = EFAULT;
  569                 goto fail5;
  570         }
  571 
  572         if (cksummedp != NULL)
  573                 *cksummedp = cksummed;
  574 
  575         return (0);
  576 
  577 fail5:
  578         EFSYS_PROBE(fail5);
  579 fail4:
  580         EFSYS_PROBE(fail4);
  581 fail3:
  582         EFSYS_PROBE(fail3);
  583 fail2:
  584         EFSYS_PROBE(fail2);
  585 fail1:
  586         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  587 
  588         return (rc);
  589 }
  590 
  591 static  uint8_t __efx_vpd_blank_pid[] = {
  592         /* Large resource type ID length 1 */
  593         0x82, 0x01, 0x00,
  594         /* Product name ' ' */
  595         0x32,
  596 };
  597 
  598 static uint8_t __efx_vpd_blank_r[] = {
  599         /* Large resource type VPD-R length 4 */
  600         0x90, 0x04, 0x00,
  601         /* RV keyword length 1 */
  602         'R', 'V', 0x01,
  603         /* RV payload checksum */
  604         0x00,
  605 };
  606 
  607         __checkReturn           efx_rc_t
  608 efx_vpd_hunk_reinit(
  609         __in_bcount(size)       caddr_t data,
  610         __in                    size_t size,
  611         __in                    boolean_t wantpid)
  612 {
  613         unsigned int offset = 0;
  614         unsigned int pos;
  615         efx_byte_t byte;
  616         uint8_t cksum;
  617         efx_rc_t rc;
  618 
  619         if (size < 0x100) {
  620                 rc = ENOSPC;
  621                 goto fail1;
  622         }
  623 
  624         if (wantpid) {
  625                 memcpy(data + offset, __efx_vpd_blank_pid,
  626                     sizeof (__efx_vpd_blank_pid));
  627                 offset += sizeof (__efx_vpd_blank_pid);
  628         }
  629 
  630         memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
  631         offset += sizeof (__efx_vpd_blank_r);
  632 
  633         /* Update checksum */
  634         cksum = 0;
  635         for (pos = 0; pos < offset; pos++)
  636                 cksum += data[pos];
  637         data[offset - 1] -= cksum;
  638 
  639         /* Append trailing tag */
  640         EFX_POPULATE_BYTE_3(byte,
  641                             TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
  642                             TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
  643                             TAG_SMALL_ITEM_SIZE, 0);
  644         data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
  645         offset++;
  646 
  647         return (0);
  648 
  649 fail1:
  650         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  651 
  652         return (rc);
  653 }
  654 
  655         __checkReturn                   efx_rc_t
  656 efx_vpd_hunk_next(
  657         __in_bcount(size)               caddr_t data,
  658         __in                            size_t size,
  659         __out                           efx_vpd_tag_t *tagp,
  660         __out                           efx_vpd_keyword_t *keywordp,
  661         __out_opt                       unsigned int *payloadp,
  662         __out_opt                       uint8_t *paylenp,
  663         __inout                         unsigned int *contp)
  664 {
  665         efx_vpd_tag_t tag;
  666         efx_vpd_keyword_t keyword = 0;
  667         unsigned int offset;
  668         unsigned int pos;
  669         unsigned int index;
  670         uint16_t taglen;
  671         uint8_t keylen;
  672         uint8_t paylen;
  673         efx_rc_t rc;
  674 
  675         offset = index = 0;
  676         _NOTE(CONSTANTCONDITION)
  677         while (1) {
  678                 if ((rc = efx_vpd_next_tag(data, size, &offset,
  679                     &tag, &taglen)) != 0)
  680                         goto fail1;
  681 
  682                 if (tag == EFX_VPD_END) {
  683                         keyword = 0;
  684                         paylen = 0;
  685                         index = 0;
  686                         break;
  687                 }
  688 
  689                 if (tag == EFX_VPD_ID) {
  690                         if (index++ == *contp) {
  691                                 EFSYS_ASSERT3U(taglen, <, 0x100);
  692                                 keyword = 0;
  693                                 paylen = (uint8_t)MIN(taglen, 0xff);
  694 
  695                                 goto done;
  696                         }
  697                 } else {
  698                         for (pos = 0; pos != taglen; pos += 3 + keylen) {
  699                                 if ((rc = efx_vpd_next_keyword(data + offset,
  700                                     taglen, pos, &keyword, &keylen)) != 0)
  701                                         goto fail2;
  702 
  703                                 if (index++ == *contp) {
  704                                         offset += pos + 3;
  705                                         paylen = keylen;
  706 
  707                                         goto done;
  708                                 }
  709                         }
  710                 }
  711 
  712                 offset += taglen;
  713         }
  714 
  715 done:
  716         *tagp = tag;
  717         *keywordp = keyword;
  718         if (payloadp != NULL)
  719                 *payloadp = offset;
  720         if (paylenp != NULL)
  721                 *paylenp = paylen;
  722 
  723         *contp = index;
  724         return (0);
  725 
  726 fail2:
  727         EFSYS_PROBE(fail2);
  728 fail1:
  729         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  730 
  731         return (rc);
  732 }
  733 
  734         __checkReturn           efx_rc_t
  735 efx_vpd_hunk_get(
  736         __in_bcount(size)       caddr_t data,
  737         __in                    size_t size,
  738         __in                    efx_vpd_tag_t tag,
  739         __in                    efx_vpd_keyword_t keyword,
  740         __out                   unsigned int *payloadp,
  741         __out                   uint8_t *paylenp)
  742 {
  743         efx_vpd_tag_t itag;
  744         efx_vpd_keyword_t ikeyword;
  745         unsigned int offset;
  746         unsigned int pos;
  747         uint16_t taglen;
  748         uint8_t keylen;
  749         efx_rc_t rc;
  750 
  751         offset = 0;
  752         _NOTE(CONSTANTCONDITION)
  753         while (1) {
  754                 if ((rc = efx_vpd_next_tag(data, size, &offset,
  755                     &itag, &taglen)) != 0)
  756                         goto fail1;
  757                 if (itag == EFX_VPD_END)
  758                         break;
  759 
  760                 if (itag == tag) {
  761                         if (itag == EFX_VPD_ID) {
  762                                 EFSYS_ASSERT3U(taglen, <, 0x100);
  763 
  764                                 *paylenp = (uint8_t)MIN(taglen, 0xff);
  765                                 *payloadp = offset;
  766                                 return (0);
  767                         }
  768 
  769                         for (pos = 0; pos != taglen; pos += 3 + keylen) {
  770                                 if ((rc = efx_vpd_next_keyword(data + offset,
  771                                     taglen, pos, &ikeyword, &keylen)) != 0)
  772                                         goto fail2;
  773 
  774                                 if (ikeyword == keyword) {
  775                                         *paylenp = keylen;
  776                                         *payloadp = offset + pos + 3;
  777                                         return (0);
  778                                 }
  779                         }
  780                 }
  781 
  782                 offset += taglen;
  783         }
  784 
  785         /* Not an error */
  786         return (ENOENT);
  787 
  788 fail2:
  789         EFSYS_PROBE(fail2);
  790 fail1:
  791         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  792 
  793         return (rc);
  794 }
  795 
  796         __checkReturn           efx_rc_t
  797 efx_vpd_hunk_set(
  798         __in_bcount(size)       caddr_t data,
  799         __in                    size_t size,
  800         __in                    efx_vpd_value_t *evvp)
  801 {
  802         efx_word_t word;
  803         efx_vpd_tag_t tag;
  804         efx_vpd_keyword_t keyword;
  805         unsigned int offset;
  806         unsigned int pos;
  807         unsigned int taghead;
  808         unsigned int source;
  809         unsigned int dest;
  810         unsigned int i;
  811         uint16_t taglen;
  812         uint8_t keylen;
  813         uint8_t cksum;
  814         size_t used;
  815         efx_rc_t rc;
  816 
  817         switch (evvp->evv_tag) {
  818         case EFX_VPD_ID:
  819                 if (evvp->evv_keyword != 0) {
  820                         rc = EINVAL;
  821                         goto fail1;
  822                 }
  823 
  824                 /* Can't delete the ID keyword */
  825                 if (evvp->evv_length == 0) {
  826                         rc = EINVAL;
  827                         goto fail1;
  828                 }
  829                 break;
  830 
  831         case EFX_VPD_RO:
  832                 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
  833                         rc = EINVAL;
  834                         goto fail1;
  835                 }
  836                 break;
  837 
  838         default:
  839                 rc = EINVAL;
  840                 goto fail1;
  841         }
  842 
  843         /* Determine total size of all current tags */
  844         if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
  845                 goto fail2;
  846 
  847         offset = 0;
  848         _NOTE(CONSTANTCONDITION)
  849         while (1) {
  850                 taghead = offset;
  851                 if ((rc = efx_vpd_next_tag(data, size, &offset,
  852                     &tag, &taglen)) != 0)
  853                         goto fail3;
  854                 if (tag == EFX_VPD_END)
  855                         break;
  856                 else if (tag != evvp->evv_tag) {
  857                         offset += taglen;
  858                         continue;
  859                 }
  860 
  861                 /* We only support modifying large resource tags */
  862                 if (offset - taghead != 3) {
  863                         rc = EINVAL;
  864                         goto fail4;
  865                 }
  866 
  867                 /*
  868                  * Work out the offset of the byte immediately after the
  869                  * old (=source) and new (=dest) new keyword/tag
  870                  */
  871                 pos = 0;
  872                 if (tag == EFX_VPD_ID) {
  873                         source = offset + taglen;
  874                         dest = offset + evvp->evv_length;
  875                         goto check_space;
  876                 }
  877 
  878                 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
  879                 source = dest = 0;
  880                 for (pos = 0; pos != taglen; pos += 3 + keylen) {
  881                         if ((rc = efx_vpd_next_keyword(data + offset,
  882                             taglen, pos, &keyword, &keylen)) != 0)
  883                                 goto fail5;
  884 
  885                         if (keyword == evvp->evv_keyword &&
  886                             evvp->evv_length == 0) {
  887                                 /* Deleting this keyword */
  888                                 source = offset + pos + 3 + keylen;
  889                                 dest = offset + pos;
  890                                 break;
  891 
  892                         } else if (keyword == evvp->evv_keyword) {
  893                                 /* Adjusting this keyword */
  894                                 source = offset + pos + 3 + keylen;
  895                                 dest = offset + pos + 3 + evvp->evv_length;
  896                                 break;
  897 
  898                         } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
  899                                 /* The RV keyword must be at the end */
  900                                 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
  901 
  902                                 /*
  903                                  * The keyword doesn't already exist. If the
  904                                  * user deleting a non-existent keyword then
  905                                  * this is a no-op.
  906                                  */
  907                                 if (evvp->evv_length == 0)
  908                                         return (0);
  909 
  910                                 /* Insert this keyword before the RV keyword */
  911                                 source = offset + pos;
  912                                 dest = offset + pos + 3 + evvp->evv_length;
  913                                 break;
  914                         }
  915                 }
  916 
  917         check_space:
  918                 if (used + dest > size + source) {
  919                         rc = ENOSPC;
  920                         goto fail6;
  921                 }
  922 
  923                 /* Move trailing data */
  924                 (void) memmove(data + dest, data + source, used - source);
  925 
  926                 /* Copy contents */
  927                 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
  928                     evvp->evv_length);
  929 
  930                 /* Insert new keyword header if required */
  931                 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
  932                         EFX_POPULATE_WORD_1(word, EFX_WORD_0,
  933                                             evvp->evv_keyword);
  934                         data[offset + pos + 0] =
  935                             EFX_WORD_FIELD(word, EFX_BYTE_0);
  936                         data[offset + pos + 1] =
  937                             EFX_WORD_FIELD(word, EFX_BYTE_1);
  938                         data[offset + pos + 2] = evvp->evv_length;
  939                 }
  940 
  941                 /* Modify tag length (large resource type) */
  942                 taglen += (uint16_t)(dest - source);
  943                 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
  944                 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
  945                 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
  946 
  947                 goto checksum;
  948         }
  949 
  950         /* Unable to find the matching tag */
  951         rc = ENOENT;
  952         goto fail7;
  953 
  954 checksum:
  955         /* Find the RV tag, and update the checksum */
  956         offset = 0;
  957         _NOTE(CONSTANTCONDITION)
  958         while (1) {
  959                 if ((rc = efx_vpd_next_tag(data, size, &offset,
  960                     &tag, &taglen)) != 0)
  961                         goto fail8;
  962                 if (tag == EFX_VPD_END)
  963                         break;
  964                 if (tag == EFX_VPD_RO) {
  965                         for (pos = 0; pos != taglen; pos += 3 + keylen) {
  966                                 if ((rc = efx_vpd_next_keyword(data + offset,
  967                                     taglen, pos, &keyword, &keylen)) != 0)
  968                                         goto fail9;
  969 
  970                                 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
  971                                         cksum = 0;
  972                                         for (i = 0; i < offset + pos + 3; i++)
  973                                                 cksum += data[i];
  974                                         data[i] = -cksum;
  975                                         break;
  976                                 }
  977                         }
  978                 }
  979 
  980                 offset += taglen;
  981         }
  982 
  983         /* Zero out the unused portion */
  984         (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
  985 
  986         return (0);
  987 
  988 fail9:
  989         EFSYS_PROBE(fail9);
  990 fail8:
  991         EFSYS_PROBE(fail8);
  992 fail7:
  993         EFSYS_PROBE(fail7);
  994 fail6:
  995         EFSYS_PROBE(fail6);
  996 fail5:
  997         EFSYS_PROBE(fail5);
  998 fail4:
  999         EFSYS_PROBE(fail4);
 1000 fail3:
 1001         EFSYS_PROBE(fail3);
 1002 fail2:
 1003         EFSYS_PROBE(fail2);
 1004 fail1:
 1005         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1006 
 1007         return (rc);
 1008 }
 1009 
 1010                                 void
 1011 efx_vpd_fini(
 1012         __in                    efx_nic_t *enp)
 1013 {
 1014         const efx_vpd_ops_t *evpdop = enp->en_evpdop;
 1015 
 1016         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 1017         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 1018         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
 1019 
 1020         if (evpdop->evpdo_fini != NULL)
 1021                 evpdop->evpdo_fini(enp);
 1022 
 1023         enp->en_evpdop = NULL;
 1024         enp->en_mod_flags &= ~EFX_MOD_VPD;
 1025 }
 1026 
 1027 #endif  /* EFSYS_OPT_VPD */

Cache object: 1ca5cfcf721ef4d30e0f200a635ffb26


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