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
_topo_init(topo_mod_t * mod,topo_version_t version)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
_topo_fini(topo_mod_t * mod)90 _topo_fini(topo_mod_t *mod)
91 {
92 topo_mod_unregister(mod);
93 }
94
95 static tnode_t *
xaui_tnode_create(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t i,void * priv)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
xaui_fru_set(topo_mod_t * mp,tnode_t * tn)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 *
xaui_topo_alloc(size_t size)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
xaui_topo_free(void * data,size_t size)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 *
xaui_trans_str(topo_mod_t * mod,char * dn,char * p,size_t buf_len)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 *
xaui_get_path(topo_mod_t * mod,void * priv,topo_instance_t inst)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
xaui_get_pri_label(topo_mod_t * mod,topo_instance_t n,void * priv,char ** labelp)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
xaui_label_set(topo_mod_t * mod,tnode_t * node,topo_instance_t n,void * priv)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 *
xaui_declare(tnode_t * parent,const char * name,topo_instance_t i,void * priv,topo_mod_t * mod)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 *
xfp_enum_load(topo_mod_t * mp)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
xaui_enum(topo_mod_t * mod,tnode_t * rnode,const char * name,topo_instance_t min,topo_instance_t max,void * arg,void * priv)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