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