xref: /freebsd/sys/dev/sfxge/common/efx_mcdi.c (revision a476e3a5678de5ca7ad765315f28308410d4f09e)
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 "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs.h"
38 #include "efx_regs_mcdi.h"
39 #include "efx_impl.h"
40 
41 #if EFSYS_OPT_MCDI
42 
43 
44 #if EFSYS_OPT_SIENA
45 
46 static efx_mcdi_ops_t	__efx_mcdi_siena_ops = {
47 	siena_mcdi_init,		/* emco_init */
48 	siena_mcdi_request_copyin,	/* emco_request_copyin */
49 	siena_mcdi_request_poll,	/* emco_request_poll */
50 	siena_mcdi_request_copyout,	/* emco_request_copyout */
51 	siena_mcdi_poll_reboot,		/* emco_poll_reboot */
52 	siena_mcdi_fini,		/* emco_fini */
53 	siena_mcdi_fw_update_supported,	/* emco_fw_update_supported */
54 	siena_mcdi_macaddr_change_supported,
55 					/* emco_macaddr_change_supported */
56 	siena_mcdi_link_control_supported,
57 					/* emco_link_control_supported */
58 };
59 
60 #endif	/* EFSYS_OPT_SIENA */
61 
62 #if EFSYS_OPT_HUNTINGTON
63 
64 static efx_mcdi_ops_t	__efx_mcdi_hunt_ops = {
65 	hunt_mcdi_init,			/* emco_init */
66 	hunt_mcdi_request_copyin,	/* emco_request_copyin */
67 	hunt_mcdi_request_poll,		/* emco_request_poll */
68 	hunt_mcdi_request_copyout,	/* emco_request_copyout */
69 	hunt_mcdi_poll_reboot,		/* emco_poll_reboot */
70 	hunt_mcdi_fini,			/* emco_fini */
71 	hunt_mcdi_fw_update_supported,	/* emco_fw_update_supported */
72 	hunt_mcdi_macaddr_change_supported,
73 					/* emco_macaddr_change_supported */
74 	hunt_mcdi_link_control_supported,
75 					/* emco_link_control_supported */
76 };
77 
78 #endif	/* EFSYS_OPT_HUNTINGTON */
79 
80 
81 
82 	__checkReturn	efx_rc_t
83 efx_mcdi_init(
84 	__in		efx_nic_t *enp,
85 	__in		const efx_mcdi_transport_t *emtp)
86 {
87 	efx_mcdi_ops_t *emcop;
88 	efx_rc_t rc;
89 
90 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
91 	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
92 
93 	switch (enp->en_family) {
94 #if EFSYS_OPT_FALCON
95 	case EFX_FAMILY_FALCON:
96 		emcop = NULL;
97 		emtp = NULL;
98 		break;
99 #endif	/* EFSYS_OPT_FALCON */
100 
101 #if EFSYS_OPT_SIENA
102 	case EFX_FAMILY_SIENA:
103 		emcop = (efx_mcdi_ops_t *)&__efx_mcdi_siena_ops;
104 		break;
105 #endif	/* EFSYS_OPT_SIENA */
106 
107 #if EFSYS_OPT_HUNTINGTON
108 	case EFX_FAMILY_HUNTINGTON:
109 		emcop = (efx_mcdi_ops_t *)&__efx_mcdi_hunt_ops;
110 		break;
111 #endif	/* EFSYS_OPT_HUNTINGTON */
112 
113 	default:
114 		EFSYS_ASSERT(0);
115 		rc = ENOTSUP;
116 		goto fail1;
117 	}
118 
119 	if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
120 		/* MCDI requires a DMA buffer in host memory */
121 		if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
122 			rc = EINVAL;
123 			goto fail2;
124 		}
125 	}
126 	enp->en_mcdi.em_emtp = emtp;
127 
128 	if (emcop != NULL && emcop->emco_init != NULL) {
129 		if ((rc = emcop->emco_init(enp, emtp)) != 0)
130 			goto fail3;
131 	}
132 
133 	enp->en_mcdi.em_emcop = emcop;
134 	enp->en_mod_flags |= EFX_MOD_MCDI;
135 
136 	return (0);
137 
138 fail3:
139 	EFSYS_PROBE(fail3);
140 fail2:
141 	EFSYS_PROBE(fail2);
142 fail1:
143 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
144 
145 	enp->en_mcdi.em_emcop = NULL;
146 	enp->en_mcdi.em_emtp = NULL;
147 	enp->en_mod_flags &= ~EFX_MOD_MCDI;
148 
149 	return (rc);
150 }
151 
152 			void
153 efx_mcdi_fini(
154 	__in		efx_nic_t *enp)
155 {
156 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
157 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
158 
159 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
160 	EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
161 
162 	if (emcop != NULL && emcop->emco_fini != NULL)
163 		emcop->emco_fini(enp);
164 
165 	emip->emi_port = 0;
166 	emip->emi_aborted = 0;
167 
168 	enp->en_mcdi.em_emcop = NULL;
169 	enp->en_mod_flags &= ~EFX_MOD_MCDI;
170 }
171 
172 			void
173 efx_mcdi_new_epoch(
174 	__in		efx_nic_t *enp)
175 {
176 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
177 	int state;
178 
179 	/* Start a new epoch (allow fresh MCDI requests to succeed) */
180 	EFSYS_LOCK(enp->en_eslp, state);
181 	emip->emi_new_epoch = B_TRUE;
182 	EFSYS_UNLOCK(enp->en_eslp, state);
183 }
184 
185 
186 			void
187 efx_mcdi_request_start(
188 	__in		efx_nic_t *enp,
189 	__in		efx_mcdi_req_t *emrp,
190 	__in		boolean_t ev_cpl)
191 {
192 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
193 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
194 	unsigned int seq;
195 	boolean_t new_epoch;
196 	int state;
197 
198 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
199 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
200 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
201 
202 	if (emcop == NULL || emcop->emco_request_copyin == NULL)
203 		return;
204 
205 	/*
206 	 * efx_mcdi_request_start() is naturally serialised against both
207 	 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
208 	 * by virtue of there only being one outstanding MCDI request.
209 	 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
210 	 * at any time, to timeout a pending mcdi request, That request may
211 	 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
212 	 * efx_mcdi_ev_death() may end up running in parallel with
213 	 * efx_mcdi_request_start(). This race is handled by ensuring that
214 	 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
215 	 * en_eslp lock.
216 	 */
217 	EFSYS_LOCK(enp->en_eslp, state);
218 	EFSYS_ASSERT(emip->emi_pending_req == NULL);
219 	emip->emi_pending_req = emrp;
220 	emip->emi_ev_cpl = ev_cpl;
221 	emip->emi_poll_cnt = 0;
222 	seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
223 	new_epoch = emip->emi_new_epoch;
224 	EFSYS_UNLOCK(enp->en_eslp, state);
225 
226 	emcop->emco_request_copyin(enp, emrp, seq, ev_cpl, new_epoch);
227 }
228 
229 	__checkReturn	boolean_t
230 efx_mcdi_request_poll(
231 	__in		efx_nic_t *enp)
232 {
233 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
234 	boolean_t completed;
235 
236 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
237 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
238 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
239 
240 	completed = B_FALSE;
241 
242 	if (emcop != NULL && emcop->emco_request_poll != NULL)
243 		completed = emcop->emco_request_poll(enp);
244 
245 	return (completed);
246 }
247 
248 	__checkReturn	boolean_t
249 efx_mcdi_request_abort(
250 	__in		efx_nic_t *enp)
251 {
252 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
253 	efx_mcdi_req_t *emrp;
254 	boolean_t aborted;
255 	int state;
256 
257 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
258 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
259 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
260 
261 	/*
262 	 * efx_mcdi_ev_* may have already completed this event, and be
263 	 * spinning/blocked on the upper layer lock. So it *is* legitimate
264 	 * to for emi_pending_req to be NULL. If there is a pending event
265 	 * completed request, then provide a "credit" to allow
266 	 * efx_mcdi_ev_cpl() to accept a single spurious completion.
267 	 */
268 	EFSYS_LOCK(enp->en_eslp, state);
269 	emrp = emip->emi_pending_req;
270 	aborted = (emrp != NULL);
271 	if (aborted) {
272 		emip->emi_pending_req = NULL;
273 
274 		/* Error the request */
275 		emrp->emr_out_length_used = 0;
276 		emrp->emr_rc = ETIMEDOUT;
277 
278 		/* Provide a credit for seqno/emr_pending_req mismatches */
279 		if (emip->emi_ev_cpl)
280 			++emip->emi_aborted;
281 
282 		/*
283 		 * The upper layer has called us, so we don't
284 		 * need to complete the request.
285 		 */
286 	}
287 	EFSYS_UNLOCK(enp->en_eslp, state);
288 
289 	return (aborted);
290 }
291 
292 	__checkReturn	efx_rc_t
293 efx_mcdi_request_errcode(
294 	__in		unsigned int err)
295 {
296 
297 	switch (err) {
298 		/* MCDI v1 */
299 	case MC_CMD_ERR_EPERM:
300 		return (EACCES);
301 	case MC_CMD_ERR_ENOENT:
302 		return (ENOENT);
303 	case MC_CMD_ERR_EINTR:
304 		return (EINTR);
305 	case MC_CMD_ERR_EACCES:
306 		return (EACCES);
307 	case MC_CMD_ERR_EBUSY:
308 		return (EBUSY);
309 	case MC_CMD_ERR_EINVAL:
310 		return (EINVAL);
311 	case MC_CMD_ERR_EDEADLK:
312 		return (EDEADLK);
313 	case MC_CMD_ERR_ENOSYS:
314 		return (ENOTSUP);
315 	case MC_CMD_ERR_ETIME:
316 		return (ETIMEDOUT);
317 	case MC_CMD_ERR_ENOTSUP:
318 		return (ENOTSUP);
319 	case MC_CMD_ERR_EALREADY:
320 		return (EALREADY);
321 
322 		/* MCDI v2 */
323 #ifdef MC_CMD_ERR_EAGAIN
324 	case MC_CMD_ERR_EAGAIN:
325 		return (EAGAIN);
326 #endif
327 #ifdef MC_CMD_ERR_ENOSPC
328 	case MC_CMD_ERR_ENOSPC:
329 		return (ENOSPC);
330 #endif
331 
332 	case MC_CMD_ERR_ALLOC_FAIL:
333 		return (ENOMEM);
334 	case MC_CMD_ERR_NO_VADAPTOR:
335 		return (ENOENT);
336 	case MC_CMD_ERR_NO_EVB_PORT:
337 		return (ENOENT);
338 	case MC_CMD_ERR_NO_VSWITCH:
339 		return (ENODEV);
340 	case MC_CMD_ERR_VLAN_LIMIT:
341 		return (EINVAL);
342 	case MC_CMD_ERR_BAD_PCI_FUNC:
343 		return (ENODEV);
344 	case MC_CMD_ERR_BAD_VLAN_MODE:
345 		return (EINVAL);
346 	case MC_CMD_ERR_BAD_VSWITCH_TYPE:
347 		return (EINVAL);
348 	case MC_CMD_ERR_BAD_VPORT_TYPE:
349 		return (EINVAL);
350 	case MC_CMD_ERR_MAC_EXIST:
351 		return (EEXIST);
352 
353 	default:
354 		EFSYS_PROBE1(mc_pcol_error, int, err);
355 		return (EIO);
356 	}
357 }
358 
359 			void
360 efx_mcdi_raise_exception(
361 	__in		efx_nic_t *enp,
362 	__in_opt	efx_mcdi_req_t *emrp,
363 	__in		int rc)
364 {
365 	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
366 	efx_mcdi_exception_t exception;
367 
368 	/* Reboot or Assertion failure only */
369 	EFSYS_ASSERT(rc == EIO || rc == EINTR);
370 
371 	/*
372 	 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
373 	 * then the EIO is not worthy of an exception.
374 	 */
375 	if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
376 		return;
377 
378 	exception = (rc == EIO)
379 		? EFX_MCDI_EXCEPTION_MC_REBOOT
380 		: EFX_MCDI_EXCEPTION_MC_BADASSERT;
381 
382 	emtp->emt_exception(emtp->emt_context, exception);
383 }
384 
385 static			efx_rc_t
386 efx_mcdi_poll_reboot(
387 	__in		efx_nic_t *enp)
388 {
389 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
390 
391 	return (emcop->emco_poll_reboot(enp));
392 }
393 
394 
395 			void
396 efx_mcdi_execute(
397 	__in		efx_nic_t *enp,
398 	__inout		efx_mcdi_req_t *emrp)
399 {
400 	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
401 
402 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
403 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
404 
405 	emrp->emr_quiet = B_FALSE;
406 	emtp->emt_execute(emtp->emt_context, emrp);
407 }
408 
409 			void
410 efx_mcdi_execute_quiet(
411 	__in		efx_nic_t *enp,
412 	__inout		efx_mcdi_req_t *emrp)
413 {
414 	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
415 
416 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
417 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
418 
419 	emrp->emr_quiet = B_TRUE;
420 	emtp->emt_execute(emtp->emt_context, emrp);
421 }
422 
423 			void
424 efx_mcdi_ev_cpl(
425 	__in		efx_nic_t *enp,
426 	__in		unsigned int seq,
427 	__in		unsigned int outlen,
428 	__in		int errcode)
429 {
430 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
431 	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
432 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
433 	efx_mcdi_req_t *emrp;
434 	int state;
435 
436 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
437 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
438 
439 	/*
440 	 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
441 	 * when we're completing an aborted request.
442 	 */
443 	EFSYS_LOCK(enp->en_eslp, state);
444 	if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
445 	    (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
446 		EFSYS_ASSERT(emip->emi_aborted > 0);
447 		if (emip->emi_aborted > 0)
448 			--emip->emi_aborted;
449 		EFSYS_UNLOCK(enp->en_eslp, state);
450 		return;
451 	}
452 
453 	emrp = emip->emi_pending_req;
454 	emip->emi_pending_req = NULL;
455 	EFSYS_UNLOCK(enp->en_eslp, state);
456 
457 	/*
458 	 * Fill out the remaining hdr fields, and copyout the payload
459 	 * if the user supplied an output buffer.
460 	 */
461 	if (errcode != 0) {
462 		if (!emrp->emr_quiet) {
463 			EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
464 			    int, errcode);
465 		}
466 		emrp->emr_out_length_used = 0;
467 		emrp->emr_rc = efx_mcdi_request_errcode(errcode);
468 	} else {
469 		emrp->emr_out_length_used = outlen;
470 		emrp->emr_rc = 0;
471 	}
472 	emcop->emco_request_copyout(enp, emrp);
473 
474 	emtp->emt_ev_cpl(emtp->emt_context);
475 }
476 
477 			void
478 efx_mcdi_ev_death(
479 	__in		efx_nic_t *enp,
480 	__in		int rc)
481 {
482 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
483 	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
484 	efx_mcdi_req_t *emrp = NULL;
485 	boolean_t ev_cpl;
486 	int state;
487 
488 	/*
489 	 * The MCDI request (if there is one) has been terminated, either
490 	 * by a BADASSERT or REBOOT event.
491 	 *
492 	 * If there is an outstanding event-completed MCDI operation, then we
493 	 * will never receive the completion event (because both MCDI
494 	 * completions and BADASSERT events are sent to the same evq). So
495 	 * complete this MCDI op.
496 	 *
497 	 * This function might run in parallel with efx_mcdi_request_poll()
498 	 * for poll completed mcdi requests, and also with
499 	 * efx_mcdi_request_start() for post-watchdog completions.
500 	 */
501 	EFSYS_LOCK(enp->en_eslp, state);
502 	emrp = emip->emi_pending_req;
503 	ev_cpl = emip->emi_ev_cpl;
504 	if (emrp != NULL && emip->emi_ev_cpl) {
505 		emip->emi_pending_req = NULL;
506 
507 		emrp->emr_out_length_used = 0;
508 		emrp->emr_rc = rc;
509 		++emip->emi_aborted;
510 	}
511 
512 	/*
513 	 * Since we're running in parallel with a request, consume the
514 	 * status word before dropping the lock.
515 	 */
516 	if (rc == EIO || rc == EINTR) {
517 		EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
518 		(void) efx_mcdi_poll_reboot(enp);
519 		emip->emi_new_epoch = B_TRUE;
520 	}
521 
522 	EFSYS_UNLOCK(enp->en_eslp, state);
523 
524 	efx_mcdi_raise_exception(enp, emrp, rc);
525 
526 	if (emrp != NULL && ev_cpl)
527 		emtp->emt_ev_cpl(emtp->emt_context);
528 }
529 
530 	__checkReturn		efx_rc_t
531 efx_mcdi_version(
532 	__in			efx_nic_t *enp,
533 	__out_ecount_opt(4)	uint16_t versionp[4],
534 	__out_opt		uint32_t *buildp,
535 	__out_opt		efx_mcdi_boot_t *statusp)
536 {
537 	efx_mcdi_req_t req;
538 	uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
539 				MC_CMD_GET_VERSION_OUT_LEN),
540 			    MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
541 				MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
542 	efx_word_t *ver_words;
543 	uint16_t version[4];
544 	uint32_t build;
545 	efx_mcdi_boot_t status;
546 	efx_rc_t rc;
547 
548 	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
549 
550 	(void) memset(payload, 0, sizeof (payload));
551 	req.emr_cmd = MC_CMD_GET_VERSION;
552 	req.emr_in_buf = payload;
553 	req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
554 	req.emr_out_buf = payload;
555 	req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
556 
557 	efx_mcdi_execute(enp, &req);
558 
559 	if (req.emr_rc != 0) {
560 		rc = req.emr_rc;
561 		goto fail1;
562 	}
563 
564 	/* bootrom support */
565 	if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
566 		version[0] = version[1] = version[2] = version[3] = 0;
567 		build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
568 
569 		goto version;
570 	}
571 
572 	if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
573 		rc = EMSGSIZE;
574 		goto fail2;
575 	}
576 
577 	ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
578 	version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
579 	version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
580 	version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
581 	version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
582 	build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
583 
584 version:
585 	/* The bootrom doesn't understand BOOT_STATUS */
586 	if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
587 		status = EFX_MCDI_BOOT_ROM;
588 		goto out;
589 	}
590 
591 	(void) memset(payload, 0, sizeof (payload));
592 	req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
593 	req.emr_in_buf = payload;
594 	req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
595 	req.emr_out_buf = payload;
596 	req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
597 
598 	efx_mcdi_execute_quiet(enp, &req);
599 
600 	if (req.emr_rc == EACCES) {
601 		/* Unprivileged functions cannot access BOOT_STATUS */
602 		status = EFX_MCDI_BOOT_PRIMARY;
603 		version[0] = version[1] = version[2] = version[3] = 0;
604 		build = 0;
605 		goto out;
606 	}
607 
608 	if (req.emr_rc != 0) {
609 		rc = req.emr_rc;
610 		goto fail3;
611 	}
612 
613 	if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
614 		rc = EMSGSIZE;
615 		goto fail4;
616 	}
617 
618 	if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
619 	    GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
620 		status = EFX_MCDI_BOOT_PRIMARY;
621 	else
622 		status = EFX_MCDI_BOOT_SECONDARY;
623 
624 out:
625 	if (versionp != NULL)
626 		memcpy(versionp, version, sizeof (version));
627 	if (buildp != NULL)
628 		*buildp = build;
629 	if (statusp != NULL)
630 		*statusp = status;
631 
632 	return (0);
633 
634 fail4:
635 	EFSYS_PROBE(fail4);
636 fail3:
637 	EFSYS_PROBE(fail3);
638 fail2:
639 	EFSYS_PROBE(fail2);
640 fail1:
641 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
642 
643 	return (rc);
644 }
645 
646 static	__checkReturn	efx_rc_t
647 efx_mcdi_do_reboot(
648 	__in		efx_nic_t *enp,
649 	__in		boolean_t after_assertion)
650 {
651 	uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
652 	efx_mcdi_req_t req;
653 	efx_rc_t rc;
654 
655 	/*
656 	 * We could require the caller to have caused en_mod_flags=0 to
657 	 * call this function. This doesn't help the other port though,
658 	 * who's about to get the MC ripped out from underneath them.
659 	 * Since they have to cope with the subsequent fallout of MCDI
660 	 * failures, we should as well.
661 	 */
662 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
663 
664 	(void) memset(payload, 0, sizeof (payload));
665 	req.emr_cmd = MC_CMD_REBOOT;
666 	req.emr_in_buf = payload;
667 	req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
668 	req.emr_out_buf = payload;
669 	req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
670 
671 	MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
672 	    (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
673 
674 	efx_mcdi_execute_quiet(enp, &req);
675 
676 	if (req.emr_rc == EACCES) {
677 		/* Unprivileged functions cannot reboot the MC. */
678 		goto out;
679 	}
680 
681 	/* A successful reboot request returns EIO. */
682 	if (req.emr_rc != 0 && req.emr_rc != EIO) {
683 		rc = req.emr_rc;
684 		goto fail1;
685 	}
686 
687 out:
688 	return (0);
689 
690 fail1:
691 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
692 
693 	return (rc);
694 }
695 
696 	__checkReturn	efx_rc_t
697 efx_mcdi_reboot(
698 	__in		efx_nic_t *enp)
699 {
700 	return (efx_mcdi_do_reboot(enp, B_FALSE));
701 }
702 
703 	__checkReturn	efx_rc_t
704 efx_mcdi_exit_assertion_handler(
705 	__in		efx_nic_t *enp)
706 {
707 	return (efx_mcdi_do_reboot(enp, B_TRUE));
708 }
709 
710 	__checkReturn	efx_rc_t
711 efx_mcdi_read_assertion(
712 	__in		efx_nic_t *enp)
713 {
714 	efx_mcdi_req_t req;
715 	uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
716 			    MC_CMD_GET_ASSERTS_OUT_LEN)];
717 	const char *reason;
718 	unsigned int flags;
719 	unsigned int index;
720 	unsigned int ofst;
721 	int retry;
722 	efx_rc_t rc;
723 
724 	/*
725 	 * Before we attempt to chat to the MC, we should verify that the MC
726 	 * isn't in it's assertion handler, either due to a previous reboot,
727 	 * or because we're reinitializing due to an eec_exception().
728 	 *
729 	 * Use GET_ASSERTS to read any assertion state that may be present.
730 	 * Retry this command twice. Once because a boot-time assertion failure
731 	 * might cause the 1st MCDI request to fail. And once again because
732 	 * we might race with efx_mcdi_exit_assertion_handler() running on
733 	 * partner port(s) on the same NIC.
734 	 */
735 	retry = 2;
736 	do {
737 		(void) memset(payload, 0, sizeof (payload));
738 		req.emr_cmd = MC_CMD_GET_ASSERTS;
739 		req.emr_in_buf = payload;
740 		req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
741 		req.emr_out_buf = payload;
742 		req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
743 
744 		MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
745 		efx_mcdi_execute_quiet(enp, &req);
746 
747 	} while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
748 
749 	if (req.emr_rc != 0) {
750 		if (req.emr_rc == EACCES) {
751 			/* Unprivileged functions cannot clear assertions. */
752 			goto out;
753 		}
754 		rc = req.emr_rc;
755 		goto fail1;
756 	}
757 
758 	if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
759 		rc = EMSGSIZE;
760 		goto fail2;
761 	}
762 
763 	/* Print out any assertion state recorded */
764 	flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
765 	if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
766 		return (0);
767 
768 	reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
769 		? "system-level assertion"
770 		: (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
771 		? "thread-level assertion"
772 		: (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
773 		? "watchdog reset"
774 		: (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
775 		? "illegal address trap"
776 		: "unknown assertion";
777 	EFSYS_PROBE3(mcpu_assertion,
778 	    const char *, reason, unsigned int,
779 	    MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
780 	    unsigned int,
781 	    MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
782 
783 	/* Print out the registers (r1 ... r31) */
784 	ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
785 	for (index = 1;
786 		index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
787 		index++) {
788 		EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
789 			    EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
790 					    EFX_DWORD_0));
791 		ofst += sizeof (efx_dword_t);
792 	}
793 	EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
794 
795 out:
796 	return (0);
797 
798 fail2:
799 	EFSYS_PROBE(fail2);
800 fail1:
801 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
802 
803 	return (rc);
804 }
805 
806 
807 /*
808  * Internal routines for for specific MCDI requests.
809  */
810 
811 	__checkReturn	efx_rc_t
812 efx_mcdi_drv_attach(
813 	__in		efx_nic_t *enp,
814 	__in		boolean_t attach)
815 {
816 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
817 	efx_mcdi_req_t req;
818 	uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
819 			    MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
820 	uint32_t flags;
821 	efx_rc_t rc;
822 
823 	(void) memset(payload, 0, sizeof (payload));
824 	req.emr_cmd = MC_CMD_DRV_ATTACH;
825 	req.emr_in_buf = payload;
826 	req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
827 	req.emr_out_buf = payload;
828 	req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
829 
830 	/*
831 	 * Use DONT_CARE for the datapath firmware type to ensure that the
832 	 * driver can attach to an unprivileged function. The datapath firmware
833 	 * type to use is controlled by the 'sfboot' utility.
834 	 */
835 	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
836 	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
837 	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
838 
839 	efx_mcdi_execute(enp, &req);
840 
841 	if (req.emr_rc != 0) {
842 		rc = req.emr_rc;
843 		goto fail1;
844 	}
845 
846 	if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
847 		rc = EMSGSIZE;
848 		goto fail2;
849 	}
850 
851 	if (attach == B_FALSE) {
852 		flags = 0;
853 	} else if (enp->en_family == EFX_FAMILY_SIENA) {
854 		efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
855 
856 		/* Create synthetic privileges for Siena functions */
857 		flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED;
858 		if (emip->emi_port == 1)
859 			flags |= EFX_NIC_FUNC_PRIMARY;
860 	} else {
861 		EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY ==
862 		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY));
863 		EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL ==
864 		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL));
865 		EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED ==
866 		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED));
867 
868 		/* Save function privilege flags (EF10 and later) */
869 		if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) {
870 			rc = EMSGSIZE;
871 			goto fail3;
872 		}
873 		flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS);
874 	}
875 	encp->enc_func_flags = flags;
876 
877 	return (0);
878 
879 fail3:
880 	EFSYS_PROBE(fail3);
881 fail2:
882 	EFSYS_PROBE(fail2);
883 fail1:
884 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
885 
886 	return (rc);
887 }
888 
889 	__checkReturn		efx_rc_t
890 efx_mcdi_get_board_cfg(
891 	__in			efx_nic_t *enp,
892 	__out_opt		uint32_t *board_typep,
893 	__out_opt		efx_dword_t *capabilitiesp,
894 	__out_ecount_opt(6)	uint8_t mac_addrp[6])
895 {
896 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
897 	efx_mcdi_req_t req;
898 	uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
899 			    MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
900 	efx_rc_t rc;
901 
902 	(void) memset(payload, 0, sizeof (payload));
903 	req.emr_cmd = MC_CMD_GET_BOARD_CFG;
904 	req.emr_in_buf = payload;
905 	req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
906 	req.emr_out_buf = payload;
907 	req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
908 
909 	efx_mcdi_execute(enp, &req);
910 
911 	if (req.emr_rc != 0) {
912 		rc = req.emr_rc;
913 		goto fail1;
914 	}
915 
916 	if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
917 		rc = EMSGSIZE;
918 		goto fail2;
919 	}
920 
921 	if (mac_addrp != NULL) {
922 		uint8_t *addrp;
923 
924 		if (emip->emi_port == 1) {
925 			addrp = MCDI_OUT2(req, uint8_t,
926 			    GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
927 		} else if (emip->emi_port == 2) {
928 			addrp = MCDI_OUT2(req, uint8_t,
929 			    GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
930 		} else {
931 			rc = EINVAL;
932 			goto fail3;
933 		}
934 
935 		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
936 	}
937 
938 	if (capabilitiesp != NULL) {
939 		if (emip->emi_port == 1) {
940 			*capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
941 			    GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
942 		} else if (emip->emi_port == 2) {
943 			*capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
944 			    GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
945 		} else {
946 			rc = EINVAL;
947 			goto fail4;
948 		}
949 	}
950 
951 	if (board_typep != NULL) {
952 		*board_typep = MCDI_OUT_DWORD(req,
953 		    GET_BOARD_CFG_OUT_BOARD_TYPE);
954 	}
955 
956 	return (0);
957 
958 fail4:
959 	EFSYS_PROBE(fail4);
960 fail3:
961 	EFSYS_PROBE(fail3);
962 fail2:
963 	EFSYS_PROBE(fail2);
964 fail1:
965 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
966 
967 	return (rc);
968 }
969 
970 	__checkReturn	efx_rc_t
971 efx_mcdi_get_resource_limits(
972 	__in		efx_nic_t *enp,
973 	__out_opt	uint32_t *nevqp,
974 	__out_opt	uint32_t *nrxqp,
975 	__out_opt	uint32_t *ntxqp)
976 {
977 	efx_mcdi_req_t req;
978 	uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
979 			    MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
980 	efx_rc_t rc;
981 
982 	(void) memset(payload, 0, sizeof (payload));
983 	req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
984 	req.emr_in_buf = payload;
985 	req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
986 	req.emr_out_buf = payload;
987 	req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
988 
989 	efx_mcdi_execute(enp, &req);
990 
991 	if (req.emr_rc != 0) {
992 		rc = req.emr_rc;
993 		goto fail1;
994 	}
995 
996 	if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
997 		rc = EMSGSIZE;
998 		goto fail2;
999 	}
1000 
1001 	if (nevqp != NULL)
1002 		*nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1003 	if (nrxqp != NULL)
1004 		*nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1005 	if (ntxqp != NULL)
1006 		*ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1007 
1008 	return (0);
1009 
1010 fail2:
1011 	EFSYS_PROBE(fail2);
1012 fail1:
1013 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1014 
1015 	return (rc);
1016 }
1017 
1018 	__checkReturn	efx_rc_t
1019 efx_mcdi_get_phy_cfg(
1020 	__in		efx_nic_t *enp)
1021 {
1022 	efx_port_t *epp = &(enp->en_port);
1023 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1024 	efx_mcdi_req_t req;
1025 	uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1026 			    MC_CMD_GET_PHY_CFG_OUT_LEN)];
1027 	efx_rc_t rc;
1028 
1029 	(void) memset(payload, 0, sizeof (payload));
1030 	req.emr_cmd = MC_CMD_GET_PHY_CFG;
1031 	req.emr_in_buf = payload;
1032 	req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1033 	req.emr_out_buf = payload;
1034 	req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1035 
1036 	efx_mcdi_execute(enp, &req);
1037 
1038 	if (req.emr_rc != 0) {
1039 		rc = req.emr_rc;
1040 		goto fail1;
1041 	}
1042 
1043 	if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1044 		rc = EMSGSIZE;
1045 		goto fail2;
1046 	}
1047 
1048 	encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1049 #if EFSYS_OPT_NAMES
1050 	(void) strncpy(encp->enc_phy_name,
1051 		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1052 		MIN(sizeof (encp->enc_phy_name) - 1,
1053 		    MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1054 #endif	/* EFSYS_OPT_NAMES */
1055 	(void) memset(encp->enc_phy_revision, 0,
1056 	    sizeof (encp->enc_phy_revision));
1057 	memcpy(encp->enc_phy_revision,
1058 		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1059 		MIN(sizeof (encp->enc_phy_revision) - 1,
1060 		    MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1061 #if EFSYS_OPT_PHY_LED_CONTROL
1062 	encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1063 			    (1 << EFX_PHY_LED_OFF) |
1064 			    (1 << EFX_PHY_LED_ON));
1065 #endif	/* EFSYS_OPT_PHY_LED_CONTROL */
1066 
1067 #if EFSYS_OPT_PHY_PROPS
1068 	encp->enc_phy_nprops  = 0;
1069 #endif	/* EFSYS_OPT_PHY_PROPS */
1070 
1071 	/* Get the media type of the fixed port, if recognised. */
1072 	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1073 	EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1074 	EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1075 	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1076 	EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1077 	EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1078 	EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1079 	epp->ep_fixed_port_type =
1080 		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1081 	if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1082 		epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1083 
1084 	epp->ep_phy_cap_mask =
1085 		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1086 #if EFSYS_OPT_PHY_FLAGS
1087 	encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1088 #endif	/* EFSYS_OPT_PHY_FLAGS */
1089 
1090 	encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1091 
1092 	/* Populate internal state */
1093 	encp->enc_mcdi_mdio_channel =
1094 		(uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1095 
1096 #if EFSYS_OPT_PHY_STATS
1097 	encp->enc_mcdi_phy_stat_mask =
1098 		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1099 #endif	/* EFSYS_OPT_PHY_STATS */
1100 
1101 #if EFSYS_OPT_BIST
1102 	encp->enc_bist_mask = 0;
1103 	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1104 	    GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1105 		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1106 	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1107 	    GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1108 		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1109 	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1110 	    GET_PHY_CFG_OUT_BIST))
1111 		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1112 #endif  /* EFSYS_OPT_BIST */
1113 
1114 	return (0);
1115 
1116 fail2:
1117 	EFSYS_PROBE(fail2);
1118 fail1:
1119 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1120 
1121 	return (rc);
1122 }
1123 
1124 
1125 	__checkReturn		efx_rc_t
1126 efx_mcdi_firmware_update_supported(
1127 	__in			efx_nic_t *enp,
1128 	__out			boolean_t *supportedp)
1129 {
1130 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1131 	efx_rc_t rc;
1132 
1133 	if (emcop != NULL && emcop->emco_fw_update_supported != NULL) {
1134 		if ((rc = emcop->emco_fw_update_supported(enp, supportedp))
1135 		    != 0)
1136 			goto fail1;
1137 	} else {
1138 		/* Earlier devices always supported updates */
1139 		*supportedp = B_TRUE;
1140 	}
1141 
1142 	return (0);
1143 
1144 fail1:
1145 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1146 
1147 	return (rc);
1148 }
1149 
1150 	__checkReturn		efx_rc_t
1151 efx_mcdi_macaddr_change_supported(
1152 	__in			efx_nic_t *enp,
1153 	__out			boolean_t *supportedp)
1154 {
1155 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1156 	efx_rc_t rc;
1157 
1158 	if (emcop != NULL && emcop->emco_macaddr_change_supported != NULL) {
1159 		if ((rc = emcop->emco_macaddr_change_supported(enp, supportedp))
1160 		    != 0)
1161 			goto fail1;
1162 	} else {
1163 		/* Earlier devices always supported MAC changes */
1164 		*supportedp = B_TRUE;
1165 	}
1166 
1167 	return (0);
1168 
1169 fail1:
1170 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1171 
1172 	return (rc);
1173 }
1174 
1175 	__checkReturn		efx_rc_t
1176 efx_mcdi_link_control_supported(
1177 	__in			efx_nic_t *enp,
1178 	__out			boolean_t *supportedp)
1179 {
1180 	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1181 	efx_rc_t rc;
1182 
1183 	if (emcop != NULL && emcop->emco_link_control_supported != NULL) {
1184 		if ((rc = emcop->emco_link_control_supported(enp, supportedp))
1185 		    != 0)
1186 			goto fail1;
1187 	} else {
1188 		/* Earlier devices always supported link control */
1189 		*supportedp = B_TRUE;
1190 	}
1191 
1192 	return (0);
1193 
1194 fail1:
1195 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1196 
1197 	return (rc);
1198 }
1199 
1200 #if EFSYS_OPT_BIST
1201 
1202 #if EFSYS_OPT_HUNTINGTON
1203 /*
1204  * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1205  * where memory BIST tests can be run and not much else can interfere or happen.
1206  * A reboot is required to exit this mode.
1207  */
1208 	__checkReturn		efx_rc_t
1209 efx_mcdi_bist_enable_offline(
1210 	__in			efx_nic_t *enp)
1211 {
1212 	efx_mcdi_req_t req;
1213 	efx_rc_t rc;
1214 
1215 	EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1216 	EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1217 
1218 	req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1219 	req.emr_in_buf = NULL;
1220 	req.emr_in_length = 0;
1221 	req.emr_out_buf = NULL;
1222 	req.emr_out_length = 0;
1223 
1224 	efx_mcdi_execute(enp, &req);
1225 
1226 	if (req.emr_rc != 0) {
1227 		rc = req.emr_rc;
1228 		goto fail1;
1229 	}
1230 
1231 	return (0);
1232 
1233 fail1:
1234 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1235 
1236 	return (rc);
1237 }
1238 #endif /* EFSYS_OPT_HUNTINGTON */
1239 
1240 	__checkReturn		efx_rc_t
1241 efx_mcdi_bist_start(
1242 	__in			efx_nic_t *enp,
1243 	__in			efx_bist_type_t type)
1244 {
1245 	efx_mcdi_req_t req;
1246 	uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1247 			    MC_CMD_START_BIST_OUT_LEN)];
1248 	efx_rc_t rc;
1249 
1250 	(void) memset(payload, 0, sizeof (payload));
1251 	req.emr_cmd = MC_CMD_START_BIST;
1252 	req.emr_in_buf = payload;
1253 	req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1254 	req.emr_out_buf = payload;
1255 	req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1256 
1257 	switch (type) {
1258 	case EFX_BIST_TYPE_PHY_NORMAL:
1259 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1260 		break;
1261 	case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1262 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1263 		    MC_CMD_PHY_BIST_CABLE_SHORT);
1264 		break;
1265 	case EFX_BIST_TYPE_PHY_CABLE_LONG:
1266 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1267 		    MC_CMD_PHY_BIST_CABLE_LONG);
1268 		break;
1269 	case EFX_BIST_TYPE_MC_MEM:
1270 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1271 		    MC_CMD_MC_MEM_BIST);
1272 		break;
1273 	case EFX_BIST_TYPE_SAT_MEM:
1274 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1275 		    MC_CMD_PORT_MEM_BIST);
1276 		break;
1277 	case EFX_BIST_TYPE_REG:
1278 		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1279 		    MC_CMD_REG_BIST);
1280 		break;
1281 	default:
1282 		EFSYS_ASSERT(0);
1283 	}
1284 
1285 	efx_mcdi_execute(enp, &req);
1286 
1287 	if (req.emr_rc != 0) {
1288 		rc = req.emr_rc;
1289 		goto fail1;
1290 	}
1291 
1292 	return (0);
1293 
1294 fail1:
1295 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1296 
1297 	return (rc);
1298 }
1299 
1300 #endif /* EFSYS_OPT_BIST */
1301 
1302 
1303 /* Enable logging of some events (e.g. link state changes) */
1304 	__checkReturn	efx_rc_t
1305 efx_mcdi_log_ctrl(
1306 	__in		efx_nic_t *enp)
1307 {
1308 	efx_mcdi_req_t req;
1309 	uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1310 			    MC_CMD_LOG_CTRL_OUT_LEN)];
1311 	efx_rc_t rc;
1312 
1313 	(void) memset(payload, 0, sizeof (payload));
1314 	req.emr_cmd = MC_CMD_LOG_CTRL;
1315 	req.emr_in_buf = payload;
1316 	req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1317 	req.emr_out_buf = payload;
1318 	req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1319 
1320 	MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1321 		    MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1322 	MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1323 
1324 	efx_mcdi_execute(enp, &req);
1325 
1326 	if (req.emr_rc != 0) {
1327 		rc = req.emr_rc;
1328 		goto fail1;
1329 	}
1330 
1331 	return (0);
1332 
1333 fail1:
1334 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1335 
1336 	return (rc);
1337 }
1338 
1339 
1340 #if EFSYS_OPT_MAC_STATS
1341 
1342 typedef enum efx_stats_action_e
1343 {
1344 	EFX_STATS_CLEAR,
1345 	EFX_STATS_UPLOAD,
1346 	EFX_STATS_ENABLE_NOEVENTS,
1347 	EFX_STATS_ENABLE_EVENTS,
1348 	EFX_STATS_DISABLE,
1349 } efx_stats_action_t;
1350 
1351 static	__checkReturn	efx_rc_t
1352 efx_mcdi_mac_stats(
1353 	__in		efx_nic_t *enp,
1354 	__in_opt	efsys_mem_t *esmp,
1355 	__in		efx_stats_action_t action)
1356 {
1357 	efx_mcdi_req_t req;
1358 	uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1359 			    MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1360 	int clear = (action == EFX_STATS_CLEAR);
1361 	int upload = (action == EFX_STATS_UPLOAD);
1362 	int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1363 	int events = (action == EFX_STATS_ENABLE_EVENTS);
1364 	int disable = (action == EFX_STATS_DISABLE);
1365 	efx_rc_t rc;
1366 
1367 	(void) memset(payload, 0, sizeof (payload));
1368 	req.emr_cmd = MC_CMD_MAC_STATS;
1369 	req.emr_in_buf = payload;
1370 	req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1371 	req.emr_out_buf = payload;
1372 	req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1373 
1374 	MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1375 	    MAC_STATS_IN_DMA, upload,
1376 	    MAC_STATS_IN_CLEAR, clear,
1377 	    MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1378 	    MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1379 	    MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1380 	    MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0);
1381 
1382 	if (esmp != NULL) {
1383 		int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1384 
1385 		EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1386 		    EFX_MAC_STATS_SIZE);
1387 
1388 		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1389 			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1390 		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1391 			    EFSYS_MEM_ADDR(esmp) >> 32);
1392 		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1393 	} else {
1394 		EFSYS_ASSERT(!upload && !enable && !events);
1395 	}
1396 
1397 	/*
1398 	 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1399 	 *	 as this may fail (and leave periodic DMA enabled) if the
1400 	 *	 vadapter has already been deleted.
1401 	 */
1402 	MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1403 	    (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1404 
1405 	efx_mcdi_execute(enp, &req);
1406 
1407 	if (req.emr_rc != 0) {
1408 		/* EF10: Expect ENOENT if no DMA queues are initialised */
1409 		if ((req.emr_rc != ENOENT) ||
1410 		    (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1411 			rc = req.emr_rc;
1412 			goto fail1;
1413 		}
1414 	}
1415 
1416 	return (0);
1417 
1418 fail1:
1419 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1420 
1421 	return (rc);
1422 }
1423 
1424 	__checkReturn	efx_rc_t
1425 efx_mcdi_mac_stats_clear(
1426 	__in		efx_nic_t *enp)
1427 {
1428 	efx_rc_t rc;
1429 
1430 	if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0)
1431 		goto fail1;
1432 
1433 	return (0);
1434 
1435 fail1:
1436 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1437 
1438 	return (rc);
1439 }
1440 
1441 	__checkReturn	efx_rc_t
1442 efx_mcdi_mac_stats_upload(
1443 	__in		efx_nic_t *enp,
1444 	__in		efsys_mem_t *esmp)
1445 {
1446 	efx_rc_t rc;
1447 
1448 	/*
1449 	 * The MC DMAs aggregate statistics for our convenience, so we can
1450 	 * avoid having to pull the statistics buffer into the cache to
1451 	 * maintain cumulative statistics.
1452 	 */
1453 	if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0)
1454 		goto fail1;
1455 
1456 	return (0);
1457 
1458 fail1:
1459 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1460 
1461 	return (rc);
1462 }
1463 
1464 	__checkReturn	efx_rc_t
1465 efx_mcdi_mac_stats_periodic(
1466 	__in		efx_nic_t *enp,
1467 	__in		efsys_mem_t *esmp,
1468 	__in		uint16_t period,
1469 	__in		boolean_t events)
1470 {
1471 	efx_rc_t rc;
1472 
1473 	/*
1474 	 * The MC DMAs aggregate statistics for our convenience, so we can
1475 	 * avoid having to pull the statistics buffer into the cache to
1476 	 * maintain cumulative statistics.
1477 	 * Huntington uses a fixed 1sec period, so use that on Siena too.
1478 	 */
1479 	if (period == 0)
1480 		rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE);
1481 	else if (events)
1482 		rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS);
1483 	else
1484 		rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS);
1485 
1486 	if (rc != 0)
1487 		goto fail1;
1488 
1489 	return (0);
1490 
1491 fail1:
1492 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1493 
1494 	return (rc);
1495 }
1496 
1497 #endif	/* EFSYS_OPT_MAC_STATS */
1498 
1499 #if EFSYS_OPT_HUNTINGTON
1500 
1501 /*
1502  * This function returns the pf and vf number of a function.  If it is a pf the
1503  * vf number is 0xffff.  The vf number is the index of the vf on that
1504  * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1505  * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1506  */
1507 	__checkReturn		efx_rc_t
1508 efx_mcdi_get_function_info(
1509 	__in			efx_nic_t *enp,
1510 	__out			uint32_t *pfp,
1511 	__out_opt		uint32_t *vfp)
1512 {
1513 	efx_mcdi_req_t req;
1514 	uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1515 			    MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1516 	efx_rc_t rc;
1517 
1518 	(void) memset(payload, 0, sizeof (payload));
1519 	req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1520 	req.emr_in_buf = payload;
1521 	req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1522 	req.emr_out_buf = payload;
1523 	req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1524 
1525 	efx_mcdi_execute(enp, &req);
1526 
1527 	if (req.emr_rc != 0) {
1528 		rc = req.emr_rc;
1529 		goto fail1;
1530 	}
1531 
1532 	if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1533 		rc = EMSGSIZE;
1534 		goto fail2;
1535 	}
1536 
1537 	*pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1538 	if (vfp != NULL)
1539 		*vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1540 
1541 	return (0);
1542 
1543 fail2:
1544 	EFSYS_PROBE(fail2);
1545 fail1:
1546 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1547 
1548 	return (rc);
1549 }
1550 
1551 	__checkReturn		efx_rc_t
1552 efx_mcdi_privilege_mask(
1553 	__in			efx_nic_t *enp,
1554 	__in			uint32_t pf,
1555 	__in			uint32_t vf,
1556 	__out			uint32_t *maskp)
1557 {
1558 	efx_mcdi_req_t req;
1559 	uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1560 			    MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1561 	efx_rc_t rc;
1562 
1563 	(void) memset(payload, 0, sizeof (payload));
1564 	req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1565 	req.emr_in_buf = payload;
1566 	req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1567 	req.emr_out_buf = payload;
1568 	req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1569 
1570 	MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1571 	    PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1572 	    PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1573 
1574 	efx_mcdi_execute(enp, &req);
1575 
1576 	if (req.emr_rc != 0) {
1577 		rc = req.emr_rc;
1578 		goto fail1;
1579 	}
1580 
1581 	if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
1582 		rc = EMSGSIZE;
1583 		goto fail2;
1584 	}
1585 
1586 	*maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
1587 
1588 	return (0);
1589 
1590 fail2:
1591 	EFSYS_PROBE(fail2);
1592 fail1:
1593 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1594 
1595 	return (rc);
1596 }
1597 
1598 #endif /* EFSYS_OPT_HUNTINGTON */
1599 
1600 	__checkReturn		efx_rc_t
1601 efx_mcdi_set_workaround(
1602 	__in			efx_nic_t *enp,
1603 	__in			uint32_t type,
1604 	__in			boolean_t enabled,
1605 	__out_opt		uint32_t *flagsp)
1606 {
1607 	efx_mcdi_req_t req;
1608 	uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1609 			    MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1610 	efx_rc_t rc;
1611 
1612 	(void) memset(payload, 0, sizeof (payload));
1613 	req.emr_cmd = MC_CMD_WORKAROUND;
1614 	req.emr_in_buf = payload;
1615 	req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1616 	req.emr_out_buf = payload;
1617 	req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1618 
1619 	MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1620 	MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1621 
1622 	efx_mcdi_execute_quiet(enp, &req);
1623 
1624 	if (req.emr_rc != 0) {
1625 		rc = req.emr_rc;
1626 		goto fail1;
1627 	}
1628 
1629 	if (flagsp != NULL) {
1630 		if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
1631 			*flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
1632 		else
1633 			*flagsp = 0;
1634 	}
1635 
1636 	return (0);
1637 
1638 fail1:
1639 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1640 
1641 	return (rc);
1642 }
1643 
1644 
1645 	__checkReturn		efx_rc_t
1646 efx_mcdi_get_workarounds(
1647 	__in			efx_nic_t *enp,
1648 	__out_opt		uint32_t *implementedp,
1649 	__out_opt		uint32_t *enabledp)
1650 {
1651 	efx_mcdi_req_t req;
1652 	uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
1653 	efx_rc_t rc;
1654 
1655 	(void) memset(payload, 0, sizeof (payload));
1656 	req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
1657 	req.emr_in_buf = NULL;
1658 	req.emr_in_length = 0;
1659 	req.emr_out_buf = payload;
1660 	req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
1661 
1662 	efx_mcdi_execute(enp, &req);
1663 
1664 	if (req.emr_rc != 0) {
1665 		rc = req.emr_rc;
1666 		goto fail1;
1667 	}
1668 
1669 	if (implementedp != NULL) {
1670 		*implementedp =
1671 		    MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1672 	}
1673 
1674 	if (enabledp != NULL) {
1675 		*enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
1676 	}
1677 
1678 	return (0);
1679 
1680 fail1:
1681 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1682 
1683 	return (rc);
1684 }
1685 
1686 
1687 #endif	/* EFSYS_OPT_MCDI */
1688