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