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