1227569Sphilip/*-
2227569Sphilip * Copyright 2009 Solarflare Communications Inc.  All rights reserved.
3227569Sphilip *
4227569Sphilip * Redistribution and use in source and binary forms, with or without
5227569Sphilip * modification, are permitted provided that the following conditions
6227569Sphilip * are met:
7227569Sphilip * 1. Redistributions of source code must retain the above copyright
8227569Sphilip *    notice, this list of conditions and the following disclaimer.
9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
10227569Sphilip *    notice, this list of conditions and the following disclaimer in the
11227569Sphilip *    documentation and/or other materials provided with the distribution.
12227569Sphilip *
13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227569Sphilip * SUCH DAMAGE.
24227569Sphilip */
25228078Sphilip
26228078Sphilip#include <sys/cdefs.h>
27228078Sphilip__FBSDID("$FreeBSD$");
28228078Sphilip
29227569Sphilip#include "efsys.h"
30227569Sphilip#include "efx.h"
31227569Sphilip#include "efx_impl.h"
32227569Sphilip
33227569Sphilip#if EFSYS_OPT_SIENA
34227569Sphilip
35227569Sphilipstatic			void
36227569Sphilipsiena_phy_decode_cap(
37227569Sphilip	__in		uint32_t mcdi_cap,
38227569Sphilip	__out		uint32_t *maskp)
39227569Sphilip{
40227569Sphilip	uint32_t mask;
41227569Sphilip
42227569Sphilip	mask = 0;
43227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
44227569Sphilip		mask |= (1 << EFX_PHY_CAP_10HDX);
45227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
46227569Sphilip		mask |= (1 << EFX_PHY_CAP_10FDX);
47227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
48227569Sphilip		mask |= (1 << EFX_PHY_CAP_100HDX);
49227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
50227569Sphilip		mask |= (1 << EFX_PHY_CAP_100FDX);
51227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
52227569Sphilip		mask |= (1 << EFX_PHY_CAP_1000HDX);
53227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
54227569Sphilip		mask |= (1 << EFX_PHY_CAP_1000FDX);
55227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
56227569Sphilip		mask |= (1 << EFX_PHY_CAP_10000FDX);
57227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
58227569Sphilip		mask |= (1 << EFX_PHY_CAP_PAUSE);
59227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
60227569Sphilip		mask |= (1 << EFX_PHY_CAP_ASYM);
61227569Sphilip	if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
62227569Sphilip		mask |= (1 << EFX_PHY_CAP_AN);
63227569Sphilip
64227569Sphilip	*maskp = mask;
65227569Sphilip}
66227569Sphilip
67227569Sphilipstatic			void
68227569Sphilipsiena_phy_decode_link_mode(
69227569Sphilip	__in		efx_nic_t *enp,
70227569Sphilip	__in		uint32_t link_flags,
71227569Sphilip	__in		unsigned int speed,
72227569Sphilip	__in		unsigned int fcntl,
73227569Sphilip	__out		efx_link_mode_t *link_modep,
74227569Sphilip	__out		unsigned int *fcntlp)
75227569Sphilip{
76227569Sphilip	boolean_t fd = !!(link_flags &
77227569Sphilip		    (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
78227569Sphilip	boolean_t up = !!(link_flags &
79227569Sphilip		    (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
80227569Sphilip
81227569Sphilip	_NOTE(ARGUNUSED(enp))
82227569Sphilip
83227569Sphilip	if (!up)
84227569Sphilip		*link_modep = EFX_LINK_DOWN;
85227569Sphilip	else if (speed == 10000 && fd)
86227569Sphilip		*link_modep = EFX_LINK_10000FDX;
87227569Sphilip	else if (speed == 1000)
88227569Sphilip		*link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
89227569Sphilip	else if (speed == 100)
90227569Sphilip		*link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
91227569Sphilip	else if (speed == 10)
92227569Sphilip		*link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
93227569Sphilip	else
94227569Sphilip		*link_modep = EFX_LINK_UNKNOWN;
95227569Sphilip
96227569Sphilip	if (fcntl == MC_CMD_FCNTL_OFF)
97227569Sphilip		*fcntlp = 0;
98227569Sphilip	else if (fcntl == MC_CMD_FCNTL_RESPOND)
99227569Sphilip		*fcntlp = EFX_FCNTL_RESPOND;
100227569Sphilip	else if (fcntl == MC_CMD_FCNTL_BIDIR)
101227569Sphilip		*fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
102227569Sphilip	else {
103227569Sphilip		EFSYS_PROBE1(mc_pcol_error, int, fcntl);
104227569Sphilip		*fcntlp = 0;
105227569Sphilip	}
106227569Sphilip}
107227569Sphilip
108227569Sphilip			void
109227569Sphilipsiena_phy_link_ev(
110227569Sphilip	__in		efx_nic_t *enp,
111227569Sphilip	__in		efx_qword_t *eqp,
112227569Sphilip	__out		efx_link_mode_t *link_modep)
113227569Sphilip{
114227569Sphilip	efx_port_t *epp = &(enp->en_port);
115227569Sphilip	unsigned int link_flags;
116227569Sphilip	unsigned int speed;
117227569Sphilip	unsigned int fcntl;
118227569Sphilip	efx_link_mode_t link_mode;
119227569Sphilip	uint32_t lp_cap_mask;
120227569Sphilip
121227569Sphilip	/*
122227569Sphilip	 * Convert the LINKCHANGE speed enumeration into mbit/s, in the
123227569Sphilip	 * same way as GET_LINK encodes the speed
124227569Sphilip	 */
125227569Sphilip	switch (MCDI_EV_FIELD(*eqp, LINKCHANGE_SPEED)) {
126227569Sphilip	case MCDI_EVENT_LINKCHANGE_SPEED_100M:
127227569Sphilip		speed = 100;
128227569Sphilip		break;
129227569Sphilip	case MCDI_EVENT_LINKCHANGE_SPEED_1G:
130227569Sphilip		speed = 1000;
131227569Sphilip		break;
132227569Sphilip	case MCDI_EVENT_LINKCHANGE_SPEED_10G:
133227569Sphilip		speed = 10000;
134227569Sphilip		break;
135227569Sphilip	default:
136227569Sphilip		speed = 0;
137227569Sphilip		break;
138227569Sphilip	}
139227569Sphilip
140227569Sphilip	link_flags = MCDI_EV_FIELD(*eqp, LINKCHANGE_LINK_FLAGS);
141227569Sphilip	siena_phy_decode_link_mode(enp, link_flags, speed,
142227569Sphilip				    MCDI_EV_FIELD(*eqp, LINKCHANGE_FCNTL),
143227569Sphilip				    &link_mode, &fcntl);
144227569Sphilip	siena_phy_decode_cap(MCDI_EV_FIELD(*eqp, LINKCHANGE_LP_CAP),
145227569Sphilip			    &lp_cap_mask);
146227569Sphilip
147227569Sphilip	/*
148227569Sphilip	 * It's safe to update ep_lp_cap_mask without the driver's port lock
149227569Sphilip	 * because presumably any concurrently running efx_port_poll() is
150227569Sphilip	 * only going to arrive at the same value.
151227569Sphilip	 *
152227569Sphilip	 * ep_fcntl has two meanings. It's either the link common fcntl
153227569Sphilip	 * (if the PHY supports AN), or it's the forced link state. If
154227569Sphilip	 * the former, it's safe to update the value for the same reason as
155227569Sphilip	 * for ep_lp_cap_mask. If the latter, then just ignore the value,
156227569Sphilip	 * because we can race with efx_mac_fcntl_set().
157227569Sphilip	 */
158227569Sphilip	epp->ep_lp_cap_mask = lp_cap_mask;
159227569Sphilip	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
160227569Sphilip		epp->ep_fcntl = fcntl;
161227569Sphilip
162227569Sphilip	*link_modep = link_mode;
163227569Sphilip}
164227569Sphilip
165227569Sphilip	__checkReturn	int
166227569Sphilipsiena_phy_power(
167227569Sphilip	__in		efx_nic_t *enp,
168227569Sphilip	__in		boolean_t power)
169227569Sphilip{
170227569Sphilip	int rc;
171227569Sphilip
172227569Sphilip	if (!power)
173227569Sphilip		return (0);
174227569Sphilip
175227569Sphilip	/* Check if the PHY is a zombie */
176227569Sphilip	if ((rc = siena_phy_verify(enp)) != 0)
177227569Sphilip		goto fail1;
178227569Sphilip
179227569Sphilip	enp->en_reset_flags |= EFX_RESET_PHY;
180227569Sphilip
181227569Sphilip	return (0);
182227569Sphilip
183227569Sphilipfail1:
184227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
185227569Sphilip
186227569Sphilip	return (rc);
187227569Sphilip}
188227569Sphilip
189227569Sphilip	__checkReturn	int
190227569Sphilipsiena_phy_get_link(
191227569Sphilip	__in		efx_nic_t *enp,
192227569Sphilip	__out		siena_link_state_t *slsp)
193227569Sphilip{
194227569Sphilip	efx_mcdi_req_t req;
195227569Sphilip	uint8_t outbuf[MC_CMD_GET_LINK_OUT_LEN];
196227569Sphilip	int rc;
197227569Sphilip
198227569Sphilip	req.emr_cmd = MC_CMD_GET_LINK;
199227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_GET_LINK_IN_LEN == 0);
200227569Sphilip	req.emr_in_buf = NULL;
201227569Sphilip	req.emr_in_length = 0;
202227569Sphilip	req.emr_out_buf = outbuf;
203227569Sphilip	req.emr_out_length = sizeof (outbuf);
204227569Sphilip
205227569Sphilip	efx_mcdi_execute(enp, &req);
206227569Sphilip
207227569Sphilip	if (req.emr_rc != 0) {
208227569Sphilip		rc = req.emr_rc;
209227569Sphilip		goto fail1;
210227569Sphilip	}
211227569Sphilip
212227569Sphilip	if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
213227569Sphilip		rc = EMSGSIZE;
214227569Sphilip		goto fail2;
215227569Sphilip	}
216227569Sphilip
217227569Sphilip	siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
218227569Sphilip			    &slsp->sls_adv_cap_mask);
219227569Sphilip	siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
220227569Sphilip			    &slsp->sls_lp_cap_mask);
221227569Sphilip
222227569Sphilip	siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
223227569Sphilip			    MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
224227569Sphilip			    MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
225227569Sphilip			    &slsp->sls_link_mode, &slsp->sls_fcntl);
226227569Sphilip
227227569Sphilip#if EFSYS_OPT_LOOPBACK
228227569Sphilip	/* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
229227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
230227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
231227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
232227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
233227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
234227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
235227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
236227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
237227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
238227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
239227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
240227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
241227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
242227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
243227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
244227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
245227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
246227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
247227569Sphilip
248227569Sphilip	slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
249227569Sphilip#endif	/* EFSYS_OPT_LOOPBACK */
250227569Sphilip
251227569Sphilip	slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
252227569Sphilip
253227569Sphilip	return (0);
254227569Sphilip
255227569Sphilipfail2:
256227569Sphilip	EFSYS_PROBE(fail2);
257227569Sphilipfail1:
258227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
259227569Sphilip
260227569Sphilip	return (rc);
261227569Sphilip}
262227569Sphilip
263227569Sphilip	__checkReturn	int
264227569Sphilipsiena_phy_reconfigure(
265227569Sphilip	__in		efx_nic_t *enp)
266227569Sphilip{
267227569Sphilip	efx_port_t *epp = &(enp->en_port);
268227569Sphilip	efx_mcdi_req_t req;
269227569Sphilip	uint8_t payload[MAX(MC_CMD_SET_ID_LED_IN_LEN,
270227569Sphilip			    MC_CMD_SET_LINK_IN_LEN)];
271227569Sphilip	uint32_t cap_mask;
272227569Sphilip	unsigned int led_mode;
273227569Sphilip	unsigned int speed;
274227569Sphilip	int rc;
275227569Sphilip
276227569Sphilip	req.emr_cmd = MC_CMD_SET_LINK;
277227569Sphilip	req.emr_in_buf = payload;
278227569Sphilip	req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
279227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_SET_LINK_OUT_LEN == 0);
280227569Sphilip	req.emr_out_buf = NULL;
281227569Sphilip	req.emr_out_length = 0;
282227569Sphilip
283227569Sphilip	cap_mask = epp->ep_adv_cap_mask;
284227569Sphilip	MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
285227569Sphilip		PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
286227569Sphilip		PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
287227569Sphilip		PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
288227569Sphilip		PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
289227569Sphilip		PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
290227569Sphilip		PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
291227569Sphilip		PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
292227569Sphilip		PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
293227569Sphilip		PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
294227569Sphilip		PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
295227569Sphilip
296227569Sphilip#if EFSYS_OPT_LOOPBACK
297227569Sphilip	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
298227569Sphilip		    epp->ep_loopback_type);
299227569Sphilip	switch (epp->ep_loopback_link_mode) {
300227569Sphilip	case EFX_LINK_100FDX:
301227569Sphilip		speed = 100;
302227569Sphilip		break;
303227569Sphilip	case EFX_LINK_1000FDX:
304227569Sphilip		speed = 1000;
305227569Sphilip		break;
306227569Sphilip	case EFX_LINK_10000FDX:
307227569Sphilip		speed = 10000;
308227569Sphilip		break;
309227569Sphilip	default:
310227569Sphilip		speed = 0;
311227569Sphilip	}
312227569Sphilip#else
313227569Sphilip	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
314227569Sphilip	speed = 0;
315227569Sphilip#endif	/* EFSYS_OPT_LOOPBACK */
316227569Sphilip	MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
317227569Sphilip
318227569Sphilip#if EFSYS_OPT_PHY_FLAGS
319227569Sphilip	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
320227569Sphilip#else
321227569Sphilip	MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
322227569Sphilip#endif	/* EFSYS_OPT_PHY_FLAGS */
323227569Sphilip
324227569Sphilip	efx_mcdi_execute(enp, &req);
325227569Sphilip
326227569Sphilip	if (req.emr_rc != 0) {
327227569Sphilip		rc = req.emr_rc;
328227569Sphilip		goto fail1;
329227569Sphilip	}
330227569Sphilip
331227569Sphilip	/* And set the blink mode */
332227569Sphilip	req.emr_cmd = MC_CMD_SET_ID_LED;
333227569Sphilip	req.emr_in_buf = payload;
334227569Sphilip	req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
335227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_SET_ID_LED_OUT_LEN == 0);
336227569Sphilip	req.emr_out_buf = NULL;
337227569Sphilip	req.emr_out_length = 0;
338227569Sphilip
339227569Sphilip#if EFSYS_OPT_PHY_LED_CONTROL
340227569Sphilip	switch (epp->ep_phy_led_mode) {
341227569Sphilip	case EFX_PHY_LED_DEFAULT:
342227569Sphilip		led_mode = MC_CMD_LED_DEFAULT;
343227569Sphilip		break;
344227569Sphilip	case EFX_PHY_LED_OFF:
345227569Sphilip		led_mode = MC_CMD_LED_OFF;
346227569Sphilip		break;
347227569Sphilip	case EFX_PHY_LED_ON:
348227569Sphilip		led_mode = MC_CMD_LED_ON;
349227569Sphilip		break;
350227569Sphilip	default:
351227569Sphilip		EFSYS_ASSERT(0);
352227569Sphilip		led_mode = MC_CMD_LED_DEFAULT;
353227569Sphilip	}
354227569Sphilip
355227569Sphilip	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
356227569Sphilip#else
357227569Sphilip	MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
358227569Sphilip#endif	/* EFSYS_OPT_PHY_LED_CONTROL */
359227569Sphilip
360227569Sphilip	efx_mcdi_execute(enp, &req);
361227569Sphilip
362227569Sphilip	if (req.emr_rc != 0) {
363227569Sphilip		rc = req.emr_rc;
364227569Sphilip		goto fail2;
365227569Sphilip	}
366227569Sphilip
367227569Sphilip	return (0);
368227569Sphilip
369227569Sphilipfail2:
370227569Sphilip	EFSYS_PROBE(fail2);
371227569Sphilipfail1:
372227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
373227569Sphilip
374227569Sphilip	return (rc);
375227569Sphilip}
376227569Sphilip
377227569Sphilip	__checkReturn	int
378227569Sphilipsiena_phy_verify(
379227569Sphilip	__in		efx_nic_t *enp)
380227569Sphilip{
381227569Sphilip	efx_mcdi_req_t req;
382227569Sphilip	uint8_t outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN];
383227569Sphilip	uint32_t state;
384227569Sphilip	int rc;
385227569Sphilip
386227569Sphilip	req.emr_cmd = MC_CMD_GET_PHY_STATE;
387227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_GET_PHY_STATE_IN_LEN == 0);
388227569Sphilip	req.emr_in_buf = NULL;
389227569Sphilip	req.emr_in_length = 0;
390227569Sphilip	req.emr_out_buf = outbuf;
391227569Sphilip	req.emr_out_length = sizeof (outbuf);
392227569Sphilip
393227569Sphilip	efx_mcdi_execute(enp, &req);
394227569Sphilip
395227569Sphilip	if (req.emr_rc != 0) {
396227569Sphilip		rc = req.emr_rc;
397227569Sphilip		goto fail1;
398227569Sphilip	}
399227569Sphilip
400227569Sphilip	if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
401227569Sphilip		rc = EMSGSIZE;
402227569Sphilip		goto fail2;
403227569Sphilip	}
404227569Sphilip
405227569Sphilip	state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
406227569Sphilip	if (state != MC_CMD_PHY_STATE_OK) {
407227569Sphilip		if (state != MC_CMD_PHY_STATE_ZOMBIE)
408227569Sphilip			EFSYS_PROBE1(mc_pcol_error, int, state);
409227569Sphilip		rc = ENOTACTIVE;
410227569Sphilip		goto fail3;
411227569Sphilip	}
412227569Sphilip
413227569Sphilip	return (0);
414227569Sphilip
415227569Sphilipfail3:
416227569Sphilip	EFSYS_PROBE(fail3);
417227569Sphilipfail2:
418227569Sphilip	EFSYS_PROBE(fail2);
419227569Sphilipfail1:
420227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
421227569Sphilip
422227569Sphilip	return (rc);
423227569Sphilip}
424227569Sphilip
425227569Sphilip	__checkReturn	int
426227569Sphilipsiena_phy_oui_get(
427227569Sphilip	__in		efx_nic_t *enp,
428227569Sphilip	__out		uint32_t *ouip)
429227569Sphilip{
430227569Sphilip	_NOTE(ARGUNUSED(enp, ouip))
431227569Sphilip
432227569Sphilip	return (ENOTSUP);
433227569Sphilip}
434227569Sphilip
435227569Sphilip#if EFSYS_OPT_PHY_STATS
436227569Sphilip
437227569Sphilip#define	SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,		\
438227569Sphilip			    _mc_record, _efx_record)			\
439227569Sphilip	if ((_vmask) & (1ULL << (_mc_record))) {			\
440227569Sphilip		(_smask) |= (1ULL << (_efx_record));			\
441227569Sphilip		if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) {	\
442227569Sphilip			efx_dword_t dword;				\
443227569Sphilip			EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\
444227569Sphilip			(_stat)[_efx_record] =				\
445227569Sphilip				EFX_DWORD_FIELD(dword, EFX_DWORD_0);	\
446227569Sphilip		}							\
447227569Sphilip	}
448227569Sphilip
449227569Sphilip#define	SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record)	\
450227569Sphilip	SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, 		\
451227569Sphilip			    MC_CMD_ ## _record,				\
452227569Sphilip			    EFX_PHY_STAT_ ## _record)
453227569Sphilip
454227569Sphilip						void
455227569Sphilipsiena_phy_decode_stats(
456227569Sphilip	__in					efx_nic_t *enp,
457227569Sphilip	__in					uint32_t vmask,
458227569Sphilip	__in_opt				efsys_mem_t *esmp,
459227569Sphilip	__out_opt				uint64_t *smaskp,
460227569Sphilip	__out_ecount_opt(EFX_PHY_NSTATS)	uint32_t *stat)
461227569Sphilip{
462227569Sphilip	uint64_t smask = 0;
463227569Sphilip
464227569Sphilip	_NOTE(ARGUNUSED(enp))
465227569Sphilip
466227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI);
467227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP);
468227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT);
469227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT);
470227569Sphilip
471227569Sphilip	if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) {
472227569Sphilip		smask |=   ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) |
473227569Sphilip			    (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) |
474227569Sphilip			    (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) |
475227569Sphilip			    (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D));
476227569Sphilip		if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
477227569Sphilip			efx_dword_t dword;
478227569Sphilip			uint32_t sig;
479227569Sphilip			EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL,
480227569Sphilip					&dword);
481227569Sphilip			sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
482227569Sphilip			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1;
483227569Sphilip			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1;
484227569Sphilip			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1;
485227569Sphilip			stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1;
486227569Sphilip		}
487227569Sphilip	}
488227569Sphilip
489227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A,
490227569Sphilip			    EFX_PHY_STAT_SNR_A);
491227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B,
492227569Sphilip			    EFX_PHY_STAT_SNR_B);
493227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C,
494227569Sphilip			    EFX_PHY_STAT_SNR_C);
495227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D,
496227569Sphilip			    EFX_PHY_STAT_SNR_D);
497227569Sphilip
498227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP);
499227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT);
500227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT);
501227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER);
502227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS);
503227569Sphilip
504227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP,
505227569Sphilip			    EFX_PHY_STAT_PHY_XS_LINK_UP);
506227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT,
507227569Sphilip			    EFX_PHY_STAT_PHY_XS_RX_FAULT);
508227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT,
509227569Sphilip			    EFX_PHY_STAT_PHY_XS_TX_FAULT);
510227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN,
511227569Sphilip			    EFX_PHY_STAT_PHY_XS_ALIGN);
512227569Sphilip
513227569Sphilip	if (vmask & (1 << MC_CMD_PHYXS_SYNC)) {
514227569Sphilip		smask |=   ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) |
515227569Sphilip			    (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) |
516227569Sphilip			    (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) |
517227569Sphilip			    (1 << EFX_PHY_STAT_PHY_XS_SYNC_D));
518227569Sphilip		if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
519227569Sphilip			efx_dword_t dword;
520227569Sphilip			uint32_t sync;
521227569Sphilip			EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword);
522227569Sphilip			sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
523227569Sphilip			stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1;
524227569Sphilip			stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1;
525227569Sphilip			stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1;
526227569Sphilip			stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1;
527227569Sphilip		}
528227569Sphilip	}
529227569Sphilip
530227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP);
531227569Sphilip	SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE);
532227569Sphilip
533227569Sphilip	SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP,
534227569Sphilip			    EFX_PHY_STAT_CL22EXT_LINK_UP);
535227569Sphilip
536227569Sphilip	if (smaskp != NULL)
537227569Sphilip		*smaskp = smask;
538227569Sphilip}
539227569Sphilip
540227569Sphilip	__checkReturn				int
541227569Sphilipsiena_phy_stats_update(
542227569Sphilip	__in					efx_nic_t *enp,
543227569Sphilip	__in					efsys_mem_t *esmp,
544227569Sphilip	__out_ecount(EFX_PHY_NSTATS)		uint32_t *stat)
545227569Sphilip{
546227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
547227569Sphilip	uint32_t vmask = encp->enc_siena_phy_stat_mask;
548227569Sphilip	uint8_t payload[MC_CMD_PHY_STATS_IN_LEN];
549227569Sphilip	uint64_t smask;
550227569Sphilip	efx_mcdi_req_t req;
551227569Sphilip	int rc;
552227569Sphilip
553227569Sphilip	req.emr_cmd = MC_CMD_PHY_STATS;
554227569Sphilip	req.emr_in_buf = payload;
555227569Sphilip	req.emr_in_length = sizeof (payload);
556227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_PHY_STATS_OUT_DMA_LEN == 0);
557227569Sphilip	req.emr_out_buf = NULL;
558227569Sphilip	req.emr_out_length = 0;
559227569Sphilip
560227569Sphilip	MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
561227569Sphilip			    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
562227569Sphilip	MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI,
563227569Sphilip			    EFSYS_MEM_ADDR(esmp) >> 32);
564227569Sphilip
565227569Sphilip	efx_mcdi_execute(enp, &req);
566227569Sphilip
567227569Sphilip	if (req.emr_rc != 0) {
568227569Sphilip		rc = req.emr_rc;
569227569Sphilip		goto fail1;
570227569Sphilip	}
571227569Sphilip	EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN);
572227569Sphilip
573227569Sphilip	siena_phy_decode_stats(enp, vmask, esmp, &smask, stat);
574227569Sphilip	EFSYS_ASSERT(smask == encp->enc_phy_stat_mask);
575227569Sphilip
576227569Sphilip	return (0);
577227569Sphilip
578227569Sphilipfail1:
579227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
580227569Sphilip
581227569Sphilip	return (0);
582227569Sphilip}
583227569Sphilip
584227569Sphilip#endif	/* EFSYS_OPT_PHY_STATS */
585227569Sphilip
586227569Sphilip#if EFSYS_OPT_PHY_PROPS
587227569Sphilip
588227569Sphilip#if EFSYS_OPT_NAMES
589227569Sphilip
590227569Sphilipextern		const char __cs *
591227569Sphilipsiena_phy_prop_name(
592227569Sphilip	__in	efx_nic_t *enp,
593227569Sphilip	__in	unsigned int id)
594227569Sphilip{
595227569Sphilip	_NOTE(ARGUNUSED(enp, id))
596227569Sphilip
597227569Sphilip	return (NULL);
598227569Sphilip}
599227569Sphilip
600227569Sphilip#endif	/* EFSYS_OPT_NAMES */
601227569Sphilip
602227569Sphilipextern	__checkReturn	int
603227569Sphilipsiena_phy_prop_get(
604227569Sphilip	__in		efx_nic_t *enp,
605227569Sphilip	__in		unsigned int id,
606227569Sphilip	__in		uint32_t flags,
607227569Sphilip	__out		uint32_t *valp)
608227569Sphilip{
609227569Sphilip	_NOTE(ARGUNUSED(enp, id, flags, valp))
610227569Sphilip
611227569Sphilip	return (ENOTSUP);
612227569Sphilip}
613227569Sphilip
614227569Sphilipextern	__checkReturn	int
615227569Sphilipsiena_phy_prop_set(
616227569Sphilip	__in		efx_nic_t *enp,
617227569Sphilip	__in		unsigned int id,
618227569Sphilip	__in		uint32_t val)
619227569Sphilip{
620227569Sphilip	_NOTE(ARGUNUSED(enp, id, val))
621227569Sphilip
622227569Sphilip	return (ENOTSUP);
623227569Sphilip}
624227569Sphilip
625227569Sphilip#endif	/* EFSYS_OPT_PHY_PROPS */
626227569Sphilip
627227569Sphilip#if EFSYS_OPT_PHY_BIST
628227569Sphilip
629227569Sphilip	__checkReturn		int
630227569Sphilipsiena_phy_bist_start(
631227569Sphilip	__in			efx_nic_t *enp,
632227569Sphilip	__in			efx_phy_bist_type_t type)
633227569Sphilip{
634227569Sphilip	uint8_t payload[MC_CMD_START_BIST_IN_LEN];
635227569Sphilip	efx_mcdi_req_t req;
636227569Sphilip	int rc;
637227569Sphilip
638227569Sphilip	req.emr_cmd = MC_CMD_START_BIST;
639227569Sphilip	req.emr_in_buf = payload;
640227569Sphilip	req.emr_in_length = sizeof (payload);
641227569Sphilip	EFX_STATIC_ASSERT(MC_CMD_START_BIST_OUT_LEN == 0);
642227569Sphilip	req.emr_out_buf = NULL;
643227569Sphilip	req.emr_out_length = 0;
644227569Sphilip
645227569Sphilip	switch (type) {
646227569Sphilip	case EFX_PHY_BIST_TYPE_NORMAL:
647227569Sphilip		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST);
648227569Sphilip		break;
649227569Sphilip	case EFX_PHY_BIST_TYPE_CABLE_SHORT:
650227569Sphilip		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
651227569Sphilip		    MC_CMD_PHY_BIST_CABLE_SHORT);
652227569Sphilip		break;
653227569Sphilip	case EFX_PHY_BIST_TYPE_CABLE_LONG:
654227569Sphilip		MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE,
655227569Sphilip		    MC_CMD_PHY_BIST_CABLE_LONG);
656227569Sphilip		break;
657227569Sphilip	default:
658227569Sphilip		EFSYS_ASSERT(0);
659227569Sphilip	}
660227569Sphilip
661227569Sphilip	efx_mcdi_execute(enp, &req);
662227569Sphilip
663227569Sphilip	if (req.emr_rc != 0) {
664227569Sphilip		rc = req.emr_rc;
665227569Sphilip		goto fail1;
666227569Sphilip	}
667227569Sphilip
668227569Sphilip	return (0);
669227569Sphilip
670227569Sphilipfail1:
671227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
672227569Sphilip
673227569Sphilip	return (rc);
674227569Sphilip}
675227569Sphilip
676227569Sphilipstatic	__checkReturn		unsigned long
677227569Sphilipsiena_phy_sft9001_bist_status(
678227569Sphilip	__in			uint16_t code)
679227569Sphilip{
680227569Sphilip	switch (code) {
681227569Sphilip	case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
682227569Sphilip		return (EFX_PHY_CABLE_STATUS_BUSY);
683227569Sphilip	case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
684227569Sphilip		return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
685227569Sphilip	case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
686227569Sphilip		return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
687227569Sphilip	case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
688227569Sphilip		return (EFX_PHY_CABLE_STATUS_OPEN);
689227569Sphilip	case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
690227569Sphilip		return (EFX_PHY_CABLE_STATUS_OK);
691227569Sphilip	default:
692227569Sphilip		return (EFX_PHY_CABLE_STATUS_INVALID);
693227569Sphilip	}
694227569Sphilip}
695227569Sphilip
696227569Sphilip	__checkReturn		int
697227569Sphilipsiena_phy_bist_poll(
698227569Sphilip	__in			efx_nic_t *enp,
699227569Sphilip	__in			efx_phy_bist_type_t type,
700227569Sphilip	__out			efx_phy_bist_result_t *resultp,
701227569Sphilip	__out_opt __drv_when(count > 0, __notnull)
702227569Sphilip	uint32_t *value_maskp,
703227569Sphilip	__out_ecount_opt(count)	__drv_when(count > 0, __notnull)
704227569Sphilip	unsigned long *valuesp,
705227569Sphilip	__in			size_t count)
706227569Sphilip{
707227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
708227569Sphilip	uint8_t payload[MCDI_CTL_SDU_LEN_MAX];
709227569Sphilip	uint32_t value_mask = 0;
710227569Sphilip	efx_mcdi_req_t req;
711227569Sphilip	uint32_t result;
712227569Sphilip	int rc;
713227569Sphilip
714227569Sphilip	req.emr_cmd = MC_CMD_POLL_BIST;
715227569Sphilip	_NOTE(CONSTANTCONDITION)
716227569Sphilip	EFSYS_ASSERT(MC_CMD_POLL_BIST_IN_LEN == 0);
717227569Sphilip	req.emr_in_buf = NULL;
718227569Sphilip	req.emr_in_length = 0;
719227569Sphilip	req.emr_out_buf = payload;
720227569Sphilip	req.emr_out_length = sizeof (payload);
721227569Sphilip
722227569Sphilip	efx_mcdi_execute(enp, &req);
723227569Sphilip
724227569Sphilip	if (req.emr_rc != 0) {
725227569Sphilip		rc = req.emr_rc;
726227569Sphilip		goto fail1;
727227569Sphilip	}
728227569Sphilip
729227569Sphilip	if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
730227569Sphilip		rc = EMSGSIZE;
731227569Sphilip		goto fail2;
732227569Sphilip	}
733227569Sphilip
734227569Sphilip	if (count > 0)
735227569Sphilip		(void) memset(valuesp, '\0', count * sizeof (unsigned long));
736227569Sphilip
737227569Sphilip	result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
738227569Sphilip
739227569Sphilip	/* Extract PHY specific results */
740227569Sphilip	if (result == MC_CMD_POLL_BIST_PASSED &&
741227569Sphilip	    encp->enc_phy_type == EFX_PHY_SFT9001B &&
742227569Sphilip	    req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
743227569Sphilip	    (type == EFX_PHY_BIST_TYPE_CABLE_SHORT ||
744227569Sphilip	    type == EFX_PHY_BIST_TYPE_CABLE_LONG)) {
745227569Sphilip		uint16_t word;
746227569Sphilip
747227569Sphilip		if (count > EFX_PHY_BIST_CABLE_LENGTH_A) {
748227569Sphilip			if (valuesp != NULL)
749227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_LENGTH_A] =
750227569Sphilip				    MCDI_OUT_DWORD(req,
751227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
752227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_A);
753227569Sphilip		}
754227569Sphilip
755227569Sphilip		if (count > EFX_PHY_BIST_CABLE_LENGTH_B) {
756227569Sphilip			if (valuesp != NULL)
757227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_LENGTH_B] =
758227569Sphilip				    MCDI_OUT_DWORD(req,
759227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
760227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_B);
761227569Sphilip		}
762227569Sphilip
763227569Sphilip		if (count > EFX_PHY_BIST_CABLE_LENGTH_C) {
764227569Sphilip			if (valuesp != NULL)
765227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_LENGTH_C] =
766227569Sphilip				    MCDI_OUT_DWORD(req,
767227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
768227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_C);
769227569Sphilip		}
770227569Sphilip
771227569Sphilip		if (count > EFX_PHY_BIST_CABLE_LENGTH_D) {
772227569Sphilip			if (valuesp != NULL)
773227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_LENGTH_D] =
774227569Sphilip				    MCDI_OUT_DWORD(req,
775227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
776227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_D);
777227569Sphilip		}
778227569Sphilip
779227569Sphilip		if (count > EFX_PHY_BIST_CABLE_STATUS_A) {
780227569Sphilip			if (valuesp != NULL) {
781227569Sphilip				word = MCDI_OUT_WORD(req,
782227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
783227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_STATUS_A] =
784227569Sphilip				    siena_phy_sft9001_bist_status(word);
785227569Sphilip			}
786227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_A);
787227569Sphilip		}
788227569Sphilip
789227569Sphilip		if (count > EFX_PHY_BIST_CABLE_STATUS_B) {
790227569Sphilip			if (valuesp != NULL) {
791227569Sphilip				word = MCDI_OUT_WORD(req,
792227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
793227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_STATUS_B] =
794227569Sphilip				    siena_phy_sft9001_bist_status(word);
795227569Sphilip			}
796227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_B);
797227569Sphilip		}
798227569Sphilip
799227569Sphilip		if (count > EFX_PHY_BIST_CABLE_STATUS_C) {
800227569Sphilip			if (valuesp != NULL) {
801227569Sphilip				word = MCDI_OUT_WORD(req,
802227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
803227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_STATUS_C] =
804227569Sphilip				    siena_phy_sft9001_bist_status(word);
805227569Sphilip			}
806227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_C);
807227569Sphilip		}
808227569Sphilip
809227569Sphilip		if (count > EFX_PHY_BIST_CABLE_STATUS_D) {
810227569Sphilip			if (valuesp != NULL) {
811227569Sphilip				word = MCDI_OUT_WORD(req,
812227569Sphilip				    POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
813227569Sphilip				valuesp[EFX_PHY_BIST_CABLE_STATUS_D] =
814227569Sphilip				    siena_phy_sft9001_bist_status(word);
815227569Sphilip			}
816227569Sphilip			value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_D);
817227569Sphilip		}
818227569Sphilip
819227569Sphilip	} else if (result == MC_CMD_POLL_BIST_FAILED &&
820227569Sphilip		    encp->enc_phy_type == EFX_PHY_QLX111V &&
821227569Sphilip		    req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
822227569Sphilip		    count > EFX_PHY_BIST_FAULT_CODE) {
823227569Sphilip		if (valuesp != NULL)
824227569Sphilip			valuesp[EFX_PHY_BIST_FAULT_CODE] =
825227569Sphilip			    MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
826227569Sphilip		value_mask |= 1 << EFX_PHY_BIST_FAULT_CODE;
827227569Sphilip	}
828227569Sphilip
829227569Sphilip	if (value_maskp != NULL)
830227569Sphilip		*value_maskp = value_mask;
831227569Sphilip
832227569Sphilip	EFSYS_ASSERT(resultp != NULL);
833227569Sphilip	if (result == MC_CMD_POLL_BIST_RUNNING)
834227569Sphilip		*resultp = EFX_PHY_BIST_RESULT_RUNNING;
835227569Sphilip	else if (result == MC_CMD_POLL_BIST_PASSED)
836227569Sphilip		*resultp = EFX_PHY_BIST_RESULT_PASSED;
837227569Sphilip	else
838227569Sphilip		*resultp = EFX_PHY_BIST_RESULT_FAILED;
839227569Sphilip
840227569Sphilip	return (0);
841227569Sphilip
842227569Sphilipfail2:
843227569Sphilip	EFSYS_PROBE(fail2);
844227569Sphilipfail1:
845227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
846227569Sphilip
847227569Sphilip	return (rc);
848227569Sphilip}
849227569Sphilip
850227569Sphilip			void
851227569Sphilipsiena_phy_bist_stop(
852227569Sphilip	__in		efx_nic_t *enp,
853227569Sphilip	__in		efx_phy_bist_type_t type)
854227569Sphilip{
855227569Sphilip	/* There is no way to stop BIST on Siena */
856227569Sphilip	_NOTE(ARGUNUSED(enp, type))
857227569Sphilip}
858227569Sphilip
859227569Sphilip#endif	/* EFSYS_OPT_PHY_BIST */
860227569Sphilip
861227569Sphilip#endif	/* EFSYS_OPT_SIENA */
862