1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <string.h>
28 #include <fm/topo_mod.h>
29 #include <fm/topo_hc.h>
30 #include <libdevinfo.h>
31 #include <limits.h>
32 #include <sys/fm/protocol.h>
33 #include <sys/param.h>
34 #include <sys/systeminfo.h>
35 #include <assert.h>
36 #include <stdlib.h>
37
38 /*
39 * niu.c
40 * sun4v specific niu enumerators
41 */
42
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46
47 #define NIU_VERSION TOPO_VERSION
48 #define NIUFN_MAX 2
49 #define XAUI_MAX 1 /* max number of XAUIs per niufn */
50
51 static int niu_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
52 topo_instance_t, void *, void *);
53
54 static const topo_modops_t niu_ops =
55 { niu_enum, NULL };
56
57 const topo_modinfo_t niu_info =
58 {NIU, FM_FMRI_SCHEME_HC, NIU_VERSION, &niu_ops};
59
60 static const topo_pgroup_info_t io_pgroup =
61 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 };
62
63 /*ARGSUSED*/
64 void
_topo_init(topo_mod_t * mod,topo_version_t version)65 _topo_init(topo_mod_t *mod, topo_version_t version)
66 {
67 /*
68 * Turn on module debugging output
69 */
70 if (getenv("TOPONIUDBG") != NULL)
71 topo_mod_setdebug(mod);
72 topo_mod_dprintf(mod, "initializing niu enumerator\n");
73
74 if (topo_mod_register(mod, &niu_info, TOPO_VERSION) < 0) {
75 topo_mod_dprintf(mod, "niu registration failed: %s\n",
76 topo_mod_errmsg(mod));
77 return; /* mod errno already set */
78 }
79 topo_mod_dprintf(mod, "NIU enumr initd\n");
80 }
81
82 void
_topo_fini(topo_mod_t * mod)83 _topo_fini(topo_mod_t *mod)
84 {
85 topo_mod_unregister(mod);
86 }
87 static int
devprop_set(tnode_t * tn,di_node_t dn,const char * tpgrp,const char * tpnm,topo_mod_t * mod)88 devprop_set(tnode_t *tn, di_node_t dn,
89 const char *tpgrp, const char *tpnm, topo_mod_t *mod)
90 {
91 char *path;
92 int err, e;
93
94 if ((path = di_devfs_path(dn)) == NULL) {
95 topo_mod_dprintf(mod, "NULL di_devfs_path.\n");
96 return (topo_mod_seterrno(mod, ETOPO_PROP_NOENT));
97 }
98 e = topo_prop_set_string(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE,
99 path, &err);
100 di_devfs_path_free(path);
101 if (e != 0)
102 return (topo_mod_seterrno(mod, err));
103 return (0);
104 }
105 /*ARGSUSED*/
106 static int
driverprop_set(tnode_t * tn,di_node_t dn,const char * tpgrp,const char * tpnm,topo_mod_t * mod)107 driverprop_set(tnode_t *tn, di_node_t dn,
108 const char *tpgrp, const char *tpnm, topo_mod_t *mod)
109 {
110 char *dnm;
111 int err;
112
113 if ((dnm = di_driver_name(dn)) == NULL)
114 return (0);
115 if (topo_prop_set_string(tn,
116 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0)
117 return (topo_mod_seterrno(mod, err));
118 return (0);
119 }
120 /*ARGSUSED*/
121 static int
moduleprop_set(tnode_t * tn,di_node_t dn,const char * tpgrp,const char * tpnm,topo_mod_t * mod)122 moduleprop_set(tnode_t *tn, di_node_t dn,
123 const char *tpgrp, const char *tpnm, topo_mod_t *mod)
124 {
125 nvlist_t *module;
126 char *dnm;
127 int err;
128
129 if ((dnm = di_driver_name(dn)) == NULL)
130 return (0);
131
132 if ((module = topo_mod_modfmri(mod, FM_MOD_SCHEME_VERSION, dnm))
133 == NULL)
134 return (0); /* driver maybe detached, return success */
135
136 if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, module,
137 &err) < 0) {
138 nvlist_free(module);
139 return (topo_mod_seterrno(mod, err));
140 }
141 nvlist_free(module);
142 return (0);
143 }
144 static tnode_t *
niu_tnode_create(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t i,void * priv)145 niu_tnode_create(topo_mod_t *mod, tnode_t *parent,
146 const char *name, topo_instance_t i, void *priv)
147 {
148 int err;
149 nvlist_t *fmri;
150 tnode_t *ntn;
151 nvlist_t *auth = topo_mod_auth(mod, parent);
152
153 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
154 NULL, auth, NULL, NULL, NULL);
155 nvlist_free(auth);
156
157 if (fmri == NULL) {
158 topo_mod_dprintf(mod,
159 "Unable to make nvlist for %s bind: %s.\n",
160 name, topo_mod_errmsg(mod));
161 return (NULL);
162 }
163
164 ntn = topo_node_bind(mod, parent, name, i, fmri);
165 if (ntn == NULL) {
166 topo_mod_dprintf(mod,
167 "topo_node_bind (%s%d/%s%d) failed: %s\n",
168 topo_node_name(parent), topo_node_instance(parent),
169 name, i,
170 topo_strerror(topo_mod_errno(mod)));
171 nvlist_free(fmri);
172 return (NULL);
173 }
174 nvlist_free(fmri);
175 topo_node_setspecific(ntn, priv);
176
177 if (topo_pgroup_create(ntn, &io_pgroup, &err) == 0) {
178 (void) devprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_DEV, mod);
179 (void) driverprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_DRIVER,
180 mod);
181 (void) moduleprop_set(ntn, priv, TOPO_PGROUP_IO, TOPO_IO_MODULE,
182 mod);
183 }
184 return (ntn);
185 }
186 static int
niu_asru_set(tnode_t * tn,di_node_t dn,topo_mod_t * mod)187 niu_asru_set(tnode_t *tn, di_node_t dn, topo_mod_t *mod)
188 {
189 char *path;
190 nvlist_t *fmri;
191 int e;
192
193 if ((path = di_devfs_path(dn)) != NULL) {
194 fmri = topo_mod_devfmri(mod, FM_DEV_SCHEME_VERSION, path, NULL);
195 if (fmri == NULL) {
196 topo_mod_dprintf(mod,
197 "dev:///%s fmri creation failed.\n", path);
198 di_devfs_path_free(path);
199 return (-1);
200 }
201 di_devfs_path_free(path);
202 } else {
203 topo_mod_dprintf(mod, "NULL di_devfs_path.\n");
204 if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL,
205 TOPO_PROP_RESOURCE, &fmri, &e) < 0)
206 return (topo_mod_seterrno(mod, e));
207 }
208 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) {
209 nvlist_free(fmri);
210 return (topo_mod_seterrno(mod, e));
211 }
212 nvlist_free(fmri);
213 return (0);
214 }
215
216 /*ARGSUSED*/
217 static tnode_t *
niu_declare(tnode_t * parent,const char * name,topo_instance_t i,void * priv,topo_mod_t * mod)218 niu_declare(tnode_t *parent, const char *name, topo_instance_t i,
219 void *priv, topo_mod_t *mod)
220 {
221 tnode_t *ntn;
222 int err;
223
224 if ((ntn = niu_tnode_create(mod, parent, name, 0, priv)) == NULL) {
225 topo_mod_dprintf(mod, "%s ntn = NULL\n", name);
226 return (NULL);
227 }
228
229 /* inherit FRU from parent */
230 (void) topo_node_fru_set(ntn, NULL, 0, &err);
231 /* inherit parent's label */
232 if (topo_node_label_set(ntn, NULL, &err) < 0) {
233 topo_mod_dprintf(mod, "niu label error %d\n", err);
234 }
235 /* set ASRU */
236 (void) niu_asru_set(ntn, priv, mod);
237
238 return (ntn);
239 }
240
241
242 /*ARGSUSED*/
243 static tnode_t *
niufn_declare(tnode_t * parent,const char * name,topo_instance_t i,void * priv,topo_mod_t * mod)244 niufn_declare(tnode_t *parent, const char *name, topo_instance_t i,
245 void *priv, topo_mod_t *mod)
246 {
247 tnode_t *ntn;
248 int err;
249
250 if ((ntn = niu_tnode_create(mod, parent, name, i, priv)) == NULL)
251 return (NULL);
252
253 /* inherit FRU from parent */
254 (void) topo_node_fru_set(ntn, NULL, 0, &err);
255 /* inherit parent's label */
256 (void) topo_node_label_set(ntn, NULL, &err);
257
258 /* set ASRU */
259 (void) niu_asru_set(ntn, priv, mod);
260
261 if (topo_node_range_create(mod, ntn, XAUI, 0, XAUI_MAX) < 0) {
262 topo_node_unbind(ntn);
263 topo_mod_dprintf(mod, "child_range_add of XAUI"
264 "failed: %s\n",
265 topo_strerror(topo_mod_errno(mod)));
266 return (NULL); /* mod_errno already set */
267 }
268 return (ntn);
269 }
270
271 /*
272 * Get the NIU/Neptune ethernet function number from the reg property
273 */
274 static int
niufn_instance_get(topo_mod_t * mod,di_node_t node,topo_instance_t * inst)275 niufn_instance_get(topo_mod_t *mod, di_node_t node, topo_instance_t *inst)
276 {
277 di_prom_handle_t phan;
278 int rval, *intp;
279
280 *inst = (topo_instance_t)0;
281 rval = -1;
282 if ((phan = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) {
283 rval = di_prom_prop_lookup_ints(phan, node,
284 DI_PROP_REG, &intp);
285 }
286 if (rval < 0) {
287 rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
288 DI_PROP_REG, &intp);
289 if (rval < 0)
290 return (-1);
291 }
292 *inst = (topo_instance_t)intp[0];
293
294 return (0);
295 }
296
297 static int
niufn_instantiate(tnode_t * parent,const char * name,di_node_t pnode,topo_mod_t * mod)298 niufn_instantiate(tnode_t *parent, const char *name, di_node_t pnode,
299 topo_mod_t *mod)
300 {
301 di_node_t sib;
302 tnode_t *ntn;
303 topo_instance_t inst;
304
305 if (strcmp(name, NIUFN) != 0) {
306 topo_mod_dprintf(mod,
307 "Currently only know how to enumerate %s components.\n",
308 NIUFN);
309 return (0);
310 }
311
312 sib = di_child_node(pnode);
313 while (sib != DI_NODE_NIL) {
314 if (niufn_instance_get(mod, sib, &inst) != 0) {
315 topo_mod_dprintf(mod, "Enumeration of %s "
316 "instance failed.\n", NIUFN);
317 sib = di_sibling_node(sib);
318 continue;
319 }
320 if ((ntn = niufn_declare(parent, NIUFN, inst, sib, mod))
321 == NULL) {
322 topo_mod_dprintf(mod, "Enumeration of %s=%d "
323 "failed: %s\n", NIUFN, inst,
324 topo_strerror(topo_mod_errno(mod)));
325 return (-1);
326 }
327 if (topo_mod_enumerate(mod,
328 ntn, XAUI, XAUI, inst, inst, sib) != 0) {
329 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
330 }
331 sib = di_sibling_node(sib);
332 }
333 return (0);
334 }
335
336 static topo_mod_t *
xaui_enum_load(topo_mod_t * mp)337 xaui_enum_load(topo_mod_t *mp)
338 {
339 topo_mod_t *rp = NULL;
340
341 if ((rp = topo_mod_load(mp, XAUI, TOPO_VERSION)) == NULL) {
342 topo_mod_dprintf(mp,
343 "%s enumerator could not load %s enum.\n", NIU, XAUI);
344 }
345 return (rp);
346 }
347 /*ARGSUSED*/
348 static int
niu_enum(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * notused)349 niu_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
350 topo_instance_t min, topo_instance_t max, void *arg, void *notused)
351 {
352 tnode_t *niun;
353 di_node_t devtree;
354 di_node_t dnode;
355
356 if (strcmp(name, NIU) != 0) {
357 topo_mod_dprintf(mod,
358 "Currently only know how to enumerate %s components.\n",
359 NIU);
360 return (0);
361 }
362
363 if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) {
364 topo_mod_dprintf(mod, "devinfo init failed.");
365 return (-1);
366 }
367
368 /*
369 * Load XAUI Enum
370 */
371 if (xaui_enum_load(mod) == NULL)
372 return (-1);
373
374 dnode = di_drv_first_node("niumx", devtree);
375 if (dnode != DI_NODE_NIL) {
376 niun = niu_declare(rnode, name, 0, dnode, mod);
377 if (niun == NULL) {
378 topo_mod_dprintf(mod, "Enumeration of niu failed: %s\n",
379 topo_strerror(topo_mod_errno(mod)));
380 return (-1); /* mod_errno already set */
381 }
382 if (topo_node_range_create(mod, niun, NIUFN,
383 0, NIUFN_MAX) < 0) {
384 topo_node_unbind(niun);
385 topo_mod_dprintf(mod, "child_range_add of NIUFN"
386 "failed: %s\n",
387 topo_strerror(topo_mod_errno(mod)));
388 return (-1); /* mod_errno already set */
389 }
390 if (niufn_instantiate(niun, NIUFN, dnode, mod) < 0) {
391 topo_mod_dprintf(mod, "Enumeration of niufn "
392 "failed %s\n",
393 topo_strerror(topo_mod_errno(mod)));
394 }
395 }
396 if (di_drv_next_node(dnode) != DI_NODE_NIL)
397 topo_mod_dprintf(mod,
398 "Currently only know how to enumerate one niu "
399 "components.\n");
400
401 return (0);
402 }
403