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