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