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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Subroutines used by the i86pc Generic Topology Enumerator 28 */ 29 30 #include <sys/types.h> 31 #include <strings.h> 32 #include <deflt.h> 33 #include <fcntl.h> 34 #include <unistd.h> 35 #include <fm/topo_mod.h> 36 #include <fm/topo_hc.h> 37 #include <sys/devfm.h> 38 #include <sys/pci.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(topo_mod_t *mod, smbs_cnt_t *stype) 139 { 140 const smb_struct_t *sp; 141 int nstructs; 142 int i, cnt; 143 smbios_hdl_t *shp; 144 145 shp = topo_mod_smbios(mod); 146 if (shp == NULL) { 147 stype->count = 0; 148 return; 149 } 150 151 nstructs = shp->sh_nstructs; 152 sp = shp->sh_structs; 153 154 for (i = 0, cnt = 0; i < nstructs; i++, sp++) { 155 if (sp->smbst_hdr->smbh_type == stype->type) { 156 stype->ids[cnt].node = NULL; 157 stype->ids[cnt].id = sp->smbst_hdr->smbh_hdl; 158 cnt++; 159 } 160 } 161 162 stype->count = cnt; 163 } 164 165 166 /* 167 * Calculate the authority information for a node. Inherit the data if 168 * possible, but always create an appropriate property group. 169 */ 170 int 171 x86pi_set_auth(topo_mod_t *mod, x86pi_hcfmri_t *hcfmri, tnode_t *t_parent, 172 tnode_t *t_node) 173 { 174 int result; 175 int err; 176 int is_chassis = 0; 177 int chassis_instance = 0; 178 nvlist_t *auth; 179 char *val = NULL; 180 char *prod = NULL; 181 char *psn = NULL; 182 char *csn = NULL; 183 char *server = NULL; 184 char *f = "x86pi_set_auth"; 185 186 if (mod == NULL || t_parent == NULL || t_node == NULL) { 187 return (-1); 188 } 189 190 result = topo_pgroup_create(t_node, &auth_pgroup, &err); 191 if (result != 0 && err != ETOPO_PROP_DEFD) { 192 /* 193 * We failed to create the property group and it was not 194 * already defined. Set the err code and return failure. 195 */ 196 (void) topo_mod_seterrno(mod, err); 197 return (-1); 198 } 199 200 /* Get the authority information already available from the parent */ 201 auth = topo_mod_auth(mod, t_parent); 202 203 /* Determnine if this is a chassis node and set it's instance */ 204 if ((strlen(hcfmri->hc_name) == strlen(CHASSIS)) && 205 strncmp(hcfmri->hc_name, CHASSIS, strlen(CHASSIS)) == 0) { 206 is_chassis = 1; 207 chassis_instance = hcfmri->instance; 208 } 209 210 /* 211 * Set the authority data, inheriting it if possible, but creating it 212 * if necessary. 213 */ 214 215 /* product-id */ 216 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 217 FM_FMRI_AUTH_PRODUCT, &err); 218 if (result != 0 && err != ETOPO_PROP_DEFD) { 219 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT, 220 &prod); 221 if (result != 0 || prod == NULL) { 222 /* 223 * No product information in the parent node or auth 224 * list. Use the product information in the hcfrmi 225 * struct. 226 */ 227 prod = (char *)hcfmri->product; 228 if (prod == NULL) { 229 topo_mod_dprintf(mod, "%s: product name not " 230 "found for %s node\n", f, hcfmri->hc_name); 231 } 232 } 233 234 /* 235 * We continue even if the product information is not available 236 * to enumerate as much as possible. 237 */ 238 if (prod != NULL) { 239 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 240 FM_FMRI_AUTH_PRODUCT, TOPO_PROP_IMMUTABLE, prod, 241 &err); 242 if (result != 0) { 243 /* Preserve the error and continue */ 244 (void) topo_mod_seterrno(mod, err); 245 topo_mod_dprintf(mod, "%s: failed to set " 246 "property %s (%d) : %s\n", f, 247 FM_FMRI_AUTH_PRODUCT, err, 248 topo_strerror(err)); 249 } 250 } 251 } 252 253 /* product-sn */ 254 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 255 FM_FMRI_AUTH_PRODUCT_SN, &err); 256 if (result != 0 && err != ETOPO_PROP_DEFD) { 257 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_PRODUCT_SN, 258 &psn); 259 if (result != 0 || psn == NULL) { 260 /* 261 * No product-sn information in the parent node or auth 262 * list. 263 */ 264 topo_mod_dprintf(mod, "%s: psn not found\n", f); 265 } else { 266 /* 267 * We continue even if the product-sn information is 268 * not available to enumerate as much as possible. 269 */ 270 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 271 FM_FMRI_AUTH_PRODUCT_SN, TOPO_PROP_IMMUTABLE, psn, 272 &err); 273 if (result != 0) { 274 /* Preserve the error and continue */ 275 (void) topo_mod_seterrno(mod, err); 276 topo_mod_dprintf(mod, "%s: failed to " 277 "set property %s (%d) : %s\n", f, 278 FM_FMRI_AUTH_PRODUCT_SN, err, 279 topo_strerror(err)); 280 } 281 } 282 } 283 284 /* chassis-id */ 285 if (is_chassis == 0 || (is_chassis == 1 && chassis_instance == 0)) { 286 /* either not a chassis node, or chassis #0 */ 287 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 288 FM_FMRI_AUTH_CHASSIS, &err); 289 } else { 290 /* chassis 'n' in a >1 chassis system */ 291 result = err = -1; 292 } 293 if (result != 0 && err != ETOPO_PROP_DEFD) { 294 if (is_chassis == 0) { 295 result = nvlist_lookup_string(auth, 296 FM_FMRI_AUTH_CHASSIS, &csn); 297 if (result != 0 || csn == NULL) { 298 /* 299 * No chassis information in the parent 300 * node or auth list. 301 */ 302 topo_mod_dprintf(mod, 303 "%s: csn name not found\n", f); 304 } 305 } else { 306 /* 307 * So as not to blindly set the chassis-id to 308 * chassis #0's serial number. 309 */ 310 csn = val = topo_mod_strdup(mod, hcfmri->serial_number); 311 } 312 313 /* 314 * We continue even if the chassis information is not available 315 * to enumerate as much as possible. 316 */ 317 if (csn != NULL) { 318 if (is_chassis == 1) 319 result = topo_prop_set_string(t_node, 320 FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 321 TOPO_PROP_MUTABLE, csn, &err); 322 else 323 result = topo_prop_set_string(t_node, 324 FM_FMRI_AUTHORITY, FM_FMRI_AUTH_CHASSIS, 325 TOPO_PROP_IMMUTABLE, csn, &err); 326 327 if (result != 0) { 328 /* Preserve the error and continue */ 329 (void) topo_mod_seterrno(mod, err); 330 topo_mod_dprintf(mod, "%s: failed to " 331 "set property %s (%d) : %s\n", f, 332 FM_FMRI_AUTH_CHASSIS, err, 333 topo_strerror(err)); 334 } 335 } 336 337 if (val != NULL) { 338 topo_mod_strfree(mod, val); 339 val = NULL; 340 } 341 } 342 343 /* server-id */ 344 result = topo_prop_inherit(t_node, FM_FMRI_AUTHORITY, 345 FM_FMRI_AUTH_SERVER, &err); 346 if (result != 0 && err != ETOPO_PROP_DEFD) { 347 result = nvlist_lookup_string(auth, FM_FMRI_AUTH_SERVER, 348 &server); 349 if (result != 0 || server == NULL) { 350 /* 351 * No server information in the parent node or auth 352 * list. Find the server information in hostname. 353 */ 354 server = val = x86pi_get_serverid(mod); 355 if (server == NULL) { 356 topo_mod_dprintf(mod, "%s: server " 357 "name not found for %s node\n", f, 358 hcfmri->hc_name); 359 } 360 } 361 362 /* 363 * We continue even if the server information is not available 364 * to enumerate as much as possible. 365 */ 366 if (server != NULL) { 367 result = topo_prop_set_string(t_node, FM_FMRI_AUTHORITY, 368 FM_FMRI_AUTH_SERVER, TOPO_PROP_IMMUTABLE, server, 369 &err); 370 if (result != 0) { 371 /* Preserve the error and continue */ 372 (void) topo_mod_seterrno(mod, err); 373 topo_mod_dprintf(mod, "%s: failed to " 374 "set property %s (%d) : %s\n", f, 375 FM_FMRI_AUTH_SERVER, err, 376 topo_strerror(err)); 377 } 378 } 379 380 if (val != NULL) 381 topo_mod_strfree(mod, val); 382 } 383 384 nvlist_free(auth); 385 386 return (0); 387 } 388 389 390 /* 391 * Calculate a generic FRU for the given node. If the node is not a FRU, 392 * then inherit the FRU data from the nodes parent. 393 */ 394 int 395 x86pi_set_frufmri(topo_mod_t *mod, x86pi_hcfmri_t *hcfmri, tnode_t *t_parent, 396 tnode_t *t_node, int flag) 397 { 398 int result; 399 int err; 400 401 nvlist_t *auth = NULL; 402 nvlist_t *frufmri = NULL; 403 404 if (t_node == NULL || mod == NULL) { 405 return (-1); 406 } 407 408 /* 409 * Determine if this node is a FRU 410 */ 411 if (!(flag & X86PI_ENUM_FRU)) { 412 /* This node is not a FRU. Inherit from parent and return */ 413 (void) topo_node_fru_set(t_node, NULL, 0, &result); 414 return (0); 415 } 416 417 /* 418 * This node is a FRU. Create an FMRI. 419 */ 420 auth = topo_mod_auth(mod, t_parent); 421 frufmri = topo_mod_hcfmri(mod, t_parent, FM_HC_SCHEME_VERSION, 422 hcfmri->hc_name, hcfmri->instance, NULL, auth, 423 hcfmri->part_number, hcfmri->version, hcfmri->serial_number); 424 if (frufmri == NULL) { 425 topo_mod_dprintf(mod, "failed to create FRU: %s\n", 426 topo_strerror(topo_mod_errno(mod))); 427 } 428 nvlist_free(auth); 429 430 /* Set the FRU, whether NULL or not */ 431 result = topo_node_fru_set(t_node, frufmri, 0, &err); 432 if (result != 0) { 433 (void) topo_mod_seterrno(mod, err); 434 } 435 nvlist_free(frufmri); 436 437 return (result); 438 } 439 440 441 /* 442 * Set the label for a topo node. 443 */ 444 int 445 x86pi_set_label(topo_mod_t *mod, const char *label, const char *name, 446 tnode_t *t_node) 447 { 448 int result; 449 int err; 450 451 if (mod == NULL) { 452 return (-1); 453 } 454 455 /* 456 * Set the label for this topology node. 457 * Note that a NULL label will inherit the label from topology 458 * node's parent. 459 */ 460 result = topo_node_label_set(t_node, (char *)label, &err); 461 if (result != 0) { 462 (void) topo_mod_seterrno(mod, err); 463 topo_mod_dprintf(mod, "x86pi_set_label: failed with label %s " 464 "on %s node: %s\n", (label == NULL ? "NULL" : label), 465 name, topo_strerror(err)); 466 } 467 468 return (result); 469 } 470 471 472 /* 473 * Calculate the system information for a node. Inherit the data if 474 * possible, but always create an appropriate property group. 475 */ 476 int 477 x86pi_set_system(topo_mod_t *mod, tnode_t *t_node) 478 { 479 int result; 480 int err; 481 struct utsname uts; 482 char isa[MAXNAMELEN]; 483 484 if (mod == NULL || t_node == NULL) { 485 return (-1); 486 } 487 488 result = topo_pgroup_create(t_node, &sys_pgroup, &err); 489 if (result != 0 && err != ETOPO_PROP_DEFD) { 490 /* 491 * We failed to create the property group and it was not 492 * already defined. Set the err code and return failure. 493 */ 494 (void) topo_mod_seterrno(mod, err); 495 return (-1); 496 } 497 498 result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 499 &err); 500 if (result != 0 && err != ETOPO_PROP_DEFD) { 501 isa[0] = '\0'; 502 result = sysinfo(SI_ARCHITECTURE, isa, sizeof (isa)); 503 if (result == -1) { 504 /* Preserve the error and continue */ 505 topo_mod_dprintf(mod, "x86pi_set_system: failed to " 506 "read SI_ARCHITECTURE: %d\n", errno); 507 } 508 if (strnlen(isa, MAXNAMELEN) > 0) { 509 result = topo_prop_set_string(t_node, 510 TOPO_PGROUP_SYSTEM, TOPO_PROP_ISA, 511 TOPO_PROP_IMMUTABLE, isa, &err); 512 if (result != 0) { 513 /* Preserve the error and continue */ 514 (void) topo_mod_seterrno(mod, err); 515 topo_mod_dprintf(mod, 516 "x86pi_set_auth: failed to " 517 "set property %s (%d) : %s\n", 518 TOPO_PROP_ISA, err, topo_strerror(err)); 519 } 520 } 521 } 522 523 result = topo_prop_inherit(t_node, TOPO_PGROUP_SYSTEM, 524 TOPO_PROP_MACHINE, &err); 525 if (result != 0 && err != ETOPO_PROP_DEFD) { 526 result = uname(&uts); 527 if (result == -1) { 528 /* Preserve the error and continue */ 529 (void) topo_mod_seterrno(mod, errno); 530 topo_mod_dprintf(mod, "x86pi_set_system: failed to " 531 "read uname: %d\n", errno); 532 } 533 if (strnlen(uts.machine, sizeof (uts.machine)) > 0) { 534 result = topo_prop_set_string(t_node, 535 TOPO_PGROUP_SYSTEM, TOPO_PROP_MACHINE, 536 TOPO_PROP_IMMUTABLE, uts.machine, &err); 537 if (result != 0) { 538 /* Preserve the error and continue */ 539 (void) topo_mod_seterrno(mod, err); 540 topo_mod_dprintf(mod, 541 "x86pi_set_auth: failed to " 542 "set property %s (%d) : %s\n", 543 TOPO_PROP_MACHINE, err, topo_strerror(err)); 544 } 545 } 546 } 547 548 return (0); 549 } 550 551 /* 552 * All the checks for compatibility are done within the kernel where the 553 * ereport generators are. They'll determine first if there's a problem 554 * and the topo enum will follow suit. The /dev/fm ioclt returns the value 555 * of the x86gentopo_legacy kernel variable which determines if this platform 556 * will provide an x86 generic topo or legacy topo enumeration. 557 */ 558 /* ARGSUSED */ 559 int 560 x86pi_check_comp(topo_mod_t *mod) 561 { 562 int rv; 563 int fd; 564 int32_t legacy; 565 nvlist_t *nvl = NULL; 566 fm_ioc_data_t fid; 567 char *ibuf = NULL, *obuf = NULL; 568 size_t insz = 0, outsz = 0; 569 char *f = "x86pi_check_comp"; 570 smbios_hdl_t *shp; 571 572 shp = topo_mod_smbios(mod); 573 if (shp == NULL) 574 return (X86PI_NONE); 575 576 /* open /dev/fm */ 577 fd = open("/dev/fm", O_RDONLY); 578 if (fd < 0) { 579 topo_mod_dprintf(mod, "%s: failed to open /dev/fm.\n", f); 580 return (X86PI_NONE); 581 } 582 583 /* set up buffers and ioctl data structure */ 584 outsz = FM_IOC_MAXBUFSZ; 585 obuf = topo_mod_alloc(mod, outsz); 586 if (obuf == NULL) { 587 perror("umem_alloc"); 588 return (X86PI_NONE); 589 } 590 591 fid.fid_version = 1; 592 fid.fid_insz = insz; 593 fid.fid_inbuf = ibuf; 594 fid.fid_outsz = outsz; 595 fid.fid_outbuf = obuf; 596 597 /* send the ioctl to /dev/fm to retrieve legacy variable */ 598 rv = ioctl(fd, FM_IOC_GENTOPO_LEGACY, &fid); 599 if (rv < 0) { 600 topo_mod_dprintf(mod, "%s: ioctl to /dev/fm failed", f); 601 perror("fm_ioctl"); 602 (void) close(fd); 603 return (X86PI_NONE); 604 } 605 (void) close(fd); 606 607 (void) nvlist_unpack(fid.fid_outbuf, fid.fid_outsz, &nvl, 0); 608 (void) nvlist_lookup_int32(nvl, FM_GENTOPO_LEGACY, &legacy); 609 610 nvlist_free(nvl); 611 topo_mod_free(mod, obuf, outsz); 612 613 if (legacy == 1) { 614 /* legacy kernel variable set; will do the same */ 615 return (X86PI_NONE); 616 } 617 618 /* legacy kernel variable not set; generic topo enum */ 619 return (X86PI_FULL); 620 } 621 622 const char * 623 x86pi_cleanup_smbios_str(topo_mod_t *mod, const char *begin, int str_type) 624 { 625 char buf[MAXNAMELEN]; 626 const char *end, *cp; 627 char *pp; 628 char c; 629 int i; 630 631 end = begin + strlen(begin); 632 633 while (begin < end && isspace(*begin)) 634 begin++; 635 while (begin < end && isspace(*(end - 1))) 636 end--; 637 638 if (begin >= end) 639 return (NULL); 640 641 cp = begin; 642 for (i = 0; i < MAXNAMELEN - 1; i++) { 643 if (cp >= end) 644 break; 645 c = *cp; 646 if (str_type == LABEL) { 647 if (!isprint(c)) 648 buf[i] = '-'; 649 else 650 buf[i] = c; 651 } else { 652 if (c == ':' || c == '=' || c == '/' || 653 isspace(c) || !isprint(c)) 654 buf[i] = '-'; 655 else 656 buf[i] = c; 657 } 658 cp++; 659 } 660 buf[i] = 0; 661 662 pp = topo_mod_strdup(mod, buf); 663 664 if (str_type == LABEL) 665 topo_mod_strfree(mod, (char *)begin); 666 667 return (pp); 668 } 669 670 /* 671 * Return Bus/Dev/Func from "reg" devinfo property. 672 */ 673 uint16_t 674 x86pi_bdf(topo_mod_t *mod, di_node_t node) 675 { 676 int *val; 677 678 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &val) < 0) { 679 topo_mod_dprintf(mod, "couldn't get \"reg\" prop: %s.\n", 680 strerror(errno)); 681 return ((uint16_t)-1); 682 } 683 684 return (uint16_t)((*val & PCI_REG_BDFR_M) >> PCI_REG_FUNC_SHIFT); 685 } 686 687 /* 688 * Return PHY from "sata-phy" devinfo proporty. 689 */ 690 int 691 x86pi_phy(topo_mod_t *mod, di_node_t node) 692 { 693 int *phy; 694 695 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "sata-phy", &phy) < 0) { 696 topo_mod_dprintf(mod, "couldn't get \"sata-phy\" prop: %s.\n", 697 strerror(errno)); 698 return (-1); 699 } 700 701 return (*phy); 702 } 703