xref: /onnv-gate/usr/src/uts/common/io/bge/bge_ndd.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "sys/bge_impl.h"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #define	BGE_DBG		BGE_DBG_NDD	/* debug flag for this code	*/
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate /*
35*0Sstevel@tonic-gate  * Property names
36*0Sstevel@tonic-gate  */
37*0Sstevel@tonic-gate static char transfer_speed_propname[] = "transfer-speed";
38*0Sstevel@tonic-gate static char speed_propname[] = "speed";
39*0Sstevel@tonic-gate static char duplex_propname[] = "full-duplex";
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * Notes:
43*0Sstevel@tonic-gate  *	The first character of the <name> field encodes the read/write
44*0Sstevel@tonic-gate  *	status of the parameter:
45*0Sstevel@tonic-gate  *		'=' => read-only,
46*0Sstevel@tonic-gate  *		'-' => read-only and forced to 0 on serdes
47*0Sstevel@tonic-gate  *		'+' => read/write,
48*0Sstevel@tonic-gate  *		'?' => read/write on copper, read-only and 0 on serdes
49*0Sstevel@tonic-gate  *		'!' => invisible!
50*0Sstevel@tonic-gate  *
51*0Sstevel@tonic-gate  *	For writable parameters, we check for a driver property with the
52*0Sstevel@tonic-gate  *	same name; if found, and its value is in range, we initialise
53*0Sstevel@tonic-gate  *	the parameter from the property, overriding the default in the
54*0Sstevel@tonic-gate  *	table below.
55*0Sstevel@tonic-gate  *
56*0Sstevel@tonic-gate  *	A NULL in the <name> field terminates the array.
57*0Sstevel@tonic-gate  *
58*0Sstevel@tonic-gate  *	The <info> field is used here to provide the index of the
59*0Sstevel@tonic-gate  *	parameter to be initialised; thus it doesn't matter whether
60*0Sstevel@tonic-gate  *	this table is kept ordered or not.
61*0Sstevel@tonic-gate  *
62*0Sstevel@tonic-gate  *	The <info> field in the per-instance copy, on the other hand,
63*0Sstevel@tonic-gate  *	is used to count assignments so that we can tell when a magic
64*0Sstevel@tonic-gate  *	parameter has been set via ndd (see bge_param_set()).
65*0Sstevel@tonic-gate  */
66*0Sstevel@tonic-gate static const nd_param_t nd_template[] = {
67*0Sstevel@tonic-gate /*	info		min	max	init	r/w+name		*/
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate /* Our hardware capabilities */
70*0Sstevel@tonic-gate { PARAM_AUTONEG_CAP,	    0,	  1,	1,	"=autoneg_cap"		},
71*0Sstevel@tonic-gate { PARAM_PAUSE_CAP,	    0,	  1,	1,	"=pause_cap"		},
72*0Sstevel@tonic-gate { PARAM_ASYM_PAUSE_CAP,	    0,	  1,	1,	"=asym_pause_cap"	},
73*0Sstevel@tonic-gate { PARAM_1000FDX_CAP,	    0,	  1,	1,	"=1000fdx_cap"		},
74*0Sstevel@tonic-gate { PARAM_1000HDX_CAP,	    0,	  1,	1,	"=1000hdx_cap"		},
75*0Sstevel@tonic-gate { PARAM_100T4_CAP,	    0,	  1,	0,	"=100T4_cap"		},
76*0Sstevel@tonic-gate { PARAM_100FDX_CAP,	    0,	  1,	1,	"-100fdx_cap"		},
77*0Sstevel@tonic-gate { PARAM_100HDX_CAP,	    0,	  1,	1,	"-100hdx_cap"		},
78*0Sstevel@tonic-gate { PARAM_10FDX_CAP,	    0,	  1,	1,	"-10fdx_cap"		},
79*0Sstevel@tonic-gate { PARAM_10HDX_CAP,	    0,	  1,	1,	"-10hdx_cap"		},
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate /* Our advertised capabilities */
82*0Sstevel@tonic-gate { PARAM_ADV_AUTONEG_CAP,    0,	  1,	1,	"+adv_autoneg_cap"	},
83*0Sstevel@tonic-gate { PARAM_ADV_PAUSE_CAP,	    0,	  1,	1,	"+adv_pause_cap"	},
84*0Sstevel@tonic-gate { PARAM_ADV_ASYM_PAUSE_CAP, 0,	  1,	1,	"+adv_asym_pause_cap"	},
85*0Sstevel@tonic-gate { PARAM_ADV_1000FDX_CAP,    0,	  1,	1,	"+adv_1000fdx_cap"	},
86*0Sstevel@tonic-gate { PARAM_ADV_1000HDX_CAP,    0,	  1,	1,	"+adv_1000hdx_cap"	},
87*0Sstevel@tonic-gate { PARAM_ADV_100T4_CAP,	    0,	  1,	0,	"=adv_100T4_cap"	},
88*0Sstevel@tonic-gate { PARAM_ADV_100FDX_CAP,	    0,	  1,	1,	"?adv_100fdx_cap"	},
89*0Sstevel@tonic-gate { PARAM_ADV_100HDX_CAP,	    0,	  1,	1,	"?adv_100hdx_cap"	},
90*0Sstevel@tonic-gate { PARAM_ADV_10FDX_CAP,	    0,	  1,	1,	"?adv_10fdx_cap"	},
91*0Sstevel@tonic-gate { PARAM_ADV_10HDX_CAP,	    0,	  1,	1,	"?adv_10hdx_cap"	},
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate /* Partner's advertised capabilities */
94*0Sstevel@tonic-gate { PARAM_LP_AUTONEG_CAP,	    0,	  1,	0,	"-lp_autoneg_cap"	},
95*0Sstevel@tonic-gate { PARAM_LP_PAUSE_CAP,	    0,	  1,	0,	"-lp_pause_cap"		},
96*0Sstevel@tonic-gate { PARAM_LP_ASYM_PAUSE_CAP,  0,	  1,	0,	"-lp_asym_pause_cap"	},
97*0Sstevel@tonic-gate { PARAM_LP_1000FDX_CAP,	    0,	  1,	0,	"-lp_1000fdx_cap"	},
98*0Sstevel@tonic-gate { PARAM_LP_1000HDX_CAP,	    0,	  1,	0,	"-lp_1000hdx_cap"	},
99*0Sstevel@tonic-gate { PARAM_LP_100T4_CAP,	    0,	  1,	0,	"-lp_100T4_cap"		},
100*0Sstevel@tonic-gate { PARAM_LP_100FDX_CAP,	    0,	  1,	0,	"-lp_100fdx_cap"	},
101*0Sstevel@tonic-gate { PARAM_LP_100HDX_CAP,	    0,	  1,	0,	"-lp_100hdx_cap"	},
102*0Sstevel@tonic-gate { PARAM_LP_10FDX_CAP,	    0,	  1,	0,	"-lp_10fdx_cap"		},
103*0Sstevel@tonic-gate { PARAM_LP_10HDX_CAP,	    0,	  1,	0,	"-lp_10hdx_cap"		},
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate /* Current operating modes */
106*0Sstevel@tonic-gate { PARAM_LINK_STATUS,	    0,	  1,	0,	"-link_status"		},
107*0Sstevel@tonic-gate { PARAM_LINK_SPEED,	    0,    1000,	0,	"-link_speed"		},
108*0Sstevel@tonic-gate { PARAM_LINK_DUPLEX,	    0,	  2,	0,	"-link_duplex"		},
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate { PARAM_LINK_AUTONEG,	    0,	  1,	0,	"-link_autoneg"		},
111*0Sstevel@tonic-gate { PARAM_LINK_RX_PAUSE,	    0,	  1,	0,	"-link_rx_pause"	},
112*0Sstevel@tonic-gate { PARAM_LINK_TX_PAUSE,	    0,	  1,	0,	"-link_tx_pause"	},
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate /* Loopback status */
115*0Sstevel@tonic-gate { PARAM_LOOP_MODE,	    0,	  5,	0,	"-loop_mode"		},
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate /* MSI count */
118*0Sstevel@tonic-gate { PARAM_MSI_CNT,	    0,	  7,	0,	"+msi_cnt"		},
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate /* Terminator */
121*0Sstevel@tonic-gate { PARAM_COUNT,		    0,	  0,	0,	NULL			}
122*0Sstevel@tonic-gate };
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate /*  ============== NDD Support Functions ===============  */
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate /*
128*0Sstevel@tonic-gate  * Extracts the value from the bge parameter array and prints
129*0Sstevel@tonic-gate  * the parameter value. cp points to the required parameter.
130*0Sstevel@tonic-gate  */
131*0Sstevel@tonic-gate static int
132*0Sstevel@tonic-gate bge_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
133*0Sstevel@tonic-gate {
134*0Sstevel@tonic-gate 	nd_param_t *ndp;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(q, credp))
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	ndp = (nd_param_t *)cp;
139*0Sstevel@tonic-gate 	(void) mi_mpprintf(mp, "%d", ndp->ndp_val);
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	return (0);
142*0Sstevel@tonic-gate }
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate /*
145*0Sstevel@tonic-gate  * Validates the request to set a BGE parameter to a specific value.
146*0Sstevel@tonic-gate  * If the request is OK, the parameter is set.  Also the <info> field
147*0Sstevel@tonic-gate  * is incremented to show that the parameter was touched, even though
148*0Sstevel@tonic-gate  * it may have been set to the same value it already had.
149*0Sstevel@tonic-gate  */
150*0Sstevel@tonic-gate static int
151*0Sstevel@tonic-gate bge_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
152*0Sstevel@tonic-gate {
153*0Sstevel@tonic-gate 	nd_param_t *ndp;
154*0Sstevel@tonic-gate 	long new_value;
155*0Sstevel@tonic-gate 	char *end;
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	_NOTE(ARGUNUSED(q, mp, credp))
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	ndp = (nd_param_t *)cp;
160*0Sstevel@tonic-gate 	new_value = mi_strtol(value, &end, 10);
161*0Sstevel@tonic-gate 	if (end == value)
162*0Sstevel@tonic-gate 		return (EINVAL);
163*0Sstevel@tonic-gate 	if (new_value < ndp->ndp_min || new_value > ndp->ndp_max)
164*0Sstevel@tonic-gate 		return (EINVAL);
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	ndp->ndp_val = new_value;
167*0Sstevel@tonic-gate 	ndp->ndp_info += 1;
168*0Sstevel@tonic-gate 	return (0);
169*0Sstevel@tonic-gate }
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate /*
172*0Sstevel@tonic-gate  * Initialise the per-instance parameter array from the global prototype,
173*0Sstevel@tonic-gate  * and register each element with the named dispatch handler using nd_load()
174*0Sstevel@tonic-gate  */
175*0Sstevel@tonic-gate static int
176*0Sstevel@tonic-gate bge_param_register(bge_t *bgep)
177*0Sstevel@tonic-gate {
178*0Sstevel@tonic-gate 	const nd_param_t *tmplp;
179*0Sstevel@tonic-gate 	dev_info_t *dip;
180*0Sstevel@tonic-gate 	nd_param_t *ndp;
181*0Sstevel@tonic-gate 	caddr_t *nddpp;
182*0Sstevel@tonic-gate 	pfi_t setfn;
183*0Sstevel@tonic-gate 	char *nm;
184*0Sstevel@tonic-gate 	int pval;
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	BGE_TRACE(("bge_param_register($%p)", (void *)bgep));
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 	dip = bgep->devinfo;
189*0Sstevel@tonic-gate 	nddpp = &bgep->nd_data_p;
190*0Sstevel@tonic-gate 	ASSERT(*nddpp == NULL);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	for (tmplp = nd_template; tmplp->ndp_name != NULL; ++tmplp) {
193*0Sstevel@tonic-gate 		/*
194*0Sstevel@tonic-gate 		 * Copy the template from nd_template[] into the
195*0Sstevel@tonic-gate 		 * proper slot in the per-instance parameters,
196*0Sstevel@tonic-gate 		 * then register the parameter with nd_load()
197*0Sstevel@tonic-gate 		 */
198*0Sstevel@tonic-gate 		ndp = &bgep->nd_params[tmplp->ndp_info];
199*0Sstevel@tonic-gate 		*ndp = *tmplp;
200*0Sstevel@tonic-gate 		nm = &ndp->ndp_name[0];
201*0Sstevel@tonic-gate 		setfn = bge_param_set;
202*0Sstevel@tonic-gate 		if (bgep->chipid.flags & CHIP_FLAG_SERDES)
203*0Sstevel@tonic-gate 			switch (*nm) {
204*0Sstevel@tonic-gate 			default:
205*0Sstevel@tonic-gate 				break;
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 			case '-':
208*0Sstevel@tonic-gate 			case '?':
209*0Sstevel@tonic-gate 				ndp->ndp_val = 0;
210*0Sstevel@tonic-gate 				setfn = NULL;
211*0Sstevel@tonic-gate 				break;
212*0Sstevel@tonic-gate 			}
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 		switch (*nm) {
215*0Sstevel@tonic-gate 		default:
216*0Sstevel@tonic-gate 		case '!':
217*0Sstevel@tonic-gate 			continue;
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 		case '+':
220*0Sstevel@tonic-gate 		case '?':
221*0Sstevel@tonic-gate 			break;
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 		case '=':
224*0Sstevel@tonic-gate 		case '-':
225*0Sstevel@tonic-gate 			setfn = NULL;
226*0Sstevel@tonic-gate 			break;
227*0Sstevel@tonic-gate 		}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 		if (!nd_load(nddpp, ++nm, bge_param_get, setfn, (caddr_t)ndp))
230*0Sstevel@tonic-gate 			goto nd_fail;
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 		/*
233*0Sstevel@tonic-gate 		 * If the parameter is writable, and there's a property
234*0Sstevel@tonic-gate 		 * with the same name, and its value is in range, we use
235*0Sstevel@tonic-gate 		 * it to initialise the parameter.  If it exists but is
236*0Sstevel@tonic-gate 		 * out of range, it's ignored.
237*0Sstevel@tonic-gate 		 */
238*0Sstevel@tonic-gate 		if (setfn && BGE_PROP_EXISTS(dip, nm)) {
239*0Sstevel@tonic-gate 			pval = BGE_PROP_GET_INT(dip, nm);
240*0Sstevel@tonic-gate 			if (pval >= ndp->ndp_min && pval <= ndp->ndp_max)
241*0Sstevel@tonic-gate 				ndp->ndp_val = pval;
242*0Sstevel@tonic-gate 		}
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	BGE_DEBUG(("bge_param_register: OK"));
246*0Sstevel@tonic-gate 	return (DDI_SUCCESS);
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate nd_fail:
249*0Sstevel@tonic-gate 	BGE_DEBUG(("bge_param_register: FAILED at index %d [info %d]",
250*0Sstevel@tonic-gate 		tmplp-nd_template, tmplp->ndp_info));
251*0Sstevel@tonic-gate 	nd_free(nddpp);
252*0Sstevel@tonic-gate 	return (DDI_FAILURE);
253*0Sstevel@tonic-gate }
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate int
256*0Sstevel@tonic-gate bge_nd_init(bge_t *bgep)
257*0Sstevel@tonic-gate {
258*0Sstevel@tonic-gate 	dev_info_t *dip;
259*0Sstevel@tonic-gate 	int duplex;
260*0Sstevel@tonic-gate 	int speed;
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	BGE_TRACE(("bge_nd_init($%p)", (void *)bgep));
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	/*
265*0Sstevel@tonic-gate 	 * Register all the per-instance properties, initialising
266*0Sstevel@tonic-gate 	 * them from the table above or from driver properties set
267*0Sstevel@tonic-gate 	 * in the .conf file
268*0Sstevel@tonic-gate 	 */
269*0Sstevel@tonic-gate 	if (bge_param_register(bgep) != DDI_SUCCESS)
270*0Sstevel@tonic-gate 		return (-1);
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	/*
273*0Sstevel@tonic-gate 	 * The link speed may be forced to 10, 100 or 1000 Mbps using
274*0Sstevel@tonic-gate 	 * the property "transfer-speed". This may be done in OBP by
275*0Sstevel@tonic-gate 	 * using the command "apply transfer-speed=<speed> <device>".
276*0Sstevel@tonic-gate 	 * The speed may be 10, 100 or 1000 - any other value will be
277*0Sstevel@tonic-gate 	 * ignored.  Note that this does *enables* autonegotiation, but
278*0Sstevel@tonic-gate 	 * restricts it to the speed specified by the property.
279*0Sstevel@tonic-gate 	 */
280*0Sstevel@tonic-gate 	dip = bgep->devinfo;
281*0Sstevel@tonic-gate 	if (BGE_PROP_EXISTS(dip, transfer_speed_propname)) {
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		speed = BGE_PROP_GET_INT(dip, transfer_speed_propname);
284*0Sstevel@tonic-gate 		bge_log(bgep, "%s property is %d",
285*0Sstevel@tonic-gate 			transfer_speed_propname, speed);
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 		switch (speed) {
288*0Sstevel@tonic-gate 		case 1000:
289*0Sstevel@tonic-gate 			bgep->param_adv_autoneg = 1;
290*0Sstevel@tonic-gate 			bgep->param_adv_1000fdx = 1;
291*0Sstevel@tonic-gate 			bgep->param_adv_1000hdx = 1;
292*0Sstevel@tonic-gate 			bgep->param_adv_100fdx = 0;
293*0Sstevel@tonic-gate 			bgep->param_adv_100hdx = 0;
294*0Sstevel@tonic-gate 			bgep->param_adv_10fdx = 0;
295*0Sstevel@tonic-gate 			bgep->param_adv_10hdx = 0;
296*0Sstevel@tonic-gate 			break;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 		case 100:
299*0Sstevel@tonic-gate 			bgep->param_adv_autoneg = 1;
300*0Sstevel@tonic-gate 			bgep->param_adv_1000fdx = 0;
301*0Sstevel@tonic-gate 			bgep->param_adv_1000hdx = 0;
302*0Sstevel@tonic-gate 			bgep->param_adv_100fdx = 1;
303*0Sstevel@tonic-gate 			bgep->param_adv_100hdx = 1;
304*0Sstevel@tonic-gate 			bgep->param_adv_10fdx = 0;
305*0Sstevel@tonic-gate 			bgep->param_adv_10hdx = 0;
306*0Sstevel@tonic-gate 			break;
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 		case 10:
309*0Sstevel@tonic-gate 			bgep->param_adv_autoneg = 1;
310*0Sstevel@tonic-gate 			bgep->param_adv_1000fdx = 0;
311*0Sstevel@tonic-gate 			bgep->param_adv_1000hdx = 0;
312*0Sstevel@tonic-gate 			bgep->param_adv_100fdx = 0;
313*0Sstevel@tonic-gate 			bgep->param_adv_100hdx = 0;
314*0Sstevel@tonic-gate 			bgep->param_adv_10fdx = 1;
315*0Sstevel@tonic-gate 			bgep->param_adv_10hdx = 1;
316*0Sstevel@tonic-gate 			break;
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 		default:
319*0Sstevel@tonic-gate 			break;
320*0Sstevel@tonic-gate 		}
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	/*
324*0Sstevel@tonic-gate 	 * Also check the "speed" and "full-duplex" properties.  Setting
325*0Sstevel@tonic-gate 	 * these properties will override all other settings and *disable*
326*0Sstevel@tonic-gate 	 * autonegotiation, so both should be specified if either one is.
327*0Sstevel@tonic-gate 	 * Otherwise, the unspecified parameter will be set to a default
328*0Sstevel@tonic-gate 	 * value (1000Mb/s, full-duplex).
329*0Sstevel@tonic-gate 	 */
330*0Sstevel@tonic-gate 	if (BGE_PROP_EXISTS(dip, speed_propname) ||
331*0Sstevel@tonic-gate 	    BGE_PROP_EXISTS(dip, duplex_propname)) {
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 		bgep->param_adv_autoneg = 0;
334*0Sstevel@tonic-gate 		bgep->param_adv_1000fdx = 1;
335*0Sstevel@tonic-gate 		bgep->param_adv_1000hdx = 1;
336*0Sstevel@tonic-gate 		bgep->param_adv_100fdx = 1;
337*0Sstevel@tonic-gate 		bgep->param_adv_100hdx = 1;
338*0Sstevel@tonic-gate 		bgep->param_adv_10fdx = 1;
339*0Sstevel@tonic-gate 		bgep->param_adv_10hdx = 1;
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 		speed = BGE_PROP_GET_INT(dip, speed_propname);
342*0Sstevel@tonic-gate 		duplex = BGE_PROP_GET_INT(dip, duplex_propname);
343*0Sstevel@tonic-gate 		bge_log(bgep, "%s property is %d",
344*0Sstevel@tonic-gate 			speed_propname, speed);
345*0Sstevel@tonic-gate 		bge_log(bgep, "%s property is %d",
346*0Sstevel@tonic-gate 			duplex_propname, duplex);
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 		switch (speed) {
349*0Sstevel@tonic-gate 		case 1000:
350*0Sstevel@tonic-gate 		default:
351*0Sstevel@tonic-gate 			bgep->param_adv_100fdx = 0;
352*0Sstevel@tonic-gate 			bgep->param_adv_100hdx = 0;
353*0Sstevel@tonic-gate 			bgep->param_adv_10fdx = 0;
354*0Sstevel@tonic-gate 			bgep->param_adv_10hdx = 0;
355*0Sstevel@tonic-gate 			break;
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 		case 100:
358*0Sstevel@tonic-gate 			bgep->param_adv_1000fdx = 0;
359*0Sstevel@tonic-gate 			bgep->param_adv_1000hdx = 0;
360*0Sstevel@tonic-gate 			bgep->param_adv_10fdx = 0;
361*0Sstevel@tonic-gate 			bgep->param_adv_10hdx = 0;
362*0Sstevel@tonic-gate 			break;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 		case 10:
365*0Sstevel@tonic-gate 			bgep->param_adv_1000fdx = 0;
366*0Sstevel@tonic-gate 			bgep->param_adv_1000hdx = 0;
367*0Sstevel@tonic-gate 			bgep->param_adv_100fdx = 0;
368*0Sstevel@tonic-gate 			bgep->param_adv_100hdx = 0;
369*0Sstevel@tonic-gate 			break;
370*0Sstevel@tonic-gate 		}
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 		switch (duplex) {
373*0Sstevel@tonic-gate 		default:
374*0Sstevel@tonic-gate 		case 1:
375*0Sstevel@tonic-gate 			bgep->param_adv_1000hdx = 0;
376*0Sstevel@tonic-gate 			bgep->param_adv_100hdx = 0;
377*0Sstevel@tonic-gate 			bgep->param_adv_10hdx = 0;
378*0Sstevel@tonic-gate 			break;
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		case 0:
381*0Sstevel@tonic-gate 			bgep->param_adv_1000fdx = 0;
382*0Sstevel@tonic-gate 			bgep->param_adv_100fdx = 0;
383*0Sstevel@tonic-gate 			bgep->param_adv_10fdx = 0;
384*0Sstevel@tonic-gate 			break;
385*0Sstevel@tonic-gate 		}
386*0Sstevel@tonic-gate 	}
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	BGE_DEBUG(("bge_nd_init: autoneg %d"
389*0Sstevel@tonic-gate 			"pause %d asym_pause %d "
390*0Sstevel@tonic-gate 			"1000fdx %d 1000hdx %d "
391*0Sstevel@tonic-gate 			"100fdx %d 100hdx %d "
392*0Sstevel@tonic-gate 			"10fdx %d 10hdx %d ",
393*0Sstevel@tonic-gate 		bgep->param_adv_autoneg,
394*0Sstevel@tonic-gate 		bgep->param_adv_pause, bgep->param_adv_asym_pause,
395*0Sstevel@tonic-gate 		bgep->param_adv_1000fdx, bgep->param_adv_1000hdx,
396*0Sstevel@tonic-gate 		bgep->param_adv_100fdx, bgep->param_adv_100hdx,
397*0Sstevel@tonic-gate 		bgep->param_adv_10fdx, bgep->param_adv_10hdx));
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	return (0);
400*0Sstevel@tonic-gate }
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate enum ioc_reply
403*0Sstevel@tonic-gate bge_nd_ioctl(bge_t *bgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
404*0Sstevel@tonic-gate {
405*0Sstevel@tonic-gate 	nd_param_t *ndp;
406*0Sstevel@tonic-gate 	boolean_t ok;
407*0Sstevel@tonic-gate 	int info;
408*0Sstevel@tonic-gate 	int cmd;
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	BGE_TRACE(("bge_nd_ioctl($%p, $%p, $%p, $%p)",
411*0Sstevel@tonic-gate 		(void *)bgep, (void *)wq, (void *)mp, (void *)iocp));
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	ASSERT(mutex_owned(bgep->genlock));
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	cmd = iocp->ioc_cmd;
416*0Sstevel@tonic-gate 	switch (cmd) {
417*0Sstevel@tonic-gate 	default:
418*0Sstevel@tonic-gate 		/* NOTREACHED */
419*0Sstevel@tonic-gate 		bge_error(bgep, "bge_nd_ioctl: invalid cmd 0x%x", cmd);
420*0Sstevel@tonic-gate 		return (IOC_INVAL);
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 	case ND_GET:
423*0Sstevel@tonic-gate 		/*
424*0Sstevel@tonic-gate 		 * If nd_getset() returns B_FALSE, the command was
425*0Sstevel@tonic-gate 		 * not valid (e.g. unknown name), so we just tell the
426*0Sstevel@tonic-gate 		 * top-level ioctl code to send a NAK (with code EINVAL).
427*0Sstevel@tonic-gate 		 *
428*0Sstevel@tonic-gate 		 * Otherwise, nd_getset() will have built the reply to
429*0Sstevel@tonic-gate 		 * be sent (but not actually sent it), so we tell the
430*0Sstevel@tonic-gate 		 * caller to send the prepared reply.
431*0Sstevel@tonic-gate 		 */
432*0Sstevel@tonic-gate 		ok = nd_getset(wq, bgep->nd_data_p, mp);
433*0Sstevel@tonic-gate 		BGE_DEBUG(("bge_nd_ioctl: get %s", ok ? "OK" : "FAIL"));
434*0Sstevel@tonic-gate 		return (ok ? IOC_REPLY : IOC_INVAL);
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	case ND_SET:
437*0Sstevel@tonic-gate 		/*
438*0Sstevel@tonic-gate 		 * All adv_* parameters are locked (read-only) while
439*0Sstevel@tonic-gate 		 * the device is in any sort of loopback mode ...
440*0Sstevel@tonic-gate 		 */
441*0Sstevel@tonic-gate 		if (bgep->param_loop_mode != BGE_LOOP_NONE) {
442*0Sstevel@tonic-gate 			iocp->ioc_error = EBUSY;
443*0Sstevel@tonic-gate 			return (IOC_INVAL);
444*0Sstevel@tonic-gate 		}
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 		/*
447*0Sstevel@tonic-gate 		 * Before calling nd_getset(), we save the <info> field
448*0Sstevel@tonic-gate 		 * of the 'autonegotiation' parameter so that we can tell
449*0Sstevel@tonic-gate 		 * whether it was assigned (even if its value doesn't
450*0Sstevel@tonic-gate 		 * actually change).
451*0Sstevel@tonic-gate 		 */
452*0Sstevel@tonic-gate 		ndp = &bgep->nd_params[PARAM_ADV_AUTONEG_CAP];
453*0Sstevel@tonic-gate 		info = ndp->ndp_info;
454*0Sstevel@tonic-gate 		ok = nd_getset(wq, bgep->nd_data_p, mp);
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 		/*
457*0Sstevel@tonic-gate 		 * If nd_getset() returns B_FALSE, the command was
458*0Sstevel@tonic-gate 		 * not valid (e.g. unknown name), so we just tell
459*0Sstevel@tonic-gate 		 * the top-level ioctl code to send a NAK (with code
460*0Sstevel@tonic-gate 		 * EINVAL by default).
461*0Sstevel@tonic-gate 		 *
462*0Sstevel@tonic-gate 		 * Otherwise, nd_getset() will have built the reply to
463*0Sstevel@tonic-gate 		 * be sent - but that doesn't imply success!  In some
464*0Sstevel@tonic-gate 		 * cases, the reply it's built will have a non-zero
465*0Sstevel@tonic-gate 		 * error code in it (e.g. EPERM if not superuser).
466*0Sstevel@tonic-gate 		 * So, we also drop out in that case ...
467*0Sstevel@tonic-gate 		 */
468*0Sstevel@tonic-gate 		BGE_DEBUG(("bge_nd_ioctl: set %s err %d autoneg %d info %d/%d",
469*0Sstevel@tonic-gate 			ok ? "OK" : "FAIL", iocp->ioc_error,
470*0Sstevel@tonic-gate 			ndp->ndp_val, info, ndp->ndp_info));
471*0Sstevel@tonic-gate 		if (!ok)
472*0Sstevel@tonic-gate 			return (IOC_INVAL);
473*0Sstevel@tonic-gate 		if (iocp->ioc_error)
474*0Sstevel@tonic-gate 			return (IOC_REPLY);
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 		/*
477*0Sstevel@tonic-gate 		 * OK, a successful 'set'.  Prepare the messages explaining
478*0Sstevel@tonic-gate 		 * the link down/up cycle that will probably follow, then
479*0Sstevel@tonic-gate 		 * return IOC_RESTART_REPLY, telling the top-level ioctl
480*0Sstevel@tonic-gate 		 * code to update the PHY and restart the chip before
481*0Sstevel@tonic-gate 		 * sending our prepared reply
482*0Sstevel@tonic-gate 		 */
483*0Sstevel@tonic-gate 		if (ndp->ndp_val) {
484*0Sstevel@tonic-gate 			bgep->link_down_msg = " (autonegotiation enabled)";
485*0Sstevel@tonic-gate 			bgep->link_up_msg = " (autonegotiated)";
486*0Sstevel@tonic-gate 		} else {
487*0Sstevel@tonic-gate 			bgep->link_down_msg = " (autonegotiation disabled)";
488*0Sstevel@tonic-gate 			bgep->link_up_msg = " (forced)";
489*0Sstevel@tonic-gate 		}
490*0Sstevel@tonic-gate 		if (ndp->ndp_info == info)
491*0Sstevel@tonic-gate 			bgep->link_down_msg = " (advertised capabilities "
492*0Sstevel@tonic-gate 						"changed)";
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 		return (IOC_RESTART_REPLY);
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate }
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate /* Free the Named Dispatch Table by calling nd_free */
499*0Sstevel@tonic-gate void
500*0Sstevel@tonic-gate bge_nd_cleanup(bge_t *bgep)
501*0Sstevel@tonic-gate {
502*0Sstevel@tonic-gate 	BGE_TRACE(("bge_nd_cleanup($%p)", (void *)bgep));
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 	nd_free(&bgep->nd_data_p);
505*0Sstevel@tonic-gate }
506