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