xref: /illumos-gate/usr/src/lib/fm/topo/modules/sun4v/niu/niu.c (revision 335777d1)
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