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