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