]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/efx_mcdi.c
MFC r292055
[FreeBSD/stable/10.git] / sys / dev / sfxge / common / efx_mcdi.c
1 /*-
2  * Copyright (c) 2008-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs.h"
38 #include "efx_regs_mcdi.h"
39 #include "efx_impl.h"
40
41 #if EFSYS_OPT_MCDI
42
43
44 #if EFSYS_OPT_SIENA
45
46 static efx_mcdi_ops_t   __efx_mcdi_siena_ops = {
47         siena_mcdi_init,                /* emco_init */
48         siena_mcdi_request_copyin,      /* emco_request_copyin */
49         siena_mcdi_request_poll,        /* emco_request_poll */
50         siena_mcdi_request_copyout,     /* emco_request_copyout */
51         siena_mcdi_poll_reboot,         /* emco_poll_reboot */
52         siena_mcdi_fini,                /* emco_fini */
53         siena_mcdi_feature_supported,   /* emco_feature_supported */
54         siena_mcdi_read_response,       /* emco_read_response */
55 };
56
57 #endif  /* EFSYS_OPT_SIENA */
58
59 #if EFSYS_OPT_HUNTINGTON
60
61 static efx_mcdi_ops_t   __efx_mcdi_hunt_ops = {
62         hunt_mcdi_init,                 /* emco_init */
63         hunt_mcdi_request_copyin,       /* emco_request_copyin */
64         hunt_mcdi_request_poll,         /* emco_request_poll */
65         hunt_mcdi_request_copyout,      /* emco_request_copyout */
66         hunt_mcdi_poll_reboot,          /* emco_poll_reboot */
67         hunt_mcdi_fini,                 /* emco_fini */
68         hunt_mcdi_feature_supported,    /* emco_feature_supported */
69         hunt_mcdi_read_response,        /* emco_read_response */
70 };
71
72 #endif  /* EFSYS_OPT_HUNTINGTON */
73
74
75
76         __checkReturn   efx_rc_t
77 efx_mcdi_init(
78         __in            efx_nic_t *enp,
79         __in            const efx_mcdi_transport_t *emtp)
80 {
81         efx_mcdi_ops_t *emcop;
82         efx_rc_t rc;
83
84         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
85         EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
86
87         switch (enp->en_family) {
88 #if EFSYS_OPT_FALCON
89         case EFX_FAMILY_FALCON:
90                 emcop = NULL;
91                 emtp = NULL;
92                 break;
93 #endif  /* EFSYS_OPT_FALCON */
94
95 #if EFSYS_OPT_SIENA
96         case EFX_FAMILY_SIENA:
97                 emcop = (efx_mcdi_ops_t *)&__efx_mcdi_siena_ops;
98                 break;
99 #endif  /* EFSYS_OPT_SIENA */
100
101 #if EFSYS_OPT_HUNTINGTON
102         case EFX_FAMILY_HUNTINGTON:
103                 emcop = (efx_mcdi_ops_t *)&__efx_mcdi_hunt_ops;
104                 break;
105 #endif  /* EFSYS_OPT_HUNTINGTON */
106
107         default:
108                 EFSYS_ASSERT(0);
109                 rc = ENOTSUP;
110                 goto fail1;
111         }
112
113         if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
114                 /* MCDI requires a DMA buffer in host memory */
115                 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
116                         rc = EINVAL;
117                         goto fail2;
118                 }
119         }
120         enp->en_mcdi.em_emtp = emtp;
121
122         if (emcop != NULL && emcop->emco_init != NULL) {
123                 if ((rc = emcop->emco_init(enp, emtp)) != 0)
124                         goto fail3;
125         }
126
127         enp->en_mcdi.em_emcop = emcop;
128         enp->en_mod_flags |= EFX_MOD_MCDI;
129
130         return (0);
131
132 fail3:
133         EFSYS_PROBE(fail3);
134 fail2:
135         EFSYS_PROBE(fail2);
136 fail1:
137         EFSYS_PROBE1(fail1, efx_rc_t, rc);
138
139         enp->en_mcdi.em_emcop = NULL;
140         enp->en_mcdi.em_emtp = NULL;
141         enp->en_mod_flags &= ~EFX_MOD_MCDI;
142
143         return (rc);
144 }
145
146                         void
147 efx_mcdi_fini(
148         __in            efx_nic_t *enp)
149 {
150         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
151         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
152
153         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
154         EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
155
156         if (emcop != NULL && emcop->emco_fini != NULL)
157                 emcop->emco_fini(enp);
158
159         emip->emi_port = 0;
160         emip->emi_aborted = 0;
161
162         enp->en_mcdi.em_emcop = NULL;
163         enp->en_mod_flags &= ~EFX_MOD_MCDI;
164 }
165
166                         void
167 efx_mcdi_new_epoch(
168         __in            efx_nic_t *enp)
169 {
170         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
171         int state;
172
173         /* Start a new epoch (allow fresh MCDI requests to succeed) */
174         EFSYS_LOCK(enp->en_eslp, state);
175         emip->emi_new_epoch = B_TRUE;
176         EFSYS_UNLOCK(enp->en_eslp, state);
177 }
178
179
180                         void
181 efx_mcdi_request_start(
182         __in            efx_nic_t *enp,
183         __in            efx_mcdi_req_t *emrp,
184         __in            boolean_t ev_cpl)
185 {
186         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
187         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
188         unsigned int seq;
189         boolean_t new_epoch;
190         int state;
191
192         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
193         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
194         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
195
196         if (emcop == NULL || emcop->emco_request_copyin == NULL)
197                 return;
198
199         /*
200          * efx_mcdi_request_start() is naturally serialised against both
201          * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
202          * by virtue of there only being one outstanding MCDI request.
203          * Unfortunately, upper layers may also call efx_mcdi_request_abort()
204          * at any time, to timeout a pending mcdi request, That request may
205          * then subsequently complete, meaning efx_mcdi_ev_cpl() or
206          * efx_mcdi_ev_death() may end up running in parallel with
207          * efx_mcdi_request_start(). This race is handled by ensuring that
208          * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
209          * en_eslp lock.
210          */
211         EFSYS_LOCK(enp->en_eslp, state);
212         EFSYS_ASSERT(emip->emi_pending_req == NULL);
213         emip->emi_pending_req = emrp;
214         emip->emi_ev_cpl = ev_cpl;
215         emip->emi_poll_cnt = 0;
216         seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
217         new_epoch = emip->emi_new_epoch;
218         EFSYS_UNLOCK(enp->en_eslp, state);
219
220         emcop->emco_request_copyin(enp, emrp, seq, ev_cpl, new_epoch);
221 }
222
223
224                         void
225 efx_mcdi_read_response_header(
226         __in            efx_nic_t *enp,
227         __inout         efx_mcdi_req_t *emrp)
228 {
229 #if EFSYS_OPT_MCDI_LOGGING
230         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
231 #endif /* EFSYS_OPT_MCDI_LOGGING */
232         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
233         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
234         efx_dword_t hdr[2];
235         unsigned int hdr_len;
236         unsigned int data_len;
237         unsigned int seq;
238         unsigned int cmd;
239         unsigned int error;
240         efx_rc_t rc;
241
242         EFSYS_ASSERT(emrp != NULL);
243
244         emcop->emco_read_response(enp, &hdr[0], 0, sizeof (hdr[0]));
245         hdr_len = sizeof (hdr[0]);
246
247         cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE);
248         seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ);
249         error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR);
250
251         if (cmd != MC_CMD_V2_EXTN) {
252                 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN);
253         } else {
254                 emcop->emco_read_response(enp, &hdr[1], hdr_len,
255                     sizeof (hdr[1]));
256                 hdr_len += sizeof (hdr[1]);
257
258                 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
259                 data_len =
260                     EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
261         }
262
263         if (error && (data_len == 0)) {
264                 /* The MC has rebooted since the request was sent. */
265                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
266                 emcop->emco_poll_reboot(enp);
267                 rc = EIO;
268                 goto fail1;
269         }
270         if ((cmd != emrp->emr_cmd) ||
271             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
272                 /* Response is for a different request */
273                 rc = EIO;
274                 goto fail2;
275         }
276         if (error) {
277                 efx_dword_t err[2];
278                 unsigned int err_len = MIN(data_len, sizeof (err));
279                 int err_code = MC_CMD_ERR_EPROTO;
280                 int err_arg = 0;
281
282                 /* Read error code (and arg num for MCDI v2 commands) */
283                 emcop->emco_read_response(enp, &err, hdr_len, err_len);
284
285                 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t)))
286                         err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0);
287 #ifdef WITH_MCDI_V2
288                 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t)))
289                         err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0);
290 #endif
291                 emrp->emr_err_code = err_code;
292                 emrp->emr_err_arg = err_arg;
293
294 #if EFSYS_OPT_MCDI_PROXY_AUTH
295                 if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
296                     (err_len == sizeof (err))) {
297                         /*
298                          * The MCDI request would normally fail with EPERM, but
299                          * firmware has forwarded it to an authorization agent
300                          * attached to a privileged PF.
301                          *
302                          * Save the authorization request handle. The client
303                          * must wait for a PROXY_RESPONSE event, or timeout.
304                          */
305                         emrp->emr_proxy_handle = err_arg;
306                 }
307 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
308
309 #if EFSYS_OPT_MCDI_LOGGING
310                 if (emtp->emt_logger != NULL) {
311                         emtp->emt_logger(emtp->emt_context,
312                             EFX_LOG_MCDI_RESPONSE,
313                             &hdr, hdr_len,
314                             &err, err_len);
315                 }
316 #endif /* EFSYS_OPT_MCDI_LOGGING */
317
318                 if (!emrp->emr_quiet) {
319                         EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
320                             int, err_code, int, err_arg);
321                 }
322
323                 rc = efx_mcdi_request_errcode(err_code);
324                 goto fail3;
325         }
326
327         emrp->emr_rc = 0;
328         emrp->emr_out_length_used = data_len;
329 #if EFSYS_OPT_MCDI_PROXY_AUTH
330         emrp->emr_proxy_handle = 0;
331 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
332         return;
333
334 fail3:
335         if (!emrp->emr_quiet)
336                 EFSYS_PROBE(fail3);
337 fail2:
338         if (!emrp->emr_quiet)
339                 EFSYS_PROBE(fail2);
340 fail1:
341         if (!emrp->emr_quiet)
342                 EFSYS_PROBE1(fail1, efx_rc_t, rc);
343
344         emrp->emr_rc = rc;
345         emrp->emr_out_length_used = 0;
346 }
347
348
349         __checkReturn   boolean_t
350 efx_mcdi_request_poll(
351         __in            efx_nic_t *enp)
352 {
353         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
354         boolean_t completed;
355
356         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
357         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
358         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
359
360         completed = B_FALSE;
361
362         if (emcop != NULL && emcop->emco_request_poll != NULL)
363                 completed = emcop->emco_request_poll(enp);
364
365         return (completed);
366 }
367
368         __checkReturn   boolean_t
369 efx_mcdi_request_abort(
370         __in            efx_nic_t *enp)
371 {
372         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
373         efx_mcdi_req_t *emrp;
374         boolean_t aborted;
375         int state;
376
377         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
378         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
379         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
380
381         /*
382          * efx_mcdi_ev_* may have already completed this event, and be
383          * spinning/blocked on the upper layer lock. So it *is* legitimate
384          * to for emi_pending_req to be NULL. If there is a pending event
385          * completed request, then provide a "credit" to allow
386          * efx_mcdi_ev_cpl() to accept a single spurious completion.
387          */
388         EFSYS_LOCK(enp->en_eslp, state);
389         emrp = emip->emi_pending_req;
390         aborted = (emrp != NULL);
391         if (aborted) {
392                 emip->emi_pending_req = NULL;
393
394                 /* Error the request */
395                 emrp->emr_out_length_used = 0;
396                 emrp->emr_rc = ETIMEDOUT;
397
398                 /* Provide a credit for seqno/emr_pending_req mismatches */
399                 if (emip->emi_ev_cpl)
400                         ++emip->emi_aborted;
401
402                 /*
403                  * The upper layer has called us, so we don't
404                  * need to complete the request.
405                  */
406         }
407         EFSYS_UNLOCK(enp->en_eslp, state);
408
409         return (aborted);
410 }
411
412         __checkReturn   efx_rc_t
413 efx_mcdi_request_errcode(
414         __in            unsigned int err)
415 {
416
417         switch (err) {
418                 /* MCDI v1 */
419         case MC_CMD_ERR_EPERM:
420                 return (EACCES);
421         case MC_CMD_ERR_ENOENT:
422                 return (ENOENT);
423         case MC_CMD_ERR_EINTR:
424                 return (EINTR);
425         case MC_CMD_ERR_EACCES:
426                 return (EACCES);
427         case MC_CMD_ERR_EBUSY:
428                 return (EBUSY);
429         case MC_CMD_ERR_EINVAL:
430                 return (EINVAL);
431         case MC_CMD_ERR_EDEADLK:
432                 return (EDEADLK);
433         case MC_CMD_ERR_ENOSYS:
434                 return (ENOTSUP);
435         case MC_CMD_ERR_ETIME:
436                 return (ETIMEDOUT);
437         case MC_CMD_ERR_ENOTSUP:
438                 return (ENOTSUP);
439         case MC_CMD_ERR_EALREADY:
440                 return (EALREADY);
441
442                 /* MCDI v2 */
443 #ifdef MC_CMD_ERR_EAGAIN
444         case MC_CMD_ERR_EAGAIN:
445                 return (EAGAIN);
446 #endif
447 #ifdef MC_CMD_ERR_ENOSPC
448         case MC_CMD_ERR_ENOSPC:
449                 return (ENOSPC);
450 #endif
451
452         case MC_CMD_ERR_ALLOC_FAIL:
453                 return (ENOMEM);
454         case MC_CMD_ERR_NO_VADAPTOR:
455                 return (ENOENT);
456         case MC_CMD_ERR_NO_EVB_PORT:
457                 return (ENOENT);
458         case MC_CMD_ERR_NO_VSWITCH:
459                 return (ENODEV);
460         case MC_CMD_ERR_VLAN_LIMIT:
461                 return (EINVAL);
462         case MC_CMD_ERR_BAD_PCI_FUNC:
463                 return (ENODEV);
464         case MC_CMD_ERR_BAD_VLAN_MODE:
465                 return (EINVAL);
466         case MC_CMD_ERR_BAD_VSWITCH_TYPE:
467                 return (EINVAL);
468         case MC_CMD_ERR_BAD_VPORT_TYPE:
469                 return (EINVAL);
470         case MC_CMD_ERR_MAC_EXIST:
471                 return (EEXIST);
472
473         case MC_CMD_ERR_PROXY_PENDING:
474                 return (EAGAIN);
475
476         default:
477                 EFSYS_PROBE1(mc_pcol_error, int, err);
478                 return (EIO);
479         }
480 }
481
482                         void
483 efx_mcdi_raise_exception(
484         __in            efx_nic_t *enp,
485         __in_opt        efx_mcdi_req_t *emrp,
486         __in            int rc)
487 {
488         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
489         efx_mcdi_exception_t exception;
490
491         /* Reboot or Assertion failure only */
492         EFSYS_ASSERT(rc == EIO || rc == EINTR);
493
494         /*
495          * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
496          * then the EIO is not worthy of an exception.
497          */
498         if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
499                 return;
500
501         exception = (rc == EIO)
502                 ? EFX_MCDI_EXCEPTION_MC_REBOOT
503                 : EFX_MCDI_EXCEPTION_MC_BADASSERT;
504
505         emtp->emt_exception(emtp->emt_context, exception);
506 }
507
508 static                  efx_rc_t
509 efx_mcdi_poll_reboot(
510         __in            efx_nic_t *enp)
511 {
512         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
513
514         return (emcop->emco_poll_reboot(enp));
515 }
516
517
518                         void
519 efx_mcdi_execute(
520         __in            efx_nic_t *enp,
521         __inout         efx_mcdi_req_t *emrp)
522 {
523         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
524
525         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
526         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
527
528         emrp->emr_quiet = B_FALSE;
529         emtp->emt_execute(emtp->emt_context, emrp);
530 }
531
532                         void
533 efx_mcdi_execute_quiet(
534         __in            efx_nic_t *enp,
535         __inout         efx_mcdi_req_t *emrp)
536 {
537         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
538
539         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
540         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
541
542         emrp->emr_quiet = B_TRUE;
543         emtp->emt_execute(emtp->emt_context, emrp);
544 }
545
546                         void
547 efx_mcdi_ev_cpl(
548         __in            efx_nic_t *enp,
549         __in            unsigned int seq,
550         __in            unsigned int outlen,
551         __in            int errcode)
552 {
553         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
554         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
555         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
556         efx_nic_cfg_t *encp = &enp->en_nic_cfg;
557         efx_mcdi_req_t *emrp;
558         int state;
559
560         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
561         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
562
563         /*
564          * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
565          * when we're completing an aborted request.
566          */
567         EFSYS_LOCK(enp->en_eslp, state);
568         if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
569             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
570                 EFSYS_ASSERT(emip->emi_aborted > 0);
571                 if (emip->emi_aborted > 0)
572                         --emip->emi_aborted;
573                 EFSYS_UNLOCK(enp->en_eslp, state);
574                 return;
575         }
576
577         emrp = emip->emi_pending_req;
578         emip->emi_pending_req = NULL;
579         EFSYS_UNLOCK(enp->en_eslp, state);
580
581         if (encp->enc_mcdi_max_payload_length > MCDI_CTL_SDU_LEN_MAX_V1) {
582                 /* MCDIv2 response details do not fit into an event. */
583                 efx_mcdi_read_response_header(enp, emrp);
584         } else {
585                 if (errcode != 0) {
586                         if (!emrp->emr_quiet) {
587                                 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
588                                     int, errcode);
589                         }
590                         emrp->emr_out_length_used = 0;
591                         emrp->emr_rc = efx_mcdi_request_errcode(errcode);
592                 } else {
593                         emrp->emr_out_length_used = outlen;
594                         emrp->emr_rc = 0;
595                 }
596         }
597         if (errcode == 0) {
598                 emcop->emco_request_copyout(enp, emrp);
599         }
600
601         emtp->emt_ev_cpl(emtp->emt_context);
602 }
603
604 #if EFSYS_OPT_MCDI_PROXY_AUTH
605
606         __checkReturn   efx_rc_t
607 efx_mcdi_get_proxy_handle(
608         __in            efx_nic_t *enp,
609         __in            efx_mcdi_req_t *emrp,
610         __out           uint32_t *handlep)
611 {
612         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
613         efx_rc_t rc;
614
615         /*
616          * Return proxy handle from MCDI request that returned with error
617          * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
618          * PROXY_RESPONSE event.
619          */
620         if ((emrp == NULL) || (handlep == NULL)) {
621                 rc = EINVAL;
622                 goto fail1;
623         }
624         if ((emrp->emr_rc != 0) &&
625             (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
626                 *handlep = emrp->emr_proxy_handle;
627                 rc = 0;
628         } else {
629                 *handlep = 0;
630                 rc = ENOENT;
631         }
632         return (rc);
633
634 fail1:
635         EFSYS_PROBE1(fail1, efx_rc_t, rc);
636         return (rc);
637 }
638
639                         void
640 efx_mcdi_ev_proxy_response(
641         __in            efx_nic_t *enp,
642         __in            unsigned int handle,
643         __in            unsigned int status)
644 {
645         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
646         efx_rc_t rc;
647
648         /*
649          * Handle results of an authorization request for a privileged MCDI
650          * command. If authorization was granted then we must re-issue the
651          * original MCDI request. If authorization failed or timed out,
652          * then the original MCDI request should be completed with the
653          * result code from this event.
654          */
655         rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
656
657         emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
658 }
659 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
660
661                         void
662 efx_mcdi_ev_death(
663         __in            efx_nic_t *enp,
664         __in            int rc)
665 {
666         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
667         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
668         efx_mcdi_req_t *emrp = NULL;
669         boolean_t ev_cpl;
670         int state;
671
672         /*
673          * The MCDI request (if there is one) has been terminated, either
674          * by a BADASSERT or REBOOT event.
675          *
676          * If there is an outstanding event-completed MCDI operation, then we
677          * will never receive the completion event (because both MCDI
678          * completions and BADASSERT events are sent to the same evq). So
679          * complete this MCDI op.
680          *
681          * This function might run in parallel with efx_mcdi_request_poll()
682          * for poll completed mcdi requests, and also with
683          * efx_mcdi_request_start() for post-watchdog completions.
684          */
685         EFSYS_LOCK(enp->en_eslp, state);
686         emrp = emip->emi_pending_req;
687         ev_cpl = emip->emi_ev_cpl;
688         if (emrp != NULL && emip->emi_ev_cpl) {
689                 emip->emi_pending_req = NULL;
690
691                 emrp->emr_out_length_used = 0;
692                 emrp->emr_rc = rc;
693                 ++emip->emi_aborted;
694         }
695
696         /*
697          * Since we're running in parallel with a request, consume the
698          * status word before dropping the lock.
699          */
700         if (rc == EIO || rc == EINTR) {
701                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
702                 (void) efx_mcdi_poll_reboot(enp);
703                 emip->emi_new_epoch = B_TRUE;
704         }
705
706         EFSYS_UNLOCK(enp->en_eslp, state);
707
708         efx_mcdi_raise_exception(enp, emrp, rc);
709
710         if (emrp != NULL && ev_cpl)
711                 emtp->emt_ev_cpl(emtp->emt_context);
712 }
713
714         __checkReturn           efx_rc_t
715 efx_mcdi_version(
716         __in                    efx_nic_t *enp,
717         __out_ecount_opt(4)     uint16_t versionp[4],
718         __out_opt               uint32_t *buildp,
719         __out_opt               efx_mcdi_boot_t *statusp)
720 {
721         efx_mcdi_req_t req;
722         uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
723                                 MC_CMD_GET_VERSION_OUT_LEN),
724                             MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
725                                 MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
726         efx_word_t *ver_words;
727         uint16_t version[4];
728         uint32_t build;
729         efx_mcdi_boot_t status;
730         efx_rc_t rc;
731
732         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
733
734         (void) memset(payload, 0, sizeof (payload));
735         req.emr_cmd = MC_CMD_GET_VERSION;
736         req.emr_in_buf = payload;
737         req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
738         req.emr_out_buf = payload;
739         req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
740
741         efx_mcdi_execute(enp, &req);
742
743         if (req.emr_rc != 0) {
744                 rc = req.emr_rc;
745                 goto fail1;
746         }
747
748         /* bootrom support */
749         if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
750                 version[0] = version[1] = version[2] = version[3] = 0;
751                 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
752
753                 goto version;
754         }
755
756         if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
757                 rc = EMSGSIZE;
758                 goto fail2;
759         }
760
761         ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
762         version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
763         version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
764         version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
765         version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
766         build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
767
768 version:
769         /* The bootrom doesn't understand BOOT_STATUS */
770         if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
771                 status = EFX_MCDI_BOOT_ROM;
772                 goto out;
773         }
774
775         (void) memset(payload, 0, sizeof (payload));
776         req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
777         req.emr_in_buf = payload;
778         req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
779         req.emr_out_buf = payload;
780         req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
781
782         efx_mcdi_execute_quiet(enp, &req);
783
784         if (req.emr_rc == EACCES) {
785                 /* Unprivileged functions cannot access BOOT_STATUS */
786                 status = EFX_MCDI_BOOT_PRIMARY;
787                 version[0] = version[1] = version[2] = version[3] = 0;
788                 build = 0;
789                 goto out;
790         }
791
792         if (req.emr_rc != 0) {
793                 rc = req.emr_rc;
794                 goto fail3;
795         }
796
797         if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
798                 rc = EMSGSIZE;
799                 goto fail4;
800         }
801
802         if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
803             GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
804                 status = EFX_MCDI_BOOT_PRIMARY;
805         else
806                 status = EFX_MCDI_BOOT_SECONDARY;
807
808 out:
809         if (versionp != NULL)
810                 memcpy(versionp, version, sizeof (version));
811         if (buildp != NULL)
812                 *buildp = build;
813         if (statusp != NULL)
814                 *statusp = status;
815
816         return (0);
817
818 fail4:
819         EFSYS_PROBE(fail4);
820 fail3:
821         EFSYS_PROBE(fail3);
822 fail2:
823         EFSYS_PROBE(fail2);
824 fail1:
825         EFSYS_PROBE1(fail1, efx_rc_t, rc);
826
827         return (rc);
828 }
829
830 static  __checkReturn   efx_rc_t
831 efx_mcdi_do_reboot(
832         __in            efx_nic_t *enp,
833         __in            boolean_t after_assertion)
834 {
835         uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
836         efx_mcdi_req_t req;
837         efx_rc_t rc;
838
839         /*
840          * We could require the caller to have caused en_mod_flags=0 to
841          * call this function. This doesn't help the other port though,
842          * who's about to get the MC ripped out from underneath them.
843          * Since they have to cope with the subsequent fallout of MCDI
844          * failures, we should as well.
845          */
846         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
847
848         (void) memset(payload, 0, sizeof (payload));
849         req.emr_cmd = MC_CMD_REBOOT;
850         req.emr_in_buf = payload;
851         req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
852         req.emr_out_buf = payload;
853         req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
854
855         MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
856             (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
857
858         efx_mcdi_execute_quiet(enp, &req);
859
860         if (req.emr_rc == EACCES) {
861                 /* Unprivileged functions cannot reboot the MC. */
862                 goto out;
863         }
864
865         /* A successful reboot request returns EIO. */
866         if (req.emr_rc != 0 && req.emr_rc != EIO) {
867                 rc = req.emr_rc;
868                 goto fail1;
869         }
870
871 out:
872         return (0);
873
874 fail1:
875         EFSYS_PROBE1(fail1, efx_rc_t, rc);
876
877         return (rc);
878 }
879
880         __checkReturn   efx_rc_t
881 efx_mcdi_reboot(
882         __in            efx_nic_t *enp)
883 {
884         return (efx_mcdi_do_reboot(enp, B_FALSE));
885 }
886
887         __checkReturn   efx_rc_t
888 efx_mcdi_exit_assertion_handler(
889         __in            efx_nic_t *enp)
890 {
891         return (efx_mcdi_do_reboot(enp, B_TRUE));
892 }
893
894         __checkReturn   efx_rc_t
895 efx_mcdi_read_assertion(
896         __in            efx_nic_t *enp)
897 {
898         efx_mcdi_req_t req;
899         uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
900                             MC_CMD_GET_ASSERTS_OUT_LEN)];
901         const char *reason;
902         unsigned int flags;
903         unsigned int index;
904         unsigned int ofst;
905         int retry;
906         efx_rc_t rc;
907
908         /*
909          * Before we attempt to chat to the MC, we should verify that the MC
910          * isn't in it's assertion handler, either due to a previous reboot,
911          * or because we're reinitializing due to an eec_exception().
912          *
913          * Use GET_ASSERTS to read any assertion state that may be present.
914          * Retry this command twice. Once because a boot-time assertion failure
915          * might cause the 1st MCDI request to fail. And once again because
916          * we might race with efx_mcdi_exit_assertion_handler() running on
917          * partner port(s) on the same NIC.
918          */
919         retry = 2;
920         do {
921                 (void) memset(payload, 0, sizeof (payload));
922                 req.emr_cmd = MC_CMD_GET_ASSERTS;
923                 req.emr_in_buf = payload;
924                 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
925                 req.emr_out_buf = payload;
926                 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
927
928                 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
929                 efx_mcdi_execute_quiet(enp, &req);
930
931         } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
932
933         if (req.emr_rc != 0) {
934                 if (req.emr_rc == EACCES) {
935                         /* Unprivileged functions cannot clear assertions. */
936                         goto out;
937                 }
938                 rc = req.emr_rc;
939                 goto fail1;
940         }
941
942         if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
943                 rc = EMSGSIZE;
944                 goto fail2;
945         }
946
947         /* Print out any assertion state recorded */
948         flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
949         if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
950                 return (0);
951
952         reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
953                 ? "system-level assertion"
954                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
955                 ? "thread-level assertion"
956                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
957                 ? "watchdog reset"
958                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
959                 ? "illegal address trap"
960                 : "unknown assertion";
961         EFSYS_PROBE3(mcpu_assertion,
962             const char *, reason, unsigned int,
963             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
964             unsigned int,
965             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
966
967         /* Print out the registers (r1 ... r31) */
968         ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
969         for (index = 1;
970                 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
971                 index++) {
972                 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
973                             EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
974                                             EFX_DWORD_0));
975                 ofst += sizeof (efx_dword_t);
976         }
977         EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
978
979 out:
980         return (0);
981
982 fail2:
983         EFSYS_PROBE(fail2);
984 fail1:
985         EFSYS_PROBE1(fail1, efx_rc_t, rc);
986
987         return (rc);
988 }
989
990
991 /*
992  * Internal routines for for specific MCDI requests.
993  */
994
995         __checkReturn   efx_rc_t
996 efx_mcdi_drv_attach(
997         __in            efx_nic_t *enp,
998         __in            boolean_t attach)
999 {
1000         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1001         efx_mcdi_req_t req;
1002         uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
1003                             MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
1004         uint32_t flags;
1005         efx_rc_t rc;
1006
1007         (void) memset(payload, 0, sizeof (payload));
1008         req.emr_cmd = MC_CMD_DRV_ATTACH;
1009         req.emr_in_buf = payload;
1010         req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
1011         req.emr_out_buf = payload;
1012         req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
1013
1014         /*
1015          * Use DONT_CARE for the datapath firmware type to ensure that the
1016          * driver can attach to an unprivileged function. The datapath firmware
1017          * type to use is controlled by the 'sfboot' utility.
1018          */
1019         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
1020         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
1021         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
1022
1023         efx_mcdi_execute(enp, &req);
1024
1025         if (req.emr_rc != 0) {
1026                 rc = req.emr_rc;
1027                 goto fail1;
1028         }
1029
1030         if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
1031                 rc = EMSGSIZE;
1032                 goto fail2;
1033         }
1034
1035         if (attach == B_FALSE) {
1036                 flags = 0;
1037         } else if (enp->en_family == EFX_FAMILY_SIENA) {
1038                 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1039
1040                 /* Create synthetic privileges for Siena functions */
1041                 flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED;
1042                 if (emip->emi_port == 1)
1043                         flags |= EFX_NIC_FUNC_PRIMARY;
1044         } else {
1045                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY ==
1046                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY));
1047                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL ==
1048                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL));
1049                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED ==
1050                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED));
1051
1052                 /* Save function privilege flags (EF10 and later) */
1053                 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) {
1054                         rc = EMSGSIZE;
1055                         goto fail3;
1056                 }
1057                 flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS);
1058         }
1059         encp->enc_func_flags = flags;
1060
1061         return (0);
1062
1063 fail3:
1064         EFSYS_PROBE(fail3);
1065 fail2:
1066         EFSYS_PROBE(fail2);
1067 fail1:
1068         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1069
1070         return (rc);
1071 }
1072
1073         __checkReturn           efx_rc_t
1074 efx_mcdi_get_board_cfg(
1075         __in                    efx_nic_t *enp,
1076         __out_opt               uint32_t *board_typep,
1077         __out_opt               efx_dword_t *capabilitiesp,
1078         __out_ecount_opt(6)     uint8_t mac_addrp[6])
1079 {
1080         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1081         efx_mcdi_req_t req;
1082         uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1083                             MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1084         efx_rc_t rc;
1085
1086         (void) memset(payload, 0, sizeof (payload));
1087         req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1088         req.emr_in_buf = payload;
1089         req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1090         req.emr_out_buf = payload;
1091         req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1092
1093         efx_mcdi_execute(enp, &req);
1094
1095         if (req.emr_rc != 0) {
1096                 rc = req.emr_rc;
1097                 goto fail1;
1098         }
1099
1100         if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1101                 rc = EMSGSIZE;
1102                 goto fail2;
1103         }
1104
1105         if (mac_addrp != NULL) {
1106                 uint8_t *addrp;
1107
1108                 if (emip->emi_port == 1) {
1109                         addrp = MCDI_OUT2(req, uint8_t,
1110                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1111                 } else if (emip->emi_port == 2) {
1112                         addrp = MCDI_OUT2(req, uint8_t,
1113                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1114                 } else {
1115                         rc = EINVAL;
1116                         goto fail3;
1117                 }
1118
1119                 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1120         }
1121
1122         if (capabilitiesp != NULL) {
1123                 if (emip->emi_port == 1) {
1124                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1125                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1126                 } else if (emip->emi_port == 2) {
1127                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1128                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1129                 } else {
1130                         rc = EINVAL;
1131                         goto fail4;
1132                 }
1133         }
1134
1135         if (board_typep != NULL) {
1136                 *board_typep = MCDI_OUT_DWORD(req,
1137                     GET_BOARD_CFG_OUT_BOARD_TYPE);
1138         }
1139
1140         return (0);
1141
1142 fail4:
1143         EFSYS_PROBE(fail4);
1144 fail3:
1145         EFSYS_PROBE(fail3);
1146 fail2:
1147         EFSYS_PROBE(fail2);
1148 fail1:
1149         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1150
1151         return (rc);
1152 }
1153
1154         __checkReturn   efx_rc_t
1155 efx_mcdi_get_resource_limits(
1156         __in            efx_nic_t *enp,
1157         __out_opt       uint32_t *nevqp,
1158         __out_opt       uint32_t *nrxqp,
1159         __out_opt       uint32_t *ntxqp)
1160 {
1161         efx_mcdi_req_t req;
1162         uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1163                             MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1164         efx_rc_t rc;
1165
1166         (void) memset(payload, 0, sizeof (payload));
1167         req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1168         req.emr_in_buf = payload;
1169         req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1170         req.emr_out_buf = payload;
1171         req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1172
1173         efx_mcdi_execute(enp, &req);
1174
1175         if (req.emr_rc != 0) {
1176                 rc = req.emr_rc;
1177                 goto fail1;
1178         }
1179
1180         if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1181                 rc = EMSGSIZE;
1182                 goto fail2;
1183         }
1184
1185         if (nevqp != NULL)
1186                 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1187         if (nrxqp != NULL)
1188                 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1189         if (ntxqp != NULL)
1190                 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1191
1192         return (0);
1193
1194 fail2:
1195         EFSYS_PROBE(fail2);
1196 fail1:
1197         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1198
1199         return (rc);
1200 }
1201
1202         __checkReturn   efx_rc_t
1203 efx_mcdi_get_phy_cfg(
1204         __in            efx_nic_t *enp)
1205 {
1206         efx_port_t *epp = &(enp->en_port);
1207         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1208         efx_mcdi_req_t req;
1209         uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1210                             MC_CMD_GET_PHY_CFG_OUT_LEN)];
1211         efx_rc_t rc;
1212
1213         (void) memset(payload, 0, sizeof (payload));
1214         req.emr_cmd = MC_CMD_GET_PHY_CFG;
1215         req.emr_in_buf = payload;
1216         req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1217         req.emr_out_buf = payload;
1218         req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1219
1220         efx_mcdi_execute(enp, &req);
1221
1222         if (req.emr_rc != 0) {
1223                 rc = req.emr_rc;
1224                 goto fail1;
1225         }
1226
1227         if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1228                 rc = EMSGSIZE;
1229                 goto fail2;
1230         }
1231
1232         encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1233 #if EFSYS_OPT_NAMES
1234         (void) strncpy(encp->enc_phy_name,
1235                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1236                 MIN(sizeof (encp->enc_phy_name) - 1,
1237                     MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1238 #endif  /* EFSYS_OPT_NAMES */
1239         (void) memset(encp->enc_phy_revision, 0,
1240             sizeof (encp->enc_phy_revision));
1241         memcpy(encp->enc_phy_revision,
1242                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1243                 MIN(sizeof (encp->enc_phy_revision) - 1,
1244                     MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1245 #if EFSYS_OPT_PHY_LED_CONTROL
1246         encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1247                             (1 << EFX_PHY_LED_OFF) |
1248                             (1 << EFX_PHY_LED_ON));
1249 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
1250
1251 #if EFSYS_OPT_PHY_PROPS
1252         encp->enc_phy_nprops  = 0;
1253 #endif  /* EFSYS_OPT_PHY_PROPS */
1254
1255         /* Get the media type of the fixed port, if recognised. */
1256         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1257         EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1258         EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1259         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1260         EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1261         EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1262         EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1263         epp->ep_fixed_port_type =
1264                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1265         if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1266                 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1267
1268         epp->ep_phy_cap_mask =
1269                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1270 #if EFSYS_OPT_PHY_FLAGS
1271         encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1272 #endif  /* EFSYS_OPT_PHY_FLAGS */
1273
1274         encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1275
1276         /* Populate internal state */
1277         encp->enc_mcdi_mdio_channel =
1278                 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1279
1280 #if EFSYS_OPT_PHY_STATS
1281         encp->enc_mcdi_phy_stat_mask =
1282                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1283 #endif  /* EFSYS_OPT_PHY_STATS */
1284
1285 #if EFSYS_OPT_BIST
1286         encp->enc_bist_mask = 0;
1287         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1288             GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1289                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1290         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1291             GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1292                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1293         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1294             GET_PHY_CFG_OUT_BIST))
1295                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1296 #endif  /* EFSYS_OPT_BIST */
1297
1298         return (0);
1299
1300 fail2:
1301         EFSYS_PROBE(fail2);
1302 fail1:
1303         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1304
1305         return (rc);
1306 }
1307
1308         __checkReturn           efx_rc_t
1309 efx_mcdi_firmware_update_supported(
1310         __in                    efx_nic_t *enp,
1311         __out                   boolean_t *supportedp)
1312 {
1313         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1314         efx_rc_t rc;
1315
1316         if (emcop != NULL) {
1317                 if ((rc = emcop->emco_feature_supported(enp,
1318                             EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0)
1319                         goto fail1;
1320         } else {
1321                 /* Earlier devices always supported updates */
1322                 *supportedp = B_TRUE;
1323         }
1324
1325         return (0);
1326
1327 fail1:
1328         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1329
1330         return (rc);
1331 }
1332
1333         __checkReturn           efx_rc_t
1334 efx_mcdi_macaddr_change_supported(
1335         __in                    efx_nic_t *enp,
1336         __out                   boolean_t *supportedp)
1337 {
1338         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1339         efx_rc_t rc;
1340
1341         if (emcop != NULL) {
1342                 if ((rc = emcop->emco_feature_supported(enp,
1343                             EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0)
1344                         goto fail1;
1345         } else {
1346                 /* Earlier devices always supported MAC changes */
1347                 *supportedp = B_TRUE;
1348         }
1349
1350         return (0);
1351
1352 fail1:
1353         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1354
1355         return (rc);
1356 }
1357
1358         __checkReturn           efx_rc_t
1359 efx_mcdi_link_control_supported(
1360         __in                    efx_nic_t *enp,
1361         __out                   boolean_t *supportedp)
1362 {
1363         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1364         efx_rc_t rc;
1365
1366         if (emcop != NULL) {
1367                 if ((rc = emcop->emco_feature_supported(enp,
1368                             EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0)
1369                         goto fail1;
1370         } else {
1371                 /* Earlier devices always supported link control */
1372                 *supportedp = B_TRUE;
1373         }
1374
1375         return (0);
1376
1377 fail1:
1378         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1379
1380         return (rc);
1381 }
1382
1383         __checkReturn           efx_rc_t
1384 efx_mcdi_mac_spoofing_supported(
1385         __in                    efx_nic_t *enp,
1386         __out                   boolean_t *supportedp)
1387 {
1388         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1389         efx_rc_t rc;
1390
1391         if (emcop != NULL) {
1392                 if ((rc = emcop->emco_feature_supported(enp,
1393                             EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0)
1394                         goto fail1;
1395         } else {
1396                 /* Earlier devices always supported MAC spoofing */
1397                 *supportedp = B_TRUE;
1398         }
1399
1400         return (0);
1401
1402 fail1:
1403         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1404
1405         return (rc);
1406 }
1407
1408 #if EFSYS_OPT_BIST
1409
1410 #if EFSYS_OPT_HUNTINGTON
1411 /*
1412  * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1413  * where memory BIST tests can be run and not much else can interfere or happen.
1414  * A reboot is required to exit this mode.
1415  */
1416         __checkReturn           efx_rc_t
1417 efx_mcdi_bist_enable_offline(
1418         __in                    efx_nic_t *enp)
1419 {
1420         efx_mcdi_req_t req;
1421         efx_rc_t rc;
1422
1423         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1424         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1425
1426         req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1427         req.emr_in_buf = NULL;
1428         req.emr_in_length = 0;
1429         req.emr_out_buf = NULL;
1430         req.emr_out_length = 0;
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         return (0);
1440
1441 fail1:
1442         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1443
1444         return (rc);
1445 }
1446 #endif /* EFSYS_OPT_HUNTINGTON */
1447
1448         __checkReturn           efx_rc_t
1449 efx_mcdi_bist_start(
1450         __in                    efx_nic_t *enp,
1451         __in                    efx_bist_type_t type)
1452 {
1453         efx_mcdi_req_t req;
1454         uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1455                             MC_CMD_START_BIST_OUT_LEN)];
1456         efx_rc_t rc;
1457
1458         (void) memset(payload, 0, sizeof (payload));
1459         req.emr_cmd = MC_CMD_START_BIST;
1460         req.emr_in_buf = payload;
1461         req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1462         req.emr_out_buf = payload;
1463         req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1464
1465         switch (type) {
1466         case EFX_BIST_TYPE_PHY_NORMAL:
1467                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1468                 break;
1469         case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1470                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1471                     MC_CMD_PHY_BIST_CABLE_SHORT);
1472                 break;
1473         case EFX_BIST_TYPE_PHY_CABLE_LONG:
1474                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1475                     MC_CMD_PHY_BIST_CABLE_LONG);
1476                 break;
1477         case EFX_BIST_TYPE_MC_MEM:
1478                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1479                     MC_CMD_MC_MEM_BIST);
1480                 break;
1481         case EFX_BIST_TYPE_SAT_MEM:
1482                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1483                     MC_CMD_PORT_MEM_BIST);
1484                 break;
1485         case EFX_BIST_TYPE_REG:
1486                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1487                     MC_CMD_REG_BIST);
1488                 break;
1489         default:
1490                 EFSYS_ASSERT(0);
1491         }
1492
1493         efx_mcdi_execute(enp, &req);
1494
1495         if (req.emr_rc != 0) {
1496                 rc = req.emr_rc;
1497                 goto fail1;
1498         }
1499
1500         return (0);
1501
1502 fail1:
1503         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1504
1505         return (rc);
1506 }
1507
1508 #endif /* EFSYS_OPT_BIST */
1509
1510
1511 /* Enable logging of some events (e.g. link state changes) */
1512         __checkReturn   efx_rc_t
1513 efx_mcdi_log_ctrl(
1514         __in            efx_nic_t *enp)
1515 {
1516         efx_mcdi_req_t req;
1517         uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1518                             MC_CMD_LOG_CTRL_OUT_LEN)];
1519         efx_rc_t rc;
1520
1521         (void) memset(payload, 0, sizeof (payload));
1522         req.emr_cmd = MC_CMD_LOG_CTRL;
1523         req.emr_in_buf = payload;
1524         req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1525         req.emr_out_buf = payload;
1526         req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1527
1528         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1529                     MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1530         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1531
1532         efx_mcdi_execute(enp, &req);
1533
1534         if (req.emr_rc != 0) {
1535                 rc = req.emr_rc;
1536                 goto fail1;
1537         }
1538
1539         return (0);
1540
1541 fail1:
1542         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1543
1544         return (rc);
1545 }
1546
1547
1548 #if EFSYS_OPT_MAC_STATS
1549
1550 typedef enum efx_stats_action_e
1551 {
1552         EFX_STATS_CLEAR,
1553         EFX_STATS_UPLOAD,
1554         EFX_STATS_ENABLE_NOEVENTS,
1555         EFX_STATS_ENABLE_EVENTS,
1556         EFX_STATS_DISABLE,
1557 } efx_stats_action_t;
1558
1559 static  __checkReturn   efx_rc_t
1560 efx_mcdi_mac_stats(
1561         __in            efx_nic_t *enp,
1562         __in_opt        efsys_mem_t *esmp,
1563         __in            efx_stats_action_t action)
1564 {
1565         efx_mcdi_req_t req;
1566         uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1567                             MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1568         int clear = (action == EFX_STATS_CLEAR);
1569         int upload = (action == EFX_STATS_UPLOAD);
1570         int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1571         int events = (action == EFX_STATS_ENABLE_EVENTS);
1572         int disable = (action == EFX_STATS_DISABLE);
1573         efx_rc_t rc;
1574
1575         (void) memset(payload, 0, sizeof (payload));
1576         req.emr_cmd = MC_CMD_MAC_STATS;
1577         req.emr_in_buf = payload;
1578         req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1579         req.emr_out_buf = payload;
1580         req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1581
1582         MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1583             MAC_STATS_IN_DMA, upload,
1584             MAC_STATS_IN_CLEAR, clear,
1585             MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1586             MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1587             MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1588             MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0);
1589
1590         if (esmp != NULL) {
1591                 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1592
1593                 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1594                     EFX_MAC_STATS_SIZE);
1595
1596                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1597                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1598                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1599                             EFSYS_MEM_ADDR(esmp) >> 32);
1600                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1601         } else {
1602                 EFSYS_ASSERT(!upload && !enable && !events);
1603         }
1604
1605         /*
1606          * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1607          *       as this may fail (and leave periodic DMA enabled) if the
1608          *       vadapter has already been deleted.
1609          */
1610         MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1611             (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1612
1613         efx_mcdi_execute(enp, &req);
1614
1615         if (req.emr_rc != 0) {
1616                 /* EF10: Expect ENOENT if no DMA queues are initialised */
1617                 if ((req.emr_rc != ENOENT) ||
1618                     (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1619                         rc = req.emr_rc;
1620                         goto fail1;
1621                 }
1622         }
1623
1624         return (0);
1625
1626 fail1:
1627         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1628
1629         return (rc);
1630 }
1631
1632         __checkReturn   efx_rc_t
1633 efx_mcdi_mac_stats_clear(
1634         __in            efx_nic_t *enp)
1635 {
1636         efx_rc_t rc;
1637
1638         if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0)
1639                 goto fail1;
1640
1641         return (0);
1642
1643 fail1:
1644         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1645
1646         return (rc);
1647 }
1648
1649         __checkReturn   efx_rc_t
1650 efx_mcdi_mac_stats_upload(
1651         __in            efx_nic_t *enp,
1652         __in            efsys_mem_t *esmp)
1653 {
1654         efx_rc_t rc;
1655
1656         /*
1657          * The MC DMAs aggregate statistics for our convenience, so we can
1658          * avoid having to pull the statistics buffer into the cache to
1659          * maintain cumulative statistics.
1660          */
1661         if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0)
1662                 goto fail1;
1663
1664         return (0);
1665
1666 fail1:
1667         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1668
1669         return (rc);
1670 }
1671
1672         __checkReturn   efx_rc_t
1673 efx_mcdi_mac_stats_periodic(
1674         __in            efx_nic_t *enp,
1675         __in            efsys_mem_t *esmp,
1676         __in            uint16_t period,
1677         __in            boolean_t events)
1678 {
1679         efx_rc_t rc;
1680
1681         /*
1682          * The MC DMAs aggregate statistics for our convenience, so we can
1683          * avoid having to pull the statistics buffer into the cache to
1684          * maintain cumulative statistics.
1685          * Huntington uses a fixed 1sec period, so use that on Siena too.
1686          */
1687         if (period == 0)
1688                 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE);
1689         else if (events)
1690                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS);
1691         else
1692                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS);
1693
1694         if (rc != 0)
1695                 goto fail1;
1696
1697         return (0);
1698
1699 fail1:
1700         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1701
1702         return (rc);
1703 }
1704
1705 #endif  /* EFSYS_OPT_MAC_STATS */
1706
1707 #if EFSYS_OPT_HUNTINGTON
1708
1709 /*
1710  * This function returns the pf and vf number of a function.  If it is a pf the
1711  * vf number is 0xffff.  The vf number is the index of the vf on that
1712  * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1713  * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1714  */
1715         __checkReturn           efx_rc_t
1716 efx_mcdi_get_function_info(
1717         __in                    efx_nic_t *enp,
1718         __out                   uint32_t *pfp,
1719         __out_opt               uint32_t *vfp)
1720 {
1721         efx_mcdi_req_t req;
1722         uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1723                             MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1724         efx_rc_t rc;
1725
1726         (void) memset(payload, 0, sizeof (payload));
1727         req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1728         req.emr_in_buf = payload;
1729         req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1730         req.emr_out_buf = payload;
1731         req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1732
1733         efx_mcdi_execute(enp, &req);
1734
1735         if (req.emr_rc != 0) {
1736                 rc = req.emr_rc;
1737                 goto fail1;
1738         }
1739
1740         if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1741                 rc = EMSGSIZE;
1742                 goto fail2;
1743         }
1744
1745         *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1746         if (vfp != NULL)
1747                 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1748
1749         return (0);
1750
1751 fail2:
1752         EFSYS_PROBE(fail2);
1753 fail1:
1754         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1755
1756         return (rc);
1757 }
1758
1759         __checkReturn           efx_rc_t
1760 efx_mcdi_privilege_mask(
1761         __in                    efx_nic_t *enp,
1762         __in                    uint32_t pf,
1763         __in                    uint32_t vf,
1764         __out                   uint32_t *maskp)
1765 {
1766         efx_mcdi_req_t req;
1767         uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1768                             MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1769         efx_rc_t rc;
1770
1771         (void) memset(payload, 0, sizeof (payload));
1772         req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1773         req.emr_in_buf = payload;
1774         req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1775         req.emr_out_buf = payload;
1776         req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1777
1778         MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1779             PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1780             PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1781
1782         efx_mcdi_execute(enp, &req);
1783
1784         if (req.emr_rc != 0) {
1785                 rc = req.emr_rc;
1786                 goto fail1;
1787         }
1788
1789         if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
1790                 rc = EMSGSIZE;
1791                 goto fail2;
1792         }
1793
1794         *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
1795
1796         return (0);
1797
1798 fail2:
1799         EFSYS_PROBE(fail2);
1800 fail1:
1801         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1802
1803         return (rc);
1804 }
1805
1806 #endif /* EFSYS_OPT_HUNTINGTON */
1807
1808         __checkReturn           efx_rc_t
1809 efx_mcdi_set_workaround(
1810         __in                    efx_nic_t *enp,
1811         __in                    uint32_t type,
1812         __in                    boolean_t enabled,
1813         __out_opt               uint32_t *flagsp)
1814 {
1815         efx_mcdi_req_t req;
1816         uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1817                             MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1818         efx_rc_t rc;
1819
1820         (void) memset(payload, 0, sizeof (payload));
1821         req.emr_cmd = MC_CMD_WORKAROUND;
1822         req.emr_in_buf = payload;
1823         req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1824         req.emr_out_buf = payload;
1825         req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1826
1827         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1828         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1829
1830         efx_mcdi_execute_quiet(enp, &req);
1831
1832         if (req.emr_rc != 0) {
1833                 rc = req.emr_rc;
1834                 goto fail1;
1835         }
1836
1837         if (flagsp != NULL) {
1838                 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
1839                         *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
1840                 else
1841                         *flagsp = 0;
1842         }
1843
1844         return (0);
1845
1846 fail1:
1847         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1848
1849         return (rc);
1850 }
1851
1852
1853         __checkReturn           efx_rc_t
1854 efx_mcdi_get_workarounds(
1855         __in                    efx_nic_t *enp,
1856         __out_opt               uint32_t *implementedp,
1857         __out_opt               uint32_t *enabledp)
1858 {
1859         efx_mcdi_req_t req;
1860         uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
1861         efx_rc_t rc;
1862
1863         (void) memset(payload, 0, sizeof (payload));
1864         req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
1865         req.emr_in_buf = NULL;
1866         req.emr_in_length = 0;
1867         req.emr_out_buf = payload;
1868         req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
1869
1870         efx_mcdi_execute(enp, &req);
1871
1872         if (req.emr_rc != 0) {
1873                 rc = req.emr_rc;
1874                 goto fail1;
1875         }
1876
1877         if (implementedp != NULL) {
1878                 *implementedp =
1879                     MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1880         }
1881
1882         if (enabledp != NULL) {
1883                 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
1884         }
1885
1886         return (0);
1887
1888 fail1:
1889         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1890
1891         return (rc);
1892 }
1893
1894
1895 #endif  /* EFSYS_OPT_MCDI */