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 #include <stdlib.h> 28 #include <string.h> 29 #include <strings.h> 30 #include <fm/topo_mod.h> 31 #include <fm/topo_hc.h> 32 #include <libdevinfo.h> 33 #include <limits.h> 34 #include <sys/fm/protocol.h> 35 #include <sys/param.h> 36 #include <sys/systeminfo.h> 37 #include <assert.h> 38 #include <sys/utsname.h> 39 #include <sys/systeminfo.h> 40 #include <fm/fmd_fmri.h> 41 #include <sys/types.h> 42 #include <sys/mdesc.h> 43 #include <sys/fm/ldom.h> 44 45 #include "cpuboard_topo.h" 46 47 /* 48 * cpuboard.c 49 * sun4v specific cpuboard enumerator 50 */ 51 52 #ifdef __cplusplus 53 extern "C" { 54 #endif 55 56 #define CPUBOARD_VERSION TOPO_VERSION 57 58 /* Until future PRI changes, make connection between cpuboard id and RC */ 59 char *cpub_rcs[] = { CPUBOARD0_RC, CPUBOARD1_RC, CPUBOARD2_RC, CPUBOARD3_RC }; 60 61 static int cpuboard_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 62 topo_instance_t, void *, void *); 63 64 static const topo_modops_t cpuboard_ops = 65 { cpuboard_enum, NULL }; 66 67 const topo_modinfo_t cpuboard_info = 68 {CPUBOARD, FM_FMRI_SCHEME_HC, CPUBOARD_VERSION, &cpuboard_ops}; 69 70 static const topo_pgroup_info_t cpuboard_auth_pgroup = 71 { FM_FMRI_AUTHORITY, TOPO_STABILITY_PRIVATE, 72 TOPO_STABILITY_PRIVATE, 1 }; 73 74 static topo_mod_t *cpuboard_mod_hdl = NULL; 75 76 static void * 77 cpuboard_topo_alloc(size_t size) 78 { 79 assert(cpuboard_mod_hdl != NULL); 80 return (topo_mod_alloc(cpuboard_mod_hdl, size)); 81 } 82 83 static void 84 cpuboard_topo_free(void *data, size_t size) 85 { 86 assert(cpuboard_mod_hdl != NULL); 87 topo_mod_free(cpuboard_mod_hdl, data, size); 88 } 89 90 static int 91 cpuboard_get_pri_info(topo_mod_t *mod, cpuboard_contents_t cpubs[]) 92 { 93 char isa[MAXNAMELEN]; 94 md_t *mdp; 95 mde_cookie_t *listp; 96 uint64_t *bufp; 97 ssize_t bufsize = 0; 98 int ncomp, num_nodes, i, len; 99 char *pstr = NULL; 100 char *sn = NULL, *pn = NULL; 101 char *dn = NULL; 102 uint32_t type = 0; 103 ldom_hdl_t *lhp; 104 uint64_t id; 105 int cpuboards_found = 0; 106 107 lhp = ldom_init(cpuboard_topo_alloc, cpuboard_topo_free); 108 if (lhp == NULL) { 109 topo_mod_dprintf(mod, "ldom_init failed\n"); 110 return (0); 111 } 112 113 (void) sysinfo(SI_MACHINE, isa, MAXNAMELEN); 114 if (strcmp(isa, "sun4v") != 0) { 115 topo_mod_dprintf(mod, "not sun4v architecture%s\n", isa); 116 ldom_fini(lhp); 117 return (0); 118 } 119 120 (void) ldom_get_type(lhp, &type); 121 if ((type & LDOM_TYPE_CONTROL) != 0) { 122 bufsize = ldom_get_core_md(lhp, &bufp); 123 } else { 124 bufsize = ldom_get_local_md(lhp, &bufp); 125 } 126 if (bufsize < 1) { 127 topo_mod_dprintf(mod, "Failed to get pri/md, bufsize=%d\n", 128 bufsize); 129 ldom_fini(lhp); 130 return (0); 131 } 132 topo_mod_dprintf(mod, "pri/md bufsize=%d\n", bufsize); 133 134 if ((mdp = md_init_intern(bufp, cpuboard_topo_alloc, 135 cpuboard_topo_free)) == NULL || 136 (num_nodes = md_node_count(mdp)) < 1) { 137 topo_mod_dprintf(mod, "md_init_intern error\n"); 138 cpuboard_topo_free(bufp, (size_t)bufsize); 139 ldom_fini(lhp); 140 return (0); 141 } 142 topo_mod_dprintf(mod, "num_nodes=%d\n", num_nodes); 143 144 if ((listp = (mde_cookie_t *)cpuboard_topo_alloc( 145 sizeof (mde_cookie_t) * num_nodes)) == NULL) { 146 topo_mod_dprintf(mod, "alloc listp error\n"); 147 cpuboard_topo_free(bufp, (size_t)bufsize); 148 (void) md_fini(mdp); 149 ldom_fini(lhp); 150 return (0); 151 } 152 ncomp = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE, 153 md_find_name(mdp, "component"), 154 md_find_name(mdp, "fwd"), listp); 155 topo_mod_dprintf(mod, "ncomp=%d\n", ncomp); 156 if (ncomp <= 0) { 157 cpuboard_topo_free(listp, sizeof (mde_cookie_t) * num_nodes); 158 cpuboard_topo_free(bufp, (size_t)bufsize); 159 (void) md_fini(mdp); 160 ldom_fini(lhp); 161 return (0); 162 } 163 for (i = 0; i < ncomp; i++) { 164 /* 165 * PRI nodes are still named "cpu-board", but the canonical 166 * names are "cpuboard". 167 */ 168 if (md_get_prop_str(mdp, listp[i], "type", &pstr) == 0 && 169 pstr != NULL && strcmp(pstr, "cpu-board") == 0) { 170 if (md_get_prop_val(mdp, listp[i], "id", &id) < 0) { 171 topo_mod_dprintf(mod, "cpuboard_get_pri_info: " 172 "id md_get_prop_val() failed. (%d: %s)\n", 173 errno, strerror(errno)); 174 continue; 175 } 176 if ((id >= CPUBOARD_MAX) || cpubs[id].present) { 177 (void) topo_mod_seterrno(mod, EMOD_NVL_INVAL); 178 topo_mod_dprintf(mod, "cpuboard_get_pri_info: " 179 "id %llx out of range. (%d: %s)\n", 180 id, errno, strerror(errno)); 181 continue; 182 } 183 cpubs[id].present = 1; 184 cpuboards_found++; 185 186 topo_mod_dprintf(mod, "got cpu-board: %llx\n", id); 187 188 sn = pn = dn = NULL; 189 190 (void) md_get_prop_str(mdp, listp[i], 191 "serial_number", &sn); 192 cpubs[id].sn = topo_mod_strdup(mod, sn); 193 194 (void) md_get_prop_str(mdp, listp[i], 195 "part_number", &pn); 196 197 (void) md_get_prop_str(mdp, listp[i], 198 "dash_number", &dn); 199 len = (pn ? strlen(pn) : 0) + (dn ? strlen(dn) : 0) + 1; 200 pstr = cpuboard_topo_alloc(len); 201 (void) snprintf(pstr, len, "%s%s", 202 pn ? pn : "", dn ? dn : ""); 203 cpubs[id].pn = topo_mod_strdup(mod, pstr); 204 cpuboard_topo_free(pstr, len); 205 } 206 } 207 cpuboard_topo_free(listp, sizeof (mde_cookie_t) * num_nodes); 208 cpuboard_topo_free(bufp, (size_t)bufsize); 209 (void) md_fini(mdp); 210 ldom_fini(lhp); 211 212 return (cpuboards_found); 213 } 214 215 /*ARGSUSED*/ 216 void 217 _topo_init(topo_mod_t *mod, topo_version_t version) 218 { 219 /* 220 * Turn on module debugging output 221 */ 222 if (getenv("TOPOCPUBOARDDBG") != NULL) { 223 topo_mod_setdebug(mod); 224 } 225 topo_mod_dprintf(mod, "initializing cpuboard enumerator\n"); 226 227 if (topo_mod_register(mod, &cpuboard_info, TOPO_VERSION) < 0) { 228 topo_mod_dprintf(mod, "cpuboard registration failed: %s\n", 229 topo_mod_errmsg(mod)); 230 return; /* mod errno already set */ 231 } 232 topo_mod_dprintf(mod, "cpuboard enumr initd\n"); 233 } 234 235 void 236 _topo_fini(topo_mod_t *mod) 237 { 238 topo_mod_unregister(mod); 239 } 240 241 static tnode_t * 242 cpuboard_tnode_create(topo_mod_t *mod, tnode_t *parent, 243 const char *name, topo_instance_t i, void *priv, cpuboard_contents_t *cpubc) 244 { 245 int err; 246 nvlist_t *fmri; 247 tnode_t *ntn; 248 nvlist_t *auth = topo_mod_auth(mod, parent); 249 250 fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i, 251 NULL, auth, cpubc->pn, NULL, cpubc->sn); 252 nvlist_free(auth); 253 254 topo_mod_strfree(mod, cpubc->sn); 255 topo_mod_strfree(mod, cpubc->pn); 256 257 cpubc->sn = cpubc->pn = NULL; 258 259 if (fmri == NULL) { 260 topo_mod_dprintf(mod, 261 "Unable to make nvlist for %s bind: %s.\n", 262 name, topo_mod_errmsg(mod)); 263 return (NULL); 264 } 265 266 ntn = topo_node_bind(mod, parent, name, i, fmri); 267 if (ntn == NULL) { 268 topo_mod_dprintf(mod, 269 "topo_node_bind (%s%d/%s%d) failed: %s\n", 270 topo_node_name(parent), topo_node_instance(parent), 271 name, i, 272 topo_strerror(topo_mod_errno(mod))); 273 nvlist_free(fmri); 274 return (NULL); 275 } 276 topo_mod_dprintf(mod, 277 "cpuboard_tnode_create: topo_node_bind (%s%d/%s%d) created!\n", 278 topo_node_name(parent), topo_node_instance(parent), name, i); 279 nvlist_free(fmri); 280 topo_node_setspecific(ntn, priv); 281 282 if (topo_pgroup_create(ntn, &cpuboard_auth_pgroup, &err) == 0) { 283 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY, 284 FM_FMRI_AUTH_PRODUCT, &err); 285 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY, 286 FM_FMRI_AUTH_PRODUCT_SN, &err); 287 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY, 288 FM_FMRI_AUTH_CHASSIS, &err); 289 (void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY, 290 FM_FMRI_AUTH_SERVER, &err); 291 } 292 293 return (ntn); 294 } 295 296 static int 297 cpuboard_fru_set(topo_mod_t *mp, tnode_t *tn) 298 { 299 nvlist_t *fmri; 300 int err, e; 301 302 if (topo_node_resource(tn, &fmri, &err) < 0 || 303 fmri == NULL) { 304 topo_mod_dprintf(mp, "FRU_fmri_set error: %s\n", 305 topo_strerror(topo_mod_errno(mp))); 306 return (topo_mod_seterrno(mp, err)); 307 } 308 e = topo_node_fru_set(tn, fmri, 0, &err); 309 nvlist_free(fmri); 310 if (e < 0) 311 return (topo_mod_seterrno(mp, err)); 312 return (0); 313 } 314 315 static int 316 cpuboard_label_set(topo_mod_t *mod, tnode_t *parent, tnode_t *node, 317 topo_instance_t n) 318 { 319 char *label = NULL; 320 char *plabel = NULL; 321 const char *cpuboard_label = "/CPU"; 322 int err, len; 323 324 if (topo_node_label(parent, &plabel, &err) != 0 || 325 plabel == NULL) { 326 return (-1); 327 } 328 329 len = strlen(plabel) + strlen(cpuboard_label) + 2; 330 label = topo_mod_alloc(mod, len); 331 (void) snprintf(label, len, "%s%s%d", plabel, cpuboard_label, n); 332 topo_mod_strfree(mod, plabel); 333 334 if (label != NULL) { 335 if (topo_prop_set_string(node, TOPO_PGROUP_PROTOCOL, 336 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, 337 &err) != 0) { 338 topo_mod_strfree(mod, label); 339 return (topo_mod_seterrno(mod, err)); 340 } 341 } 342 topo_mod_free(mod, label, len); 343 return (0); 344 } 345 346 347 /*ARGSUSED*/ 348 static tnode_t * 349 cpuboard_declare(tnode_t *parent, const char *name, topo_instance_t i, 350 void *priv, topo_mod_t *mod, cpuboard_contents_t *cpubc) 351 { 352 tnode_t *ntn; 353 nvlist_t *fmri = NULL; 354 int err; 355 356 if ((ntn = cpuboard_tnode_create(mod, parent, name, i, priv, 357 cpubc)) == NULL) { 358 topo_mod_dprintf(mod, "%s ntn = NULL\n", name); 359 return (NULL); 360 } 361 362 (void) cpuboard_fru_set(mod, ntn); 363 364 (void) cpuboard_label_set(mod, parent, ntn, i); 365 366 /* set ASRU to resource fmri */ 367 if (topo_prop_get_fmri(ntn, TOPO_PGROUP_PROTOCOL, 368 TOPO_PROP_RESOURCE, &fmri, &err) == 0) 369 (void) topo_node_asru_set(ntn, fmri, 0, &err); 370 nvlist_free(fmri); 371 372 return (ntn); 373 } 374 375 static int 376 chip_instantiate(tnode_t *parent, const char *name, topo_mod_t *mod, 377 topo_instance_t inst) 378 { 379 if (strcmp(name, CPUBOARD) != 0) { 380 topo_mod_dprintf(mod, 381 "Currently only know how to enumerate %s components.\n", 382 CPUBOARD); 383 return (0); 384 } 385 topo_mod_dprintf(mod, 386 "Calling chip_enum for inst: %lx\n", inst); 387 if (topo_mod_enumerate(mod, 388 parent, CHIP, CHIP, inst, inst, NULL) != 0) { 389 return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM)); 390 } 391 return (0); 392 } 393 394 static topo_mod_t * 395 chip_enum_load(topo_mod_t *mp) 396 { 397 topo_mod_t *rp = NULL; 398 399 topo_mod_dprintf(mp, "chip_enum_load: %s\n", CPUBOARD); 400 if ((rp = topo_mod_load(mp, CHIP, TOPO_VERSION)) == NULL) { 401 topo_mod_dprintf(mp, 402 "%s enumerator could not load %s enum. (%d: %s)\n", 403 CPUBOARD, CHIP, errno, strerror(errno)); 404 } 405 topo_mod_dprintf(mp, "chip_enum_load(EXIT): %s, rp=%p\n", CPUBOARD, rp); 406 return (rp); 407 } 408 409 static di_node_t 410 cpuboard_findrc(topo_mod_t *mod, uint64_t id) 411 { 412 di_node_t devtree; 413 di_node_t dnode; 414 415 if ((devtree = topo_mod_devinfo(mod)) == DI_NODE_NIL) { 416 topo_mod_dprintf(mod, "devinfo init failed."); 417 return (NULL); 418 } 419 dnode = di_drv_first_node(CPUBOARD_PX_DRV, devtree); 420 while (dnode != DI_NODE_NIL) { 421 char *path; 422 423 if ((path = di_devfs_path(dnode)) == NULL) { 424 topo_mod_dprintf(mod, "cpuboard_findrc: " 425 "NULL di_devfs_path.\n"); 426 (void) topo_mod_seterrno(mod, ETOPO_PROP_NOENT); 427 return (NULL); 428 } 429 topo_mod_dprintf(mod, "cpuboard_findrc: " 430 "got px %d, node named: %s, path: %s\n", 431 di_instance(dnode), di_node_name(dnode), path); 432 433 if (strcmp(cpub_rcs[id], path) == 0) { 434 di_devfs_path_free(path); 435 return (dnode); 436 } 437 438 di_devfs_path_free(path); 439 440 dnode = di_drv_next_node(dnode); 441 } 442 return (NULL); 443 } 444 445 /*ARGSUSED*/ 446 static int 447 cpuboard_enum(topo_mod_t *mod, tnode_t *parent, const char *name, 448 topo_instance_t min, topo_instance_t max, void *arg, void *notused) 449 { 450 tnode_t *cpuboardn; 451 topo_instance_t i = 0; 452 cpuboard_contents_t cpuboard_list[CPUBOARD_MAX]; 453 454 if (strcmp(name, CPUBOARD) != 0) { 455 topo_mod_dprintf(mod, 456 "Currently only know how to enumerate %s components.\n", 457 CPUBOARD); 458 return (-1); 459 } 460 /* Make sure we don't exceed CPUBOARD_MAX */ 461 if (max >= CPUBOARD_MAX) { 462 max = CPUBOARD_MAX; 463 } 464 465 bzero(cpuboard_list, sizeof (cpuboard_list)); 466 467 /* Scan PRI for cpu-boards. */ 468 cpuboard_mod_hdl = mod; 469 if (cpuboard_get_pri_info(mod, cpuboard_list) == 0) { 470 int cpuboards_found = 0; 471 /* 472 * if no PRI available (i.e. not in Control Domain), 473 * use px driver to determine cpuboard presence. 474 * NOTE: with this approach there will be no 475 * identity information - no SN nor PN. 476 */ 477 bzero(cpuboard_list, sizeof (cpuboard_list)); 478 for (i = min; i <= max; i++) { 479 if (cpuboard_findrc(mod, i) != NULL) { 480 cpuboard_list[i].present = 1; 481 cpuboards_found++; 482 } 483 } 484 if (cpuboards_found == 0) { 485 topo_mod_dprintf(mod, "No cpuboards found.\n"); 486 return (-1); 487 } 488 } 489 490 if (chip_enum_load(mod) == NULL) 491 return (-1); 492 493 for (i = min; i <= max; i++) { 494 if (cpuboard_list[i].present == 0) 495 continue; 496 497 cpuboardn = cpuboard_declare(parent, name, i, 498 NULL, mod, &cpuboard_list[i]); 499 if (cpuboardn == NULL) { 500 topo_mod_dprintf(mod, 501 "Enumeration of cpuboard failed: %s\n", 502 topo_strerror(topo_mod_errno(mod))); 503 return (-1); /* mod_errno already set */ 504 } 505 if (topo_node_range_create(mod, cpuboardn, CHIP, 0, 506 CHIP_MAX) < 0) { 507 topo_node_unbind(cpuboardn); 508 topo_mod_dprintf(mod, "topo_node_range_create CHIP " 509 "failed: %s\n", topo_strerror(topo_mod_errno(mod))); 510 return (-1); /* mod_errno already set */ 511 } 512 if (chip_instantiate(cpuboardn, CPUBOARD, mod, i) < 0) { 513 topo_mod_dprintf(mod, "Enumeration of chip " 514 "failed %s\n", 515 topo_strerror(topo_mod_errno(mod))); 516 return (-1); 517 } 518 if (topo_node_range_create(mod, cpuboardn, HOSTBRIDGE, 0, 519 HOSTBRIDGE_MAX) < 0) { 520 topo_node_unbind(cpuboardn); 521 topo_mod_dprintf(mod, "topo_node_range_create: " 522 "HOSTBRIDGE failed: %s\n", 523 topo_strerror(topo_mod_errno(mod))); 524 return (-1); 525 } 526 if (cpuboard_hb_enum(mod, cpuboard_findrc(mod, i), cpub_rcs[i], 527 cpuboardn, i) < 0) { 528 topo_node_unbind(cpuboardn); 529 topo_mod_dprintf(mod, "cpuboard_hb_enum: " 530 "failed: %s\n", 531 topo_strerror(topo_mod_errno(mod))); 532 return (-1); 533 } 534 } 535 return (0); 536 } 537