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