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 /* 28 * Subroutines used by the i86pc Generic Topology Enumerator 29 */ 30 31 #include <sys/types.h> 32 #include <strings.h> 33 #include <deflt.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <fm/topo_mod.h> 37 #include <fm/topo_hc.h> 38 #include <sys/devfm.h> 39 #include <sys/systeminfo.h> 40 #include <sys/fm/protocol.h> 41 #include <sys/utsname.h> 42 #include <sys/smbios.h> 43 #include <sys/smbios_impl.h> 44 #include <x86pi_impl.h> 45 46 47 static const topo_pgroup_info_t sys_pgroup = { 48 TOPO_PGROUP_SYSTEM, 49 TOPO_STABILITY_PRIVATE, 50 TOPO_STABILITY_PRIVATE, 51 1 52 }; 53 54 static const topo_pgroup_info_t auth_pgroup = { 55 FM_FMRI_AUTHORITY, 56 TOPO_STABILITY_PRIVATE, 57 TOPO_STABILITY_PRIVATE, 58 1 59 }; 60 61 62 /* 63 * Free hcfmri strings. 64 */ 65 void 66 x86pi_hcfmri_info_fini(topo_mod_t *mod, x86pi_hcfmri_t *hc) 67 { 68 if (hc->hc_name != NULL) 69 topo_mod_strfree(mod, (char *)hc->hc_name); 70 if (hc->manufacturer != NULL) 71 topo_mod_strfree(mod, (char *)hc->manufacturer); 72 if (hc->product != NULL) 73 topo_mod_strfree(mod, (char *)hc->product); 74 if (hc->version != NULL) 75 topo_mod_strfree(mod, (char *)hc->version); 76 if (hc->serial_number != NULL) 77 topo_mod_strfree(mod, (char *)hc->serial_number); 78 if (hc->asset_tag != NULL) 79 topo_mod_strfree(mod, (char *)hc->asset_tag); 80 if (hc->location != NULL) 81 topo_mod_strfree(mod, (char *)hc->location); 82 if (hc->part_number != NULL) 83 topo_mod_strfree(mod, (char *)hc->part_number); 84 } 85 86 87 /* 88 * Get the server hostname (the ID as far as the topo authority is 89 * concerned) from sysinfo and return a copy to the caller. 90 * 91 * The string must be freed with topo_mod_strfree() 92 */ 93 char * 94 x86pi_get_serverid(topo_mod_t *mod) 95 { 96 int result; 97 char hostname[MAXNAMELEN]; 98 99 topo_mod_dprintf(mod, "x86pi_get_serverid\n"); 100 101 result = sysinfo(SI_HOSTNAME, hostname, sizeof (hostname)); 102 /* Everything is freed up and it's time to return the platform-id */ 103 if (result == -1) { 104 return (NULL); 105 } 106 topo_mod_dprintf(mod, "x86pi_get_serverid: hostname = %s\n", hostname); 107 108 return (topo_mod_strdup(mod, hostname)); 109 } 110 111 112 /* 113 * Get copy of SMBIOS. 114 */ 115 smbios_hdl_t * 116 x86pi_smb_open(topo_mod_t *mod) 117 { 118 smbios_hdl_t *smb_hdl; 119 char *f = "x86pi_smb_open"; 120 121 topo_mod_dprintf(mod, "%s\n", f); 122 123 smb_hdl = topo_mod_smbios(mod); 124 if (smb_hdl == NULL) { 125 topo_mod_dprintf(mod, "%s: failed to load SMBIOS\n", f); 126 return (NULL); 127 } 128 129 return (smb_hdl); 130 } 131 132 133 /* 134 * Go through the smbios structures looking for a type. Fill in 135 * the structure count as well as the id(s) of the struct types. 136 */ 137 void 138 x86pi_smb_strcnt(smbios_hdl_t *shp, smbs_cnt_t *stype) 139 { 140 const smb_struct_t *sp = shp->sh_structs; 141 int nstructs = shp->sh_nstructs; 142 int i, cnt; 143 144 for (i = 0, cnt = 0; i < nstructs; i++, sp++) { 145 if (sp->smbst_hdr->smbh_type == stype->type) { 146 stype->ids[cnt].node = NULL; 147 stype->ids[cnt].id = sp->smbst_hdr->smbh_hdl; 148 cnt++; 149 } 150 } 151 152 stype->count = cnt; 153 } 154 155 156 /* 157 * Calculate the authority information for a node. Inherit the data if 158 * possible, but always create an appropriate property group. 159 */ 160 int 161 x86pi_set_auth(topo_mod_t *mod, x86pi_hcfmri_t *hcfmri, tnode_t *t_parent, 162 tnode_t *t_node) 163 { 164 int result; 165 int err; 166 int is_chassis = 0; 167 int chassis_instance = 0; 168 nvlist_t *auth; 169 char *val = NULL; 170 char *prod = NULL; 171 char *psn = NULL; 172 char *csn = NULL; 173 char *server = NULL; 174 char *f = "x86pi_set_auth"; 175 176 if (mod == NULL || t_parent == NULL || t_node == NULL) { 177 return (-1); 178 } 179 180 result = topo_pgroup_create(t_node, &auth_pgroup, &err); 181 if (result != 0 && err != ETOPO_PROP_DEFD) { 182 /* 183 * We failed to create the property group and it was not 184 * already defined. Set the err code and return failure. 185 */ 186 topo_mod_seterrno(mod, err); 187 return (-1); 188 } 189 190 /* Get the authority information already available from the parent */ 191 auth = topo_mod_auth(mod, t_parent); 192 193 /* Determnine if this is a chassis node and set it's instance */ 194 if ((strlen(hcfmri->hc_name) == strlen(CHASSIS)) && 195 strncmp(hcfmri->hc_name, CHASSIS, strlen(CHASSIS)) == 0) { 196 is_chassis = 1; 197 chassis_instance = hcfmri->instance; 198 } 199 200 /* 201 * Set the authority data, inheriting it if possible, but creating it 202 * if necessary. 203 */ 204 205 /* product-id */ 206 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 207 FM_FMRI_AUTH_PRODUCT, &err); 208 if (result != 0 && err != ETOPO_PROP_DEFD) { 209 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, 210 &prod); 211 if (result != 0 || prod == NULL) { 212 /* 213 * No product information in the parent node or auth 214 * list. Use the product information in the hcfrmi 215 * struct. 216 */ 217 prod = (char *)hcfmri->product; 218 if (prod == NULL) { 219 topo_mod_dprintf(mod, "%s: product name not " 220 "found for %s node\n", f, hcfmri->hc_name); 221 } 222 } 223 224 /* 225 * We continue even if the product information is not available 226 * to enumerate as much as possible. 227 */ 228 if (prod != NULL) { 229 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 230 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 231 &err); 232 if (result != 0) { 233 /* Preserve the error and continue */ 234 topo_mod_seterrno(mod, err); 235 topo_mod_dprintf(mod, "%s: failed to set " 236 "property %s (%d) : %s\n", f, 237 FM_FMRI_AUTH_PRODUCT, err, 238 topo_strerror(err)); 239 } 240 } 241 } 242 243 /* product-sn */ 244 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 245 FM_FMRI_AUTH_PRODUCT_SN, &err); 246 if (result != 0 && err != ETOPO_PROP_DEFD) { 247 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, 248 &psn); 249 if (result != 0 || psn == NULL) { 250 /* 251 * No product-sn information in the parent node or auth 252 * list. 253 */ 254 topo_mod_dprintf(mod, "%s: psn not found\n", f); 255 } else { 256 /* 257 * We continue even if the product-sn information is 258 * not available to enumerate as much as possible. 259 */ 260 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 261 FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn, 262 &err); 263 if (result != 0) { 264 /* Preserve the error and continue */ 265 topo_mod_seterrno(mod, err); 266 topo_mod_dprintf(mod, "%s: failed to " 267 "set property %s (%d) : %s\n", f, 268 FM_FMRI_AUTH_PRODUCT_SN, err, 269 topo_strerror(err)); 270 } 271 } 272 } 273 274 /* chassis-id */ 275 if (is_chassis == 0 || (is_chassis == 1 && chassis_instance == 0)) { 276 /* either not a chassis node, or chassis #0 */ 277 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 278 FM_FMRI_AUTH_CHASSIS, &err); 279 } else { 280 /* chassis 'n' in a >1 chassis system */ 281 result = err = -1; 282 } 283 if (result != 0 && err != ETOPO_PROP_DEFD) { 284 if (is_chassis == 0) { 285 result = nvlist_lookup_string(auth, 286 FM_FMRI_AUTH_CHASSIS, &csn); 287 if (result != 0 || csn == NULL) { 288 /* 289 * No chassis information in the parent 290 * node or auth list. 291 */ 292 topo_mod_dprintf(mod, 293 "%s: csn name not found\n", f); 294 } 295 } else { 296 /* 297 * So as not to blindly set the chassis-id to 298 * chassis #0's serial number. 299 */ 300 csn = val = topo_mod_strdup(mod, hcfmri->serial_number); 301 } 302 303 /* 304 * We continue even if the chassis information is not available 305 * to enumerate as much as possible. 306 */ 307 if (csn != NULL) { 308 if (is_chassis == 1) 309 result = topo_prop_set_string(t_node, 310 FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 311 TOPO_PROP_MUTABLE, csn, &err); 312 else 313 result = topo_prop_set_string(t_node, 314 FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 315 TOPO_PROP_IMMUTABLE, csn, &err); 316 317 if (result != 0) { 318 /* Preserve the error and continue */ 319 topo_mod_seterrno(mod, err); 320 topo_mod_dprintf(mod, "%s: failed to " 321 "set property %s (%d) : %s\n", f, 322 FM_FMRI_AUTH_CHASSIS, err, 323 topo_strerror(err)); 324 } 325 } 326 327 if (val != NULL) { 328 topo_mod_strfree(mod, val); 329 val = NULL; 330 } 331 } 332 333 /* server-id */ 334 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 335 FM_FMRI_AUTH_SERVER, &err); 336 if (result != 0 && err != ETOPO_PROP_DEFD) { 337 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, 338 &server); 339 if (result != 0 || server == NULL) { 340 /* 341 * No server information in the parent node or auth 342 * list. Find the server information in hostname. 343 */ 344 server = val = x86pi_get_serverid(mod); 345 if (server == NULL) { 346 topo_mod_dprintf(mod, "%s: server " 347 "name not found for %s node\n", f, 348 hcfmri->hc_name); 349 } 350 } 351 352 /* 353 * We continue even if the server information is not available 354 * to enumerate as much as possible. 355 */ 356 if (server != NULL) { 357 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 358 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 359 &err); 360 if (result != 0) { 361 /* Preserve the error and continue */ 362 topo_mod_seterrno(mod, err); 363 topo_mod_dprintf(mod, "%s: failed to " 364 "set property %s (%d) : %s\n", f, 365 FM_FMRI_AUTH_SERVER, err, 366 topo_strerror(err)); 367 } 368 } 369 370 if (val != NULL) 371 topo_mod_strfree(mod, val); 372 } 373 374 nvlist_free(auth); 375 376 return (0); 377 } 378 379 380 /* 381 * Calculate a generic FRU for the given node. If the node is not a FRU, 382 * then inherit the FRU data from the nodes parent. 383 */ 384 int 385 x86pi_set_frufmri(topo_mod_t *mod, x86pi_hcfmri_t *hcfmri, tnode_t *t_parent, 386 tnode_t *t_node, int flag) 387 { 388 int result; 389 int err; 390 391 nvlist_t *auth = NULL; 392 nvlist_t *frufmri = NULL; 393 394 if (t_node == NULL || mod == NULL) { 395 return (-1); 396 } 397 398 /* 399 * Determine if this node is a FRU 400 */ 401 if (!(flag & X86PI_ENUM_FRU)) { 402 /* This node is not a FRU. Inherit from parent and return */ 403 topo_node_fru_set(t_node, NULL, 0, &result); 404 return (0); 405 } 406 407 /* 408 * This node is a FRU. Create an FMRI. 409 */ 410 auth = topo_mod_auth(mod, t_parent); 411 frufmri = topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION, 412 hcfmri->hc_name, hcfmri->instance, NULL, auth, 413 hcfmri->part_number, hcfmri->version, hcfmri->serial_number); 414 if (frufmri == NULL) { 415 topo_mod_dprintf(mod, "failed to create FRU: %s\n", 416 topo_strerror(topo_mod_errno(mod))); 417 } 418 nvlist_free(auth); 419 420 /* Set the FRU, whether NULL or not */ 421 result = topo_node_fru_set(t_node, frufmri, 0, &err); 422 if (result != 0) { 423 topo_mod_seterrno(mod, err); 424 } 425 nvlist_free(frufmri); 426 427 return (result); 428 } 429 430 431 /* 432 * Set the label for a topo node. 433 */ 434 int 435 x86pi_set_label(topo_mod_t *mod, const char *label, const char *name, 436 tnode_t *t_node) 437 { 438 int result; 439 int err; 440 441 if (mod == NULL) { 442 return (-1); 443 } 444 445 /* 446 * Set the label for this topology node. 447 * Note that a NULL label will inherit the label from topology 448 * node's parent. 449 */ 450 result = topo_node_label_set(t_node, (char *)label, &err); 451 if (result != 0) { 452 topo_mod_seterrno(mod, err); 453 topo_mod_dprintf(mod, "x86pi_set_label: failed with label %s " 454 "on %s node: %s\n", (label == NULL ? "NULL" : label), 455 name, topo_strerror(err)); 456 } 457 458 return (result); 459 } 460 461 462 /* 463 * Calculate the system information for a node. Inherit the data if 464 * possible, but always create an appropriate property group. 465 */ 466 int 467 x86pi_set_system(topo_mod_t *mod, tnode_t *t_node) 468 { 469 int result; 470 int err; 471 struct utsname uts; 472 char isa[MAXNAMELEN]; 473 474 if (mod == NULL || t_node == NULL) { 475 return (-1); 476 } 477 478 result = topo_pgroup_create(t_node, &sys_pgroup, &err); 479 if (result != 0 && err != ETOPO_PROP_DEFD) { 480 /* 481 * We failed to create the property group and it was not 482 * already defined. Set the err code and return failure. 483 */ 484 topo_mod_seterrno(mod, err); 485 return (-1); 486 } 487 488 result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 489 &err); 490 if (result != 0 && err != ETOPO_PROP_DEFD) { 491 isa[0] = '\0'; 492 result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)); 493 if (result == -1) { 494 /* Preserve the error and continue */ 495 topo_mod_dprintf(mod, "x86pi_set_system: failed to " 496 "read SI_ARCHITECTURE: %d\n", errno); 497 } 498 if (strnlen(isa, MAXNAMELEN) > 0) { 499 result = topo_prop_set_string(t_node, 500 TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 501 TOPO_PROP_IMMUTABLE, isa, &err); 502 if (result != 0) { 503 /* Preserve the error and continue */ 504 topo_mod_seterrno(mod, err); 505 topo_mod_dprintf(mod, 506 "x86pi_set_auth: failed to " 507 "set property %s (%d) : %s\n", 508 TOPO_PROP_ISA, err, topo_strerror(err)); 509 } 510 } 511 } 512 513 result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, 514 TOPO_PROP_MACHINE, &err); 515 if (result != 0 && err != ETOPO_PROP_DEFD) { 516 result = uname(&uts); 517 if (result == -1) { 518 /* Preserve the error and continue */ 519 topo_mod_seterrno(mod, errno); 520 topo_mod_dprintf(mod, "x86pi_set_system: failed to " 521 "read uname: %d\n", errno); 522 } 523 if (strnlen(uts.machine, sizeof (uts.machine)) > 0) { 524 result = topo_prop_set_string(t_node, 525 TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, 526 TOPO_PROP_IMMUTABLE, uts.machine, &err); 527 if (result != 0) { 528 /* Preserve the error and continue */ 529 topo_mod_seterrno(mod, err); 530 topo_mod_dprintf(mod, 531 "x86pi_set_auth: failed to " 532 "set property %s (%d) : %s\n", 533 TOPO_PROP_MACHINE, err, topo_strerror(err)); 534 } 535 } 536 } 537 538 return (0); 539 } 540 541 /* 542 * All the checks for compatibility are done within the kernel where the 543 * ereport generators are. They'll determine first if there's a problem 544 * and the topo enum will follow suit. The /dev/fm ioclt returns the value 545 * of the x86gentopo_legacy kernel variable which determines if this platform 546 * will provide an x86 generic topo or legacy topo enumeration. 547 */ 548 /* ARGSUSED */ 549 int 550 x86pi_check_comp(topo_mod_t *mod, smbios_hdl_t *shp) 551 { 552 int rv; 553 int fd; 554 int32_t legacy; 555 nvlist_t *nvl = NULL; 556 fm_ioc_data_t fid; 557 char *ibuf = NULL, *obuf = NULL; 558 size_t insz = 0, outsz = 0; 559 char *f = "x86pi_check_comp"; 560 561 /* open /dev/fm */ 562 fd = open("/dev/fm", O_RDONLY); 563 if (fd < 0) { 564 topo_mod_dprintf(mod, "%s: failed to open /dev/fm.\n", f); 565 return (X86PI_NONE); 566 } 567 568 /* set up buffers and ioctl data structure */ 569 outsz = FM_IOC_MAXBUFSZ; 570 obuf = topo_mod_alloc(mod, outsz); 571 if (obuf == NULL) { 572 perror("umem_alloc"); 573 return (X86PI_NONE); 574 } 575 576 fid.fid_version = 1; 577 fid.fid_insz = insz; 578 fid.fid_inbuf = ibuf; 579 fid.fid_outsz = outsz; 580 fid.fid_outbuf = obuf; 581 582 /* send the ioctl to /dev/fm to retrieve legacy variable */ 583 rv = ioctl(fd, FM_IOC_GENTOPO_LEGACY, &fid); 584 if (rv < 0) { 585 topo_mod_dprintf(mod, "%s: ioctl to /dev/fm failed", f); 586 perror("fm_ioctl"); 587 (void) close(fd); 588 return (X86PI_NONE); 589 } 590 (void) close(fd); 591 592 (void) nvlist_unpack(fid.fid_outbuf, fid.fid_outsz, &nvl, 0); 593 (void) nvlist_lookup_int32(nvl, FM_GENTOPO_LEGACY, &legacy); 594 595 nvlist_free(nvl); 596 topo_mod_free(mod, obuf, outsz); 597 598 if (legacy == 1) { 599 /* legacy kernel variable set; will do the same */ 600 return (X86PI_NONE); 601 } 602 603 /* legacy kernel variable not set; generic topo enum */ 604 return (X86PI_FULL); 605 } 606 607 const char * 608 x86pi_cleanup_smbios_str(topo_mod_t *mod, const char *begin, int str_type) 609 { 610 char buf[MAXNAMELEN]; 611 const char *end, *cp; 612 char *pp; 613 char c; 614 int i; 615 616 end = begin + strlen(begin); 617 618 while (begin < end && isspace(*begin)) 619 begin++; 620 while (begin < end && isspace(*(end - 1))) 621 end--; 622 623 if (begin >= end) 624 return (NULL); 625 626 cp = begin; 627 for (i = 0; i < MAXNAMELEN - 1; i++) { 628 if (cp >= end) 629 break; 630 c = *cp; 631 if (str_type == LABEL) { 632 if (!isprint(c)) 633 buf[i] = '-'; 634 else 635 buf[i] = c; 636 } else { 637 if (c == ':' || c == '=' || c == '/' || 638 isspace(c) || !isprint(c)) 639 buf[i] = '-'; 640 else 641 buf[i] = c; 642 } 643 cp++; 644 } 645 buf[i] = 0; 646 647 pp = topo_mod_strdup(mod, buf); 648 649 if (str_type == LABEL) 650 topo_mod_strfree(mod, (char *)begin); 651 652 return (pp); 653 } 654