1227569Sphilip/*-
2284555Sarybchik * Copyright (c) 2008-2015 Solarflare Communications Inc.
3284555Sarybchik * All rights reserved.
4227569Sphilip *
5227569Sphilip * Redistribution and use in source and binary forms, with or without
6284555Sarybchik * modification, are permitted provided that the following conditions are met:
7227569Sphilip *
8284555Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9284555Sarybchik *    this list of conditions and the following disclaimer.
10284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11284555Sarybchik *    this list of conditions and the following disclaimer in the documentation
12284555Sarybchik *    and/or other materials provided with the distribution.
13284555Sarybchik *
14284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15284555Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16284555Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17284555Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18284555Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19284555Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20284555Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21284555Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22284555Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23284555Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24284555Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25284555Sarybchik *
26284555Sarybchik * The views and conclusions contained in the software and documentation are
27284555Sarybchik * those of the authors and should not be interpreted as representing official
28284555Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29227569Sphilip */
30227569Sphilip
31228078Sphilip#include <sys/cdefs.h>
32228078Sphilip__FBSDID("$FreeBSD: releng/10.2/sys/dev/sfxge/common/efx_mcdi.c 284555 2015-06-18 15:46:39Z arybchik $");
33228078Sphilip
34227569Sphilip#include "efsys.h"
35227569Sphilip#include "efx.h"
36227569Sphilip#include "efx_types.h"
37227569Sphilip#include "efx_regs.h"
38227569Sphilip#include "efx_regs_mcdi.h"
39227569Sphilip#include "efx_impl.h"
40227569Sphilip
41227569Sphilip#if EFSYS_OPT_MCDI
42227569Sphilip
43227569Sphilip
44284555Sarybchik#if EFSYS_OPT_SIENA
45284555Sarybchik
46284555Sarybchikstatic efx_mcdi_ops_t	__efx_mcdi_siena_ops = {
47284555Sarybchik	siena_mcdi_init,		/* emco_init */
48284555Sarybchik	siena_mcdi_request_copyin,	/* emco_request_copyin */
49284555Sarybchik	siena_mcdi_request_poll,	/* emco_request_poll */
50284555Sarybchik	siena_mcdi_request_copyout,	/* emco_request_copyout */
51284555Sarybchik	siena_mcdi_poll_reboot,		/* emco_poll_reboot */
52284555Sarybchik	siena_mcdi_fini,		/* emco_fini */
53284555Sarybchik	siena_mcdi_fw_update_supported,	/* emco_fw_update_supported */
54284555Sarybchik	siena_mcdi_macaddr_change_supported,
55284555Sarybchik				/* emco_macaddr_change_supported */
56284555Sarybchik};
57284555Sarybchik
58284555Sarybchik#endif	/* EFSYS_OPT_SIENA */
59284555Sarybchik
60284555Sarybchik#if EFSYS_OPT_HUNTINGTON
61284555Sarybchik
62284555Sarybchikstatic efx_mcdi_ops_t	__efx_mcdi_hunt_ops = {
63284555Sarybchik	hunt_mcdi_init,			/* emco_init */
64284555Sarybchik	hunt_mcdi_request_copyin,	/* emco_request_copyin */
65284555Sarybchik	hunt_mcdi_request_poll,		/* emco_request_poll */
66284555Sarybchik	hunt_mcdi_request_copyout,	/* emco_request_copyout */
67284555Sarybchik	hunt_mcdi_poll_reboot,		/* emco_poll_reboot */
68284555Sarybchik	hunt_mcdi_fini,			/* emco_fini */
69284555Sarybchik	hunt_mcdi_fw_update_supported,	/* emco_fw_update_supported */
70284555Sarybchik	hunt_mcdi_macaddr_change_supported,
71284555Sarybchik				/* emco_macaddr_change_supported */
72284555Sarybchik};
73284555Sarybchik
74284555Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
75284555Sarybchik
76284555Sarybchik
77284555Sarybchik
78284555Sarybchik	__checkReturn	int
79284555Sarybchikefx_mcdi_init(
80284555Sarybchik	__in		efx_nic_t *enp,
81284555Sarybchik	__in		const efx_mcdi_transport_t *emtp)
82284555Sarybchik{
83284555Sarybchik	efx_mcdi_ops_t *emcop;
84284555Sarybchik	int rc;
85284555Sarybchik
86284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
87284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0);
88284555Sarybchik
89284555Sarybchik	switch (enp->en_family) {
90284555Sarybchik#if EFSYS_OPT_FALCON
91284555Sarybchik	case EFX_FAMILY_FALCON:
92284555Sarybchik		emcop = NULL;
93284555Sarybchik		emtp = NULL;
94284555Sarybchik		break;
95284555Sarybchik#endif	/* EFSYS_OPT_FALCON */
96284555Sarybchik
97284555Sarybchik#if EFSYS_OPT_SIENA
98284555Sarybchik	case EFX_FAMILY_SIENA:
99284555Sarybchik		emcop = (efx_mcdi_ops_t *)&__efx_mcdi_siena_ops;
100284555Sarybchik		break;
101284555Sarybchik#endif	/* EFSYS_OPT_SIENA */
102284555Sarybchik
103284555Sarybchik#if EFSYS_OPT_HUNTINGTON
104284555Sarybchik	case EFX_FAMILY_HUNTINGTON:
105284555Sarybchik		emcop = (efx_mcdi_ops_t *)&__efx_mcdi_hunt_ops;
106284555Sarybchik		break;
107284555Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
108284555Sarybchik
109284555Sarybchik	default:
110284555Sarybchik		EFSYS_ASSERT(0);
111284555Sarybchik		rc = ENOTSUP;
112284555Sarybchik		goto fail1;
113284555Sarybchik	}
114284555Sarybchik
115284555Sarybchik	if (enp->en_features & EFX_FEATURE_MCDI_DMA) {
116284555Sarybchik		/* MCDI requires a DMA buffer in host memory */
117284555Sarybchik		if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) {
118284555Sarybchik			rc = EINVAL;
119284555Sarybchik			goto fail2;
120284555Sarybchik		}
121284555Sarybchik	}
122284555Sarybchik	enp->en_mcdi.em_emtp = emtp;
123284555Sarybchik
124284555Sarybchik	if (emcop != NULL && emcop->emco_init != NULL) {
125284555Sarybchik		if ((rc = emcop->emco_init(enp, emtp)) != 0)
126284555Sarybchik			goto fail3;
127284555Sarybchik	}
128284555Sarybchik
129284555Sarybchik	enp->en_mcdi.em_emcop = emcop;
130284555Sarybchik	enp->en_mod_flags |= EFX_MOD_MCDI;
131284555Sarybchik
132284555Sarybchik	return (0);
133284555Sarybchik
134284555Sarybchikfail3:
135284555Sarybchik	EFSYS_PROBE(fail3);
136284555Sarybchikfail2:
137284555Sarybchik	EFSYS_PROBE(fail2);
138284555Sarybchikfail1:
139284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
140284555Sarybchik
141284555Sarybchik	enp->en_mcdi.em_emcop = NULL;
142284555Sarybchik	enp->en_mcdi.em_emtp = NULL;
143284555Sarybchik	enp->en_mod_flags &= ~EFX_MOD_MCDI;
144284555Sarybchik
145284555Sarybchik	return (rc);
146284555Sarybchik}
147284555Sarybchik
148227569Sphilip			void
149284555Sarybchikefx_mcdi_fini(
150284555Sarybchik	__in		efx_nic_t *enp)
151284555Sarybchik{
152284555Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
153284555Sarybchik	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
154284555Sarybchik
155284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
156284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI);
157284555Sarybchik
158284555Sarybchik	if (emcop != NULL && emcop->emco_fini != NULL)
159284555Sarybchik		emcop->emco_fini(enp);
160284555Sarybchik
161284555Sarybchik	emip->emi_port = 0;
162284555Sarybchik	emip->emi_aborted = 0;
163284555Sarybchik
164284555Sarybchik	enp->en_mcdi.em_emcop = NULL;
165284555Sarybchik	enp->en_mod_flags &= ~EFX_MOD_MCDI;
166284555Sarybchik}
167284555Sarybchik
168284555Sarybchik			void
169284555Sarybchikefx_mcdi_new_epoch(
170284555Sarybchik	__in		efx_nic_t *enp)
171284555Sarybchik{
172284555Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
173284555Sarybchik	int state;
174284555Sarybchik
175284555Sarybchik	/* Start a new epoch (allow fresh MCDI requests to succeed) */
176284555Sarybchik	EFSYS_LOCK(enp->en_eslp, state);
177284555Sarybchik	emip->emi_new_epoch = B_TRUE;
178284555Sarybchik	EFSYS_UNLOCK(enp->en_eslp, state);
179284555Sarybchik}
180284555Sarybchik
181284555Sarybchik
182284555Sarybchik			void
183227569Sphilipefx_mcdi_request_start(
184227569Sphilip	__in		efx_nic_t *enp,
185227569Sphilip	__in		efx_mcdi_req_t *emrp,
186227569Sphilip	__in		boolean_t ev_cpl)
187227569Sphilip{
188284555Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
189284555Sarybchik	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
190227569Sphilip	unsigned int seq;
191284555Sarybchik	boolean_t new_epoch;
192227569Sphilip	int state;
193227569Sphilip
194227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
195227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
196227569Sphilip	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
197227569Sphilip
198284555Sarybchik	if (emcop == NULL || emcop->emco_request_copyin == NULL)
199284555Sarybchik		return;
200227569Sphilip
201227569Sphilip	/*
202227569Sphilip	 * efx_mcdi_request_start() is naturally serialised against both
203227569Sphilip	 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(),
204250460Seadler	 * by virtue of there only being one outstanding MCDI request.
205227569Sphilip	 * Unfortunately, upper layers may also call efx_mcdi_request_abort()
206227569Sphilip	 * at any time, to timeout a pending mcdi request, That request may
207227569Sphilip	 * then subsequently complete, meaning efx_mcdi_ev_cpl() or
208227569Sphilip	 * efx_mcdi_ev_death() may end up running in parallel with
209227569Sphilip	 * efx_mcdi_request_start(). This race is handled by ensuring that
210227569Sphilip	 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the
211227569Sphilip	 * en_eslp lock.
212227569Sphilip	 */
213227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
214227569Sphilip	EFSYS_ASSERT(emip->emi_pending_req == NULL);
215227569Sphilip	emip->emi_pending_req = emrp;
216227569Sphilip	emip->emi_ev_cpl = ev_cpl;
217227569Sphilip	emip->emi_poll_cnt = 0;
218284555Sarybchik	seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ);
219284555Sarybchik	new_epoch = emip->emi_new_epoch;
220227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
221227569Sphilip
222284555Sarybchik	emcop->emco_request_copyin(enp, emrp, seq, ev_cpl, new_epoch);
223284555Sarybchik}
224227569Sphilip
225284555Sarybchik	__checkReturn	boolean_t
226284555Sarybchikefx_mcdi_request_poll(
227284555Sarybchik	__in		efx_nic_t *enp)
228284555Sarybchik{
229284555Sarybchik	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
230284555Sarybchik	boolean_t completed;
231227569Sphilip
232284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
233284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
234284555Sarybchik	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
235227569Sphilip
236284555Sarybchik	completed = B_FALSE;
237284555Sarybchik
238284555Sarybchik	if (emcop != NULL && emcop->emco_request_poll != NULL)
239284555Sarybchik		completed = emcop->emco_request_poll(enp);
240284555Sarybchik
241284555Sarybchik	return (completed);
242227569Sphilip}
243227569Sphilip
244284555Sarybchik	__checkReturn	boolean_t
245284555Sarybchikefx_mcdi_request_abort(
246284555Sarybchik	__in		efx_nic_t *enp)
247227569Sphilip{
248284555Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
249284555Sarybchik	efx_mcdi_req_t *emrp;
250284555Sarybchik	boolean_t aborted;
251284555Sarybchik	int state;
252227569Sphilip
253284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
254284555Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
255284555Sarybchik	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
256227569Sphilip
257284555Sarybchik	/*
258284555Sarybchik	 * efx_mcdi_ev_* may have already completed this event, and be
259284555Sarybchik	 * spinning/blocked on the upper layer lock. So it *is* legitimate
260284555Sarybchik	 * to for emi_pending_req to be NULL. If there is a pending event
261284555Sarybchik	 * completed request, then provide a "credit" to allow
262284555Sarybchik	 * efx_mcdi_ev_cpl() to accept a single spurious completion.
263284555Sarybchik	 */
264284555Sarybchik	EFSYS_LOCK(enp->en_eslp, state);
265284555Sarybchik	emrp = emip->emi_pending_req;
266284555Sarybchik	aborted = (emrp != NULL);
267284555Sarybchik	if (aborted) {
268284555Sarybchik		emip->emi_pending_req = NULL;
269284555Sarybchik
270284555Sarybchik		/* Error the request */
271284555Sarybchik		emrp->emr_out_length_used = 0;
272284555Sarybchik		emrp->emr_rc = ETIMEDOUT;
273284555Sarybchik
274284555Sarybchik		/* Provide a credit for seqno/emr_pending_req mismatches */
275284555Sarybchik		if (emip->emi_ev_cpl)
276284555Sarybchik			++emip->emi_aborted;
277284555Sarybchik
278284555Sarybchik		/*
279284555Sarybchik		 * The upper layer has called us, so we don't
280284555Sarybchik		 * need to complete the request.
281284555Sarybchik		 */
282227569Sphilip	}
283284555Sarybchik	EFSYS_UNLOCK(enp->en_eslp, state);
284284555Sarybchik
285284555Sarybchik	return (aborted);
286227569Sphilip}
287227569Sphilip
288284555Sarybchik	__checkReturn	int
289227569Sphilipefx_mcdi_request_errcode(
290227569Sphilip	__in		unsigned int err)
291227569Sphilip{
292227569Sphilip
293227569Sphilip	switch (err) {
294284555Sarybchik		/* MCDI v1 */
295284555Sarybchik	case MC_CMD_ERR_EPERM:
296284555Sarybchik		return (EACCES);
297227569Sphilip	case MC_CMD_ERR_ENOENT:
298227569Sphilip		return (ENOENT);
299227569Sphilip	case MC_CMD_ERR_EINTR:
300227569Sphilip		return (EINTR);
301227569Sphilip	case MC_CMD_ERR_EACCES:
302227569Sphilip		return (EACCES);
303227569Sphilip	case MC_CMD_ERR_EBUSY:
304227569Sphilip		return (EBUSY);
305227569Sphilip	case MC_CMD_ERR_EINVAL:
306227569Sphilip		return (EINVAL);
307227569Sphilip	case MC_CMD_ERR_EDEADLK:
308227569Sphilip		return (EDEADLK);
309227569Sphilip	case MC_CMD_ERR_ENOSYS:
310227569Sphilip		return (ENOTSUP);
311227569Sphilip	case MC_CMD_ERR_ETIME:
312227569Sphilip		return (ETIMEDOUT);
313284555Sarybchik	case MC_CMD_ERR_ENOTSUP:
314284555Sarybchik		return (ENOTSUP);
315284555Sarybchik	case MC_CMD_ERR_EALREADY:
316284555Sarybchik		return (EALREADY);
317284555Sarybchik
318284555Sarybchik		/* MCDI v2 */
319284555Sarybchik#ifdef MC_CMD_ERR_EAGAIN
320227569Sphilip	case MC_CMD_ERR_EAGAIN:
321227569Sphilip		return (EAGAIN);
322284555Sarybchik#endif
323284555Sarybchik#ifdef MC_CMD_ERR_ENOSPC
324227569Sphilip	case MC_CMD_ERR_ENOSPC:
325227569Sphilip		return (ENOSPC);
326227569Sphilip#endif
327284555Sarybchik
328284555Sarybchik	case MC_CMD_ERR_ALLOC_FAIL:
329284555Sarybchik		return (ENOMEM);
330284555Sarybchik	case MC_CMD_ERR_NO_VADAPTOR:
331284555Sarybchik		return (ENOENT);
332284555Sarybchik	case MC_CMD_ERR_NO_EVB_PORT:
333284555Sarybchik		return (ENOENT);
334284555Sarybchik	case MC_CMD_ERR_NO_VSWITCH:
335284555Sarybchik		return (ENODEV);
336284555Sarybchik	case MC_CMD_ERR_VLAN_LIMIT:
337284555Sarybchik		return (EINVAL);
338284555Sarybchik	case MC_CMD_ERR_BAD_PCI_FUNC:
339284555Sarybchik		return (ENODEV);
340284555Sarybchik	case MC_CMD_ERR_BAD_VLAN_MODE:
341284555Sarybchik		return (EINVAL);
342284555Sarybchik	case MC_CMD_ERR_BAD_VSWITCH_TYPE:
343284555Sarybchik		return (EINVAL);
344284555Sarybchik	case MC_CMD_ERR_BAD_VPORT_TYPE:
345284555Sarybchik		return (EINVAL);
346284555Sarybchik	case MC_CMD_ERR_MAC_EXIST:
347284555Sarybchik		return (EEXIST);
348284555Sarybchik
349227569Sphilip	default:
350227569Sphilip		EFSYS_PROBE1(mc_pcol_error, int, err);
351227569Sphilip		return (EIO);
352227569Sphilip	}
353227569Sphilip}
354227569Sphilip
355284555Sarybchik			void
356227569Sphilipefx_mcdi_raise_exception(
357227569Sphilip	__in		efx_nic_t *enp,
358227569Sphilip	__in_opt	efx_mcdi_req_t *emrp,
359227569Sphilip	__in		int rc)
360227569Sphilip{
361284555Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
362227569Sphilip	efx_mcdi_exception_t exception;
363227569Sphilip
364227569Sphilip	/* Reboot or Assertion failure only */
365227569Sphilip	EFSYS_ASSERT(rc == EIO || rc == EINTR);
366227569Sphilip
367227569Sphilip	/*
368227569Sphilip	 * If MC_CMD_REBOOT causes a reboot (dependent on parameters),
369227569Sphilip	 * then the EIO is not worthy of an exception.
370227569Sphilip	 */
371227569Sphilip	if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO)
372227569Sphilip		return;
373227569Sphilip
374227569Sphilip	exception = (rc == EIO)
375227569Sphilip		? EFX_MCDI_EXCEPTION_MC_REBOOT
376227569Sphilip		: EFX_MCDI_EXCEPTION_MC_BADASSERT;
377227569Sphilip
378227569Sphilip	emtp->emt_exception(emtp->emt_context, exception);
379227569Sphilip}
380227569Sphilip
381227569Sphilipstatic			int
382227569Sphilipefx_mcdi_poll_reboot(
383227569Sphilip	__in		efx_nic_t *enp)
384227569Sphilip{
385284555Sarybchik	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
386227569Sphilip
387284555Sarybchik	return (emcop->emco_poll_reboot(enp));
388284555Sarybchik}
389227569Sphilip
390227569Sphilip
391284555Sarybchik			void
392284555Sarybchikefx_mcdi_execute(
393284555Sarybchik	__in		efx_nic_t *enp,
394284555Sarybchik	__inout		efx_mcdi_req_t *emrp)
395227569Sphilip{
396284555Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
397227569Sphilip
398227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
399227569Sphilip	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
400227569Sphilip
401284555Sarybchik	emrp->emr_quiet = B_FALSE;
402284555Sarybchik	emtp->emt_execute(emtp->emt_context, emrp);
403227569Sphilip}
404227569Sphilip
405227569Sphilip			void
406284555Sarybchikefx_mcdi_execute_quiet(
407227569Sphilip	__in		efx_nic_t *enp,
408284555Sarybchik	__inout		efx_mcdi_req_t *emrp)
409227569Sphilip{
410284555Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
411227569Sphilip
412227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
413227569Sphilip	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
414227569Sphilip
415284555Sarybchik	emrp->emr_quiet = B_TRUE;
416227569Sphilip	emtp->emt_execute(emtp->emt_context, emrp);
417227569Sphilip}
418227569Sphilip
419227569Sphilip			void
420227569Sphilipefx_mcdi_ev_cpl(
421227569Sphilip	__in		efx_nic_t *enp,
422227569Sphilip	__in		unsigned int seq,
423227569Sphilip	__in		unsigned int outlen,
424227569Sphilip	__in		int errcode)
425227569Sphilip{
426284555Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
427284555Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
428284555Sarybchik	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
429227569Sphilip	efx_mcdi_req_t *emrp;
430227569Sphilip	int state;
431227569Sphilip
432227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI);
433227569Sphilip	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
434227569Sphilip
435227569Sphilip	/*
436227569Sphilip	 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start()
437227569Sphilip	 * when we're completing an aborted request.
438227569Sphilip	 */
439227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
440227569Sphilip	if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl ||
441284555Sarybchik	    (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) {
442227569Sphilip		EFSYS_ASSERT(emip->emi_aborted > 0);
443227569Sphilip		if (emip->emi_aborted > 0)
444227569Sphilip			--emip->emi_aborted;
445227569Sphilip		EFSYS_UNLOCK(enp->en_eslp, state);
446227569Sphilip		return;
447227569Sphilip	}
448227569Sphilip
449227569Sphilip	emrp = emip->emi_pending_req;
450227569Sphilip	emip->emi_pending_req = NULL;
451227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
452227569Sphilip
453227569Sphilip	/*
454227569Sphilip	 * Fill out the remaining hdr fields, and copyout the payload
455227569Sphilip	 * if the user supplied an output buffer.
456227569Sphilip	 */
457227569Sphilip	if (errcode != 0) {
458284555Sarybchik		if (!emrp->emr_quiet) {
459284555Sarybchik			EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd,
460284555Sarybchik			    int, errcode);
461284555Sarybchik		}
462227569Sphilip		emrp->emr_out_length_used = 0;
463227569Sphilip		emrp->emr_rc = efx_mcdi_request_errcode(errcode);
464227569Sphilip	} else {
465227569Sphilip		emrp->emr_out_length_used = outlen;
466227569Sphilip		emrp->emr_rc = 0;
467284555Sarybchik
468284555Sarybchik		emcop->emco_request_copyout(enp, emrp);
469227569Sphilip	}
470227569Sphilip
471227569Sphilip	emtp->emt_ev_cpl(emtp->emt_context);
472227569Sphilip}
473227569Sphilip
474227569Sphilip			void
475227569Sphilipefx_mcdi_ev_death(
476227569Sphilip	__in		efx_nic_t *enp,
477227569Sphilip	__in		int rc)
478227569Sphilip{
479284555Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
480284555Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
481227569Sphilip	efx_mcdi_req_t *emrp = NULL;
482227569Sphilip	boolean_t ev_cpl;
483227569Sphilip	int state;
484227569Sphilip
485227569Sphilip	/*
486227569Sphilip	 * The MCDI request (if there is one) has been terminated, either
487227569Sphilip	 * by a BADASSERT or REBOOT event.
488227569Sphilip	 *
489250460Seadler	 * If there is an outstanding event-completed MCDI operation, then we
490227569Sphilip	 * will never receive the completion event (because both MCDI
491227569Sphilip	 * completions and BADASSERT events are sent to the same evq). So
492227569Sphilip	 * complete this MCDI op.
493227569Sphilip	 *
494227569Sphilip	 * This function might run in parallel with efx_mcdi_request_poll()
495227569Sphilip	 * for poll completed mcdi requests, and also with
496227569Sphilip	 * efx_mcdi_request_start() for post-watchdog completions.
497227569Sphilip	 */
498227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
499227569Sphilip	emrp = emip->emi_pending_req;
500227569Sphilip	ev_cpl = emip->emi_ev_cpl;
501227569Sphilip	if (emrp != NULL && emip->emi_ev_cpl) {
502227569Sphilip		emip->emi_pending_req = NULL;
503227569Sphilip
504227569Sphilip		emrp->emr_out_length_used = 0;
505227569Sphilip		emrp->emr_rc = rc;
506227569Sphilip		++emip->emi_aborted;
507227569Sphilip	}
508227569Sphilip
509280535Sarybchik	/*
510280535Sarybchik	 * Since we're running in parallel with a request, consume the
511227569Sphilip	 * status word before dropping the lock.
512227569Sphilip	 */
513227569Sphilip	if (rc == EIO || rc == EINTR) {
514284555Sarybchik		EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
515227569Sphilip		(void) efx_mcdi_poll_reboot(enp);
516284555Sarybchik		emip->emi_new_epoch = B_TRUE;
517227569Sphilip	}
518227569Sphilip
519227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
520227569Sphilip
521227569Sphilip	efx_mcdi_raise_exception(enp, emrp, rc);
522227569Sphilip
523227569Sphilip	if (emrp != NULL && ev_cpl)
524227569Sphilip		emtp->emt_ev_cpl(emtp->emt_context);
525227569Sphilip}
526227569Sphilip
527227569Sphilip	__checkReturn		int
528227569Sphilipefx_mcdi_version(
529227569Sphilip	__in			efx_nic_t *enp,
530227569Sphilip	__out_ecount_opt(4)	uint16_t versionp[4],
531227569Sphilip	__out_opt		uint32_t *buildp,
532227569Sphilip	__out_opt		efx_mcdi_boot_t *statusp)
533227569Sphilip{
534227569Sphilip	efx_mcdi_req_t req;
535284555Sarybchik	uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN,
536284555Sarybchik				MC_CMD_GET_VERSION_OUT_LEN),
537284555Sarybchik			    MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN,
538284555Sarybchik				MC_CMD_GET_BOOT_STATUS_OUT_LEN))];
539227569Sphilip	efx_word_t *ver_words;
540227569Sphilip	uint16_t version[4];
541227569Sphilip	uint32_t build;
542227569Sphilip	efx_mcdi_boot_t status;
543227569Sphilip	int rc;
544227569Sphilip
545227569Sphilip	EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI);
546227569Sphilip
547284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
548227569Sphilip	req.emr_cmd = MC_CMD_GET_VERSION;
549284555Sarybchik	req.emr_in_buf = payload;
550284555Sarybchik	req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN;
551284555Sarybchik	req.emr_out_buf = payload;
552227569Sphilip	req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN;
553227569Sphilip
554227569Sphilip	efx_mcdi_execute(enp, &req);
555227569Sphilip
556227569Sphilip	if (req.emr_rc != 0) {
557227569Sphilip		rc = req.emr_rc;
558227569Sphilip		goto fail1;
559227569Sphilip	}
560227569Sphilip
561227569Sphilip	/* bootrom support */
562227569Sphilip	if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) {
563227569Sphilip		version[0] = version[1] = version[2] = version[3] = 0;
564227569Sphilip		build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
565227569Sphilip
566227569Sphilip		goto version;
567227569Sphilip	}
568227569Sphilip
569227569Sphilip	if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) {
570227569Sphilip		rc = EMSGSIZE;
571227569Sphilip		goto fail2;
572227569Sphilip	}
573227569Sphilip
574227569Sphilip	ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION);
575227569Sphilip	version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0);
576227569Sphilip	version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0);
577227569Sphilip	version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0);
578227569Sphilip	version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0);
579227569Sphilip	build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE);
580227569Sphilip
581227569Sphilipversion:
582227569Sphilip	/* The bootrom doesn't understand BOOT_STATUS */
583284555Sarybchik	if (MC_FW_VERSION_IS_BOOTLOADER(build)) {
584227569Sphilip		status = EFX_MCDI_BOOT_ROM;
585227569Sphilip		goto out;
586227569Sphilip	}
587227569Sphilip
588284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
589227569Sphilip	req.emr_cmd = MC_CMD_GET_BOOT_STATUS;
590284555Sarybchik	req.emr_in_buf = payload;
591284555Sarybchik	req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN;
592284555Sarybchik	req.emr_out_buf = payload;
593227569Sphilip	req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN;
594227569Sphilip
595284555Sarybchik	efx_mcdi_execute_quiet(enp, &req);
596227569Sphilip
597284555Sarybchik	if (req.emr_rc == EACCES) {
598284555Sarybchik		/* Unprivileged functions cannot access BOOT_STATUS */
599284555Sarybchik		status = EFX_MCDI_BOOT_PRIMARY;
600284555Sarybchik		version[0] = version[1] = version[2] = version[3] = 0;
601284555Sarybchik		build = 0;
602284555Sarybchik		goto out;
603284555Sarybchik	}
604284555Sarybchik
605227569Sphilip	if (req.emr_rc != 0) {
606227569Sphilip		rc = req.emr_rc;
607227569Sphilip		goto fail3;
608227569Sphilip	}
609227569Sphilip
610227569Sphilip	if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) {
611227569Sphilip		rc = EMSGSIZE;
612227569Sphilip		goto fail4;
613227569Sphilip	}
614227569Sphilip
615227569Sphilip	if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS,
616227569Sphilip	    GET_BOOT_STATUS_OUT_FLAGS_PRIMARY))
617227569Sphilip		status = EFX_MCDI_BOOT_PRIMARY;
618227569Sphilip	else
619227569Sphilip		status = EFX_MCDI_BOOT_SECONDARY;
620227569Sphilip
621227569Sphilipout:
622227569Sphilip	if (versionp != NULL)
623227569Sphilip		memcpy(versionp, version, sizeof (version));
624227569Sphilip	if (buildp != NULL)
625227569Sphilip		*buildp = build;
626227569Sphilip	if (statusp != NULL)
627227569Sphilip		*statusp = status;
628227569Sphilip
629227569Sphilip	return (0);
630227569Sphilip
631227569Sphilipfail4:
632227569Sphilip	EFSYS_PROBE(fail4);
633227569Sphilipfail3:
634227569Sphilip	EFSYS_PROBE(fail3);
635227569Sphilipfail2:
636227569Sphilip	EFSYS_PROBE(fail2);
637227569Sphilipfail1:
638227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
639227569Sphilip
640227569Sphilip	return (rc);
641227569Sphilip}
642227569Sphilip
643284555Sarybchikstatic	__checkReturn	int
644284555Sarybchikefx_mcdi_do_reboot(
645227569Sphilip	__in		efx_nic_t *enp,
646284555Sarybchik	__in		boolean_t after_assertion)
647227569Sphilip{
648284555Sarybchik	uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)];
649284555Sarybchik	efx_mcdi_req_t req;
650227569Sphilip	int rc;
651227569Sphilip
652284555Sarybchik	/*
653284555Sarybchik	 * We could require the caller to have caused en_mod_flags=0 to
654284555Sarybchik	 * call this function. This doesn't help the other port though,
655284555Sarybchik	 * who's about to get the MC ripped out from underneath them.
656284555Sarybchik	 * Since they have to cope with the subsequent fallout of MCDI
657284555Sarybchik	 * failures, we should as well.
658284555Sarybchik	 */
659284555Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
660227569Sphilip
661284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
662284555Sarybchik	req.emr_cmd = MC_CMD_REBOOT;
663284555Sarybchik	req.emr_in_buf = payload;
664284555Sarybchik	req.emr_in_length = MC_CMD_REBOOT_IN_LEN;
665284555Sarybchik	req.emr_out_buf = payload;
666284555Sarybchik	req.emr_out_length = MC_CMD_REBOOT_OUT_LEN;
667227569Sphilip
668284555Sarybchik	MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS,
669284555Sarybchik	    (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0));
670227569Sphilip
671284555Sarybchik	efx_mcdi_execute_quiet(enp, &req);
672227569Sphilip
673284555Sarybchik	if (req.emr_rc == EACCES) {
674284555Sarybchik		/* Unprivileged functions cannot reboot the MC. */
675284555Sarybchik		goto out;
676284555Sarybchik	}
677284555Sarybchik
678284555Sarybchik	/* A successful reboot request returns EIO. */
679284555Sarybchik	if (req.emr_rc != 0 && req.emr_rc != EIO) {
680284555Sarybchik		rc = req.emr_rc;
681227569Sphilip		goto fail1;
682227569Sphilip	}
683227569Sphilip
684284555Sarybchikout:
685284555Sarybchik	return (0);
686284555Sarybchik
687284555Sarybchikfail1:
688284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
689284555Sarybchik
690284555Sarybchik	return (rc);
691284555Sarybchik}
692284555Sarybchik
693284555Sarybchik	__checkReturn	int
694284555Sarybchikefx_mcdi_reboot(
695284555Sarybchik	__in		efx_nic_t *enp)
696284555Sarybchik{
697284555Sarybchik	return (efx_mcdi_do_reboot(enp, B_FALSE));
698284555Sarybchik}
699284555Sarybchik
700284555Sarybchik	__checkReturn	int
701284555Sarybchikefx_mcdi_exit_assertion_handler(
702284555Sarybchik	__in		efx_nic_t *enp)
703284555Sarybchik{
704284555Sarybchik	return (efx_mcdi_do_reboot(enp, B_TRUE));
705284555Sarybchik}
706284555Sarybchik
707284555Sarybchik	__checkReturn	int
708284555Sarybchikefx_mcdi_read_assertion(
709284555Sarybchik	__in		efx_nic_t *enp)
710284555Sarybchik{
711284555Sarybchik	efx_mcdi_req_t req;
712284555Sarybchik	uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN,
713284555Sarybchik			    MC_CMD_GET_ASSERTS_OUT_LEN)];
714284555Sarybchik	const char *reason;
715284555Sarybchik	unsigned int flags;
716284555Sarybchik	unsigned int index;
717284555Sarybchik	unsigned int ofst;
718284555Sarybchik	int retry;
719284555Sarybchik	int rc;
720284555Sarybchik
721227569Sphilip	/*
722284555Sarybchik	 * Before we attempt to chat to the MC, we should verify that the MC
723284555Sarybchik	 * isn't in it's assertion handler, either due to a previous reboot,
724284555Sarybchik	 * or because we're reinitializing due to an eec_exception().
725284555Sarybchik	 *
726284555Sarybchik	 * Use GET_ASSERTS to read any assertion state that may be present.
727284555Sarybchik	 * Retry this command twice. Once because a boot-time assertion failure
728284555Sarybchik	 * might cause the 1st MCDI request to fail. And once again because
729284555Sarybchik	 * we might race with efx_mcdi_exit_assertion_handler() running on
730284555Sarybchik	 * partner port(s) on the same NIC.
731227569Sphilip	 */
732284555Sarybchik	retry = 2;
733284555Sarybchik	do {
734284555Sarybchik		(void) memset(payload, 0, sizeof (payload));
735284555Sarybchik		req.emr_cmd = MC_CMD_GET_ASSERTS;
736284555Sarybchik		req.emr_in_buf = payload;
737284555Sarybchik		req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN;
738284555Sarybchik		req.emr_out_buf = payload;
739284555Sarybchik		req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN;
740227569Sphilip
741284555Sarybchik		MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1);
742284555Sarybchik		efx_mcdi_execute_quiet(enp, &req);
743284555Sarybchik
744284555Sarybchik	} while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0);
745284555Sarybchik
746284555Sarybchik	if (req.emr_rc != 0) {
747284555Sarybchik		if (req.emr_rc == EACCES) {
748284555Sarybchik			/* Unprivileged functions cannot clear assertions. */
749284555Sarybchik			goto out;
750284555Sarybchik		}
751284555Sarybchik		rc = req.emr_rc;
752284555Sarybchik		goto fail1;
753284555Sarybchik	}
754284555Sarybchik
755284555Sarybchik	if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) {
756284555Sarybchik		rc = EMSGSIZE;
757284555Sarybchik		goto fail2;
758284555Sarybchik	}
759284555Sarybchik
760284555Sarybchik	/* Print out any assertion state recorded */
761284555Sarybchik	flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS);
762284555Sarybchik	if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS)
763284555Sarybchik		return (0);
764284555Sarybchik
765284555Sarybchik	reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL)
766284555Sarybchik		? "system-level assertion"
767284555Sarybchik		: (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL)
768284555Sarybchik		? "thread-level assertion"
769284555Sarybchik		: (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED)
770284555Sarybchik		? "watchdog reset"
771284555Sarybchik		: (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP)
772284555Sarybchik		? "illegal address trap"
773284555Sarybchik		: "unknown assertion";
774284555Sarybchik	EFSYS_PROBE3(mcpu_assertion,
775284555Sarybchik	    const char *, reason, unsigned int,
776284555Sarybchik	    MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS),
777284555Sarybchik	    unsigned int,
778284555Sarybchik	    MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS));
779284555Sarybchik
780284555Sarybchik	/* Print out the registers (r1 ... r31) */
781284555Sarybchik	ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST;
782284555Sarybchik	for (index = 1;
783284555Sarybchik		index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM;
784284555Sarybchik		index++) {
785284555Sarybchik		EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int,
786284555Sarybchik			    EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst),
787284555Sarybchik					    EFX_DWORD_0));
788284555Sarybchik		ofst += sizeof (efx_dword_t);
789284555Sarybchik	}
790284555Sarybchik	EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN);
791284555Sarybchik
792284555Sarybchikout:
793227569Sphilip	return (0);
794227569Sphilip
795284555Sarybchikfail2:
796284555Sarybchik	EFSYS_PROBE(fail2);
797227569Sphilipfail1:
798227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
799227569Sphilip
800227569Sphilip	return (rc);
801227569Sphilip}
802227569Sphilip
803227569Sphilip
804284555Sarybchik/*
805284555Sarybchik * Internal routines for for specific MCDI requests.
806284555Sarybchik */
807284555Sarybchik
808227569Sphilip	__checkReturn	int
809284555Sarybchikefx_mcdi_drv_attach(
810284555Sarybchik	__in		efx_nic_t *enp,
811284555Sarybchik	__in		boolean_t attach)
812227569Sphilip{
813284555Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
814227569Sphilip	efx_mcdi_req_t req;
815284555Sarybchik	uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN,
816284555Sarybchik			    MC_CMD_DRV_ATTACH_EXT_OUT_LEN)];
817284555Sarybchik	uint32_t flags;
818227569Sphilip	int rc;
819227569Sphilip
820284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
821284555Sarybchik	req.emr_cmd = MC_CMD_DRV_ATTACH;
822284555Sarybchik	req.emr_in_buf = payload;
823284555Sarybchik	req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN;
824284555Sarybchik	req.emr_out_buf = payload;
825284555Sarybchik	req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN;
826284555Sarybchik
827227569Sphilip	/*
828284555Sarybchik	 * Use DONT_CARE for the datapath firmware type to ensure that the
829284555Sarybchik	 * driver can attach to an unprivileged function. The datapath firmware
830284555Sarybchik	 * type to use is controlled by the 'sfboot' utility.
831227569Sphilip	 */
832284555Sarybchik	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0);
833284555Sarybchik	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1);
834284555Sarybchik	MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE);
835227569Sphilip
836284555Sarybchik	efx_mcdi_execute(enp, &req);
837284555Sarybchik
838284555Sarybchik	if (req.emr_rc != 0) {
839284555Sarybchik		rc = req.emr_rc;
840284555Sarybchik		goto fail1;
841284555Sarybchik	}
842284555Sarybchik
843284555Sarybchik	if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) {
844284555Sarybchik		rc = EMSGSIZE;
845284555Sarybchik		goto fail2;
846284555Sarybchik	}
847284555Sarybchik
848284555Sarybchik	if (attach == B_FALSE) {
849284555Sarybchik		flags = 0;
850284555Sarybchik	} else if (enp->en_family == EFX_FAMILY_SIENA) {
851284555Sarybchik		efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
852284555Sarybchik
853284555Sarybchik		/* Create synthetic privileges for Siena functions */
854284555Sarybchik		flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED;
855284555Sarybchik		if (emip->emi_port == 1)
856284555Sarybchik			flags |= EFX_NIC_FUNC_PRIMARY;
857284555Sarybchik	} else {
858284555Sarybchik		EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY ==
859284555Sarybchik		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY));
860284555Sarybchik		EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL ==
861284555Sarybchik		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL));
862284555Sarybchik		EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED ==
863284555Sarybchik		    (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED));
864284555Sarybchik
865284555Sarybchik		/* Save function privilege flags (EF10 and later) */
866284555Sarybchik		if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) {
867284555Sarybchik			rc = EMSGSIZE;
868284555Sarybchik			goto fail3;
869284555Sarybchik		}
870284555Sarybchik		flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS);
871284555Sarybchik	}
872284555Sarybchik	encp->enc_func_flags = flags;
873284555Sarybchik
874284555Sarybchik	return (0);
875284555Sarybchik
876284555Sarybchikfail3:
877284555Sarybchik	EFSYS_PROBE(fail3);
878284555Sarybchikfail2:
879284555Sarybchik	EFSYS_PROBE(fail2);
880284555Sarybchikfail1:
881284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
882284555Sarybchik
883284555Sarybchik	return (rc);
884284555Sarybchik}
885284555Sarybchik
886284555Sarybchik	__checkReturn		int
887284555Sarybchikefx_mcdi_get_board_cfg(
888284555Sarybchik	__in			efx_nic_t *enp,
889284555Sarybchik	__out_opt		uint32_t *board_typep,
890284555Sarybchik	__out_opt		efx_dword_t *capabilitiesp,
891284555Sarybchik	__out_ecount_opt(6)	uint8_t mac_addrp[6])
892284555Sarybchik{
893284555Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
894284555Sarybchik	efx_mcdi_req_t req;
895284555Sarybchik	uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
896284555Sarybchik			    MC_CMD_GET_BOARD_CFG_OUT_LENMIN)];
897284555Sarybchik	int rc;
898284555Sarybchik
899284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
900284555Sarybchik	req.emr_cmd = MC_CMD_GET_BOARD_CFG;
901227569Sphilip	req.emr_in_buf = payload;
902284555Sarybchik	req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
903284555Sarybchik	req.emr_out_buf = payload;
904284555Sarybchik	req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN;
905284555Sarybchik
906284555Sarybchik	efx_mcdi_execute(enp, &req);
907284555Sarybchik
908284555Sarybchik	if (req.emr_rc != 0) {
909284555Sarybchik		rc = req.emr_rc;
910284555Sarybchik		goto fail1;
911284555Sarybchik	}
912284555Sarybchik
913284555Sarybchik	if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
914284555Sarybchik		rc = EMSGSIZE;
915284555Sarybchik		goto fail2;
916284555Sarybchik	}
917284555Sarybchik
918284555Sarybchik	if (mac_addrp != NULL) {
919284555Sarybchik		uint8_t *addrp;
920284555Sarybchik
921284555Sarybchik		if (emip->emi_port == 1) {
922284555Sarybchik			addrp = MCDI_OUT2(req, uint8_t,
923284555Sarybchik			    GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0);
924284555Sarybchik		} else if (emip->emi_port == 2) {
925284555Sarybchik			addrp = MCDI_OUT2(req, uint8_t,
926284555Sarybchik			    GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1);
927284555Sarybchik		} else {
928284555Sarybchik			rc = EINVAL;
929284555Sarybchik			goto fail3;
930284555Sarybchik		}
931284555Sarybchik
932284555Sarybchik		EFX_MAC_ADDR_COPY(mac_addrp, addrp);
933284555Sarybchik	}
934284555Sarybchik
935284555Sarybchik	if (capabilitiesp != NULL) {
936284555Sarybchik		if (emip->emi_port == 1) {
937284555Sarybchik			*capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
938284555Sarybchik			    GET_BOARD_CFG_OUT_CAPABILITIES_PORT0);
939284555Sarybchik		} else if (emip->emi_port == 2) {
940284555Sarybchik			*capabilitiesp = *MCDI_OUT2(req, efx_dword_t,
941284555Sarybchik			    GET_BOARD_CFG_OUT_CAPABILITIES_PORT1);
942284555Sarybchik		} else {
943284555Sarybchik			rc = EINVAL;
944284555Sarybchik			goto fail4;
945284555Sarybchik		}
946284555Sarybchik	}
947284555Sarybchik
948284555Sarybchik	if (board_typep != NULL) {
949284555Sarybchik		*board_typep = MCDI_OUT_DWORD(req,
950284555Sarybchik		    GET_BOARD_CFG_OUT_BOARD_TYPE);
951284555Sarybchik	}
952284555Sarybchik
953284555Sarybchik	return (0);
954284555Sarybchik
955284555Sarybchikfail4:
956284555Sarybchik	EFSYS_PROBE(fail4);
957284555Sarybchikfail3:
958284555Sarybchik	EFSYS_PROBE(fail3);
959284555Sarybchikfail2:
960284555Sarybchik	EFSYS_PROBE(fail2);
961284555Sarybchikfail1:
962284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
963284555Sarybchik
964284555Sarybchik	return (rc);
965284555Sarybchik}
966284555Sarybchik
967284555Sarybchik	__checkReturn	int
968284555Sarybchikefx_mcdi_get_resource_limits(
969284555Sarybchik	__in		efx_nic_t *enp,
970284555Sarybchik	__out_opt	uint32_t *nevqp,
971284555Sarybchik	__out_opt	uint32_t *nrxqp,
972284555Sarybchik	__out_opt	uint32_t *ntxqp)
973284555Sarybchik{
974284555Sarybchik	efx_mcdi_req_t req;
975284555Sarybchik	uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN,
976284555Sarybchik			    MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)];
977284555Sarybchik	int rc;
978284555Sarybchik
979284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
980284555Sarybchik	req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS;
981284555Sarybchik	req.emr_in_buf = payload;
982284555Sarybchik	req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN;
983284555Sarybchik	req.emr_out_buf = payload;
984284555Sarybchik	req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN;
985284555Sarybchik
986284555Sarybchik	efx_mcdi_execute(enp, &req);
987284555Sarybchik
988284555Sarybchik	if (req.emr_rc != 0) {
989284555Sarybchik		rc = req.emr_rc;
990284555Sarybchik		goto fail1;
991284555Sarybchik	}
992284555Sarybchik
993284555Sarybchik	if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) {
994284555Sarybchik		rc = EMSGSIZE;
995284555Sarybchik		goto fail2;
996284555Sarybchik	}
997284555Sarybchik
998284555Sarybchik	if (nevqp != NULL)
999284555Sarybchik		*nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ);
1000284555Sarybchik	if (nrxqp != NULL)
1001284555Sarybchik		*nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ);
1002284555Sarybchik	if (ntxqp != NULL)
1003284555Sarybchik		*ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ);
1004284555Sarybchik
1005284555Sarybchik	return (0);
1006284555Sarybchik
1007284555Sarybchikfail2:
1008284555Sarybchik	EFSYS_PROBE(fail2);
1009284555Sarybchikfail1:
1010284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1011284555Sarybchik
1012284555Sarybchik	return (rc);
1013284555Sarybchik}
1014284555Sarybchik
1015284555Sarybchik	__checkReturn	int
1016284555Sarybchikefx_mcdi_get_phy_cfg(
1017284555Sarybchik	__in		efx_nic_t *enp)
1018284555Sarybchik{
1019284555Sarybchik	efx_port_t *epp = &(enp->en_port);
1020284555Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1021284555Sarybchik	efx_mcdi_req_t req;
1022284555Sarybchik	uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN,
1023284555Sarybchik			    MC_CMD_GET_PHY_CFG_OUT_LEN)];
1024284555Sarybchik	int rc;
1025284555Sarybchik
1026284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1027284555Sarybchik	req.emr_cmd = MC_CMD_GET_PHY_CFG;
1028284555Sarybchik	req.emr_in_buf = payload;
1029284555Sarybchik	req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN;
1030284555Sarybchik	req.emr_out_buf = payload;
1031284555Sarybchik	req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN;
1032284555Sarybchik
1033284555Sarybchik	efx_mcdi_execute(enp, &req);
1034284555Sarybchik
1035284555Sarybchik	if (req.emr_rc != 0) {
1036284555Sarybchik		rc = req.emr_rc;
1037284555Sarybchik		goto fail1;
1038284555Sarybchik	}
1039284555Sarybchik
1040284555Sarybchik	if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) {
1041284555Sarybchik		rc = EMSGSIZE;
1042284555Sarybchik		goto fail2;
1043284555Sarybchik	}
1044284555Sarybchik
1045284555Sarybchik	encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE);
1046284555Sarybchik#if EFSYS_OPT_NAMES
1047284555Sarybchik	(void) strncpy(encp->enc_phy_name,
1048284555Sarybchik		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME),
1049284555Sarybchik		MIN(sizeof (encp->enc_phy_name) - 1,
1050284555Sarybchik		    MC_CMD_GET_PHY_CFG_OUT_NAME_LEN));
1051284555Sarybchik#endif	/* EFSYS_OPT_NAMES */
1052284555Sarybchik	(void) memset(encp->enc_phy_revision, 0,
1053284555Sarybchik	    sizeof (encp->enc_phy_revision));
1054284555Sarybchik	memcpy(encp->enc_phy_revision,
1055284555Sarybchik		MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION),
1056284555Sarybchik		MIN(sizeof (encp->enc_phy_revision) - 1,
1057284555Sarybchik		    MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN));
1058284555Sarybchik#if EFSYS_OPT_PHY_LED_CONTROL
1059284555Sarybchik	encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) |
1060284555Sarybchik			    (1 << EFX_PHY_LED_OFF) |
1061284555Sarybchik			    (1 << EFX_PHY_LED_ON));
1062284555Sarybchik#endif	/* EFSYS_OPT_PHY_LED_CONTROL */
1063284555Sarybchik
1064284555Sarybchik#if EFSYS_OPT_PHY_PROPS
1065284555Sarybchik	encp->enc_phy_nprops  = 0;
1066284555Sarybchik#endif	/* EFSYS_OPT_PHY_PROPS */
1067284555Sarybchik
1068284555Sarybchik	/* Get the media type of the fixed port, if recognised. */
1069284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI);
1070284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4);
1071284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4);
1072284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP);
1073284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS);
1074284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T);
1075284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS);
1076284555Sarybchik	epp->ep_fixed_port_type =
1077284555Sarybchik		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE);
1078284555Sarybchik	if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES)
1079284555Sarybchik		epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID;
1080284555Sarybchik
1081284555Sarybchik	epp->ep_phy_cap_mask =
1082284555Sarybchik		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP);
1083284555Sarybchik#if EFSYS_OPT_PHY_FLAGS
1084284555Sarybchik	encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS);
1085284555Sarybchik#endif	/* EFSYS_OPT_PHY_FLAGS */
1086284555Sarybchik
1087284555Sarybchik	encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT);
1088284555Sarybchik
1089284555Sarybchik	/* Populate internal state */
1090284555Sarybchik	encp->enc_mcdi_mdio_channel =
1091284555Sarybchik		(uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL);
1092284555Sarybchik
1093284555Sarybchik#if EFSYS_OPT_PHY_STATS
1094284555Sarybchik	encp->enc_mcdi_phy_stat_mask =
1095284555Sarybchik		MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK);
1096284555Sarybchik#endif	/* EFSYS_OPT_PHY_STATS */
1097284555Sarybchik
1098284555Sarybchik#if EFSYS_OPT_BIST
1099284555Sarybchik	encp->enc_bist_mask = 0;
1100284555Sarybchik	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1101284555Sarybchik	    GET_PHY_CFG_OUT_BIST_CABLE_SHORT))
1102284555Sarybchik		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT);
1103284555Sarybchik	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1104284555Sarybchik	    GET_PHY_CFG_OUT_BIST_CABLE_LONG))
1105284555Sarybchik		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG);
1106284555Sarybchik	if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS,
1107284555Sarybchik	    GET_PHY_CFG_OUT_BIST))
1108284555Sarybchik		encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL);
1109284555Sarybchik#endif  /* EFSYS_OPT_BIST */
1110284555Sarybchik
1111284555Sarybchik	return (0);
1112284555Sarybchik
1113284555Sarybchikfail2:
1114284555Sarybchik	EFSYS_PROBE(fail2);
1115284555Sarybchikfail1:
1116284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1117284555Sarybchik
1118284555Sarybchik	return (rc);
1119284555Sarybchik}
1120284555Sarybchik
1121284555Sarybchik
1122284555Sarybchik	__checkReturn		int
1123284555Sarybchikefx_mcdi_firmware_update_supported(
1124284555Sarybchik	__in			efx_nic_t *enp,
1125284555Sarybchik	__out			boolean_t *supportedp)
1126284555Sarybchik{
1127284555Sarybchik	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1128284555Sarybchik	int rc;
1129284555Sarybchik
1130284555Sarybchik	if (emcop != NULL && emcop->emco_fw_update_supported != NULL) {
1131284555Sarybchik		if ((rc = emcop->emco_fw_update_supported(enp, supportedp))
1132284555Sarybchik		    != 0)
1133284555Sarybchik			goto fail1;
1134284555Sarybchik	} else {
1135284555Sarybchik		/* Earlier devices always supported updates */
1136284555Sarybchik		*supportedp = B_TRUE;
1137284555Sarybchik	}
1138284555Sarybchik
1139284555Sarybchik	return (0);
1140284555Sarybchik
1141284555Sarybchikfail1:
1142284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1143284555Sarybchik
1144284555Sarybchik	return (rc);
1145284555Sarybchik}
1146284555Sarybchik
1147284555Sarybchik	__checkReturn		int
1148284555Sarybchikefx_mcdi_macaddr_change_supported(
1149284555Sarybchik	__in			efx_nic_t *enp,
1150284555Sarybchik	__out			boolean_t *supportedp)
1151284555Sarybchik{
1152284555Sarybchik	efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop;
1153284555Sarybchik	int rc;
1154284555Sarybchik
1155284555Sarybchik	if (emcop != NULL && emcop->emco_macaddr_change_supported != NULL) {
1156284555Sarybchik		if ((rc = emcop->emco_macaddr_change_supported(enp, supportedp))
1157284555Sarybchik		    != 0)
1158284555Sarybchik			goto fail1;
1159284555Sarybchik	} else {
1160284555Sarybchik		/* Earlier devices always supported MAC changes */
1161284555Sarybchik		*supportedp = B_TRUE;
1162284555Sarybchik	}
1163284555Sarybchik
1164284555Sarybchik	return (0);
1165284555Sarybchik
1166284555Sarybchikfail1:
1167284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1168284555Sarybchik
1169284555Sarybchik	return (rc);
1170284555Sarybchik}
1171284555Sarybchik
1172284555Sarybchik#if EFSYS_OPT_BIST
1173284555Sarybchik
1174284555Sarybchik#if EFSYS_OPT_HUNTINGTON
1175284555Sarybchik/*
1176284555Sarybchik * Enter bist offline mode. This is a fw mode which puts the NIC into a state
1177284555Sarybchik * where memory BIST tests can be run and not much else can interfere or happen.
1178284555Sarybchik * A reboot is required to exit this mode.
1179284555Sarybchik */
1180284555Sarybchik	__checkReturn		int
1181284555Sarybchikefx_mcdi_bist_enable_offline(
1182284555Sarybchik	__in			efx_nic_t *enp)
1183284555Sarybchik{
1184284555Sarybchik	efx_mcdi_req_t req;
1185284555Sarybchik	int rc;
1186284555Sarybchik
1187284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0);
1188284555Sarybchik	EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0);
1189284555Sarybchik
1190284555Sarybchik	req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST;
1191284555Sarybchik	req.emr_in_buf = NULL;
1192284555Sarybchik	req.emr_in_length = 0;
1193227569Sphilip	req.emr_out_buf = NULL;
1194227569Sphilip	req.emr_out_length = 0;
1195227569Sphilip
1196284555Sarybchik	efx_mcdi_execute(enp, &req);
1197227569Sphilip
1198284555Sarybchik	if (req.emr_rc != 0) {
1199284555Sarybchik		rc = req.emr_rc;
1200284555Sarybchik		goto fail1;
1201284555Sarybchik	}
1202284555Sarybchik
1203284555Sarybchik	return (0);
1204284555Sarybchik
1205284555Sarybchikfail1:
1206284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1207284555Sarybchik
1208284555Sarybchik	return (rc);
1209284555Sarybchik}
1210284555Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
1211284555Sarybchik
1212284555Sarybchik	__checkReturn		int
1213284555Sarybchikefx_mcdi_bist_start(
1214284555Sarybchik	__in			efx_nic_t *enp,
1215284555Sarybchik	__in			efx_bist_type_t type)
1216284555Sarybchik{
1217284555Sarybchik	efx_mcdi_req_t req;
1218284555Sarybchik	uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN,
1219284555Sarybchik			    MC_CMD_START_BIST_OUT_LEN)];
1220284555Sarybchik	int rc;
1221284555Sarybchik
1222284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1223284555Sarybchik	req.emr_cmd = MC_CMD_START_BIST;
1224284555Sarybchik	req.emr_in_buf = payload;
1225284555Sarybchik	req.emr_in_length = MC_CMD_START_BIST_IN_LEN;
1226284555Sarybchik	req.emr_out_buf = payload;
1227284555Sarybchik	req.emr_out_length = MC_CMD_START_BIST_OUT_LEN;
1228284555Sarybchik
1229284555Sarybchik	switch (type) {
1230284555Sarybchik	case EFX_BIST_TYPE_PHY_NORMAL:
1231284555Sarybchik		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
1232284555Sarybchik		break;
1233284555Sarybchik	case EFX_BIST_TYPE_PHY_CABLE_SHORT:
1234284555Sarybchik		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1235284555Sarybchik		    MC_CMD_PHY_BIST_CABLE_SHORT);
1236284555Sarybchik		break;
1237284555Sarybchik	case EFX_BIST_TYPE_PHY_CABLE_LONG:
1238284555Sarybchik		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1239284555Sarybchik		    MC_CMD_PHY_BIST_CABLE_LONG);
1240284555Sarybchik		break;
1241284555Sarybchik	case EFX_BIST_TYPE_MC_MEM:
1242284555Sarybchik		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1243284555Sarybchik		    MC_CMD_MC_MEM_BIST);
1244284555Sarybchik		break;
1245284555Sarybchik	case EFX_BIST_TYPE_SAT_MEM:
1246284555Sarybchik		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1247284555Sarybchik		    MC_CMD_PORT_MEM_BIST);
1248284555Sarybchik		break;
1249284555Sarybchik	case EFX_BIST_TYPE_REG:
1250284555Sarybchik		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
1251284555Sarybchik		    MC_CMD_REG_BIST);
1252284555Sarybchik		break;
1253284555Sarybchik	default:
1254284555Sarybchik		EFSYS_ASSERT(0);
1255284555Sarybchik	}
1256284555Sarybchik
1257227569Sphilip	efx_mcdi_execute(enp, &req);
1258227569Sphilip
1259284555Sarybchik	if (req.emr_rc != 0) {
1260284555Sarybchik		rc = req.emr_rc;
1261227569Sphilip		goto fail1;
1262227569Sphilip	}
1263227569Sphilip
1264227569Sphilip	return (0);
1265227569Sphilip
1266227569Sphilipfail1:
1267227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
1268227569Sphilip
1269227569Sphilip	return (rc);
1270227569Sphilip}
1271227569Sphilip
1272284555Sarybchik#endif /* EFSYS_OPT_BIST */
1273284555Sarybchik
1274284555Sarybchik
1275284555Sarybchik/* Enable logging of some events (e.g. link state changes) */
1276284555Sarybchik	__checkReturn	int
1277284555Sarybchikefx_mcdi_log_ctrl(
1278227569Sphilip	__in		efx_nic_t *enp)
1279227569Sphilip{
1280284555Sarybchik	efx_mcdi_req_t req;
1281284555Sarybchik	uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN,
1282284555Sarybchik			    MC_CMD_LOG_CTRL_OUT_LEN)];
1283284555Sarybchik	int rc;
1284227569Sphilip
1285284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1286284555Sarybchik	req.emr_cmd = MC_CMD_LOG_CTRL;
1287284555Sarybchik	req.emr_in_buf = payload;
1288284555Sarybchik	req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN;
1289284555Sarybchik	req.emr_out_buf = payload;
1290284555Sarybchik	req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN;
1291227569Sphilip
1292284555Sarybchik	MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST,
1293284555Sarybchik		    MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ);
1294284555Sarybchik	MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0);
1295284555Sarybchik
1296284555Sarybchik	efx_mcdi_execute(enp, &req);
1297284555Sarybchik
1298284555Sarybchik	if (req.emr_rc != 0) {
1299284555Sarybchik		rc = req.emr_rc;
1300284555Sarybchik		goto fail1;
1301284555Sarybchik	}
1302284555Sarybchik
1303284555Sarybchik	return (0);
1304284555Sarybchik
1305284555Sarybchikfail1:
1306284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1307284555Sarybchik
1308284555Sarybchik	return (rc);
1309284555Sarybchik}
1310284555Sarybchik
1311284555Sarybchik
1312284555Sarybchik#if EFSYS_OPT_MAC_STATS
1313284555Sarybchik
1314284555Sarybchiktypedef enum efx_stats_action_e
1315284555Sarybchik{
1316284555Sarybchik	EFX_STATS_CLEAR,
1317284555Sarybchik	EFX_STATS_UPLOAD,
1318284555Sarybchik	EFX_STATS_ENABLE_NOEVENTS,
1319284555Sarybchik	EFX_STATS_ENABLE_EVENTS,
1320284555Sarybchik	EFX_STATS_DISABLE,
1321284555Sarybchik} efx_stats_action_t;
1322284555Sarybchik
1323284555Sarybchikstatic	__checkReturn	int
1324284555Sarybchikefx_mcdi_mac_stats(
1325284555Sarybchik	__in		efx_nic_t *enp,
1326284555Sarybchik	__in_opt	efsys_mem_t *esmp,
1327284555Sarybchik	__in		efx_stats_action_t action)
1328284555Sarybchik{
1329284555Sarybchik	efx_mcdi_req_t req;
1330284555Sarybchik	uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN,
1331284555Sarybchik			    MC_CMD_MAC_STATS_OUT_DMA_LEN)];
1332284555Sarybchik	int clear = (action == EFX_STATS_CLEAR);
1333284555Sarybchik	int upload = (action == EFX_STATS_UPLOAD);
1334284555Sarybchik	int enable = (action == EFX_STATS_ENABLE_NOEVENTS);
1335284555Sarybchik	int events = (action == EFX_STATS_ENABLE_EVENTS);
1336284555Sarybchik	int disable = (action == EFX_STATS_DISABLE);
1337284555Sarybchik	int rc;
1338284555Sarybchik
1339284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1340284555Sarybchik	req.emr_cmd = MC_CMD_MAC_STATS;
1341284555Sarybchik	req.emr_in_buf = payload;
1342284555Sarybchik	req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN;
1343284555Sarybchik	req.emr_out_buf = payload;
1344284555Sarybchik	req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN;
1345284555Sarybchik
1346284555Sarybchik	MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD,
1347284555Sarybchik	    MAC_STATS_IN_DMA, upload,
1348284555Sarybchik	    MAC_STATS_IN_CLEAR, clear,
1349284555Sarybchik	    MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable,
1350284555Sarybchik	    MAC_STATS_IN_PERIODIC_ENABLE, enable | events,
1351284555Sarybchik	    MAC_STATS_IN_PERIODIC_NOEVENT, !events,
1352284555Sarybchik	    MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0);
1353284555Sarybchik
1354284555Sarybchik	if (esmp != NULL) {
1355284555Sarybchik		int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t);
1356284555Sarybchik
1357284555Sarybchik		EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <=
1358284555Sarybchik		    EFX_MAC_STATS_SIZE);
1359284555Sarybchik
1360284555Sarybchik		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO,
1361284555Sarybchik			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
1362284555Sarybchik		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI,
1363284555Sarybchik			    EFSYS_MEM_ADDR(esmp) >> 32);
1364284555Sarybchik		MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes);
1365284555Sarybchik	} else {
1366284555Sarybchik		EFSYS_ASSERT(!upload && !enable && !events);
1367284555Sarybchik	}
1368284555Sarybchik
1369227569Sphilip	/*
1370284555Sarybchik	 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats,
1371284555Sarybchik	 *	 as this may fail (and leave periodic DMA enabled) if the
1372284555Sarybchik	 *	 vadapter has already been deleted.
1373227569Sphilip	 */
1374284555Sarybchik	MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID,
1375284555Sarybchik	    (disable ? EVB_PORT_ID_NULL : enp->en_vport_id));
1376227569Sphilip
1377284555Sarybchik	efx_mcdi_execute(enp, &req);
1378227569Sphilip
1379284555Sarybchik	if (req.emr_rc != 0) {
1380284555Sarybchik		/* EF10: Expect ENOENT if no DMA queues are initialised */
1381284555Sarybchik		if ((req.emr_rc != ENOENT) ||
1382284555Sarybchik		    (enp->en_rx_qcount + enp->en_tx_qcount != 0)) {
1383284555Sarybchik			rc = req.emr_rc;
1384284555Sarybchik			goto fail1;
1385284555Sarybchik		}
1386227569Sphilip	}
1387227569Sphilip
1388284555Sarybchik	return (0);
1389284555Sarybchik
1390284555Sarybchikfail1:
1391284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1392284555Sarybchik
1393284555Sarybchik	return (rc);
1394227569Sphilip}
1395227569Sphilip
1396284555Sarybchik	__checkReturn	int
1397284555Sarybchikefx_mcdi_mac_stats_clear(
1398227569Sphilip	__in		efx_nic_t *enp)
1399227569Sphilip{
1400284555Sarybchik	int rc;
1401227569Sphilip
1402284555Sarybchik	if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0)
1403284555Sarybchik		goto fail1;
1404227569Sphilip
1405284555Sarybchik	return (0);
1406227569Sphilip
1407284555Sarybchikfail1:
1408284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1409284555Sarybchik
1410284555Sarybchik	return (rc);
1411227569Sphilip}
1412227569Sphilip
1413284555Sarybchik	__checkReturn	int
1414284555Sarybchikefx_mcdi_mac_stats_upload(
1415284555Sarybchik	__in		efx_nic_t *enp,
1416284555Sarybchik	__in		efsys_mem_t *esmp)
1417284555Sarybchik{
1418284555Sarybchik	int rc;
1419284555Sarybchik
1420284555Sarybchik	/*
1421284555Sarybchik	 * The MC DMAs aggregate statistics for our convenience, so we can
1422284555Sarybchik	 * avoid having to pull the statistics buffer into the cache to
1423284555Sarybchik	 * maintain cumulative statistics.
1424284555Sarybchik	 */
1425284555Sarybchik	if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0)
1426284555Sarybchik		goto fail1;
1427284555Sarybchik
1428284555Sarybchik	return (0);
1429284555Sarybchik
1430284555Sarybchikfail1:
1431284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1432284555Sarybchik
1433284555Sarybchik	return (rc);
1434284555Sarybchik}
1435284555Sarybchik
1436284555Sarybchik	__checkReturn	int
1437284555Sarybchikefx_mcdi_mac_stats_periodic(
1438284555Sarybchik	__in		efx_nic_t *enp,
1439284555Sarybchik	__in		efsys_mem_t *esmp,
1440284555Sarybchik	__in		uint16_t period,
1441284555Sarybchik	__in		boolean_t events)
1442284555Sarybchik{
1443284555Sarybchik	int rc;
1444284555Sarybchik
1445284555Sarybchik	/*
1446284555Sarybchik	 * The MC DMAs aggregate statistics for our convenience, so we can
1447284555Sarybchik	 * avoid having to pull the statistics buffer into the cache to
1448284555Sarybchik	 * maintain cumulative statistics.
1449284555Sarybchik	 * Huntington uses a fixed 1sec period, so use that on Siena too.
1450284555Sarybchik	 */
1451284555Sarybchik	if (period == 0)
1452284555Sarybchik		rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE);
1453284555Sarybchik	else if (events)
1454284555Sarybchik		rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS);
1455284555Sarybchik	else
1456284555Sarybchik		rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS);
1457284555Sarybchik
1458284555Sarybchik	if (rc != 0)
1459284555Sarybchik		goto fail1;
1460284555Sarybchik
1461284555Sarybchik	return (0);
1462284555Sarybchik
1463284555Sarybchikfail1:
1464284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1465284555Sarybchik
1466284555Sarybchik	return (rc);
1467284555Sarybchik}
1468284555Sarybchik
1469284555Sarybchik#endif	/* EFSYS_OPT_MAC_STATS */
1470284555Sarybchik
1471284555Sarybchik#if EFSYS_OPT_HUNTINGTON
1472284555Sarybchik
1473284555Sarybchik/*
1474284555Sarybchik * This function returns the pf and vf number of a function.  If it is a pf the
1475284555Sarybchik * vf number is 0xffff.  The vf number is the index of the vf on that
1476284555Sarybchik * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0),
1477284555Sarybchik * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff).
1478284555Sarybchik */
1479284555Sarybchik	__checkReturn		int
1480284555Sarybchikefx_mcdi_get_function_info(
1481284555Sarybchik	__in			efx_nic_t *enp,
1482284555Sarybchik	__out			uint32_t *pfp,
1483284555Sarybchik	__out_opt		uint32_t *vfp)
1484284555Sarybchik{
1485284555Sarybchik	efx_mcdi_req_t req;
1486284555Sarybchik	uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN,
1487284555Sarybchik			    MC_CMD_GET_FUNCTION_INFO_OUT_LEN)];
1488284555Sarybchik	int rc;
1489284555Sarybchik
1490284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1491284555Sarybchik	req.emr_cmd = MC_CMD_GET_FUNCTION_INFO;
1492284555Sarybchik	req.emr_in_buf = payload;
1493284555Sarybchik	req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN;
1494284555Sarybchik	req.emr_out_buf = payload;
1495284555Sarybchik	req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN;
1496284555Sarybchik
1497284555Sarybchik	efx_mcdi_execute(enp, &req);
1498284555Sarybchik
1499284555Sarybchik	if (req.emr_rc != 0) {
1500284555Sarybchik		rc = req.emr_rc;
1501284555Sarybchik		goto fail1;
1502284555Sarybchik	}
1503284555Sarybchik
1504284555Sarybchik	if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) {
1505284555Sarybchik		rc = EMSGSIZE;
1506284555Sarybchik		goto fail2;
1507284555Sarybchik	}
1508284555Sarybchik
1509284555Sarybchik	*pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF);
1510284555Sarybchik	if (vfp != NULL)
1511284555Sarybchik		*vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF);
1512284555Sarybchik
1513284555Sarybchik	return (0);
1514284555Sarybchik
1515284555Sarybchikfail2:
1516284555Sarybchik	EFSYS_PROBE(fail2);
1517284555Sarybchikfail1:
1518284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1519284555Sarybchik
1520284555Sarybchik	return (rc);
1521284555Sarybchik}
1522284555Sarybchik
1523284555Sarybchik	__checkReturn		int
1524284555Sarybchikefx_mcdi_privilege_mask(
1525284555Sarybchik	__in			efx_nic_t *enp,
1526284555Sarybchik	__in			uint32_t pf,
1527284555Sarybchik	__in			uint32_t vf,
1528284555Sarybchik	__out			uint32_t *maskp)
1529284555Sarybchik{
1530284555Sarybchik	efx_mcdi_req_t req;
1531284555Sarybchik	uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN,
1532284555Sarybchik			    MC_CMD_PRIVILEGE_MASK_OUT_LEN)];
1533284555Sarybchik	int rc;
1534284555Sarybchik
1535284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1536284555Sarybchik	req.emr_cmd = MC_CMD_PRIVILEGE_MASK;
1537284555Sarybchik	req.emr_in_buf = payload;
1538284555Sarybchik	req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN;
1539284555Sarybchik	req.emr_out_buf = payload;
1540284555Sarybchik	req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN;
1541284555Sarybchik
1542284555Sarybchik	MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION,
1543284555Sarybchik	    PRIVILEGE_MASK_IN_FUNCTION_PF, pf,
1544284555Sarybchik	    PRIVILEGE_MASK_IN_FUNCTION_VF, vf);
1545284555Sarybchik
1546284555Sarybchik	efx_mcdi_execute(enp, &req);
1547284555Sarybchik
1548284555Sarybchik	if (req.emr_rc != 0) {
1549284555Sarybchik		rc = req.emr_rc;
1550284555Sarybchik		goto fail1;
1551284555Sarybchik	}
1552284555Sarybchik
1553284555Sarybchik	if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) {
1554284555Sarybchik		rc = EMSGSIZE;
1555284555Sarybchik		goto fail2;
1556284555Sarybchik	}
1557284555Sarybchik
1558284555Sarybchik	*maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK);
1559284555Sarybchik
1560284555Sarybchik	return (0);
1561284555Sarybchik
1562284555Sarybchikfail2:
1563284555Sarybchik	EFSYS_PROBE(fail2);
1564284555Sarybchikfail1:
1565284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1566284555Sarybchik
1567284555Sarybchik	return (rc);
1568284555Sarybchik}
1569284555Sarybchik
1570284555Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */
1571284555Sarybchik
1572284555Sarybchik	__checkReturn		int
1573284555Sarybchikefx_mcdi_set_workaround(
1574284555Sarybchik	__in			efx_nic_t *enp,
1575284555Sarybchik	__in			uint32_t type,
1576284555Sarybchik	__in			boolean_t enabled,
1577284555Sarybchik	__out_opt		uint32_t *flagsp)
1578284555Sarybchik{
1579284555Sarybchik	efx_mcdi_req_t req;
1580284555Sarybchik	uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN,
1581284555Sarybchik			    MC_CMD_WORKAROUND_EXT_OUT_LEN)];
1582284555Sarybchik	int rc;
1583284555Sarybchik
1584284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1585284555Sarybchik	req.emr_cmd = MC_CMD_WORKAROUND;
1586284555Sarybchik	req.emr_in_buf = payload;
1587284555Sarybchik	req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN;
1588284555Sarybchik	req.emr_out_buf = payload;
1589284555Sarybchik	req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN;
1590284555Sarybchik
1591284555Sarybchik	MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type);
1592284555Sarybchik	MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0);
1593284555Sarybchik
1594284555Sarybchik	efx_mcdi_execute_quiet(enp, &req);
1595284555Sarybchik
1596284555Sarybchik	if (req.emr_rc != 0) {
1597284555Sarybchik		rc = req.emr_rc;
1598284555Sarybchik		goto fail1;
1599284555Sarybchik	}
1600284555Sarybchik
1601284555Sarybchik	if (flagsp != NULL) {
1602284555Sarybchik		if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN)
1603284555Sarybchik			*flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS);
1604284555Sarybchik		else
1605284555Sarybchik			*flagsp = 0;
1606284555Sarybchik	}
1607284555Sarybchik
1608284555Sarybchik	return (0);
1609284555Sarybchik
1610284555Sarybchikfail1:
1611284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1612284555Sarybchik
1613284555Sarybchik	return (rc);
1614284555Sarybchik}
1615284555Sarybchik
1616284555Sarybchik
1617284555Sarybchik	__checkReturn		int
1618284555Sarybchikefx_mcdi_get_workarounds(
1619284555Sarybchik	__in			efx_nic_t *enp,
1620284555Sarybchik	__out_opt		uint32_t *implementedp,
1621284555Sarybchik	__out_opt		uint32_t *enabledp)
1622284555Sarybchik{
1623284555Sarybchik	efx_mcdi_req_t req;
1624284555Sarybchik	uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN];
1625284555Sarybchik	int rc;
1626284555Sarybchik
1627284555Sarybchik	(void) memset(payload, 0, sizeof (payload));
1628284555Sarybchik	req.emr_cmd = MC_CMD_GET_WORKAROUNDS;
1629284555Sarybchik	req.emr_in_buf = NULL;
1630284555Sarybchik	req.emr_in_length = 0;
1631284555Sarybchik	req.emr_out_buf = payload;
1632284555Sarybchik	req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN;
1633284555Sarybchik
1634284555Sarybchik	efx_mcdi_execute(enp, &req);
1635284555Sarybchik
1636284555Sarybchik	if (req.emr_rc != 0) {
1637284555Sarybchik		rc = req.emr_rc;
1638284555Sarybchik		goto fail1;
1639284555Sarybchik	}
1640284555Sarybchik
1641284555Sarybchik	if (implementedp != NULL) {
1642284555Sarybchik		*implementedp =
1643284555Sarybchik		    MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED);
1644284555Sarybchik	}
1645284555Sarybchik
1646284555Sarybchik	if (enabledp != NULL) {
1647284555Sarybchik		*enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED);
1648284555Sarybchik	}
1649284555Sarybchik
1650284555Sarybchik	return (0);
1651284555Sarybchik
1652284555Sarybchikfail1:
1653284555Sarybchik	EFSYS_PROBE1(fail1, int, rc);
1654284555Sarybchik
1655284555Sarybchik	return (rc);
1656284555Sarybchik}
1657284555Sarybchik
1658284555Sarybchik
1659227569Sphilip#endif	/* EFSYS_OPT_MCDI */
1660