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