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