xref: /titanic_51/usr/src/lib/fm/topo/modules/sun4v/xaui/xaui.c (revision 3357fc65c82fa21d1aabd8d906fb1f49810afe0b)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <strings.h>
29 #include <fm/topo_mod.h>
30 #include <fm/topo_hc.h>
31 #include <sys/fm/protocol.h>
32 #include <sys/fm/ldom.h>
33 #include <sys/mdesc.h>
34 #include <assert.h>
35 #include <sys/systeminfo.h>
36 #include "xaui.h"
37 
38 /*
39  * xaui.c
40  *	sun4v specific xaui enumerators
41  */
42 
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
46 
47 #define	XAUI_VERSION		TOPO_VERSION
48 #define	XFP_MAX			1	/* max number of xfp per xaui card */
49 
50 static int xaui_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
51 		    topo_instance_t, void *, void *);
52 
53 static const topo_modops_t xaui_ops =
54 	{ xaui_enum, NULL };
55 
56 const topo_modinfo_t xaui_info =
57 	{XAUI, FM_FMRI_SCHEME_HC, XAUI_VERSION, &xaui_ops};
58 
59 static const topo_pgroup_info_t xaui_auth_pgroup = {
60 	FM_FMRI_AUTHORITY,
61 	TOPO_STABILITY_PRIVATE,
62 	TOPO_STABILITY_PRIVATE,
63 	1
64 };
65 
66 static topo_mod_t *xaui_mod_hdl = NULL;
67 static int freeprilabel = 0;
68 static int ispci = 0;
69 
70 /*ARGSUSED*/
71 void
72 _topo_init(topo_mod_t *mod, topo_version_t version)
73 {
74 	/*
75 	 * Turn on module debugging output
76 	 */
77 	if (getenv("TOPOXAUIDBG") != NULL)
78 		topo_mod_setdebug(mod);
79 	topo_mod_dprintf(mod, "initializing xaui enumerator\n");
80 
81 	if (topo_mod_register(mod, &xaui_info, TOPO_VERSION) < 0) {
82 		topo_mod_dprintf(mod, "xaui registration failed: %s\n",
83 		    topo_mod_errmsg(mod));
84 		return; /* mod errno already set */
85 	}
86 	topo_mod_dprintf(mod, "xaui enum initd\n");
87 }
88 
89 void
90 _topo_fini(topo_mod_t *mod)
91 {
92 	topo_mod_unregister(mod);
93 }
94 
95 static tnode_t *
96 xaui_tnode_create(topo_mod_t *mod, tnode_t *parent,
97     const char *name, topo_instance_t i, void *priv)
98 {
99 	int err;
100 	nvlist_t *fmri;
101 	tnode_t *ntn;
102 	nvlist_t *auth = topo_mod_auth(mod, parent);
103 
104 	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
105 	    NULL, auth, NULL, NULL, NULL);
106 	nvlist_free(auth);
107 
108 	if (fmri == NULL) {
109 		topo_mod_dprintf(mod,
110 		    "Unable to make nvlist for %s bind: %s.\n",
111 		    name, topo_mod_errmsg(mod));
112 		return (NULL);
113 	}
114 
115 	ntn = topo_node_bind(mod, parent, name, i, fmri);
116 	nvlist_free(fmri);
117 	if (ntn == NULL) {
118 		topo_mod_dprintf(mod,
119 		    "topo_node_bind (%s%d/%s%d) failed: %s\n",
120 		    topo_node_name(parent), topo_node_instance(parent),
121 		    name, i,
122 		    topo_strerror(topo_mod_errno(mod)));
123 		return (NULL);
124 	}
125 
126 	topo_node_setspecific(ntn, priv);
127 	if (topo_pgroup_create(ntn, &xaui_auth_pgroup, &err) == 0) {
128 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
129 		    FM_FMRI_AUTH_PRODUCT, &err);
130 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
131 		    FM_FMRI_AUTH_PRODUCT_SN, &err);
132 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
133 		    FM_FMRI_AUTH_CHASSIS, &err);
134 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
135 		    FM_FMRI_AUTH_SERVER, &err);
136 	}
137 	return (ntn);
138 }
139 
140 
141 static int
142 xaui_fru_set(topo_mod_t *mp, tnode_t *tn)
143 {
144 	nvlist_t *fmri;
145 	int err, e;
146 
147 	if (topo_node_resource(tn, &fmri, &err) < 0 ||
148 	    fmri == NULL) {
149 		topo_mod_dprintf(mp, "FRU_fmri_set error: %s\n",
150 		    topo_strerror(topo_mod_errno(mp)));
151 		return (topo_mod_seterrno(mp, err));
152 	}
153 	e = topo_node_fru_set(tn, fmri, 0, &err);
154 	nvlist_free(fmri);
155 	if (e < 0)
156 		return (topo_mod_seterrno(mp, err));
157 	return (0);
158 }
159 
160 
161 static void *
162 xaui_topo_alloc(size_t size)
163 {
164 	assert(xaui_mod_hdl != NULL);
165 	return (topo_mod_alloc(xaui_mod_hdl, size));
166 }
167 
168 
169 static void
170 xaui_topo_free(void *data, size_t size)
171 {
172 	assert(xaui_mod_hdl != NULL);
173 	topo_mod_free(xaui_mod_hdl, data, size);
174 }
175 
176 
177 /*
178  * Remove the 3 character device name (pci/niu) from devfs path.
179  */
180 static char *
181 xaui_trans_str(topo_mod_t *mod, char *dn, char *p, size_t buf_len)
182 {
183 	int i = 0;
184 	int j = 0;
185 	char buf[MAXPATHLEN];
186 
187 	topo_mod_dprintf(mod, "xaui_trans_str: dev path(%s) dev name(%s)\n",
188 	    dn, p);
189 	do {
190 		/* strip out either "pci" or "niu" */
191 		if (dn[i] == p[0] && dn[i + 1] == p[1] && dn[i + 2] == p[2])
192 			i += 3;
193 		else
194 			buf[j++] = dn[i++];
195 	} while (i < buf_len);
196 
197 	topo_mod_dprintf(mod, "xaui_trans_str: return(%s)\n", buf);
198 	return (topo_mod_strdup(mod, (char *)buf));
199 }
200 
201 
202 static char *
203 xaui_get_path(topo_mod_t *mod, void *priv, topo_instance_t inst)
204 {
205 	di_node_t dnode;
206 	char *devfs_path;
207 	char *path;
208 	char *buf = NULL;
209 	size_t buf_len;
210 	size_t dev_path_len;
211 	size_t path_len;
212 
213 	/*
214 	 * There are two ways to get here:
215 	 * 1. niu enum  - private data is the di_node_t for this xaui
216 	 *		- instance is the ethernet function number
217 	 *    device path looks like: /niu@80/network@0:nxge@0
218 	 *    PRI path looks like:    /@80/@0
219 	 *
220 	 * 2. pcibus enum - private data is the parent tnode_t
221 	 *		  - instance is the pci function number
222 	 *    device path looks like: /pci@500/pci@0/pci@8/network@0:nxge0
223 	 *    PRI path looks like:    /@500/@0/@8/@0
224 	 *
225 	 *    PRI path for pciex is /@Bus/@Dev/@Func/@Instance
226 	 */
227 	if (ispci == 1) {
228 		/* coming from pcibus */
229 		topo_mod_dprintf(mod, "from pcibus\n");
230 		dnode = topo_node_getspecific((tnode_t *)priv);
231 	} else {
232 		/* coming from niu */
233 		topo_mod_dprintf(mod, "from niu\n");
234 		dnode = (struct di_node *)priv;
235 	}
236 	if (dnode == DI_NODE_NIL) {
237 		topo_mod_dprintf(mod, "DI_NODE_NIL\n");
238 		return (NULL);
239 	}
240 
241 	/* get device path */
242 	devfs_path = di_devfs_path(dnode);
243 	if (devfs_path == NULL) {
244 		topo_mod_dprintf(mod, "NULL devfs_path\n");
245 		return (NULL);
246 	}
247 	topo_mod_dprintf(mod, "devfs_path (%s)\n", devfs_path);
248 	dev_path_len = strlen(devfs_path) + 1;
249 
250 	/* remove device name from path */
251 	if (ispci == 1) {
252 		topo_mod_dprintf(mod, "ispci\n");
253 		buf = xaui_trans_str(mod, devfs_path, "pci", dev_path_len);
254 		buf_len = strlen(buf) + 1;
255 	} else {
256 		buf = xaui_trans_str(mod, devfs_path, "niu", dev_path_len);
257 		buf_len = strlen(buf) + 1;
258 	}
259 	di_devfs_path_free(devfs_path);
260 
261 	/* lop off "/network@" */
262 	buf[(strstr(buf, "/network@") - buf)] = '\0';
263 
264 	/* path: transposed address + '/@instance' (0/1) + '\0' */
265 	path_len = strlen(buf) + 3 + 1;
266 	path = (char *)xaui_topo_alloc(path_len);
267 	if (snprintf(path, path_len, "%s/@%d", buf, inst) < 0) {
268 		topo_mod_dprintf(mod, "snprintf failed\n");
269 		path = NULL;
270 	}
271 	xaui_topo_free(buf, buf_len);
272 
273 	/* should return something like /@500/@0/@8/@0 or /@80/@0 */
274 	topo_mod_dprintf(mod, "xaui_get_path: path(%s)\n", path);
275 	return (path);
276 }
277 
278 
279 static int
280 xaui_get_pri_label(topo_mod_t *mod, topo_instance_t n, void *priv,
281     char **labelp)
282 {
283 	ldom_hdl_t *hdlp;
284 	uint32_t type = 0;
285 	ssize_t bufsize = 0;
286 	uint64_t *bufp;
287 	md_t *mdp;
288 	int num_nodes, ncomp;
289 	mde_cookie_t *listp;
290 	char *pstr = NULL;
291 	int i;
292 	char *path;
293 
294 	/* Get device path minus the device names */
295 	path = xaui_get_path(mod, priv, n);
296 	if (path == NULL) {
297 		topo_mod_dprintf(mod, "can't get path\n");
298 		return (-1);
299 	}
300 
301 	hdlp = ldom_init(xaui_topo_alloc, xaui_topo_free);
302 	if (hdlp == NULL) {
303 		topo_mod_dprintf(mod, "ldom_init failed\n");
304 		return (-1);
305 	}
306 
307 	(void) ldom_get_type(hdlp, &type);
308 	if ((type & LDOM_TYPE_CONTROL) != 0) {
309 		bufsize = ldom_get_core_md(hdlp, &bufp);
310 	} else {
311 		bufsize = ldom_get_local_md(hdlp, &bufp);
312 	}
313 	if (bufsize < 1) {
314 		topo_mod_dprintf(mod, "failed to get pri/md (%d)\n", bufsize);
315 		ldom_fini(hdlp);
316 		return (-1);
317 	}
318 
319 	if ((mdp = md_init_intern(bufp, xaui_topo_alloc, xaui_topo_free)) ==
320 	    NULL || (num_nodes = md_node_count(mdp)) < 1) {
321 		topo_mod_dprintf(mod, "md_init_intern failed\n");
322 		xaui_topo_free(bufp, (size_t)bufsize);
323 		ldom_fini(hdlp);
324 		return (-1);
325 	}
326 
327 	if ((listp = (mde_cookie_t *)xaui_topo_alloc(
328 	    sizeof (mde_cookie_t) * num_nodes)) == NULL) {
329 		topo_mod_dprintf(mod, "can't alloc listp\n");
330 		xaui_topo_free(bufp, (size_t)bufsize);
331 		(void) md_fini(mdp);
332 		ldom_fini(hdlp);
333 		return (-1);
334 	}
335 
336 	ncomp = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE,
337 	    md_find_name(mdp, "component"),
338 	    md_find_name(mdp, "fwd"), listp);
339 	if (ncomp <= 0) {
340 		topo_mod_dprintf(mod, "no component nodes found\n");
341 		xaui_topo_free(listp, sizeof (mde_cookie_t) * num_nodes);
342 		xaui_topo_free(bufp, (size_t)bufsize);
343 		(void) md_fini(mdp);
344 		ldom_fini(hdlp);
345 		return (-1);
346 	}
347 	topo_mod_dprintf(mod, "number of comps (%d)\n", ncomp);
348 
349 	for (i = 0; i < ncomp; i++) {
350 		/*
351 		 * Look for type == "io", topo-hc-name == "xaui";
352 		 * match "path" md property.
353 		 */
354 		if ((md_get_prop_str(mdp, listp[i], "type", &pstr) == 0) &&
355 		    (pstr != NULL) &&
356 		    (strncmp(pstr, "io", strlen(pstr)) == 0) &&
357 		    (md_get_prop_str(mdp, listp[i], "topo-hc-name", &pstr)
358 		    == 0) && (pstr != NULL) &&
359 		    (strncmp(pstr, "xaui", strlen(pstr)) == 0) &&
360 		    (md_get_prop_str(mdp, listp[i], "path", &pstr) == 0) &&
361 		    (pstr != NULL)) {
362 			/* check node path */
363 			if (strncmp(pstr, path, sizeof (path)) == 0) {
364 				/* this is the node, grab the label */
365 				if (md_get_prop_str(mdp, listp[i], "nac",
366 				    &pstr) == 0) {
367 					*labelp = topo_mod_strdup(mod, pstr);
368 					/* need to free this later */
369 					freeprilabel = 1;
370 					break;
371 				}
372 			}
373 		}
374 	}
375 
376 	xaui_topo_free(listp, sizeof (mde_cookie_t) * num_nodes);
377 	xaui_topo_free(bufp, (size_t)bufsize);
378 	(void) md_fini(mdp);
379 	ldom_fini(hdlp);
380 
381 	if (path != NULL) {
382 		xaui_topo_free(path, strlen(path) + 1);
383 	}
384 	return (0);
385 }
386 
387 
388 static int
389 xaui_label_set(topo_mod_t *mod, tnode_t *node, topo_instance_t n, void *priv)
390 {
391 	const char *label = NULL;
392 	char *plat, *pp;
393 	int err;
394 	int i, p;
395 
396 	(void) xaui_get_pri_label(mod, n, priv, (char **)&label);
397 	if (label == NULL) {
398 		topo_mod_dprintf(mod, "no PRI node for label\n");
399 		if (Phyxaui_Names == NULL)
400 			return (-1);
401 
402 		if (topo_prop_get_string(node,
403 		    FM_FMRI_AUTHORITY, FM_FMRI_AUTH_PRODUCT, &plat, &err) < 0) {
404 			return (topo_mod_seterrno(mod, err));
405 		}
406 		/*
407 		 * Trim SUNW, from the platform name
408 		 */
409 		pp = strchr(plat, ',');
410 		if (pp == NULL)
411 			pp = plat;
412 		else
413 			++pp;
414 
415 		for (p = 0; p < Phyxaui_Names->psn_nplats; p++) {
416 			if (strcmp(Phyxaui_Names->psn_names[p].pnm_platform,
417 			    pp) != 0)
418 				continue;
419 			for (i = 0; i < Phyxaui_Names->psn_names[p].pnm_nnames;
420 			    i++) {
421 				physnm_t ps;
422 				ps = Phyxaui_Names->psn_names[p].pnm_names[i];
423 				if (ps.ps_num == n) {
424 					label = ps.ps_label;
425 					break;
426 				}
427 			}
428 			break;
429 		}
430 		topo_mod_strfree(mod, plat);
431 	}
432 
433 	if (label != NULL) {
434 		if (topo_prop_set_string(node, TOPO_PGROUP_PROTOCOL,
435 		    TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE,
436 		    label, &err) != 0) {
437 			if (freeprilabel == 1) {
438 				topo_mod_strfree(mod, (char *)label);
439 			}
440 			return (topo_mod_seterrno(mod, err));
441 		}
442 		if (freeprilabel == 1) {
443 			topo_mod_strfree(mod, (char *)label);
444 		}
445 	}
446 
447 	return (0);
448 }
449 
450 
451 /*ARGSUSED*/
452 static tnode_t *
453 xaui_declare(tnode_t *parent, const char *name, topo_instance_t i,
454 	void *priv, topo_mod_t *mod)
455 {
456 	tnode_t *ntn;
457 	nvlist_t *fmri = NULL;
458 	int e;
459 
460 	if ((ntn = xaui_tnode_create(mod, parent, name, i, NULL)) == NULL) {
461 		topo_mod_dprintf(mod, "%s ntn = NULL\n", name);
462 		return (NULL);
463 	}
464 
465 	(void) xaui_fru_set(mod, ntn);
466 
467 	/* when coming from pcibus: private data == parent tnode */
468 	if (priv == (void *)parent) {
469 		ispci = 1;
470 	}
471 
472 	(void) xaui_label_set(mod, ntn, i, priv);
473 
474 	/* reset pcibus/niu switch */
475 	ispci = 0;
476 
477 	/* set ASRU to resource fmri */
478 	if (topo_prop_get_fmri(ntn, TOPO_PGROUP_PROTOCOL,
479 	    TOPO_PROP_RESOURCE, &fmri, &e) == 0)
480 		(void) topo_node_asru_set(ntn, fmri, 0, &e);
481 	nvlist_free(fmri);
482 
483 	if (topo_node_range_create(mod, ntn, XFP,
484 	    0, XFP_MAX) < 0) {
485 		topo_node_unbind(ntn);
486 		topo_mod_dprintf(mod, "child_range_add of XFP"
487 		    "failed: %s\n",
488 		    topo_strerror(topo_mod_errno(mod)));
489 		return (NULL); /* mod_errno already set */
490 	}
491 	return (ntn);
492 }
493 
494 
495 static topo_mod_t *
496 xfp_enum_load(topo_mod_t *mp)
497 {
498 	topo_mod_t *rp = NULL;
499 
500 	if ((rp = topo_mod_load(mp, XFP, TOPO_VERSION)) == NULL) {
501 		topo_mod_dprintf(mp,
502 		    "%s enumerator could not load %s enum.\n", XAUI, XFP);
503 	}
504 	return (rp);
505 }
506 
507 
508 /*ARGSUSED*/
509 static int
510 xaui_enum(topo_mod_t *mod, tnode_t *rnode, const char *name,
511 	topo_instance_t min, topo_instance_t max, void *arg, void *priv)
512 {
513 	tnode_t *xauin;
514 
515 	if (strcmp(name, XAUI) != 0) {
516 		topo_mod_dprintf(mod,
517 		    "Currently only know how to enumerate %s components.\n",
518 		    XAUI);
519 		return (0);
520 	}
521 
522 	xaui_mod_hdl = mod;
523 
524 	/*
525 	 * Load XFP enum
526 	 */
527 	if (xfp_enum_load(mod) == NULL)
528 		return (-1);
529 
530 	if ((xauin = xaui_declare(rnode, name, min, priv, mod)) == NULL)
531 		return (-1);
532 
533 	/* set the private data to be the instance number of niufn */
534 	if (topo_mod_enumerate(mod,
535 	    xauin, XFP, XFP, 0, 0, NULL) != 0) {
536 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
537 	}
538 	return (0);
539 }
540