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