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