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_mcdi.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) 2008-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_MCDI
   40 
   41 /*
   42  * There are three versions of the MCDI interface:
   43  *  - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers.
   44  *  - MCDIv1: Siena firmware and Huntington BootROM.
   45  *  - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM.
   46  *            Transport uses MCDIv2 headers.
   47  *
   48  * MCDIv2 Header NOT_EPOCH flag
   49  * ----------------------------
   50  * A new epoch begins at initial startup or after an MC reboot, and defines when
   51  * the MC should reject stale MCDI requests.
   52  *
   53  * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
   54  * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
   55  *
   56  * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
   57  * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
   58  */
   59 
   60 #if EFSYS_OPT_SIENA
   61 
   62 static const efx_mcdi_ops_t     __efx_mcdi_siena_ops = {
   63         siena_mcdi_init,                /* emco_init */
   64         siena_mcdi_send_request,        /* emco_send_request */
   65         siena_mcdi_poll_reboot,         /* emco_poll_reboot */
   66         siena_mcdi_poll_response,       /* emco_poll_response */
   67         siena_mcdi_read_response,       /* emco_read_response */
   68         siena_mcdi_fini,                /* emco_fini */
   69         siena_mcdi_feature_supported,   /* emco_feature_supported */
   70         siena_mcdi_get_timeout,         /* emco_get_timeout */
   71 };
   72 
   73 #endif  /* EFSYS_OPT_SIENA */
   74 
   75 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
   76 
   77 static const efx_mcdi_ops_t     __efx_mcdi_ef10_ops = {
   78         ef10_mcdi_init,                 /* emco_init */
   79         ef10_mcdi_send_request,         /* emco_send_request */
   80         ef10_mcdi_poll_reboot,          /* emco_poll_reboot */
   81         ef10_mcdi_poll_response,        /* emco_poll_response */
   82         ef10_mcdi_read_response,        /* emco_read_response */
   83         ef10_mcdi_fini,                 /* emco_fini */
   84         ef10_mcdi_feature_supported,    /* emco_feature_supported */
   85         ef10_mcdi_get_timeout,          /* emco_get_timeout */
   86 };
   87 
   88 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
   89 
   90         __checkReturn   efx_rc_t
   91 efx_mcdi_init(
   92         __in            efx_nic_t *enp,
   93         __in            const efx_mcdi_transport_t *emtp)
   94 {
   95         const efx_mcdi_ops_t *emcop;
   96         efx_rc_t rc;
   97 
   98         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
   99         EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
  100 
  101         switch (enp->en_family) {
  102 #if EFSYS_OPT_SIENA
  103         case EFX_FAMILY_SIENA:
  104                 emcop = &__efx_mcdi_siena_ops;
  105                 break;
  106 #endif  /* EFSYS_OPT_SIENA */
  107 
  108 #if EFSYS_OPT_HUNTINGTON
  109         case EFX_FAMILY_HUNTINGTON:
  110                 emcop = &__efx_mcdi_ef10_ops;
  111                 break;
  112 #endif  /* EFSYS_OPT_HUNTINGTON */
  113 
  114 #if EFSYS_OPT_MEDFORD
  115         case EFX_FAMILY_MEDFORD:
  116                 emcop = &__efx_mcdi_ef10_ops;
  117                 break;
  118 #endif  /* EFSYS_OPT_MEDFORD */
  119 
  120 #if EFSYS_OPT_MEDFORD2
  121         case EFX_FAMILY_MEDFORD2:
  122                 emcop = &__efx_mcdi_ef10_ops;
  123                 break;
  124 #endif  /* EFSYS_OPT_MEDFORD2 */
  125 
  126         default:
  127                 EFSYS_ASSERT(0);
  128                 rc = ENOTSUP;
  129                 goto fail1;
  130         }
  131 
  132         if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
  133                 /* MCDI requires a DMA buffer in host memory */
  134                 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
  135                         rc = EINVAL;
  136                         goto fail2;
  137                 }
  138         }
  139         enp->en_mcdi.em_emtp = emtp;
  140 
  141         if (emcop != NULL && emcop->emco_init != NULL) {
  142                 if ((rc = emcop->emco_init(enp, emtp)) != 0)
  143                         goto fail3;
  144         }
  145 
  146         enp->en_mcdi.em_emcop = emcop;
  147         enp->en_mod_flags |= EFX_MOD_MCDI;
  148 
  149         return (0);
  150 
  151 fail3:
  152         EFSYS_PROBE(fail3);
  153 fail2:
  154         EFSYS_PROBE(fail2);
  155 fail1:
  156         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  157 
  158         enp->en_mcdi.em_emcop = NULL;
  159         enp->en_mcdi.em_emtp = NULL;
  160         enp->en_mod_flags &= ~EFX_MOD_MCDI;
  161 
  162         return (rc);
  163 }
  164 
  165                         void
  166 efx_mcdi_fini(
  167         __in            efx_nic_t *enp)
  168 {
  169         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  170         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
  171 
  172         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  173         EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
  174 
  175         if (emcop != NULL && emcop->emco_fini != NULL)
  176                 emcop->emco_fini(enp);
  177 
  178         emip->emi_port = 0;
  179         emip->emi_aborted = 0;
  180 
  181         enp->en_mcdi.em_emcop = NULL;
  182         enp->en_mod_flags &= ~EFX_MOD_MCDI;
  183 }
  184 
  185                         void
  186 efx_mcdi_new_epoch(
  187         __in            efx_nic_t *enp)
  188 {
  189         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  190         efsys_lock_state_t state;
  191 
  192         /* Start a new epoch (allow fresh MCDI requests to succeed) */
  193         EFSYS_LOCK(enp->en_eslp, state);
  194         emip->emi_new_epoch = B_TRUE;
  195         EFSYS_UNLOCK(enp->en_eslp, state);
  196 }
  197 
  198 static                  void
  199 efx_mcdi_send_request(
  200         __in            efx_nic_t *enp,
  201         __in            void *hdrp,
  202         __in            size_t hdr_len,
  203         __in            void *sdup,
  204         __in            size_t sdu_len)
  205 {
  206         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
  207 
  208         emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len);
  209 }
  210 
  211 static                  efx_rc_t
  212 efx_mcdi_poll_reboot(
  213         __in            efx_nic_t *enp)
  214 {
  215         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
  216         efx_rc_t rc;
  217 
  218         rc = emcop->emco_poll_reboot(enp);
  219         return (rc);
  220 }
  221 
  222 static                  boolean_t
  223 efx_mcdi_poll_response(
  224         __in            efx_nic_t *enp)
  225 {
  226         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
  227         boolean_t available;
  228 
  229         available = emcop->emco_poll_response(enp);
  230         return (available);
  231 }
  232 
  233 static                  void
  234 efx_mcdi_read_response(
  235         __in            efx_nic_t *enp,
  236         __out           void *bufferp,
  237         __in            size_t offset,
  238         __in            size_t length)
  239 {
  240         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
  241 
  242         emcop->emco_read_response(enp, bufferp, offset, length);
  243 }
  244 
  245                         void
  246 efx_mcdi_request_start(
  247         __in            efx_nic_t *enp,
  248         __in            efx_mcdi_req_t *emrp,
  249         __in            boolean_t ev_cpl)
  250 {
  251 #if EFSYS_OPT_MCDI_LOGGING
  252         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  253 #endif
  254         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  255         efx_dword_t hdr[2];
  256         size_t hdr_len;
  257         unsigned int max_version;
  258         unsigned int seq;
  259         unsigned int xflags;
  260         boolean_t new_epoch;
  261         efsys_lock_state_t state;
  262 
  263         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  264         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
  265         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
  266 
  267         /*
  268          * efx_mcdi_request_start() is naturally serialised against both
  269          * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
  270          * by virtue of there only being one outstanding MCDI request.
  271          * Unfortunately, upper layers may also call efx_mcdi_request_abort()
  272          * at any time, to timeout a pending mcdi request, That request may
  273          * then subsequently complete, meaning efx_mcdi_ev_cpl() or
  274          * efx_mcdi_ev_death() may end up running in parallel with
  275          * efx_mcdi_request_start(). This race is handled by ensuring that
  276          * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
  277          * en_eslp lock.
  278          */
  279         EFSYS_LOCK(enp->en_eslp, state);
  280         EFSYS_ASSERT(emip->emi_pending_req == NULL);
  281         emip->emi_pending_req = emrp;
  282         emip->emi_ev_cpl = ev_cpl;
  283         emip->emi_poll_cnt = 0;
  284         seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
  285         new_epoch = emip->emi_new_epoch;
  286         max_version = emip->emi_max_version;
  287         EFSYS_UNLOCK(enp->en_eslp, state);
  288 
  289         xflags = 0;
  290         if (ev_cpl)
  291                 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
  292 
  293         /*
  294          * Huntington firmware supports MCDIv2, but the Huntington BootROM only
  295          * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where
  296          * possible to support this.
  297          */
  298         if ((max_version >= 2) &&
  299             ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) ||
  300             (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1) ||
  301             (emrp->emr_out_length > MCDI_CTL_SDU_LEN_MAX_V1))) {
  302                 /* Construct MCDI v2 header */
  303                 hdr_len = sizeof (hdr);
  304                 EFX_POPULATE_DWORD_8(hdr[0],
  305                     MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
  306                     MCDI_HEADER_RESYNC, 1,
  307                     MCDI_HEADER_DATALEN, 0,
  308                     MCDI_HEADER_SEQ, seq,
  309                     MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
  310                     MCDI_HEADER_ERROR, 0,
  311                     MCDI_HEADER_RESPONSE, 0,
  312                     MCDI_HEADER_XFLAGS, xflags);
  313 
  314                 EFX_POPULATE_DWORD_2(hdr[1],
  315                     MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
  316                     MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
  317         } else {
  318                 /* Construct MCDI v1 header */
  319                 hdr_len = sizeof (hdr[0]);
  320                 EFX_POPULATE_DWORD_8(hdr[0],
  321                     MCDI_HEADER_CODE, emrp->emr_cmd,
  322                     MCDI_HEADER_RESYNC, 1,
  323                     MCDI_HEADER_DATALEN, emrp->emr_in_length,
  324                     MCDI_HEADER_SEQ, seq,
  325                     MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
  326                     MCDI_HEADER_ERROR, 0,
  327                     MCDI_HEADER_RESPONSE, 0,
  328                     MCDI_HEADER_XFLAGS, xflags);
  329         }
  330 
  331 #if EFSYS_OPT_MCDI_LOGGING
  332         if (emtp->emt_logger != NULL) {
  333                 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
  334                     &hdr, hdr_len,
  335                     emrp->emr_in_buf, emrp->emr_in_length);
  336         }
  337 #endif /* EFSYS_OPT_MCDI_LOGGING */
  338 
  339         efx_mcdi_send_request(enp, &hdr[0], hdr_len,
  340             emrp->emr_in_buf, emrp->emr_in_length);
  341 }
  342 
  343 static                  void
  344 efx_mcdi_read_response_header(
  345         __in            efx_nic_t *enp,
  346         __inout         efx_mcdi_req_t *emrp)
  347 {
  348 #if EFSYS_OPT_MCDI_LOGGING
  349         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  350 #endif /* EFSYS_OPT_MCDI_LOGGING */
  351         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  352         efx_dword_t hdr[2];
  353         unsigned int hdr_len;
  354         unsigned int data_len;
  355         unsigned int seq;
  356         unsigned int cmd;
  357         unsigned int error;
  358         efx_rc_t rc;
  359 
  360         EFSYS_ASSERT(emrp != NULL);
  361 
  362         efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
  363         hdr_len = sizeof (hdr[0]);
  364 
  365         cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
  366         seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
  367         error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
  368 
  369         if (cmd != MC_CMD_V2_EXTN) {
  370                 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
  371         } else {
  372                 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
  373                 hdr_len += sizeof (hdr[1]);
  374 
  375                 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
  376                 data_len =
  377                     EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
  378         }
  379 
  380         if (error && (data_len == 0)) {
  381                 /* The MC has rebooted since the request was sent. */
  382                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
  383                 efx_mcdi_poll_reboot(enp);
  384                 rc = EIO;
  385                 goto fail1;
  386         }
  387         if ((cmd != emrp->emr_cmd) ||
  388             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
  389                 /* Response is for a different request */
  390                 rc = EIO;
  391                 goto fail2;
  392         }
  393         if (error) {
  394                 efx_dword_t err[2];
  395                 unsigned int err_len = MIN(data_len, sizeof (err));
  396                 int err_code = MC_CMD_ERR_EPROTO;
  397                 int err_arg = 0;
  398 
  399                 /* Read error code (and arg num for MCDI v2 commands) */
  400                 efx_mcdi_read_response(enp, &err, hdr_len, err_len);
  401 
  402                 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
  403                         err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
  404 #ifdef WITH_MCDI_V2
  405                 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
  406                         err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
  407 #endif
  408                 emrp->emr_err_code = err_code;
  409                 emrp->emr_err_arg = err_arg;
  410 
  411 #if EFSYS_OPT_MCDI_PROXY_AUTH
  412                 if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
  413                     (err_len == sizeof (err))) {
  414                         /*
  415                          * The MCDI request would normally fail with EPERM, but
  416                          * firmware has forwarded it to an authorization agent
  417                          * attached to a privileged PF.
  418                          *
  419                          * Save the authorization request handle. The client
  420                          * must wait for a PROXY_RESPONSE event, or timeout.
  421                          */
  422                         emrp->emr_proxy_handle = err_arg;
  423                 }
  424 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
  425 
  426 #if EFSYS_OPT_MCDI_LOGGING
  427                 if (emtp->emt_logger != NULL) {
  428                         emtp->emt_logger(emtp->emt_context,
  429                             EFX_LOG_MCDI_RESPONSE,
  430                             &hdr, hdr_len,
  431                             &err, err_len);
  432                 }
  433 #endif /* EFSYS_OPT_MCDI_LOGGING */
  434 
  435                 if (!emrp->emr_quiet) {
  436                         EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
  437                             int, err_code, int, err_arg);
  438                 }
  439 
  440                 rc = efx_mcdi_request_errcode(err_code);
  441                 goto fail3;
  442         }
  443 
  444         emrp->emr_rc = 0;
  445         emrp->emr_out_length_used = data_len;
  446 #if EFSYS_OPT_MCDI_PROXY_AUTH
  447         emrp->emr_proxy_handle = 0;
  448 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
  449         return;
  450 
  451 fail3:
  452 fail2:
  453 fail1:
  454         emrp->emr_rc = rc;
  455         emrp->emr_out_length_used = 0;
  456 }
  457 
  458 static                  void
  459 efx_mcdi_finish_response(
  460         __in            efx_nic_t *enp,
  461         __in            efx_mcdi_req_t *emrp)
  462 {
  463 #if EFSYS_OPT_MCDI_LOGGING
  464         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  465 #endif /* EFSYS_OPT_MCDI_LOGGING */
  466         efx_dword_t hdr[2];
  467         unsigned int hdr_len;
  468         size_t bytes;
  469 
  470         if (emrp->emr_out_buf == NULL)
  471                 return;
  472 
  473         /* Read the command header to detect MCDI response format */
  474         hdr_len = sizeof (hdr[0]);
  475         efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len);
  476         if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
  477                 /*
  478                  * Read the actual payload length. The length given in the event
  479                  * is only correct for responses with the V1 format.
  480                  */
  481                 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1]));
  482                 hdr_len += sizeof (hdr[1]);
  483 
  484                 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1],
  485                                             MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
  486         }
  487 
  488         /* Copy payload out into caller supplied buffer */
  489         bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
  490         efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes);
  491 
  492 #if EFSYS_OPT_MCDI_LOGGING
  493         if (emtp->emt_logger != NULL) {
  494                 emtp->emt_logger(emtp->emt_context,
  495                     EFX_LOG_MCDI_RESPONSE,
  496                     &hdr, hdr_len,
  497                     emrp->emr_out_buf, bytes);
  498         }
  499 #endif /* EFSYS_OPT_MCDI_LOGGING */
  500 }
  501 
  502         __checkReturn   boolean_t
  503 efx_mcdi_request_poll(
  504         __in            efx_nic_t *enp)
  505 {
  506         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  507         efx_mcdi_req_t *emrp;
  508         efsys_lock_state_t state;
  509         efx_rc_t rc;
  510 
  511         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  512         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
  513         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
  514 
  515         /* Serialise against post-watchdog efx_mcdi_ev* */
  516         EFSYS_LOCK(enp->en_eslp, state);
  517 
  518         EFSYS_ASSERT(emip->emi_pending_req != NULL);
  519         EFSYS_ASSERT(!emip->emi_ev_cpl);
  520         emrp = emip->emi_pending_req;
  521 
  522         /* Check if hardware is unavailable */
  523         if (efx_nic_hw_unavailable(enp)) {
  524                 EFSYS_UNLOCK(enp->en_eslp, state);
  525                 return (B_FALSE);
  526         }
  527 
  528         /* Check for reboot atomically w.r.t efx_mcdi_request_start */
  529         if (emip->emi_poll_cnt++ == 0) {
  530                 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) {
  531                         emip->emi_pending_req = NULL;
  532                         EFSYS_UNLOCK(enp->en_eslp, state);
  533 
  534                         /* Reboot/Assertion */
  535                         if (rc == EIO || rc == EINTR)
  536                                 efx_mcdi_raise_exception(enp, emrp, rc);
  537 
  538                         goto fail1;
  539                 }
  540         }
  541 
  542         /* Check if a response is available */
  543         if (efx_mcdi_poll_response(enp) == B_FALSE) {
  544                 EFSYS_UNLOCK(enp->en_eslp, state);
  545                 return (B_FALSE);
  546         }
  547 
  548         /* Read the response header */
  549         efx_mcdi_read_response_header(enp, emrp);
  550 
  551         /* Request complete */
  552         emip->emi_pending_req = NULL;
  553 
  554         /* Ensure stale MCDI requests fail after an MC reboot. */
  555         emip->emi_new_epoch = B_FALSE;
  556 
  557         EFSYS_UNLOCK(enp->en_eslp, state);
  558 
  559         if ((rc = emrp->emr_rc) != 0)
  560                 goto fail2;
  561 
  562         efx_mcdi_finish_response(enp, emrp);
  563         return (B_TRUE);
  564 
  565 fail2:
  566         if (!emrp->emr_quiet)
  567                 EFSYS_PROBE(fail2);
  568 fail1:
  569         if (!emrp->emr_quiet)
  570                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
  571 
  572         return (B_TRUE);
  573 }
  574 
  575         __checkReturn   boolean_t
  576 efx_mcdi_request_abort(
  577         __in            efx_nic_t *enp)
  578 {
  579         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  580         efx_mcdi_req_t *emrp;
  581         boolean_t aborted;
  582         efsys_lock_state_t state;
  583 
  584         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
  585         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
  586         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
  587 
  588         /*
  589          * efx_mcdi_ev_* may have already completed this event, and be
  590          * spinning/blocked on the upper layer lock. So it *is* legitimate
  591          * to for emi_pending_req to be NULL. If there is a pending event
  592          * completed request, then provide a "credit" to allow
  593          * efx_mcdi_ev_cpl() to accept a single spurious completion.
  594          */
  595         EFSYS_LOCK(enp->en_eslp, state);
  596         emrp = emip->emi_pending_req;
  597         aborted = (emrp != NULL);
  598         if (aborted) {
  599                 emip->emi_pending_req = NULL;
  600 
  601                 /* Error the request */
  602                 emrp->emr_out_length_used = 0;
  603                 emrp->emr_rc = ETIMEDOUT;
  604 
  605                 /* Provide a credit for seqno/emr_pending_req mismatches */
  606                 if (emip->emi_ev_cpl)
  607                         ++emip->emi_aborted;
  608 
  609                 /*
  610                  * The upper layer has called us, so we don't
  611                  * need to complete the request.
  612                  */
  613         }
  614         EFSYS_UNLOCK(enp->en_eslp, state);
  615 
  616         return (aborted);
  617 }
  618 
  619                         void
  620 efx_mcdi_get_timeout(
  621         __in            efx_nic_t *enp,
  622         __in            efx_mcdi_req_t *emrp,
  623         __out           uint32_t *timeoutp)
  624 {
  625         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
  626 
  627         emcop->emco_get_timeout(enp, emrp, timeoutp);
  628 }
  629 
  630         __checkReturn   efx_rc_t
  631 efx_mcdi_request_errcode(
  632         __in            unsigned int err)
  633 {
  634 
  635         switch (err) {
  636                 /* MCDI v1 */
  637         case MC_CMD_ERR_EPERM:
  638                 return (EACCES);
  639         case MC_CMD_ERR_ENOENT:
  640                 return (ENOENT);
  641         case MC_CMD_ERR_EINTR:
  642                 return (EINTR);
  643         case MC_CMD_ERR_EACCES:
  644                 return (EACCES);
  645         case MC_CMD_ERR_EBUSY:
  646                 return (EBUSY);
  647         case MC_CMD_ERR_EINVAL:
  648                 return (EINVAL);
  649         case MC_CMD_ERR_EDEADLK:
  650                 return (EDEADLK);
  651         case MC_CMD_ERR_ENOSYS:
  652                 return (ENOTSUP);
  653         case MC_CMD_ERR_ETIME:
  654                 return (ETIMEDOUT);
  655         case MC_CMD_ERR_ENOTSUP:
  656                 return (ENOTSUP);
  657         case MC_CMD_ERR_EALREADY:
  658                 return (EALREADY);
  659 
  660                 /* MCDI v2 */
  661         case MC_CMD_ERR_EEXIST:
  662                 return (EEXIST);
  663 #ifdef MC_CMD_ERR_EAGAIN
  664         case MC_CMD_ERR_EAGAIN:
  665                 return (EAGAIN);
  666 #endif
  667 #ifdef MC_CMD_ERR_ENOSPC
  668         case MC_CMD_ERR_ENOSPC:
  669                 return (ENOSPC);
  670 #endif
  671         case MC_CMD_ERR_ERANGE:
  672                 return (ERANGE);
  673 
  674         case MC_CMD_ERR_ALLOC_FAIL:
  675                 return (ENOMEM);
  676         case MC_CMD_ERR_NO_VADAPTOR:
  677                 return (ENOENT);
  678         case MC_CMD_ERR_NO_EVB_PORT:
  679                 return (ENOENT);
  680         case MC_CMD_ERR_NO_VSWITCH:
  681                 return (ENODEV);
  682         case MC_CMD_ERR_VLAN_LIMIT:
  683                 return (EINVAL);
  684         case MC_CMD_ERR_BAD_PCI_FUNC:
  685                 return (ENODEV);
  686         case MC_CMD_ERR_BAD_VLAN_MODE:
  687                 return (EINVAL);
  688         case MC_CMD_ERR_BAD_VSWITCH_TYPE:
  689                 return (EINVAL);
  690         case MC_CMD_ERR_BAD_VPORT_TYPE:
  691                 return (EINVAL);
  692         case MC_CMD_ERR_MAC_EXIST:
  693                 return (EEXIST);
  694 
  695         case MC_CMD_ERR_PROXY_PENDING:
  696                 return (EAGAIN);
  697 
  698         default:
  699                 EFSYS_PROBE1(mc_pcol_error, int, err);
  700                 return (EIO);
  701         }
  702 }
  703 
  704                         void
  705 efx_mcdi_raise_exception(
  706         __in            efx_nic_t *enp,
  707         __in_opt        efx_mcdi_req_t *emrp,
  708         __in            int rc)
  709 {
  710         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  711         efx_mcdi_exception_t exception;
  712 
  713         /* Reboot or Assertion failure only */
  714         EFSYS_ASSERT(rc == EIO || rc == EINTR);
  715 
  716         /*
  717          * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
  718          * then the EIO is not worthy of an exception.
  719          */
  720         if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
  721                 return;
  722 
  723         exception = (rc == EIO)
  724                 ? EFX_MCDI_EXCEPTION_MC_REBOOT
  725                 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
  726 
  727         emtp->emt_exception(emtp->emt_context, exception);
  728 }
  729 
  730                         void
  731 efx_mcdi_execute(
  732         __in            efx_nic_t *enp,
  733         __inout         efx_mcdi_req_t *emrp)
  734 {
  735         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  736 
  737         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
  738         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
  739 
  740         emrp->emr_quiet = B_FALSE;
  741         emtp->emt_execute(emtp->emt_context, emrp);
  742 }
  743 
  744                         void
  745 efx_mcdi_execute_quiet(
  746         __in            efx_nic_t *enp,
  747         __inout         efx_mcdi_req_t *emrp)
  748 {
  749         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  750 
  751         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
  752         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
  753 
  754         emrp->emr_quiet = B_TRUE;
  755         emtp->emt_execute(emtp->emt_context, emrp);
  756 }
  757 
  758                         void
  759 efx_mcdi_ev_cpl(
  760         __in            efx_nic_t *enp,
  761         __in            unsigned int seq,
  762         __in            unsigned int outlen,
  763         __in            int errcode)
  764 {
  765         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  766         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  767         efx_mcdi_req_t *emrp;
  768         efsys_lock_state_t state;
  769 
  770         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
  771         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
  772 
  773         /*
  774          * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
  775          * when we're completing an aborted request.
  776          */
  777         EFSYS_LOCK(enp->en_eslp, state);
  778         if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
  779             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
  780                 EFSYS_ASSERT(emip->emi_aborted > 0);
  781                 if (emip->emi_aborted > 0)
  782                         --emip->emi_aborted;
  783                 EFSYS_UNLOCK(enp->en_eslp, state);
  784                 return;
  785         }
  786 
  787         emrp = emip->emi_pending_req;
  788         emip->emi_pending_req = NULL;
  789         EFSYS_UNLOCK(enp->en_eslp, state);
  790 
  791         if (emip->emi_max_version >= 2) {
  792                 /* MCDIv2 response details do not fit into an event. */
  793                 efx_mcdi_read_response_header(enp, emrp);
  794         } else {
  795                 if (errcode != 0) {
  796                         if (!emrp->emr_quiet) {
  797                                 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
  798                                     int, errcode);
  799                         }
  800                         emrp->emr_out_length_used = 0;
  801                         emrp->emr_rc = efx_mcdi_request_errcode(errcode);
  802                 } else {
  803                         emrp->emr_out_length_used = outlen;
  804                         emrp->emr_rc = 0;
  805                 }
  806         }
  807         if (emrp->emr_rc == 0)
  808                 efx_mcdi_finish_response(enp, emrp);
  809 
  810         emtp->emt_ev_cpl(emtp->emt_context);
  811 }
  812 
  813 #if EFSYS_OPT_MCDI_PROXY_AUTH
  814 
  815         __checkReturn   efx_rc_t
  816 efx_mcdi_get_proxy_handle(
  817         __in            efx_nic_t *enp,
  818         __in            efx_mcdi_req_t *emrp,
  819         __out           uint32_t *handlep)
  820 {
  821         efx_rc_t rc;
  822 
  823         _NOTE(ARGUNUSED(enp))
  824 
  825         /*
  826          * Return proxy handle from MCDI request that returned with error
  827          * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
  828          * PROXY_RESPONSE event.
  829          */
  830         if ((emrp == NULL) || (handlep == NULL)) {
  831                 rc = EINVAL;
  832                 goto fail1;
  833         }
  834         if ((emrp->emr_rc != 0) &&
  835             (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
  836                 *handlep = emrp->emr_proxy_handle;
  837                 rc = 0;
  838         } else {
  839                 *handlep = 0;
  840                 rc = ENOENT;
  841         }
  842         return (rc);
  843 
  844 fail1:
  845         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  846         return (rc);
  847 }
  848 
  849                         void
  850 efx_mcdi_ev_proxy_response(
  851         __in            efx_nic_t *enp,
  852         __in            unsigned int handle,
  853         __in            unsigned int status)
  854 {
  855         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  856         efx_rc_t rc;
  857 
  858         /*
  859          * Handle results of an authorization request for a privileged MCDI
  860          * command. If authorization was granted then we must re-issue the
  861          * original MCDI request. If authorization failed or timed out,
  862          * then the original MCDI request should be completed with the
  863          * result code from this event.
  864          */
  865         rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
  866 
  867         emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
  868 }
  869 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
  870 
  871                         void
  872 efx_mcdi_ev_death(
  873         __in            efx_nic_t *enp,
  874         __in            int rc)
  875 {
  876         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  877         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
  878         efx_mcdi_req_t *emrp = NULL;
  879         boolean_t ev_cpl;
  880         efsys_lock_state_t state;
  881 
  882         /*
  883          * The MCDI request (if there is one) has been terminated, either
  884          * by a BADASSERT or REBOOT event.
  885          *
  886          * If there is an outstanding event-completed MCDI operation, then we
  887          * will never receive the completion event (because both MCDI
  888          * completions and BADASSERT events are sent to the same evq). So
  889          * complete this MCDI op.
  890          *
  891          * This function might run in parallel with efx_mcdi_request_poll()
  892          * for poll completed mcdi requests, and also with
  893          * efx_mcdi_request_start() for post-watchdog completions.
  894          */
  895         EFSYS_LOCK(enp->en_eslp, state);
  896         emrp = emip->emi_pending_req;
  897         ev_cpl = emip->emi_ev_cpl;
  898         if (emrp != NULL && emip->emi_ev_cpl) {
  899                 emip->emi_pending_req = NULL;
  900 
  901                 emrp->emr_out_length_used = 0;
  902                 emrp->emr_rc = rc;
  903                 ++emip->emi_aborted;
  904         }
  905 
  906         /*
  907          * Since we're running in parallel with a request, consume the
  908          * status word before dropping the lock.
  909          */
  910         if (rc == EIO || rc == EINTR) {
  911                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
  912                 (void) efx_mcdi_poll_reboot(enp);
  913                 emip->emi_new_epoch = B_TRUE;
  914         }
  915 
  916         EFSYS_UNLOCK(enp->en_eslp, state);
  917 
  918         efx_mcdi_raise_exception(enp, emrp, rc);
  919 
  920         if (emrp != NULL && ev_cpl)
  921                 emtp->emt_ev_cpl(emtp->emt_context);
  922 }
  923 
  924         __checkReturn           efx_rc_t
  925 efx_mcdi_version(
  926         __in                    efx_nic_t *enp,
  927         __out_ecount_opt(4)     uint16_t versionp[4],
  928         __out_opt               uint32_t *buildp,
  929         __out_opt               efx_mcdi_boot_t *statusp)
  930 {
  931         efx_mcdi_req_t req;
  932         EFX_MCDI_DECLARE_BUF(payload,
  933                 MAX(MC_CMD_GET_VERSION_IN_LEN, MC_CMD_GET_BOOT_STATUS_IN_LEN),
  934                 MAX(MC_CMD_GET_VERSION_OUT_LEN,
  935                         MC_CMD_GET_BOOT_STATUS_OUT_LEN));
  936         efx_word_t *ver_words;
  937         uint16_t version[4];
  938         uint32_t build;
  939         efx_mcdi_boot_t status;
  940         efx_rc_t rc;
  941 
  942         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
  943 
  944         req.emr_cmd = MC_CMD_GET_VERSION;
  945         req.emr_in_buf = payload;
  946         req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
  947         req.emr_out_buf = payload;
  948         req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
  949 
  950         efx_mcdi_execute(enp, &req);
  951 
  952         if (req.emr_rc != 0) {
  953                 rc = req.emr_rc;
  954                 goto fail1;
  955         }
  956 
  957         /* bootrom support */
  958         if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
  959                 version[0] = version[1] = version[2] = version[3] = 0;
  960                 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
  961 
  962                 goto version;
  963         }
  964 
  965         if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
  966                 rc = EMSGSIZE;
  967                 goto fail2;
  968         }
  969 
  970         ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
  971         version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
  972         version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
  973         version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
  974         version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
  975         build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
  976 
  977 version:
  978         /* The bootrom doesn't understand BOOT_STATUS */
  979         if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
  980                 status = EFX_MCDI_BOOT_ROM;
  981                 goto out;
  982         }
  983 
  984         (void) memset(payload, 0, sizeof (payload));
  985         req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
  986         req.emr_in_buf = payload;
  987         req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
  988         req.emr_out_buf = payload;
  989         req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
  990 
  991         efx_mcdi_execute_quiet(enp, &req);
  992 
  993         if (req.emr_rc == EACCES) {
  994                 /* Unprivileged functions cannot access BOOT_STATUS */
  995                 status = EFX_MCDI_BOOT_PRIMARY;
  996                 version[0] = version[1] = version[2] = version[3] = 0;
  997                 build = 0;
  998                 goto out;
  999         }
 1000 
 1001         if (req.emr_rc != 0) {
 1002                 rc = req.emr_rc;
 1003                 goto fail3;
 1004         }
 1005 
 1006         if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
 1007                 rc = EMSGSIZE;
 1008                 goto fail4;
 1009         }
 1010 
 1011         if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
 1012             GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
 1013                 status = EFX_MCDI_BOOT_PRIMARY;
 1014         else
 1015                 status = EFX_MCDI_BOOT_SECONDARY;
 1016 
 1017 out:
 1018         if (versionp != NULL)
 1019                 memcpy(versionp, version, sizeof (version));
 1020         if (buildp != NULL)
 1021                 *buildp = build;
 1022         if (statusp != NULL)
 1023                 *statusp = status;
 1024 
 1025         return (0);
 1026 
 1027 fail4:
 1028         EFSYS_PROBE(fail4);
 1029 fail3:
 1030         EFSYS_PROBE(fail3);
 1031 fail2:
 1032         EFSYS_PROBE(fail2);
 1033 fail1:
 1034         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1035 
 1036         return (rc);
 1037 }
 1038 
 1039         __checkReturn   efx_rc_t
 1040 efx_mcdi_get_capabilities(
 1041         __in            efx_nic_t *enp,
 1042         __out_opt       uint32_t *flagsp,
 1043         __out_opt       uint16_t *rx_dpcpu_fw_idp,
 1044         __out_opt       uint16_t *tx_dpcpu_fw_idp,
 1045         __out_opt       uint32_t *flags2p,
 1046         __out_opt       uint32_t *tso2ncp)
 1047 {
 1048         efx_mcdi_req_t req;
 1049         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN,
 1050                 MC_CMD_GET_CAPABILITIES_V2_OUT_LEN);
 1051         boolean_t v2_capable;
 1052         efx_rc_t rc;
 1053 
 1054         req.emr_cmd = MC_CMD_GET_CAPABILITIES;
 1055         req.emr_in_buf = payload;
 1056         req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
 1057         req.emr_out_buf = payload;
 1058         req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN;
 1059 
 1060         efx_mcdi_execute_quiet(enp, &req);
 1061 
 1062         if (req.emr_rc != 0) {
 1063                 rc = req.emr_rc;
 1064                 goto fail1;
 1065         }
 1066 
 1067         if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) {
 1068                 rc = EMSGSIZE;
 1069                 goto fail2;
 1070         }
 1071 
 1072         if (flagsp != NULL)
 1073                 *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1);
 1074 
 1075         if (rx_dpcpu_fw_idp != NULL)
 1076                 *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
 1077                                         GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID);
 1078 
 1079         if (tx_dpcpu_fw_idp != NULL)
 1080                 *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req,
 1081                                         GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID);
 1082 
 1083         if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)
 1084                 v2_capable = B_FALSE;
 1085         else
 1086                 v2_capable = B_TRUE;
 1087 
 1088         if (flags2p != NULL) {
 1089                 *flags2p = (v2_capable) ?
 1090                         MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) :
 1091                         0;
 1092         }
 1093 
 1094         if (tso2ncp != NULL) {
 1095                 *tso2ncp = (v2_capable) ?
 1096                         MCDI_OUT_WORD(req,
 1097                                 GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) :
 1098                         0;
 1099         }
 1100 
 1101         return (0);
 1102 
 1103 fail2:
 1104         EFSYS_PROBE(fail2);
 1105 fail1:
 1106         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1107 
 1108         return (rc);
 1109 }
 1110 
 1111 static  __checkReturn   efx_rc_t
 1112 efx_mcdi_do_reboot(
 1113         __in            efx_nic_t *enp,
 1114         __in            boolean_t after_assertion)
 1115 {
 1116         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_REBOOT_IN_LEN,
 1117                 MC_CMD_REBOOT_OUT_LEN);
 1118         efx_mcdi_req_t req;
 1119         efx_rc_t rc;
 1120 
 1121         /*
 1122          * We could require the caller to have caused en_mod_flags=0 to
 1123          * call this function. This doesn't help the other port though,
 1124          * who's about to get the MC ripped out from underneath them.
 1125          * Since they have to cope with the subsequent fallout of MCDI
 1126          * failures, we should as well.
 1127          */
 1128         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 1129 
 1130         req.emr_cmd = MC_CMD_REBOOT;
 1131         req.emr_in_buf = payload;
 1132         req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
 1133         req.emr_out_buf = payload;
 1134         req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
 1135 
 1136         MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
 1137             (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
 1138 
 1139         efx_mcdi_execute_quiet(enp, &req);
 1140 
 1141         if (req.emr_rc == EACCES) {
 1142                 /* Unprivileged functions cannot reboot the MC. */
 1143                 goto out;
 1144         }
 1145 
 1146         /* A successful reboot request returns EIO. */
 1147         if (req.emr_rc != 0 && req.emr_rc != EIO) {
 1148                 rc = req.emr_rc;
 1149                 goto fail1;
 1150         }
 1151 
 1152 out:
 1153         return (0);
 1154 
 1155 fail1:
 1156         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1157 
 1158         return (rc);
 1159 }
 1160 
 1161         __checkReturn   efx_rc_t
 1162 efx_mcdi_reboot(
 1163         __in            efx_nic_t *enp)
 1164 {
 1165         return (efx_mcdi_do_reboot(enp, B_FALSE));
 1166 }
 1167 
 1168         __checkReturn   efx_rc_t
 1169 efx_mcdi_exit_assertion_handler(
 1170         __in            efx_nic_t *enp)
 1171 {
 1172         return (efx_mcdi_do_reboot(enp, B_TRUE));
 1173 }
 1174 
 1175         __checkReturn   efx_rc_t
 1176 efx_mcdi_read_assertion(
 1177         __in            efx_nic_t *enp)
 1178 {
 1179         efx_mcdi_req_t req;
 1180         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_ASSERTS_IN_LEN,
 1181                 MC_CMD_GET_ASSERTS_OUT_LEN);
 1182 #ifdef KDTRACE_HOOKS
 1183         const char *reason;
 1184 #else
 1185         const char *reason __unused;
 1186 #endif
 1187         unsigned int flags;
 1188         unsigned int index;
 1189         unsigned int ofst;
 1190         int retry;
 1191         efx_rc_t rc;
 1192 
 1193         /*
 1194          * Before we attempt to chat to the MC, we should verify that the MC
 1195          * isn't in its assertion handler, either due to a previous reboot,
 1196          * or because we're reinitializing due to an eec_exception().
 1197          *
 1198          * Use GET_ASSERTS to read any assertion state that may be present.
 1199          * Retry this command twice. Once because a boot-time assertion failure
 1200          * might cause the 1st MCDI request to fail. And once again because
 1201          * we might race with efx_mcdi_exit_assertion_handler() running on
 1202          * partner port(s) on the same NIC.
 1203          */
 1204         retry = 2;
 1205         do {
 1206                 (void) memset(payload, 0, sizeof (payload));
 1207                 req.emr_cmd = MC_CMD_GET_ASSERTS;
 1208                 req.emr_in_buf = payload;
 1209                 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
 1210                 req.emr_out_buf = payload;
 1211                 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
 1212 
 1213                 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
 1214                 efx_mcdi_execute_quiet(enp, &req);
 1215 
 1216         } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
 1217 
 1218         if (req.emr_rc != 0) {
 1219                 if (req.emr_rc == EACCES) {
 1220                         /* Unprivileged functions cannot clear assertions. */
 1221                         goto out;
 1222                 }
 1223                 rc = req.emr_rc;
 1224                 goto fail1;
 1225         }
 1226 
 1227         if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
 1228                 rc = EMSGSIZE;
 1229                 goto fail2;
 1230         }
 1231 
 1232         /* Print out any assertion state recorded */
 1233         flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
 1234         if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
 1235                 return (0);
 1236 
 1237         reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
 1238                 ? "system-level assertion"
 1239                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
 1240                 ? "thread-level assertion"
 1241                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
 1242                 ? "watchdog reset"
 1243                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
 1244                 ? "illegal address trap"
 1245                 : "unknown assertion";
 1246         EFSYS_PROBE3(mcpu_assertion,
 1247             const char *, reason, unsigned int,
 1248             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
 1249             unsigned int,
 1250             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
 1251 
 1252         /* Print out the registers (r1 ... r31) */
 1253         ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
 1254         for (index = 1;
 1255                 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
 1256                 index++) {
 1257                 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
 1258                             EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
 1259                                             EFX_DWORD_0));
 1260                 ofst += sizeof (efx_dword_t);
 1261         }
 1262         EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
 1263 
 1264 out:
 1265         return (0);
 1266 
 1267 fail2:
 1268         EFSYS_PROBE(fail2);
 1269 fail1:
 1270         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1271 
 1272         return (rc);
 1273 }
 1274 
 1275 /*
 1276  * Internal routines for specific MCDI requests.
 1277  */
 1278 
 1279         __checkReturn   efx_rc_t
 1280 efx_mcdi_drv_attach(
 1281         __in            efx_nic_t *enp,
 1282         __in            boolean_t attach)
 1283 {
 1284         efx_mcdi_req_t req;
 1285         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_DRV_ATTACH_IN_LEN,
 1286                 MC_CMD_DRV_ATTACH_EXT_OUT_LEN);
 1287         efx_rc_t rc;
 1288 
 1289         req.emr_cmd = MC_CMD_DRV_ATTACH;
 1290         req.emr_in_buf = payload;
 1291         req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
 1292         req.emr_out_buf = payload;
 1293         req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
 1294 
 1295         /*
 1296          * Typically, client drivers use DONT_CARE for the datapath firmware
 1297          * type to ensure that the driver can attach to an unprivileged
 1298          * function. The datapath firmware type to use is controlled by the
 1299          * 'sfboot' utility.
 1300          * If a client driver wishes to attach with a specific datapath firmware
 1301          * type, that can be passed in second argument of efx_nic_probe API. One
 1302          * such example is the ESXi native driver that attempts attaching with
 1303          * FULL_FEATURED datapath firmware type first and fall backs to
 1304          * DONT_CARE datapath firmware type if MC_CMD_DRV_ATTACH fails.
 1305          */
 1306         MCDI_IN_POPULATE_DWORD_2(req, DRV_ATTACH_IN_NEW_STATE,
 1307             DRV_ATTACH_IN_ATTACH, attach ? 1 : 0,
 1308             DRV_ATTACH_IN_SUBVARIANT_AWARE, EFSYS_OPT_FW_SUBVARIANT_AWARE);
 1309         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
 1310         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, enp->efv);
 1311 
 1312         efx_mcdi_execute(enp, &req);
 1313 
 1314         if (req.emr_rc != 0) {
 1315                 rc = req.emr_rc;
 1316                 goto fail1;
 1317         }
 1318 
 1319         if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
 1320                 rc = EMSGSIZE;
 1321                 goto fail2;
 1322         }
 1323 
 1324         return (0);
 1325 
 1326 fail2:
 1327         EFSYS_PROBE(fail2);
 1328 fail1:
 1329         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1330 
 1331         return (rc);
 1332 }
 1333 
 1334         __checkReturn           efx_rc_t
 1335 efx_mcdi_get_board_cfg(
 1336         __in                    efx_nic_t *enp,
 1337         __out_opt               uint32_t *board_typep,
 1338         __out_opt               efx_dword_t *capabilitiesp,
 1339         __out_ecount_opt(6)     uint8_t mac_addrp[6])
 1340 {
 1341         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
 1342         efx_mcdi_req_t req;
 1343         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN,
 1344                 MC_CMD_GET_BOARD_CFG_OUT_LENMIN);
 1345         efx_rc_t rc;
 1346 
 1347         req.emr_cmd = MC_CMD_GET_BOARD_CFG;
 1348         req.emr_in_buf = payload;
 1349         req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
 1350         req.emr_out_buf = payload;
 1351         req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
 1352 
 1353         efx_mcdi_execute(enp, &req);
 1354 
 1355         if (req.emr_rc != 0) {
 1356                 rc = req.emr_rc;
 1357                 goto fail1;
 1358         }
 1359 
 1360         if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
 1361                 rc = EMSGSIZE;
 1362                 goto fail2;
 1363         }
 1364 
 1365         if (mac_addrp != NULL) {
 1366                 uint8_t *addrp;
 1367 
 1368                 if (emip->emi_port == 1) {
 1369                         addrp = MCDI_OUT2(req, uint8_t,
 1370                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
 1371                 } else if (emip->emi_port == 2) {
 1372                         addrp = MCDI_OUT2(req, uint8_t,
 1373                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
 1374                 } else {
 1375                         rc = EINVAL;
 1376                         goto fail3;
 1377                 }
 1378 
 1379                 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
 1380         }
 1381 
 1382         if (capabilitiesp != NULL) {
 1383                 if (emip->emi_port == 1) {
 1384                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
 1385                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
 1386                 } else if (emip->emi_port == 2) {
 1387                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
 1388                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
 1389                 } else {
 1390                         rc = EINVAL;
 1391                         goto fail4;
 1392                 }
 1393         }
 1394 
 1395         if (board_typep != NULL) {
 1396                 *board_typep = MCDI_OUT_DWORD(req,
 1397                     GET_BOARD_CFG_OUT_BOARD_TYPE);
 1398         }
 1399 
 1400         return (0);
 1401 
 1402 fail4:
 1403         EFSYS_PROBE(fail4);
 1404 fail3:
 1405         EFSYS_PROBE(fail3);
 1406 fail2:
 1407         EFSYS_PROBE(fail2);
 1408 fail1:
 1409         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1410 
 1411         return (rc);
 1412 }
 1413 
 1414         __checkReturn   efx_rc_t
 1415 efx_mcdi_get_resource_limits(
 1416         __in            efx_nic_t *enp,
 1417         __out_opt       uint32_t *nevqp,
 1418         __out_opt       uint32_t *nrxqp,
 1419         __out_opt       uint32_t *ntxqp)
 1420 {
 1421         efx_mcdi_req_t req;
 1422         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
 1423                 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN);
 1424         efx_rc_t rc;
 1425 
 1426         req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
 1427         req.emr_in_buf = payload;
 1428         req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
 1429         req.emr_out_buf = payload;
 1430         req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
 1431 
 1432         efx_mcdi_execute(enp, &req);
 1433 
 1434         if (req.emr_rc != 0) {
 1435                 rc = req.emr_rc;
 1436                 goto fail1;
 1437         }
 1438 
 1439         if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
 1440                 rc = EMSGSIZE;
 1441                 goto fail2;
 1442         }
 1443 
 1444         if (nevqp != NULL)
 1445                 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
 1446         if (nrxqp != NULL)
 1447                 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
 1448         if (ntxqp != NULL)
 1449                 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
 1450 
 1451         return (0);
 1452 
 1453 fail2:
 1454         EFSYS_PROBE(fail2);
 1455 fail1:
 1456         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1457 
 1458         return (rc);
 1459 }
 1460 
 1461         __checkReturn   efx_rc_t
 1462 efx_mcdi_get_phy_cfg(
 1463         __in            efx_nic_t *enp)
 1464 {
 1465         efx_port_t *epp = &(enp->en_port);
 1466         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 1467         efx_mcdi_req_t req;
 1468         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_CFG_IN_LEN,
 1469                 MC_CMD_GET_PHY_CFG_OUT_LEN);
 1470 #if EFSYS_OPT_NAMES
 1471         const char *namep;
 1472         size_t namelen;
 1473 #endif
 1474         uint32_t phy_media_type;
 1475         efx_rc_t rc;
 1476 
 1477         req.emr_cmd = MC_CMD_GET_PHY_CFG;
 1478         req.emr_in_buf = payload;
 1479         req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
 1480         req.emr_out_buf = payload;
 1481         req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
 1482 
 1483         efx_mcdi_execute(enp, &req);
 1484 
 1485         if (req.emr_rc != 0) {
 1486                 rc = req.emr_rc;
 1487                 goto fail1;
 1488         }
 1489 
 1490         if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
 1491                 rc = EMSGSIZE;
 1492                 goto fail2;
 1493         }
 1494 
 1495         encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
 1496 #if EFSYS_OPT_NAMES
 1497         namep = MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME);
 1498         namelen = MIN(sizeof (encp->enc_phy_name) - 1,
 1499                     strnlen(namep, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
 1500         (void) memset(encp->enc_phy_name, 0,
 1501             sizeof (encp->enc_phy_name));
 1502         memcpy(encp->enc_phy_name, namep, namelen);
 1503 #endif  /* EFSYS_OPT_NAMES */
 1504         (void) memset(encp->enc_phy_revision, 0,
 1505             sizeof (encp->enc_phy_revision));
 1506         memcpy(encp->enc_phy_revision,
 1507                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
 1508                 MIN(sizeof (encp->enc_phy_revision) - 1,
 1509                     MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
 1510 #if EFSYS_OPT_PHY_LED_CONTROL
 1511         encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
 1512                             (1 << EFX_PHY_LED_OFF) |
 1513                             (1 << EFX_PHY_LED_ON));
 1514 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
 1515 
 1516         /* Get the media type of the fixed port, if recognised. */
 1517         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
 1518         EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
 1519         EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
 1520         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
 1521         EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
 1522         EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
 1523         EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
 1524         phy_media_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
 1525         epp->ep_fixed_port_type = (efx_phy_media_type_t) phy_media_type;
 1526         if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
 1527                 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
 1528 
 1529         epp->ep_phy_cap_mask =
 1530                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
 1531 #if EFSYS_OPT_PHY_FLAGS
 1532         encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
 1533 #endif  /* EFSYS_OPT_PHY_FLAGS */
 1534 
 1535         encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
 1536 
 1537         /* Populate internal state */
 1538         encp->enc_mcdi_mdio_channel =
 1539                 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
 1540 
 1541 #if EFSYS_OPT_PHY_STATS
 1542         encp->enc_mcdi_phy_stat_mask =
 1543                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
 1544 #endif  /* EFSYS_OPT_PHY_STATS */
 1545 
 1546 #if EFSYS_OPT_BIST
 1547         encp->enc_bist_mask = 0;
 1548         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
 1549             GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
 1550                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
 1551         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
 1552             GET_PHY_CFG_OUT_BIST_CABLE_LONG))
 1553                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
 1554         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
 1555             GET_PHY_CFG_OUT_BIST))
 1556                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
 1557 #endif  /* EFSYS_OPT_BIST */
 1558 
 1559         return (0);
 1560 
 1561 fail2:
 1562         EFSYS_PROBE(fail2);
 1563 fail1:
 1564         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1565 
 1566         return (rc);
 1567 }
 1568 
 1569         __checkReturn           efx_rc_t
 1570 efx_mcdi_firmware_update_supported(
 1571         __in                    efx_nic_t *enp,
 1572         __out                   boolean_t *supportedp)
 1573 {
 1574         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
 1575         efx_rc_t rc;
 1576 
 1577         if (emcop != NULL) {
 1578                 if ((rc = emcop->emco_feature_supported(enp,
 1579                             EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
 1580                         goto fail1;
 1581         } else {
 1582                 /* Earlier devices always supported updates */
 1583                 *supportedp = B_TRUE;
 1584         }
 1585 
 1586         return (0);
 1587 
 1588 fail1:
 1589         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1590 
 1591         return (rc);
 1592 }
 1593 
 1594         __checkReturn           efx_rc_t
 1595 efx_mcdi_macaddr_change_supported(
 1596         __in                    efx_nic_t *enp,
 1597         __out                   boolean_t *supportedp)
 1598 {
 1599         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
 1600         efx_rc_t rc;
 1601 
 1602         if (emcop != NULL) {
 1603                 if ((rc = emcop->emco_feature_supported(enp,
 1604                             EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
 1605                         goto fail1;
 1606         } else {
 1607                 /* Earlier devices always supported MAC changes */
 1608                 *supportedp = B_TRUE;
 1609         }
 1610 
 1611         return (0);
 1612 
 1613 fail1:
 1614         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1615 
 1616         return (rc);
 1617 }
 1618 
 1619         __checkReturn           efx_rc_t
 1620 efx_mcdi_link_control_supported(
 1621         __in                    efx_nic_t *enp,
 1622         __out                   boolean_t *supportedp)
 1623 {
 1624         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
 1625         efx_rc_t rc;
 1626 
 1627         if (emcop != NULL) {
 1628                 if ((rc = emcop->emco_feature_supported(enp,
 1629                             EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
 1630                         goto fail1;
 1631         } else {
 1632                 /* Earlier devices always supported link control */
 1633                 *supportedp = B_TRUE;
 1634         }
 1635 
 1636         return (0);
 1637 
 1638 fail1:
 1639         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1640 
 1641         return (rc);
 1642 }
 1643 
 1644         __checkReturn           efx_rc_t
 1645 efx_mcdi_mac_spoofing_supported(
 1646         __in                    efx_nic_t *enp,
 1647         __out                   boolean_t *supportedp)
 1648 {
 1649         const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
 1650         efx_rc_t rc;
 1651 
 1652         if (emcop != NULL) {
 1653                 if ((rc = emcop->emco_feature_supported(enp,
 1654                             EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
 1655                         goto fail1;
 1656         } else {
 1657                 /* Earlier devices always supported MAC spoofing */
 1658                 *supportedp = B_TRUE;
 1659         }
 1660 
 1661         return (0);
 1662 
 1663 fail1:
 1664         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1665 
 1666         return (rc);
 1667 }
 1668 
 1669 #if EFSYS_OPT_BIST
 1670 
 1671 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
 1672 /*
 1673  * Enter bist offline mode. This is a fw mode which puts the NIC into a state
 1674  * where memory BIST tests can be run and not much else can interfere or happen.
 1675  * A reboot is required to exit this mode.
 1676  */
 1677         __checkReturn           efx_rc_t
 1678 efx_mcdi_bist_enable_offline(
 1679         __in                    efx_nic_t *enp)
 1680 {
 1681         efx_mcdi_req_t req;
 1682         efx_rc_t rc;
 1683 
 1684         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
 1685         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
 1686 
 1687         req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
 1688         req.emr_in_buf = NULL;
 1689         req.emr_in_length = 0;
 1690         req.emr_out_buf = NULL;
 1691         req.emr_out_length = 0;
 1692 
 1693         efx_mcdi_execute(enp, &req);
 1694 
 1695         if (req.emr_rc != 0) {
 1696                 rc = req.emr_rc;
 1697                 goto fail1;
 1698         }
 1699 
 1700         return (0);
 1701 
 1702 fail1:
 1703         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1704 
 1705         return (rc);
 1706 }
 1707 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
 1708 
 1709         __checkReturn           efx_rc_t
 1710 efx_mcdi_bist_start(
 1711         __in                    efx_nic_t *enp,
 1712         __in                    efx_bist_type_t type)
 1713 {
 1714         efx_mcdi_req_t req;
 1715         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_START_BIST_IN_LEN,
 1716                 MC_CMD_START_BIST_OUT_LEN);
 1717         efx_rc_t rc;
 1718 
 1719         req.emr_cmd = MC_CMD_START_BIST;
 1720         req.emr_in_buf = payload;
 1721         req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
 1722         req.emr_out_buf = payload;
 1723         req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
 1724 
 1725         switch (type) {
 1726         case EFX_BIST_TYPE_PHY_NORMAL:
 1727                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
 1728                 break;
 1729         case EFX_BIST_TYPE_PHY_CABLE_SHORT:
 1730                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
 1731                     MC_CMD_PHY_BIST_CABLE_SHORT);
 1732                 break;
 1733         case EFX_BIST_TYPE_PHY_CABLE_LONG:
 1734                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
 1735                     MC_CMD_PHY_BIST_CABLE_LONG);
 1736                 break;
 1737         case EFX_BIST_TYPE_MC_MEM:
 1738                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
 1739                     MC_CMD_MC_MEM_BIST);
 1740                 break;
 1741         case EFX_BIST_TYPE_SAT_MEM:
 1742                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
 1743                     MC_CMD_PORT_MEM_BIST);
 1744                 break;
 1745         case EFX_BIST_TYPE_REG:
 1746                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
 1747                     MC_CMD_REG_BIST);
 1748                 break;
 1749         default:
 1750                 EFSYS_ASSERT(0);
 1751         }
 1752 
 1753         efx_mcdi_execute(enp, &req);
 1754 
 1755         if (req.emr_rc != 0) {
 1756                 rc = req.emr_rc;
 1757                 goto fail1;
 1758         }
 1759 
 1760         return (0);
 1761 
 1762 fail1:
 1763         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1764 
 1765         return (rc);
 1766 }
 1767 
 1768 #endif /* EFSYS_OPT_BIST */
 1769 
 1770 /* Enable logging of some events (e.g. link state changes) */
 1771         __checkReturn   efx_rc_t
 1772 efx_mcdi_log_ctrl(
 1773         __in            efx_nic_t *enp)
 1774 {
 1775         efx_mcdi_req_t req;
 1776         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LOG_CTRL_IN_LEN,
 1777                 MC_CMD_LOG_CTRL_OUT_LEN);
 1778         efx_rc_t rc;
 1779 
 1780         req.emr_cmd = MC_CMD_LOG_CTRL;
 1781         req.emr_in_buf = payload;
 1782         req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
 1783         req.emr_out_buf = payload;
 1784         req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
 1785 
 1786         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
 1787                     MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
 1788         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
 1789 
 1790         efx_mcdi_execute(enp, &req);
 1791 
 1792         if (req.emr_rc != 0) {
 1793                 rc = req.emr_rc;
 1794                 goto fail1;
 1795         }
 1796 
 1797         return (0);
 1798 
 1799 fail1:
 1800         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1801 
 1802         return (rc);
 1803 }
 1804 
 1805 #if EFSYS_OPT_MAC_STATS
 1806 
 1807 typedef enum efx_stats_action_e {
 1808         EFX_STATS_CLEAR,
 1809         EFX_STATS_UPLOAD,
 1810         EFX_STATS_ENABLE_NOEVENTS,
 1811         EFX_STATS_ENABLE_EVENTS,
 1812         EFX_STATS_DISABLE,
 1813 } efx_stats_action_t;
 1814 
 1815 static  __checkReturn   efx_rc_t
 1816 efx_mcdi_mac_stats(
 1817         __in            efx_nic_t *enp,
 1818         __in_opt        efsys_mem_t *esmp,
 1819         __in            efx_stats_action_t action,
 1820         __in            uint16_t period_ms)
 1821 {
 1822         efx_mcdi_req_t req;
 1823         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAC_STATS_IN_LEN,
 1824                 MC_CMD_MAC_STATS_V2_OUT_DMA_LEN);
 1825         int clear = (action == EFX_STATS_CLEAR);
 1826         int upload = (action == EFX_STATS_UPLOAD);
 1827         int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
 1828         int events = (action == EFX_STATS_ENABLE_EVENTS);
 1829         int disable = (action == EFX_STATS_DISABLE);
 1830         efx_rc_t rc;
 1831 
 1832         req.emr_cmd = MC_CMD_MAC_STATS;
 1833         req.emr_in_buf = payload;
 1834         req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
 1835         req.emr_out_buf = payload;
 1836         req.emr_out_length = MC_CMD_MAC_STATS_V2_OUT_DMA_LEN;
 1837 
 1838         MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
 1839             MAC_STATS_IN_DMA, upload,
 1840             MAC_STATS_IN_CLEAR, clear,
 1841             MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
 1842             MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
 1843             MAC_STATS_IN_PERIODIC_NOEVENT, !events,
 1844             MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0);
 1845 
 1846         if (enable || events || upload) {
 1847                 const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
 1848                 uint32_t bytes;
 1849 
 1850                 /* Periodic stats or stats upload require a DMA buffer */
 1851                 if (esmp == NULL) {
 1852                         rc = EINVAL;
 1853                         goto fail1;
 1854                 }
 1855 
 1856                 if (encp->enc_mac_stats_nstats < MC_CMD_MAC_NSTATS) {
 1857                         /* MAC stats count too small for legacy MAC stats */
 1858                         rc = ENOSPC;
 1859                         goto fail2;
 1860                 }
 1861 
 1862                 bytes = encp->enc_mac_stats_nstats * sizeof (efx_qword_t);
 1863 
 1864                 if (EFSYS_MEM_SIZE(esmp) < bytes) {
 1865                         /* DMA buffer too small */
 1866                         rc = ENOSPC;
 1867                         goto fail3;
 1868                 }
 1869 
 1870                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
 1871                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
 1872                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
 1873                             EFSYS_MEM_ADDR(esmp) >> 32);
 1874                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
 1875         }
 1876 
 1877         /*
 1878          * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
 1879          *       as this may fail (and leave periodic DMA enabled) if the
 1880          *       vadapter has already been deleted.
 1881          */
 1882         MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
 1883             (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
 1884 
 1885         efx_mcdi_execute(enp, &req);
 1886 
 1887         if (req.emr_rc != 0) {
 1888                 /* EF10: Expect ENOENT if no DMA queues are initialised */
 1889                 if ((req.emr_rc != ENOENT) ||
 1890                     (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
 1891                         rc = req.emr_rc;
 1892                         goto fail4;
 1893                 }
 1894         }
 1895 
 1896         return (0);
 1897 
 1898 fail4:
 1899         EFSYS_PROBE(fail4);
 1900 fail3:
 1901         EFSYS_PROBE(fail3);
 1902 fail2:
 1903         EFSYS_PROBE(fail2);
 1904 fail1:
 1905         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1906 
 1907         return (rc);
 1908 }
 1909 
 1910         __checkReturn   efx_rc_t
 1911 efx_mcdi_mac_stats_clear(
 1912         __in            efx_nic_t *enp)
 1913 {
 1914         efx_rc_t rc;
 1915 
 1916         if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR, 0)) != 0)
 1917                 goto fail1;
 1918 
 1919         return (0);
 1920 
 1921 fail1:
 1922         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1923 
 1924         return (rc);
 1925 }
 1926 
 1927         __checkReturn   efx_rc_t
 1928 efx_mcdi_mac_stats_upload(
 1929         __in            efx_nic_t *enp,
 1930         __in            efsys_mem_t *esmp)
 1931 {
 1932         efx_rc_t rc;
 1933 
 1934         /*
 1935          * The MC DMAs aggregate statistics for our convenience, so we can
 1936          * avoid having to pull the statistics buffer into the cache to
 1937          * maintain cumulative statistics.
 1938          */
 1939         if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD, 0)) != 0)
 1940                 goto fail1;
 1941 
 1942         return (0);
 1943 
 1944 fail1:
 1945         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1946 
 1947         return (rc);
 1948 }
 1949 
 1950         __checkReturn   efx_rc_t
 1951 efx_mcdi_mac_stats_periodic(
 1952         __in            efx_nic_t *enp,
 1953         __in            efsys_mem_t *esmp,
 1954         __in            uint16_t period_ms,
 1955         __in            boolean_t events)
 1956 {
 1957         efx_rc_t rc;
 1958 
 1959         /*
 1960          * The MC DMAs aggregate statistics for our convenience, so we can
 1961          * avoid having to pull the statistics buffer into the cache to
 1962          * maintain cumulative statistics.
 1963          * Huntington uses a fixed 1sec period.
 1964          * Medford uses a fixed 1sec period before v6.2.1.1033 firmware.
 1965          */
 1966         if (period_ms == 0)
 1967                 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE, 0);
 1968         else if (events)
 1969                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS,
 1970                     period_ms);
 1971         else
 1972                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS,
 1973                     period_ms);
 1974 
 1975         if (rc != 0)
 1976                 goto fail1;
 1977 
 1978         return (0);
 1979 
 1980 fail1:
 1981         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 1982 
 1983         return (rc);
 1984 }
 1985 
 1986 #endif  /* EFSYS_OPT_MAC_STATS */
 1987 
 1988 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
 1989 
 1990 /*
 1991  * This function returns the pf and vf number of a function.  If it is a pf the
 1992  * vf number is 0xffff.  The vf number is the index of the vf on that
 1993  * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
 1994  * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
 1995  */
 1996         __checkReturn           efx_rc_t
 1997 efx_mcdi_get_function_info(
 1998         __in                    efx_nic_t *enp,
 1999         __out                   uint32_t *pfp,
 2000         __out_opt               uint32_t *vfp)
 2001 {
 2002         efx_mcdi_req_t req;
 2003         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_FUNCTION_INFO_IN_LEN,
 2004                 MC_CMD_GET_FUNCTION_INFO_OUT_LEN);
 2005         efx_rc_t rc;
 2006 
 2007         req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
 2008         req.emr_in_buf = payload;
 2009         req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
 2010         req.emr_out_buf = payload;
 2011         req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
 2012 
 2013         efx_mcdi_execute(enp, &req);
 2014 
 2015         if (req.emr_rc != 0) {
 2016                 rc = req.emr_rc;
 2017                 goto fail1;
 2018         }
 2019 
 2020         if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
 2021                 rc = EMSGSIZE;
 2022                 goto fail2;
 2023         }
 2024 
 2025         *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
 2026         if (vfp != NULL)
 2027                 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
 2028 
 2029         return (0);
 2030 
 2031 fail2:
 2032         EFSYS_PROBE(fail2);
 2033 fail1:
 2034         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 2035 
 2036         return (rc);
 2037 }
 2038 
 2039         __checkReturn           efx_rc_t
 2040 efx_mcdi_privilege_mask(
 2041         __in                    efx_nic_t *enp,
 2042         __in                    uint32_t pf,
 2043         __in                    uint32_t vf,
 2044         __out                   uint32_t *maskp)
 2045 {
 2046         efx_mcdi_req_t req;
 2047         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PRIVILEGE_MASK_IN_LEN,
 2048                 MC_CMD_PRIVILEGE_MASK_OUT_LEN);
 2049         efx_rc_t rc;
 2050 
 2051         req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
 2052         req.emr_in_buf = payload;
 2053         req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
 2054         req.emr_out_buf = payload;
 2055         req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
 2056 
 2057         MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
 2058             PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
 2059             PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
 2060 
 2061         efx_mcdi_execute(enp, &req);
 2062 
 2063         if (req.emr_rc != 0) {
 2064                 rc = req.emr_rc;
 2065                 goto fail1;
 2066         }
 2067 
 2068         if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
 2069                 rc = EMSGSIZE;
 2070                 goto fail2;
 2071         }
 2072 
 2073         *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
 2074 
 2075         return (0);
 2076 
 2077 fail2:
 2078         EFSYS_PROBE(fail2);
 2079 fail1:
 2080         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 2081 
 2082         return (rc);
 2083 }
 2084 
 2085 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
 2086 
 2087         __checkReturn           efx_rc_t
 2088 efx_mcdi_set_workaround(
 2089         __in                    efx_nic_t *enp,
 2090         __in                    uint32_t type,
 2091         __in                    boolean_t enabled,
 2092         __out_opt               uint32_t *flagsp)
 2093 {
 2094         efx_mcdi_req_t req;
 2095         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_WORKAROUND_IN_LEN,
 2096                 MC_CMD_WORKAROUND_EXT_OUT_LEN);
 2097         efx_rc_t rc;
 2098 
 2099         req.emr_cmd = MC_CMD_WORKAROUND;
 2100         req.emr_in_buf = payload;
 2101         req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
 2102         req.emr_out_buf = payload;
 2103         req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
 2104 
 2105         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
 2106         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
 2107 
 2108         efx_mcdi_execute_quiet(enp, &req);
 2109 
 2110         if (req.emr_rc != 0) {
 2111                 rc = req.emr_rc;
 2112                 goto fail1;
 2113         }
 2114 
 2115         if (flagsp != NULL) {
 2116                 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
 2117                         *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
 2118                 else
 2119                         *flagsp = 0;
 2120         }
 2121 
 2122         return (0);
 2123 
 2124 fail1:
 2125         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 2126 
 2127         return (rc);
 2128 }
 2129 
 2130         __checkReturn           efx_rc_t
 2131 efx_mcdi_get_workarounds(
 2132         __in                    efx_nic_t *enp,
 2133         __out_opt               uint32_t *implementedp,
 2134         __out_opt               uint32_t *enabledp)
 2135 {
 2136         efx_mcdi_req_t req;
 2137         EFX_MCDI_DECLARE_BUF(payload, 0, MC_CMD_GET_WORKAROUNDS_OUT_LEN);
 2138         efx_rc_t rc;
 2139 
 2140         req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
 2141         req.emr_in_buf = NULL;
 2142         req.emr_in_length = 0;
 2143         req.emr_out_buf = payload;
 2144         req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
 2145 
 2146         efx_mcdi_execute(enp, &req);
 2147 
 2148         if (req.emr_rc != 0) {
 2149                 rc = req.emr_rc;
 2150                 goto fail1;
 2151         }
 2152 
 2153         if (implementedp != NULL) {
 2154                 *implementedp =
 2155                     MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
 2156         }
 2157 
 2158         if (enabledp != NULL) {
 2159                 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
 2160         }
 2161 
 2162         return (0);
 2163 
 2164 fail1:
 2165         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 2166 
 2167         return (rc);
 2168 }
 2169 
 2170 /*
 2171  * Size of media information page in accordance with SFF-8472 and SFF-8436.
 2172  * It is used in MCDI interface as well.
 2173  */
 2174 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE            0x80
 2175 
 2176 /*
 2177  * Transceiver identifiers from SFF-8024 Table 4-1.
 2178  */
 2179 #define EFX_SFF_TRANSCEIVER_ID_SFP              0x03 /* SFP/SFP+/SFP28 */
 2180 #define EFX_SFF_TRANSCEIVER_ID_QSFP             0x0c /* QSFP */
 2181 #define EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS        0x0d /* QSFP+ or later */
 2182 #define EFX_SFF_TRANSCEIVER_ID_QSFP28           0x11 /* QSFP28 or later */
 2183 
 2184 static  __checkReturn           efx_rc_t
 2185 efx_mcdi_get_phy_media_info(
 2186         __in                    efx_nic_t *enp,
 2187         __in                    uint32_t mcdi_page,
 2188         __in                    uint8_t offset,
 2189         __in                    uint8_t len,
 2190         __out_bcount(len)       uint8_t *data)
 2191 {
 2192         efx_mcdi_req_t req;
 2193         EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN,
 2194                 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(
 2195                         EFX_PHY_MEDIA_INFO_PAGE_SIZE));
 2196         efx_rc_t rc;
 2197 
 2198         EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE);
 2199 
 2200         req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO;
 2201         req.emr_in_buf = payload;
 2202         req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN;
 2203         req.emr_out_buf = payload;
 2204         req.emr_out_length =
 2205             MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE);
 2206 
 2207         MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page);
 2208 
 2209         efx_mcdi_execute(enp, &req);
 2210 
 2211         if (req.emr_rc != 0) {
 2212                 rc = req.emr_rc;
 2213                 goto fail1;
 2214         }
 2215 
 2216         if (req.emr_out_length_used !=
 2217             MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) {
 2218                 rc = EMSGSIZE;
 2219                 goto fail2;
 2220         }
 2221 
 2222         if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) !=
 2223             EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
 2224                 rc = EIO;
 2225                 goto fail3;
 2226         }
 2227 
 2228         memcpy(data,
 2229             MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset,
 2230             len);
 2231 
 2232         return (0);
 2233 
 2234 fail3:
 2235         EFSYS_PROBE(fail3);
 2236 fail2:
 2237         EFSYS_PROBE(fail2);
 2238 fail1:
 2239         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 2240 
 2241         return (rc);
 2242 }
 2243 
 2244         __checkReturn           efx_rc_t
 2245 efx_mcdi_phy_module_get_info(
 2246         __in                    efx_nic_t *enp,
 2247         __in                    uint8_t dev_addr,
 2248         __in                    size_t offset,
 2249         __in                    size_t len,
 2250         __out_bcount(len)       uint8_t *data)
 2251 {
 2252         efx_port_t *epp = &(enp->en_port);
 2253         efx_rc_t rc;
 2254         uint32_t mcdi_lower_page;
 2255         uint32_t mcdi_upper_page;
 2256         uint8_t id;
 2257 
 2258         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 2259 
 2260         /*
 2261          * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages.
 2262          * Offset plus length interface allows to access page 0 only.
 2263          * I.e. non-zero upper pages are not accessible.
 2264          * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6
 2265          * QSFP+ Memory Map for details on how information is structured
 2266          * and accessible.
 2267          */
 2268         switch (epp->ep_fixed_port_type) {
 2269         case EFX_PHY_MEDIA_SFP_PLUS:
 2270         case EFX_PHY_MEDIA_QSFP_PLUS:
 2271                 /* Port type supports modules */
 2272                 break;
 2273         default:
 2274                 rc = ENOTSUP;
 2275                 goto fail1;
 2276         }
 2277 
 2278         /*
 2279          * For all supported port types, MCDI page 0 offset 0 holds the
 2280          * transceiver identifier. Probe to determine the data layout.
 2281          * Definitions from SFF-8024 Table 4-1.
 2282          */
 2283         rc = efx_mcdi_get_phy_media_info(enp, 0, 0, sizeof (id), &id);
 2284         if (rc != 0)
 2285                 goto fail2;
 2286 
 2287         switch (id) {
 2288         case EFX_SFF_TRANSCEIVER_ID_SFP:
 2289                 /*
 2290                  * In accordance with SFF-8472 Diagnostic Monitoring
 2291                  * Interface for Optical Transceivers section 4 Memory
 2292                  * Organization two 2-wire addresses are defined.
 2293                  */
 2294                 switch (dev_addr) {
 2295                 /* Base information */
 2296                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE:
 2297                         /*
 2298                          * MCDI page 0 should be used to access lower
 2299                          * page 0 (0x00 - 0x7f) at the device address 0xA0.
 2300                          */
 2301                         mcdi_lower_page = 0;
 2302                         /*
 2303                          * MCDI page 1 should be used to access  upper
 2304                          * page 0 (0x80 - 0xff) at the device address 0xA0.
 2305                          */
 2306                         mcdi_upper_page = 1;
 2307                         break;
 2308                 /* Diagnostics */
 2309                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM:
 2310                         /*
 2311                          * MCDI page 2 should be used to access lower
 2312                          * page 0 (0x00 - 0x7f) at the device address 0xA2.
 2313                          */
 2314                         mcdi_lower_page = 2;
 2315                         /*
 2316                          * MCDI page 3 should be used to access upper
 2317                          * page 0 (0x80 - 0xff) at the device address 0xA2.
 2318                          */
 2319                         mcdi_upper_page = 3;
 2320                         break;
 2321                 default:
 2322                         rc = ENOTSUP;
 2323                         goto fail3;
 2324                 }
 2325                 break;
 2326         case EFX_SFF_TRANSCEIVER_ID_QSFP:
 2327         case EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS:
 2328         case EFX_SFF_TRANSCEIVER_ID_QSFP28:
 2329                 switch (dev_addr) {
 2330                 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP:
 2331                         /*
 2332                          * MCDI page -1 should be used to access lower page 0
 2333                          * (0x00 - 0x7f).
 2334                          */
 2335                         mcdi_lower_page = (uint32_t)-1;
 2336                         /*
 2337                          * MCDI page 0 should be used to access upper page 0
 2338                          * (0x80h - 0xff).
 2339                          */
 2340                         mcdi_upper_page = 0;
 2341                         break;
 2342                 default:
 2343                         rc = ENOTSUP;
 2344                         goto fail3;
 2345                 }
 2346                 break;
 2347         default:
 2348                 rc = ENOTSUP;
 2349                 goto fail3;
 2350         }
 2351 
 2352         EFX_STATIC_ASSERT(EFX_PHY_MEDIA_INFO_PAGE_SIZE <= 0xFF);
 2353 
 2354         if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) {
 2355                 size_t read_len =
 2356                     MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset);
 2357 
 2358                 rc = efx_mcdi_get_phy_media_info(enp,
 2359                     mcdi_lower_page, (uint8_t)offset, (uint8_t)read_len, data);
 2360                 if (rc != 0)
 2361                         goto fail4;
 2362 
 2363                 data += read_len;
 2364                 len -= read_len;
 2365 
 2366                 offset = 0;
 2367         } else {
 2368                 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE;
 2369         }
 2370 
 2371         if (len > 0) {
 2372                 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
 2373                 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE);
 2374 
 2375                 rc = efx_mcdi_get_phy_media_info(enp,
 2376                     mcdi_upper_page, (uint8_t)offset, (uint8_t)len, data);
 2377                 if (rc != 0)
 2378                         goto fail5;
 2379         }
 2380 
 2381         return (0);
 2382 
 2383 fail5:
 2384         EFSYS_PROBE(fail5);
 2385 fail4:
 2386         EFSYS_PROBE(fail4);
 2387 fail3:
 2388         EFSYS_PROBE(fail3);
 2389 fail2:
 2390         EFSYS_PROBE(fail2);
 2391 fail1:
 2392         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 2393 
 2394         return (rc);
 2395 }
 2396 
 2397 #endif  /* EFSYS_OPT_MCDI */

Cache object: b2a39e4493927efa42a18fd99a1ba55c


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