]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/common/efx_mcdi.c
MFC r292050
[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_nic_cfg_t *encp = &enp->en_nic_cfg;
544         efx_mcdi_req_t *emrp;
545         int state;
546
547         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
548         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
549
550         /*
551          * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
552          * when we're completing an aborted request.
553          */
554         EFSYS_LOCK(enp->en_eslp, state);
555         if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
556             (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
557                 EFSYS_ASSERT(emip->emi_aborted > 0);
558                 if (emip->emi_aborted > 0)
559                         --emip->emi_aborted;
560                 EFSYS_UNLOCK(enp->en_eslp, state);
561                 return;
562         }
563
564         emrp = emip->emi_pending_req;
565         emip->emi_pending_req = NULL;
566         EFSYS_UNLOCK(enp->en_eslp, state);
567
568         if (encp->enc_mcdi_max_payload_length > MCDI_CTL_SDU_LEN_MAX_V1) {
569                 /* MCDIv2 response details do not fit into an event. */
570                 efx_mcdi_read_response_header(enp, emrp);
571         } else {
572                 if (errcode != 0) {
573                         if (!emrp->emr_quiet) {
574                                 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
575                                     int, errcode);
576                         }
577                         emrp->emr_out_length_used = 0;
578                         emrp->emr_rc = efx_mcdi_request_errcode(errcode);
579                 } else {
580                         emrp->emr_out_length_used = outlen;
581                         emrp->emr_rc = 0;
582                 }
583         }
584         emcop->emco_request_copyout(enp, emrp);
585
586         emtp->emt_ev_cpl(emtp->emt_context);
587 }
588
589                         void
590 efx_mcdi_ev_death(
591         __in            efx_nic_t *enp,
592         __in            int rc)
593 {
594         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
595         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
596         efx_mcdi_req_t *emrp = NULL;
597         boolean_t ev_cpl;
598         int state;
599
600         /*
601          * The MCDI request (if there is one) has been terminated, either
602          * by a BADASSERT or REBOOT event.
603          *
604          * If there is an outstanding event-completed MCDI operation, then we
605          * will never receive the completion event (because both MCDI
606          * completions and BADASSERT events are sent to the same evq). So
607          * complete this MCDI op.
608          *
609          * This function might run in parallel with efx_mcdi_request_poll()
610          * for poll completed mcdi requests, and also with
611          * efx_mcdi_request_start() for post-watchdog completions.
612          */
613         EFSYS_LOCK(enp->en_eslp, state);
614         emrp = emip->emi_pending_req;
615         ev_cpl = emip->emi_ev_cpl;
616         if (emrp != NULL && emip->emi_ev_cpl) {
617                 emip->emi_pending_req = NULL;
618
619                 emrp->emr_out_length_used = 0;
620                 emrp->emr_rc = rc;
621                 ++emip->emi_aborted;
622         }
623
624         /*
625          * Since we're running in parallel with a request, consume the
626          * status word before dropping the lock.
627          */
628         if (rc == EIO || rc == EINTR) {
629                 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
630                 (void) efx_mcdi_poll_reboot(enp);
631                 emip->emi_new_epoch = B_TRUE;
632         }
633
634         EFSYS_UNLOCK(enp->en_eslp, state);
635
636         efx_mcdi_raise_exception(enp, emrp, rc);
637
638         if (emrp != NULL && ev_cpl)
639                 emtp->emt_ev_cpl(emtp->emt_context);
640 }
641
642         __checkReturn           efx_rc_t
643 efx_mcdi_version(
644         __in                    efx_nic_t *enp,
645         __out_ecount_opt(4)     uint16_t versionp[4],
646         __out_opt               uint32_t *buildp,
647         __out_opt               efx_mcdi_boot_t *statusp)
648 {
649         efx_mcdi_req_t req;
650         uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
651                                 MC_CMD_GET_VERSION_OUT_LEN),
652                             MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
653                                 MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
654         efx_word_t *ver_words;
655         uint16_t version[4];
656         uint32_t build;
657         efx_mcdi_boot_t status;
658         efx_rc_t rc;
659
660         EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
661
662         (void) memset(payload, 0, sizeof (payload));
663         req.emr_cmd = MC_CMD_GET_VERSION;
664         req.emr_in_buf = payload;
665         req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
666         req.emr_out_buf = payload;
667         req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
668
669         efx_mcdi_execute(enp, &req);
670
671         if (req.emr_rc != 0) {
672                 rc = req.emr_rc;
673                 goto fail1;
674         }
675
676         /* bootrom support */
677         if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
678                 version[0] = version[1] = version[2] = version[3] = 0;
679                 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
680
681                 goto version;
682         }
683
684         if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
685                 rc = EMSGSIZE;
686                 goto fail2;
687         }
688
689         ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
690         version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
691         version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
692         version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
693         version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
694         build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
695
696 version:
697         /* The bootrom doesn't understand BOOT_STATUS */
698         if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
699                 status = EFX_MCDI_BOOT_ROM;
700                 goto out;
701         }
702
703         (void) memset(payload, 0, sizeof (payload));
704         req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
705         req.emr_in_buf = payload;
706         req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
707         req.emr_out_buf = payload;
708         req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
709
710         efx_mcdi_execute_quiet(enp, &req);
711
712         if (req.emr_rc == EACCES) {
713                 /* Unprivileged functions cannot access BOOT_STATUS */
714                 status = EFX_MCDI_BOOT_PRIMARY;
715                 version[0] = version[1] = version[2] = version[3] = 0;
716                 build = 0;
717                 goto out;
718         }
719
720         if (req.emr_rc != 0) {
721                 rc = req.emr_rc;
722                 goto fail3;
723         }
724
725         if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
726                 rc = EMSGSIZE;
727                 goto fail4;
728         }
729
730         if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
731             GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
732                 status = EFX_MCDI_BOOT_PRIMARY;
733         else
734                 status = EFX_MCDI_BOOT_SECONDARY;
735
736 out:
737         if (versionp != NULL)
738                 memcpy(versionp, version, sizeof (version));
739         if (buildp != NULL)
740                 *buildp = build;
741         if (statusp != NULL)
742                 *statusp = status;
743
744         return (0);
745
746 fail4:
747         EFSYS_PROBE(fail4);
748 fail3:
749         EFSYS_PROBE(fail3);
750 fail2:
751         EFSYS_PROBE(fail2);
752 fail1:
753         EFSYS_PROBE1(fail1, efx_rc_t, rc);
754
755         return (rc);
756 }
757
758 static  __checkReturn   efx_rc_t
759 efx_mcdi_do_reboot(
760         __in            efx_nic_t *enp,
761         __in            boolean_t after_assertion)
762 {
763         uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
764         efx_mcdi_req_t req;
765         efx_rc_t rc;
766
767         /*
768          * We could require the caller to have caused en_mod_flags=0 to
769          * call this function. This doesn't help the other port though,
770          * who's about to get the MC ripped out from underneath them.
771          * Since they have to cope with the subsequent fallout of MCDI
772          * failures, we should as well.
773          */
774         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
775
776         (void) memset(payload, 0, sizeof (payload));
777         req.emr_cmd = MC_CMD_REBOOT;
778         req.emr_in_buf = payload;
779         req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
780         req.emr_out_buf = payload;
781         req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
782
783         MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
784             (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
785
786         efx_mcdi_execute_quiet(enp, &req);
787
788         if (req.emr_rc == EACCES) {
789                 /* Unprivileged functions cannot reboot the MC. */
790                 goto out;
791         }
792
793         /* A successful reboot request returns EIO. */
794         if (req.emr_rc != 0 && req.emr_rc != EIO) {
795                 rc = req.emr_rc;
796                 goto fail1;
797         }
798
799 out:
800         return (0);
801
802 fail1:
803         EFSYS_PROBE1(fail1, efx_rc_t, rc);
804
805         return (rc);
806 }
807
808         __checkReturn   efx_rc_t
809 efx_mcdi_reboot(
810         __in            efx_nic_t *enp)
811 {
812         return (efx_mcdi_do_reboot(enp, B_FALSE));
813 }
814
815         __checkReturn   efx_rc_t
816 efx_mcdi_exit_assertion_handler(
817         __in            efx_nic_t *enp)
818 {
819         return (efx_mcdi_do_reboot(enp, B_TRUE));
820 }
821
822         __checkReturn   efx_rc_t
823 efx_mcdi_read_assertion(
824         __in            efx_nic_t *enp)
825 {
826         efx_mcdi_req_t req;
827         uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
828                             MC_CMD_GET_ASSERTS_OUT_LEN)];
829         const char *reason;
830         unsigned int flags;
831         unsigned int index;
832         unsigned int ofst;
833         int retry;
834         efx_rc_t rc;
835
836         /*
837          * Before we attempt to chat to the MC, we should verify that the MC
838          * isn't in it's assertion handler, either due to a previous reboot,
839          * or because we're reinitializing due to an eec_exception().
840          *
841          * Use GET_ASSERTS to read any assertion state that may be present.
842          * Retry this command twice. Once because a boot-time assertion failure
843          * might cause the 1st MCDI request to fail. And once again because
844          * we might race with efx_mcdi_exit_assertion_handler() running on
845          * partner port(s) on the same NIC.
846          */
847         retry = 2;
848         do {
849                 (void) memset(payload, 0, sizeof (payload));
850                 req.emr_cmd = MC_CMD_GET_ASSERTS;
851                 req.emr_in_buf = payload;
852                 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
853                 req.emr_out_buf = payload;
854                 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
855
856                 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
857                 efx_mcdi_execute_quiet(enp, &req);
858
859         } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
860
861         if (req.emr_rc != 0) {
862                 if (req.emr_rc == EACCES) {
863                         /* Unprivileged functions cannot clear assertions. */
864                         goto out;
865                 }
866                 rc = req.emr_rc;
867                 goto fail1;
868         }
869
870         if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
871                 rc = EMSGSIZE;
872                 goto fail2;
873         }
874
875         /* Print out any assertion state recorded */
876         flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
877         if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
878                 return (0);
879
880         reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
881                 ? "system-level assertion"
882                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
883                 ? "thread-level assertion"
884                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
885                 ? "watchdog reset"
886                 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
887                 ? "illegal address trap"
888                 : "unknown assertion";
889         EFSYS_PROBE3(mcpu_assertion,
890             const char *, reason, unsigned int,
891             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
892             unsigned int,
893             MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
894
895         /* Print out the registers (r1 ... r31) */
896         ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
897         for (index = 1;
898                 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
899                 index++) {
900                 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
901                             EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
902                                             EFX_DWORD_0));
903                 ofst += sizeof (efx_dword_t);
904         }
905         EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
906
907 out:
908         return (0);
909
910 fail2:
911         EFSYS_PROBE(fail2);
912 fail1:
913         EFSYS_PROBE1(fail1, efx_rc_t, rc);
914
915         return (rc);
916 }
917
918
919 /*
920  * Internal routines for for specific MCDI requests.
921  */
922
923         __checkReturn   efx_rc_t
924 efx_mcdi_drv_attach(
925         __in            efx_nic_t *enp,
926         __in            boolean_t attach)
927 {
928         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
929         efx_mcdi_req_t req;
930         uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
931                             MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
932         uint32_t flags;
933         efx_rc_t rc;
934
935         (void) memset(payload, 0, sizeof (payload));
936         req.emr_cmd = MC_CMD_DRV_ATTACH;
937         req.emr_in_buf = payload;
938         req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
939         req.emr_out_buf = payload;
940         req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
941
942         /*
943          * Use DONT_CARE for the datapath firmware type to ensure that the
944          * driver can attach to an unprivileged function. The datapath firmware
945          * type to use is controlled by the 'sfboot' utility.
946          */
947         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
948         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
949         MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
950
951         efx_mcdi_execute(enp, &req);
952
953         if (req.emr_rc != 0) {
954                 rc = req.emr_rc;
955                 goto fail1;
956         }
957
958         if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
959                 rc = EMSGSIZE;
960                 goto fail2;
961         }
962
963         if (attach == B_FALSE) {
964                 flags = 0;
965         } else if (enp->en_family == EFX_FAMILY_SIENA) {
966                 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
967
968                 /* Create synthetic privileges for Siena functions */
969                 flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED;
970                 if (emip->emi_port == 1)
971                         flags |= EFX_NIC_FUNC_PRIMARY;
972         } else {
973                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY ==
974                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY));
975                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL ==
976                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL));
977                 EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED ==
978                     (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED));
979
980                 /* Save function privilege flags (EF10 and later) */
981                 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) {
982                         rc = EMSGSIZE;
983                         goto fail3;
984                 }
985                 flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS);
986         }
987         encp->enc_func_flags = flags;
988
989         return (0);
990
991 fail3:
992         EFSYS_PROBE(fail3);
993 fail2:
994         EFSYS_PROBE(fail2);
995 fail1:
996         EFSYS_PROBE1(fail1, efx_rc_t, rc);
997
998         return (rc);
999 }
1000
1001         __checkReturn           efx_rc_t
1002 efx_mcdi_get_board_cfg(
1003         __in                    efx_nic_t *enp,
1004         __out_opt               uint32_t *board_typep,
1005         __out_opt               efx_dword_t *capabilitiesp,
1006         __out_ecount_opt(6)     uint8_t mac_addrp[6])
1007 {
1008         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1009         efx_mcdi_req_t req;
1010         uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
1011                             MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
1012         efx_rc_t rc;
1013
1014         (void) memset(payload, 0, sizeof (payload));
1015         req.emr_cmd = MC_CMD_GET_BOARD_CFG;
1016         req.emr_in_buf = payload;
1017         req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
1018         req.emr_out_buf = payload;
1019         req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
1020
1021         efx_mcdi_execute(enp, &req);
1022
1023         if (req.emr_rc != 0) {
1024                 rc = req.emr_rc;
1025                 goto fail1;
1026         }
1027
1028         if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
1029                 rc = EMSGSIZE;
1030                 goto fail2;
1031         }
1032
1033         if (mac_addrp != NULL) {
1034                 uint8_t *addrp;
1035
1036                 if (emip->emi_port == 1) {
1037                         addrp = MCDI_OUT2(req, uint8_t,
1038                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
1039                 } else if (emip->emi_port == 2) {
1040                         addrp = MCDI_OUT2(req, uint8_t,
1041                             GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
1042                 } else {
1043                         rc = EINVAL;
1044                         goto fail3;
1045                 }
1046
1047                 EFX_MAC_ADDR_COPY(mac_addrp, addrp);
1048         }
1049
1050         if (capabilitiesp != NULL) {
1051                 if (emip->emi_port == 1) {
1052                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1053                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
1054                 } else if (emip->emi_port == 2) {
1055                         *capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
1056                             GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
1057                 } else {
1058                         rc = EINVAL;
1059                         goto fail4;
1060                 }
1061         }
1062
1063         if (board_typep != NULL) {
1064                 *board_typep = MCDI_OUT_DWORD(req,
1065                     GET_BOARD_CFG_OUT_BOARD_TYPE);
1066         }
1067
1068         return (0);
1069
1070 fail4:
1071         EFSYS_PROBE(fail4);
1072 fail3:
1073         EFSYS_PROBE(fail3);
1074 fail2:
1075         EFSYS_PROBE(fail2);
1076 fail1:
1077         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1078
1079         return (rc);
1080 }
1081
1082         __checkReturn   efx_rc_t
1083 efx_mcdi_get_resource_limits(
1084         __in            efx_nic_t *enp,
1085         __out_opt       uint32_t *nevqp,
1086         __out_opt       uint32_t *nrxqp,
1087         __out_opt       uint32_t *ntxqp)
1088 {
1089         efx_mcdi_req_t req;
1090         uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
1091                             MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
1092         efx_rc_t rc;
1093
1094         (void) memset(payload, 0, sizeof (payload));
1095         req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
1096         req.emr_in_buf = payload;
1097         req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
1098         req.emr_out_buf = payload;
1099         req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
1100
1101         efx_mcdi_execute(enp, &req);
1102
1103         if (req.emr_rc != 0) {
1104                 rc = req.emr_rc;
1105                 goto fail1;
1106         }
1107
1108         if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
1109                 rc = EMSGSIZE;
1110                 goto fail2;
1111         }
1112
1113         if (nevqp != NULL)
1114                 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1115         if (nrxqp != NULL)
1116                 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1117         if (ntxqp != NULL)
1118                 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1119
1120         return (0);
1121
1122 fail2:
1123         EFSYS_PROBE(fail2);
1124 fail1:
1125         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1126
1127         return (rc);
1128 }
1129
1130         __checkReturn   efx_rc_t
1131 efx_mcdi_get_phy_cfg(
1132         __in            efx_nic_t *enp)
1133 {
1134         efx_port_t *epp = &(enp->en_port);
1135         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1136         efx_mcdi_req_t req;
1137         uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1138                             MC_CMD_GET_PHY_CFG_OUT_LEN)];
1139         efx_rc_t rc;
1140
1141         (void) memset(payload, 0, sizeof (payload));
1142         req.emr_cmd = MC_CMD_GET_PHY_CFG;
1143         req.emr_in_buf = payload;
1144         req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1145         req.emr_out_buf = payload;
1146         req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1147
1148         efx_mcdi_execute(enp, &req);
1149
1150         if (req.emr_rc != 0) {
1151                 rc = req.emr_rc;
1152                 goto fail1;
1153         }
1154
1155         if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1156                 rc = EMSGSIZE;
1157                 goto fail2;
1158         }
1159
1160         encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1161 #if EFSYS_OPT_NAMES
1162         (void) strncpy(encp->enc_phy_name,
1163                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1164                 MIN(sizeof (encp->enc_phy_name) - 1,
1165                     MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1166 #endif  /* EFSYS_OPT_NAMES */
1167         (void) memset(encp->enc_phy_revision, 0,
1168             sizeof (encp->enc_phy_revision));
1169         memcpy(encp->enc_phy_revision,
1170                 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1171                 MIN(sizeof (encp->enc_phy_revision) - 1,
1172                     MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1173 #if EFSYS_OPT_PHY_LED_CONTROL
1174         encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1175                             (1 << EFX_PHY_LED_OFF) |
1176                             (1 << EFX_PHY_LED_ON));
1177 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
1178
1179 #if EFSYS_OPT_PHY_PROPS
1180         encp->enc_phy_nprops  = 0;
1181 #endif  /* EFSYS_OPT_PHY_PROPS */
1182
1183         /* Get the media type of the fixed port, if recognised. */
1184         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1185         EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1186         EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1187         EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1188         EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1189         EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1190         EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1191         epp->ep_fixed_port_type =
1192                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1193         if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1194                 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1195
1196         epp->ep_phy_cap_mask =
1197                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1198 #if EFSYS_OPT_PHY_FLAGS
1199         encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1200 #endif  /* EFSYS_OPT_PHY_FLAGS */
1201
1202         encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1203
1204         /* Populate internal state */
1205         encp->enc_mcdi_mdio_channel =
1206                 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1207
1208 #if EFSYS_OPT_PHY_STATS
1209         encp->enc_mcdi_phy_stat_mask =
1210                 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1211 #endif  /* EFSYS_OPT_PHY_STATS */
1212
1213 #if EFSYS_OPT_BIST
1214         encp->enc_bist_mask = 0;
1215         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1216             GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1217                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1218         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1219             GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1220                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1221         if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1222             GET_PHY_CFG_OUT_BIST))
1223                 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1224 #endif  /* EFSYS_OPT_BIST */
1225
1226         return (0);
1227
1228 fail2:
1229         EFSYS_PROBE(fail2);
1230 fail1:
1231         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1232
1233         return (rc);
1234 }
1235
1236
1237         __checkReturn           efx_rc_t
1238 efx_mcdi_firmware_update_supported(
1239         __in                    efx_nic_t *enp,
1240         __out                   boolean_t *supportedp)
1241 {
1242         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1243         efx_rc_t rc;
1244
1245         if (emcop != NULL && emcop->emco_fw_update_supported != NULL) {
1246                 if ((rc = emcop->emco_fw_update_supported(enp, supportedp))
1247                     != 0)
1248                         goto fail1;
1249         } else {
1250                 /* Earlier devices always supported updates */
1251                 *supportedp = B_TRUE;
1252         }
1253
1254         return (0);
1255
1256 fail1:
1257         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1258
1259         return (rc);
1260 }
1261
1262         __checkReturn           efx_rc_t
1263 efx_mcdi_macaddr_change_supported(
1264         __in                    efx_nic_t *enp,
1265         __out                   boolean_t *supportedp)
1266 {
1267         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1268         efx_rc_t rc;
1269
1270         if (emcop != NULL && emcop->emco_macaddr_change_supported != NULL) {
1271                 if ((rc = emcop->emco_macaddr_change_supported(enp, supportedp))
1272                     != 0)
1273                         goto fail1;
1274         } else {
1275                 /* Earlier devices always supported MAC changes */
1276                 *supportedp = B_TRUE;
1277         }
1278
1279         return (0);
1280
1281 fail1:
1282         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1283
1284         return (rc);
1285 }
1286
1287         __checkReturn           efx_rc_t
1288 efx_mcdi_link_control_supported(
1289         __in                    efx_nic_t *enp,
1290         __out                   boolean_t *supportedp)
1291 {
1292         efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1293         efx_rc_t rc;
1294
1295         if (emcop != NULL && emcop->emco_link_control_supported != NULL) {
1296                 if ((rc = emcop->emco_link_control_supported(enp, supportedp))
1297                     != 0)
1298                         goto fail1;
1299         } else {
1300                 /* Earlier devices always supported link control */
1301                 *supportedp = B_TRUE;
1302         }
1303
1304         return (0);
1305
1306 fail1:
1307         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1308
1309         return (rc);
1310 }
1311
1312 #if EFSYS_OPT_BIST
1313
1314 #if EFSYS_OPT_HUNTINGTON
1315 /*
1316  * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1317  * where memory BIST tests can be run and not much else can interfere or happen.
1318  * A reboot is required to exit this mode.
1319  */
1320         __checkReturn           efx_rc_t
1321 efx_mcdi_bist_enable_offline(
1322         __in                    efx_nic_t *enp)
1323 {
1324         efx_mcdi_req_t req;
1325         efx_rc_t rc;
1326
1327         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1328         EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1329
1330         req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1331         req.emr_in_buf = NULL;
1332         req.emr_in_length = 0;
1333         req.emr_out_buf = NULL;
1334         req.emr_out_length = 0;
1335
1336         efx_mcdi_execute(enp, &req);
1337
1338         if (req.emr_rc != 0) {
1339                 rc = req.emr_rc;
1340                 goto fail1;
1341         }
1342
1343         return (0);
1344
1345 fail1:
1346         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1347
1348         return (rc);
1349 }
1350 #endif /* EFSYS_OPT_HUNTINGTON */
1351
1352         __checkReturn           efx_rc_t
1353 efx_mcdi_bist_start(
1354         __in                    efx_nic_t *enp,
1355         __in                    efx_bist_type_t type)
1356 {
1357         efx_mcdi_req_t req;
1358         uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1359                             MC_CMD_START_BIST_OUT_LEN)];
1360         efx_rc_t rc;
1361
1362         (void) memset(payload, 0, sizeof (payload));
1363         req.emr_cmd = MC_CMD_START_BIST;
1364         req.emr_in_buf = payload;
1365         req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1366         req.emr_out_buf = payload;
1367         req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1368
1369         switch (type) {
1370         case EFX_BIST_TYPE_PHY_NORMAL:
1371                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1372                 break;
1373         case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1374                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1375                     MC_CMD_PHY_BIST_CABLE_SHORT);
1376                 break;
1377         case EFX_BIST_TYPE_PHY_CABLE_LONG:
1378                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1379                     MC_CMD_PHY_BIST_CABLE_LONG);
1380                 break;
1381         case EFX_BIST_TYPE_MC_MEM:
1382                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1383                     MC_CMD_MC_MEM_BIST);
1384                 break;
1385         case EFX_BIST_TYPE_SAT_MEM:
1386                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1387                     MC_CMD_PORT_MEM_BIST);
1388                 break;
1389         case EFX_BIST_TYPE_REG:
1390                 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1391                     MC_CMD_REG_BIST);
1392                 break;
1393         default:
1394                 EFSYS_ASSERT(0);
1395         }
1396
1397         efx_mcdi_execute(enp, &req);
1398
1399         if (req.emr_rc != 0) {
1400                 rc = req.emr_rc;
1401                 goto fail1;
1402         }
1403
1404         return (0);
1405
1406 fail1:
1407         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1408
1409         return (rc);
1410 }
1411
1412 #endif /* EFSYS_OPT_BIST */
1413
1414
1415 /* Enable logging of some events (e.g. link state changes) */
1416         __checkReturn   efx_rc_t
1417 efx_mcdi_log_ctrl(
1418         __in            efx_nic_t *enp)
1419 {
1420         efx_mcdi_req_t req;
1421         uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1422                             MC_CMD_LOG_CTRL_OUT_LEN)];
1423         efx_rc_t rc;
1424
1425         (void) memset(payload, 0, sizeof (payload));
1426         req.emr_cmd = MC_CMD_LOG_CTRL;
1427         req.emr_in_buf = payload;
1428         req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1429         req.emr_out_buf = payload;
1430         req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1431
1432         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1433                     MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1434         MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1435
1436         efx_mcdi_execute(enp, &req);
1437
1438         if (req.emr_rc != 0) {
1439                 rc = req.emr_rc;
1440                 goto fail1;
1441         }
1442
1443         return (0);
1444
1445 fail1:
1446         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1447
1448         return (rc);
1449 }
1450
1451
1452 #if EFSYS_OPT_MAC_STATS
1453
1454 typedef enum efx_stats_action_e
1455 {
1456         EFX_STATS_CLEAR,
1457         EFX_STATS_UPLOAD,
1458         EFX_STATS_ENABLE_NOEVENTS,
1459         EFX_STATS_ENABLE_EVENTS,
1460         EFX_STATS_DISABLE,
1461 } efx_stats_action_t;
1462
1463 static  __checkReturn   efx_rc_t
1464 efx_mcdi_mac_stats(
1465         __in            efx_nic_t *enp,
1466         __in_opt        efsys_mem_t *esmp,
1467         __in            efx_stats_action_t action)
1468 {
1469         efx_mcdi_req_t req;
1470         uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1471                             MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1472         int clear = (action == EFX_STATS_CLEAR);
1473         int upload = (action == EFX_STATS_UPLOAD);
1474         int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1475         int events = (action == EFX_STATS_ENABLE_EVENTS);
1476         int disable = (action == EFX_STATS_DISABLE);
1477         efx_rc_t rc;
1478
1479         (void) memset(payload, 0, sizeof (payload));
1480         req.emr_cmd = MC_CMD_MAC_STATS;
1481         req.emr_in_buf = payload;
1482         req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1483         req.emr_out_buf = payload;
1484         req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1485
1486         MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1487             MAC_STATS_IN_DMA, upload,
1488             MAC_STATS_IN_CLEAR, clear,
1489             MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1490             MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1491             MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1492             MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0);
1493
1494         if (esmp != NULL) {
1495                 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1496
1497                 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1498                     EFX_MAC_STATS_SIZE);
1499
1500                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1501                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1502                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1503                             EFSYS_MEM_ADDR(esmp) >> 32);
1504                 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1505         } else {
1506                 EFSYS_ASSERT(!upload && !enable && !events);
1507         }
1508
1509         /*
1510          * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1511          *       as this may fail (and leave periodic DMA enabled) if the
1512          *       vadapter has already been deleted.
1513          */
1514         MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1515             (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1516
1517         efx_mcdi_execute(enp, &req);
1518
1519         if (req.emr_rc != 0) {
1520                 /* EF10: Expect ENOENT if no DMA queues are initialised */
1521                 if ((req.emr_rc != ENOENT) ||
1522                     (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1523                         rc = req.emr_rc;
1524                         goto fail1;
1525                 }
1526         }
1527
1528         return (0);
1529
1530 fail1:
1531         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1532
1533         return (rc);
1534 }
1535
1536         __checkReturn   efx_rc_t
1537 efx_mcdi_mac_stats_clear(
1538         __in            efx_nic_t *enp)
1539 {
1540         efx_rc_t rc;
1541
1542         if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0)
1543                 goto fail1;
1544
1545         return (0);
1546
1547 fail1:
1548         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1549
1550         return (rc);
1551 }
1552
1553         __checkReturn   efx_rc_t
1554 efx_mcdi_mac_stats_upload(
1555         __in            efx_nic_t *enp,
1556         __in            efsys_mem_t *esmp)
1557 {
1558         efx_rc_t rc;
1559
1560         /*
1561          * The MC DMAs aggregate statistics for our convenience, so we can
1562          * avoid having to pull the statistics buffer into the cache to
1563          * maintain cumulative statistics.
1564          */
1565         if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0)
1566                 goto fail1;
1567
1568         return (0);
1569
1570 fail1:
1571         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1572
1573         return (rc);
1574 }
1575
1576         __checkReturn   efx_rc_t
1577 efx_mcdi_mac_stats_periodic(
1578         __in            efx_nic_t *enp,
1579         __in            efsys_mem_t *esmp,
1580         __in            uint16_t period,
1581         __in            boolean_t events)
1582 {
1583         efx_rc_t rc;
1584
1585         /*
1586          * The MC DMAs aggregate statistics for our convenience, so we can
1587          * avoid having to pull the statistics buffer into the cache to
1588          * maintain cumulative statistics.
1589          * Huntington uses a fixed 1sec period, so use that on Siena too.
1590          */
1591         if (period == 0)
1592                 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE);
1593         else if (events)
1594                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS);
1595         else
1596                 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS);
1597
1598         if (rc != 0)
1599                 goto fail1;
1600
1601         return (0);
1602
1603 fail1:
1604         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1605
1606         return (rc);
1607 }
1608
1609 #endif  /* EFSYS_OPT_MAC_STATS */
1610
1611 #if EFSYS_OPT_HUNTINGTON
1612
1613 /*
1614  * This function returns the pf and vf number of a function.  If it is a pf the
1615  * vf number is 0xffff.  The vf number is the index of the vf on that
1616  * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1617  * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1618  */
1619         __checkReturn           efx_rc_t
1620 efx_mcdi_get_function_info(
1621         __in                    efx_nic_t *enp,
1622         __out                   uint32_t *pfp,
1623         __out_opt               uint32_t *vfp)
1624 {
1625         efx_mcdi_req_t req;
1626         uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1627                             MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1628         efx_rc_t rc;
1629
1630         (void) memset(payload, 0, sizeof (payload));
1631         req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1632         req.emr_in_buf = payload;
1633         req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1634         req.emr_out_buf = payload;
1635         req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1636
1637         efx_mcdi_execute(enp, &req);
1638
1639         if (req.emr_rc != 0) {
1640                 rc = req.emr_rc;
1641                 goto fail1;
1642         }
1643
1644         if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1645                 rc = EMSGSIZE;
1646                 goto fail2;
1647         }
1648
1649         *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1650         if (vfp != NULL)
1651                 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1652
1653         return (0);
1654
1655 fail2:
1656         EFSYS_PROBE(fail2);
1657 fail1:
1658         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1659
1660         return (rc);
1661 }
1662
1663         __checkReturn           efx_rc_t
1664 efx_mcdi_privilege_mask(
1665         __in                    efx_nic_t *enp,
1666         __in                    uint32_t pf,
1667         __in                    uint32_t vf,
1668         __out                   uint32_t *maskp)
1669 {
1670         efx_mcdi_req_t req;
1671         uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1672                             MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1673         efx_rc_t rc;
1674
1675         (void) memset(payload, 0, sizeof (payload));
1676         req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1677         req.emr_in_buf = payload;
1678         req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1679         req.emr_out_buf = payload;
1680         req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1681
1682         MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1683             PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1684             PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1685
1686         efx_mcdi_execute(enp, &req);
1687
1688         if (req.emr_rc != 0) {
1689                 rc = req.emr_rc;
1690                 goto fail1;
1691         }
1692
1693         if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
1694                 rc = EMSGSIZE;
1695                 goto fail2;
1696         }
1697
1698         *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
1699
1700         return (0);
1701
1702 fail2:
1703         EFSYS_PROBE(fail2);
1704 fail1:
1705         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1706
1707         return (rc);
1708 }
1709
1710 #endif /* EFSYS_OPT_HUNTINGTON */
1711
1712         __checkReturn           efx_rc_t
1713 efx_mcdi_set_workaround(
1714         __in                    efx_nic_t *enp,
1715         __in                    uint32_t type,
1716         __in                    boolean_t enabled,
1717         __out_opt               uint32_t *flagsp)
1718 {
1719         efx_mcdi_req_t req;
1720         uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1721                             MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1722         efx_rc_t rc;
1723
1724         (void) memset(payload, 0, sizeof (payload));
1725         req.emr_cmd = MC_CMD_WORKAROUND;
1726         req.emr_in_buf = payload;
1727         req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1728         req.emr_out_buf = payload;
1729         req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1730
1731         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1732         MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1733
1734         efx_mcdi_execute_quiet(enp, &req);
1735
1736         if (req.emr_rc != 0) {
1737                 rc = req.emr_rc;
1738                 goto fail1;
1739         }
1740
1741         if (flagsp != NULL) {
1742                 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
1743                         *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
1744                 else
1745                         *flagsp = 0;
1746         }
1747
1748         return (0);
1749
1750 fail1:
1751         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1752
1753         return (rc);
1754 }
1755
1756
1757         __checkReturn           efx_rc_t
1758 efx_mcdi_get_workarounds(
1759         __in                    efx_nic_t *enp,
1760         __out_opt               uint32_t *implementedp,
1761         __out_opt               uint32_t *enabledp)
1762 {
1763         efx_mcdi_req_t req;
1764         uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
1765         efx_rc_t rc;
1766
1767         (void) memset(payload, 0, sizeof (payload));
1768         req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
1769         req.emr_in_buf = NULL;
1770         req.emr_in_length = 0;
1771         req.emr_out_buf = payload;
1772         req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
1773
1774         efx_mcdi_execute(enp, &req);
1775
1776         if (req.emr_rc != 0) {
1777                 rc = req.emr_rc;
1778                 goto fail1;
1779         }
1780
1781         if (implementedp != NULL) {
1782                 *implementedp =
1783                     MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1784         }
1785
1786         if (enabledp != NULL) {
1787                 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
1788         }
1789
1790         return (0);
1791
1792 fail1:
1793         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1794
1795         return (rc);
1796 }
1797
1798
1799 #endif  /* EFSYS_OPT_MCDI */