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