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 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2020 Peter Tribble. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <alloca.h> 29 #include <unistd.h> 30 #include <ctype.h> 31 #include <string.h> 32 #include <kvm.h> 33 #include <varargs.h> 34 #include <time.h> 35 #include <dirent.h> 36 #include <fcntl.h> 37 #include <sys/param.h> 38 #include <sys/stat.h> 39 #include <sys/types.h> 40 #include <sys/utsname.h> 41 #include <sys/openpromio.h> 42 #include <libintl.h> 43 #include <syslog.h> 44 #include <sys/dkio.h> 45 #include <sys/systeminfo.h> 46 #include <picldefs.h> 47 #include <math.h> 48 #include <errno.h> 49 #include "pdevinfo.h" 50 #include "display.h" 51 #include "display_sun4v.h" 52 #include "libprtdiag.h" 53 54 #if !defined(TEXT_DOMAIN) 55 #define TEXT_DOMAIN "SYS_TEST" 56 #endif 57 58 #define MOTHERBOARD "MB" 59 #define NETWORK "network" 60 #define SUN4V_MACHINE "sun4v" 61 #define PARENT_NAMES 10 62 63 /* 64 * Additional OBP properties 65 */ 66 #define OBP_PROP_COMPATIBLE "compatible" 67 #define OBP_PROP_MODEL "model" 68 #define OBP_PROP_SLOT_NAMES "slot-names" 69 #define OBP_PROP_VERSION "version" 70 71 #define PICL_NODE_PHYSICAL_PLATFORM "physical-platform" 72 #define PICL_NODE_CHASSIS "chassis" 73 #define MEMORY_SIZE_FIELD 11 74 #define INVALID_THRESHOLD 1000000 75 76 /* 77 * Additional picl classes 78 */ 79 #ifndef PICL_CLASS_SUN4V 80 #define PICL_CLASS_SUN4V "sun4v" 81 #endif 82 83 #ifndef PICL_PROP_NAC 84 #define PICL_PROP_NAC "nac" 85 #endif 86 87 extern int sys_clk; 88 extern picl_errno_t sun4v_get_node_by_name(picl_nodehdl_t, char *, 89 picl_nodehdl_t *); 90 91 static picl_nodehdl_t rooth = 0, phyplatformh = 0; 92 static picl_nodehdl_t chassish = 0; 93 static int class_node_found; 94 static int syserrlog; 95 static int all_status_ok; 96 97 /* local functions */ 98 static int sun4v_get_first_compatible_value(picl_nodehdl_t, char **); 99 static void sun4v_display_memory_conf(picl_nodehdl_t); 100 static int sun4v_disp_env_status(); 101 static void sun4v_env_print_fan_sensors(); 102 static void sun4v_env_print_fan_indicators(); 103 static void sun4v_env_print_temp_sensors(); 104 static void sun4v_env_print_temp_indicators(); 105 static void sun4v_env_print_current_sensors(); 106 static void sun4v_env_print_current_indicators(); 107 static void sun4v_env_print_voltage_sensors(); 108 static void sun4v_env_print_voltage_indicators(); 109 static void sun4v_env_print_LEDs(); 110 static void sun4v_print_fru_status(); 111 static int is_fru_absent(picl_nodehdl_t); 112 static void sun4v_print_fw_rev(); 113 static void sun4v_print_chassis_serial_no(); 114 static int openprom_callback(picl_nodehdl_t openpromh, void *arg); 115 static void sun4v_print_openprom_rev(); 116 117 int 118 sun4v_display(Sys_tree *tree, Prom_node *root, int log, 119 picl_nodehdl_t plafh) 120 { 121 void *value; /* used for opaque PROM data */ 122 struct mem_total memory_total; /* Total memory in system */ 123 char machine[MAXSTRLEN]; 124 int exit_code = 0; 125 126 if (sysinfo(SI_MACHINE, machine, sizeof (machine)) == -1) 127 return (1); 128 if (strncmp(machine, SUN4V_MACHINE, strlen(SUN4V_MACHINE)) != 0) 129 return (1); 130 131 sys_clk = -1; /* System clock freq. (in MHz) */ 132 133 /* 134 * Now display the machine's configuration. We do this if we 135 * are not logging. 136 */ 137 if (!logging) { 138 struct utsname uts_buf; 139 140 /* 141 * Display system banner 142 */ 143 (void) uname(&uts_buf); 144 145 log_printf(dgettext(TEXT_DOMAIN, "System Configuration: " 146 "Oracle Corporation %s %s\n"), uts_buf.machine, 147 get_prop_val(find_prop(root, "banner-name")), 0); 148 149 /* display system clock frequency */ 150 value = get_prop_val(find_prop(root, "clock-frequency")); 151 if (value != NULL) { 152 sys_clk = ((*((int *)value)) + 500000) / 1000000; 153 log_printf(dgettext(TEXT_DOMAIN, "System clock " 154 "frequency: %d MHz\n"), sys_clk, 0); 155 } 156 157 /* Display the Memory Size */ 158 display_memorysize(tree, NULL, &memory_total); 159 160 /* Display the CPU devices */ 161 sun4v_display_cpu_devices(plafh); 162 163 /* Display the Memory configuration */ 164 class_node_found = 0; 165 sun4v_display_memory_conf(plafh); 166 167 /* Display all the IO cards. */ 168 (void) sun4v_display_pci(plafh); 169 sun4v_display_diaginfo((log || (logging)), root, plafh); 170 171 if (picl_get_root(&rooth) != PICL_SUCCESS) 172 return (1); 173 174 /* 175 * The physical-platform node may be missing on systems with 176 * older firmware so don't consider that an error. 177 */ 178 if (sun4v_get_node_by_name(rooth, PICL_NODE_PHYSICAL_PLATFORM, 179 &phyplatformh) != PICL_SUCCESS) 180 return (0); 181 182 if (picl_find_node(phyplatformh, PICL_PROP_CLASSNAME, 183 PICL_PTYPE_CHARSTRING, (void *)PICL_CLASS_CHASSIS, 184 strlen(PICL_CLASS_CHASSIS), &chassish) != PICL_SUCCESS) 185 return (1); 186 187 syserrlog = log; 188 exit_code = sun4v_disp_env_status(); 189 } 190 return (exit_code); 191 } 192 193 /* 194 * The binding-name property encodes the bus type. 195 */ 196 static void 197 get_bus_type(picl_nodehdl_t nodeh, struct io_card *card) 198 { 199 char val[PICL_PROPNAMELEN_MAX], *p, *q; 200 201 card->bus_type[0] = '\0'; 202 203 if (picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, val, 204 sizeof (val)) == PICL_SUCCESS) { 205 if (strstr(val, PICL_CLASS_PCIEX)) 206 (void) strlcpy(card->bus_type, "PCIE", 207 sizeof (card->bus_type)); 208 else if (strstr(val, PICL_CLASS_PCI)) 209 (void) strlcpy(card->bus_type, "PCIX", 210 sizeof (card->bus_type)); 211 else { 212 /* 213 * Not perfect: process the binding-name until 214 * we encounter something that we don't think would 215 * be part of a bus type. This may get confused a bit 216 * if a device or vendor id is encoded right after 217 * the bus class since there's no delimiter. If the 218 * id number begins with a hex digit [abcdef] then 219 * this will become part of the bus type string 220 * reported by prtdiag. This is all an effort to 221 * print something potentially useful for bus types 222 * other than PCI/PCIe. 223 * 224 * We do this because this code will get called for 225 * non-PCI class devices like the xaui (class sun4v.) 226 */ 227 if (strstr(val, "SUNW,") != NULL) 228 p = strchr(val, ',') + 1; 229 else 230 p = val; 231 q = p; 232 while (*p != '\0') { 233 if (isdigit((char)*p) || ispunct((char)*p)) { 234 *p = '\0'; 235 break; 236 } 237 *p = (char)_toupper((int)*p); 238 ++p; 239 } 240 (void) strlcpy(card->bus_type, q, 241 sizeof (card->bus_type)); 242 } 243 } 244 } 245 246 /* 247 * Fetch the Label property for this device. If none is found then 248 * search all the siblings with the same device ID for a 249 * Label and return that Label. The plug-in can only match the canonical 250 * path from the PRI with a specific devfs path. So we take care of 251 * devices with multiple functions here. A leaf device downstream of 252 * a bridge should fall out of here with PICL_PROPNOTFOUND, and the 253 * caller can walk back up the tree in search of the slot's Label. 254 */ 255 static picl_errno_t 256 get_slot_label(picl_nodehdl_t nodeh, struct io_card *card) 257 { 258 char val[PICL_PROPNAMELEN_MAX]; 259 picl_errno_t err; 260 picl_nodehdl_t pnodeh; 261 uint32_t devid, sib_devid; 262 int32_t instance; 263 264 /* 265 * If there's a Label at this node then return it - we're 266 * done. 267 */ 268 err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val, 269 sizeof (val)); 270 if (err == PICL_SUCCESS) { 271 (void) strlcpy(card->slot_str, val, sizeof (card->slot_str)); 272 return (err); 273 } else if (err != PICL_PROPNOTFOUND) 274 return (err); 275 276 /* 277 * At this point we're starting to extrapolate what the Label 278 * should be since there is none at this specific node. 279 * Note that until the value of "err" is overwritten in the 280 * loop below, its value should be PICL_PROPNOTFOUND. 281 */ 282 283 /* 284 * The device must be attached, and we can figure that out if 285 * the instance number is present and is not equal to -1. 286 * This will prevent is from returning a Label for a sibling 287 * node when the node passed in would have a unique Label if the 288 * device were attached. But if the device is downstream of a 289 * node with a Label then pci_callback() will still find that 290 * and use it. 291 */ 292 if (picl_get_propval_by_name(nodeh, PICL_PROP_INSTANCE, &instance, 293 sizeof (instance)) != PICL_SUCCESS) 294 return (err); 295 if (instance == -1) 296 return (err); 297 298 /* 299 * Narrow the search to just the one device ID. 300 */ 301 if (picl_get_propval_by_name(nodeh, PICL_PROP_DEVICE_ID, &devid, 302 sizeof (devid)) != PICL_SUCCESS) 303 return (err); 304 305 /* 306 * Go find the first child of the parent so we can search 307 * all of the siblings. 308 */ 309 if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh, 310 sizeof (pnodeh)) != PICL_SUCCESS) 311 return (err); 312 if (picl_get_propval_by_name(pnodeh, PICL_PROP_CHILD, &pnodeh, 313 sizeof (pnodeh)) != PICL_SUCCESS) 314 return (err); 315 316 /* 317 * If the child's device ID matches, then fetch the Label and 318 * return it. The first child/device ID should have a Label 319 * associated with it. 320 */ 321 do { 322 if (picl_get_propval_by_name(pnodeh, PICL_PROP_DEVICE_ID, 323 &sib_devid, sizeof (sib_devid)) == PICL_SUCCESS) { 324 if (sib_devid == devid) { 325 if ((err = picl_get_propval_by_name(pnodeh, 326 PICL_PROP_LABEL, val, sizeof (val))) == 327 PICL_SUCCESS) { 328 (void) strlcpy(card->slot_str, val, 329 sizeof (card->slot_str)); 330 break; 331 } 332 } 333 } 334 } while (picl_get_propval_by_name(pnodeh, PICL_PROP_PEER, &pnodeh, 335 sizeof (pnodeh)) == PICL_SUCCESS); 336 337 return (err); 338 } 339 340 static void 341 get_slot_number(picl_nodehdl_t nodeh, struct io_card *card) 342 { 343 picl_errno_t err; 344 picl_prophdl_t proph; 345 picl_propinfo_t pinfo; 346 picl_nodehdl_t pnodeh; 347 uint8_t *pval; 348 uint32_t dev_mask; 349 char uaddr[MAXSTRLEN]; 350 int i; 351 352 err = PICL_SUCCESS; 353 while (err == PICL_SUCCESS) { 354 if (picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &pnodeh, 355 sizeof (pnodeh)) != PICL_SUCCESS) { 356 (void) strlcpy(card->slot_str, MOTHERBOARD, 357 sizeof (card->slot_str)); 358 card->slot = -1; 359 return; 360 } 361 if (picl_get_propinfo_by_name(pnodeh, OBP_PROP_SLOT_NAMES, 362 &pinfo, &proph) == PICL_SUCCESS) { 363 break; 364 } 365 nodeh = pnodeh; 366 } 367 if (picl_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, uaddr, 368 sizeof (uaddr)) != PICL_SUCCESS) { 369 (void) strlcpy(card->slot_str, MOTHERBOARD, 370 sizeof (card->slot_str)); 371 card->slot = -1; 372 return; 373 } 374 pval = (uint8_t *)malloc(pinfo.size); 375 if (!pval) { 376 (void) strlcpy(card->slot_str, MOTHERBOARD, 377 sizeof (card->slot_str)); 378 card->slot = -1; 379 return; 380 } 381 if (picl_get_propval(proph, pval, pinfo.size) != PICL_SUCCESS) { 382 (void) strlcpy(card->slot_str, MOTHERBOARD, 383 sizeof (card->slot_str)); 384 card->slot = -1; 385 free(pval); 386 return; 387 } 388 389 dev_mask = 0; 390 for (i = 0; i < sizeof (dev_mask); i++) 391 dev_mask |= (*(pval+i) << 8*(sizeof (dev_mask)-1-i)); 392 for (i = 0; i < sizeof (uaddr) && uaddr[i] != '\0'; i++) { 393 if (uaddr[i] == ',') { 394 uaddr[i] = '\0'; 395 break; 396 } 397 } 398 card->slot = atol(uaddr); 399 if (((1 << card->slot) & dev_mask) == 0) { 400 (void) strlcpy(card->slot_str, MOTHERBOARD, 401 sizeof (card->slot_str)); 402 card->slot = -1; 403 } else { 404 char *p = (char *)(pval+sizeof (dev_mask)); 405 int shift = sizeof (uint32_t)*8-1-card->slot; 406 uint32_t x = (dev_mask << shift) >> shift; 407 int count = 0; /* count # of 1's in x */ 408 int i = 0; 409 while (x != 0) { 410 count++; 411 x &= x-1; 412 } 413 while (count > 1) { 414 while (p[i++] != '\0') 415 ; 416 count--; 417 } 418 (void) strlcpy(card->slot_str, (char *)(p+i), 419 sizeof (card->slot_str)); 420 } 421 free(pval); 422 } 423 424 /* 425 * add all io devices under pci in io list 426 */ 427 /* ARGSUSED */ 428 static int 429 sun4v_pci_callback(picl_nodehdl_t pcih, void *args) 430 { 431 char path[PICL_PROPNAMELEN_MAX]; 432 char class[PICL_CLASSNAMELEN_MAX]; 433 char name[PICL_PROPNAMELEN_MAX]; 434 char model[PICL_PROPNAMELEN_MAX]; 435 char binding_name[PICL_PROPNAMELEN_MAX]; 436 char val[PICL_PROPNAMELEN_MAX]; 437 char *compatible; 438 picl_errno_t err; 439 picl_nodehdl_t nodeh, pnodeh; 440 struct io_card pci_card; 441 442 /* Walk through the children */ 443 444 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 445 sizeof (picl_nodehdl_t)); 446 447 while (err == PICL_SUCCESS) { 448 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 449 class, sizeof (class)); 450 if (err != PICL_SUCCESS) 451 return (err); 452 453 if (args) { 454 char *val = args; 455 if (strcmp(class, val) == 0) { 456 err = picl_get_propval_by_name(nodeh, 457 PICL_PROP_PEER, &nodeh, 458 sizeof (picl_nodehdl_t)); 459 continue; 460 } else if (strcmp(val, PICL_CLASS_PCIEX) == 0 && 461 strcmp(class, PICL_CLASS_PCI) == 0) { 462 err = picl_get_propval_by_name(nodeh, 463 PICL_PROP_PEER, &nodeh, 464 sizeof (picl_nodehdl_t)); 465 continue; 466 } else if (strcmp(val, PICL_CLASS_PCI) == 0 && 467 strcmp(class, PICL_CLASS_PCIEX) == 0) { 468 err = picl_get_propval_by_name(nodeh, 469 PICL_PROP_PEER, &nodeh, 470 sizeof (picl_nodehdl_t)); 471 continue; 472 } 473 } 474 475 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH, 476 path, sizeof (path)); 477 if (err != PICL_SUCCESS) 478 return (err); 479 480 (void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes)); 481 482 pnodeh = nodeh; 483 err = get_slot_label(nodeh, &pci_card); 484 485 /* 486 * No Label at this node, maybe we're looking at a device 487 * downstream of a bridge. Walk back up and find a Label and 488 * record that node in "pnodeh". 489 */ 490 while (err != PICL_SUCCESS) { 491 if (err != PICL_PROPNOTFOUND) 492 break; 493 else if (picl_get_propval_by_name(pnodeh, 494 PICL_PROP_PARENT, &pnodeh, sizeof (pnodeh)) == 495 PICL_SUCCESS) 496 err = get_slot_label(pnodeh, &pci_card); 497 else 498 break; 499 } 500 501 /* 502 * Can't find a Label for this device in the PCI heirarchy. 503 * Try to synthesize a slot name from atoms. This depends 504 * on the OBP slot_names property being implemented, and this 505 * so far doesn't seem to be on sun4v. But just in case that 506 * is resurrected, the code is here. 507 */ 508 if (err != PICL_SUCCESS) { 509 pnodeh = nodeh; 510 get_slot_number(nodeh, &pci_card); 511 } 512 513 /* 514 * Passing in pnodeh instead of nodeh will cause prtdiag 515 * to display the type of IO slot for the leaf node. For 516 * built-in devices and a lot of IO cards these will be 517 * the same thing. But for IO cards with bridge chips or 518 * for things like expansion chassis, prtdiag will report 519 * the bus type of the IO slot and not the leaf, which 520 * could be different things. 521 */ 522 get_bus_type(pnodeh, &pci_card); 523 524 err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, name, 525 sizeof (name)); 526 if (err == PICL_PROPNOTFOUND) 527 (void) strlcpy(name, "", sizeof (name)); 528 else if (err != PICL_SUCCESS) 529 return (err); 530 531 err = picl_get_propval_by_name(nodeh, PICL_PROP_STATUS, val, 532 sizeof (val)); 533 if (err == PICL_PROPNOTFOUND) 534 (void) strlcpy(val, "", sizeof (val)); 535 else if (err != PICL_SUCCESS) 536 return (err); 537 538 (void) snprintf(pci_card.status, sizeof (pci_card.status), 539 "%s", pci_card.slot_str); 540 541 /* 542 * Get the name of this card. If binding_name is found, 543 * name will be <nodename>-<binding_name>. 544 */ 545 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, 546 binding_name, sizeof (binding_name)); 547 if (err == PICL_SUCCESS) { 548 if (strcmp(name, binding_name) != 0) { 549 (void) strlcat(name, "-", sizeof (name)); 550 (void) strlcat(name, binding_name, 551 sizeof (name)); 552 } 553 } else if (err == PICL_PROPNOTFOUND) { 554 /* 555 * if compatible prop is not found, name will be 556 * <nodename>-<compatible> 557 */ 558 err = sun4v_get_first_compatible_value(nodeh, 559 &compatible); 560 if (err == PICL_SUCCESS) { 561 (void) strlcat(name, "-", sizeof (name)); 562 (void) strlcat(name, compatible, 563 sizeof (name)); 564 free(compatible); 565 } 566 } else 567 return (err); 568 569 (void) strlcpy(pci_card.name, name, sizeof (pci_card.name)); 570 571 /* Get the model of this card */ 572 573 err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL, 574 model, sizeof (model)); 575 if (err == PICL_PROPNOTFOUND) 576 (void) strlcpy(model, "", sizeof (model)); 577 else if (err != PICL_SUCCESS) 578 return (err); 579 (void) strlcpy(pci_card.model, model, sizeof (pci_card.model)); 580 581 /* Print NAC name */ 582 log_printf("%-18s", pci_card.status); 583 /* Print IO Type */ 584 log_printf("%-6s", pci_card.bus_type); 585 /* Printf Card Name */ 586 log_printf("%-34s", pci_card.name); 587 /* Print Card Model */ 588 log_printf("%-8s", pci_card.model); 589 log_printf("\n"); 590 /* Print Status */ 591 log_printf("%-18s", val); 592 /* Print IO Type */ 593 log_printf("%-6s", ""); 594 /* Print Parent Path */ 595 log_printf("%-44s", pci_card.notes); 596 log_printf("\n"); 597 598 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 599 sizeof (picl_nodehdl_t)); 600 } 601 return (PICL_WALK_CONTINUE); 602 } 603 604 /* 605 * display_pci 606 * Display all the PCI IO cards on this board. 607 */ 608 void 609 sun4v_display_pci(picl_nodehdl_t plafh) 610 { 611 char *fmt = "%-17s %-5s %-33s %-8s"; 612 /* Have we printed the column headings? */ 613 static int banner = FALSE; 614 615 if (banner == FALSE) { 616 log_printf("\n"); 617 log_printf("================================"); 618 log_printf(" IO Devices "); 619 log_printf("================================"); 620 log_printf("\n"); 621 log_printf(fmt, "Slot +", "Bus", "Name +", "Model", 0); 622 log_printf("\n"); 623 log_printf(fmt, "Status", "Type", "Path", "", 0); 624 log_printf("\n"); 625 log_printf("---------------------------------" 626 "-------------------------------------------\n"); 627 banner = TRUE; 628 } 629 630 (void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCIEX, 631 PICL_CLASS_PCIEX, sun4v_pci_callback); 632 (void) picl_walk_tree_by_class(plafh, PICL_CLASS_PCI, 633 PICL_CLASS_PCI, sun4v_pci_callback); 634 (void) picl_walk_tree_by_class(plafh, PICL_CLASS_SUN4V, 635 PICL_CLASS_SUN4V, sun4v_pci_callback); 636 } 637 638 /* 639 * return the first compatible value 640 */ 641 static int 642 sun4v_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 643 { 644 picl_errno_t err; 645 picl_prophdl_t proph; 646 picl_propinfo_t pinfo; 647 picl_prophdl_t tblh; 648 picl_prophdl_t rowproph; 649 char *pval; 650 651 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 652 &pinfo, &proph); 653 if (err != PICL_SUCCESS) 654 return (err); 655 656 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 657 pval = malloc(pinfo.size); 658 if (pval == NULL) 659 return (PICL_FAILURE); 660 err = picl_get_propval(proph, pval, pinfo.size); 661 if (err != PICL_SUCCESS) { 662 free(pval); 663 return (err); 664 } 665 *outbuf = pval; 666 return (PICL_SUCCESS); 667 } 668 669 if (pinfo.type != PICL_PTYPE_TABLE) 670 return (PICL_FAILURE); 671 672 /* get first string from table */ 673 err = picl_get_propval(proph, &tblh, pinfo.size); 674 if (err != PICL_SUCCESS) 675 return (err); 676 677 err = picl_get_next_by_row(tblh, &rowproph); 678 if (err != PICL_SUCCESS) 679 return (err); 680 681 err = picl_get_propinfo(rowproph, &pinfo); 682 if (err != PICL_SUCCESS) 683 return (err); 684 685 pval = malloc(pinfo.size); 686 if (pval == NULL) 687 return (PICL_FAILURE); 688 689 err = picl_get_propval(rowproph, pval, pinfo.size); 690 if (err != PICL_SUCCESS) { 691 free(pval); 692 return (err); 693 } 694 695 *outbuf = pval; 696 return (PICL_SUCCESS); 697 } 698 699 /* 700 * print size of a memory segment 701 */ 702 static void 703 print_memory_segment_size(uint64_t size) 704 { 705 uint64_t kbyte = 1024; 706 uint64_t mbyte = kbyte * kbyte; 707 uint64_t gbyte = kbyte * mbyte; 708 uint64_t tbyte = kbyte * gbyte; 709 char buf[MEMORY_SIZE_FIELD]; 710 711 if (size >= tbyte) { 712 if (size % tbyte == 0) 713 (void) snprintf(buf, sizeof (buf), "%d TB", 714 (int)(size / tbyte)); 715 else 716 (void) snprintf(buf, sizeof (buf), "%.2f TB", 717 (float)size / tbyte); 718 } else if (size >= gbyte) { 719 if (size % gbyte == 0) 720 (void) snprintf(buf, sizeof (buf), "%d GB", 721 (int)(size / gbyte)); 722 else 723 (void) snprintf(buf, sizeof (buf), "%.2f GB", 724 (float)size / gbyte); 725 } else if (size >= mbyte) { 726 if (size % mbyte == 0) 727 (void) snprintf(buf, sizeof (buf), "%d MB", 728 (int)(size / mbyte)); 729 else 730 (void) snprintf(buf, sizeof (buf), "%.2f MB", 731 (float)size / mbyte); 732 } else { 733 if (size % kbyte == 0) 734 (void) snprintf(buf, sizeof (buf), "%d KB", 735 (int)(size / kbyte)); 736 else 737 (void) snprintf(buf, sizeof (buf), "%.2f KB", 738 (float)size / kbyte); 739 } 740 log_printf("%-9s", buf); 741 } 742 743 /* 744 * Enumerate banks and dimms within a memory segment. We're handed 745 * the first bank within the segment - we assume there are dimms 746 * (memory-module) nodes underneath. 747 */ 748 static void 749 print_memory_segment_contain(picl_nodehdl_t bank_nodeh) 750 { 751 char val[PICL_PROPNAMELEN_MAX]; 752 picl_nodehdl_t module_nodeh; 753 int flag = 0; 754 uint64_t size; 755 756 do { 757 if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_CHILD, 758 &module_nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) 759 continue; 760 if (picl_get_propval_by_name(bank_nodeh, PICL_PROP_SIZE, 761 &size, sizeof (size)) == PICL_SUCCESS) { 762 if (!flag) { 763 print_memory_segment_size(size); 764 } else { 765 log_printf(" " 766 " "); 767 print_memory_segment_size(size); 768 flag = 0; 769 } 770 } 771 do { 772 if (picl_get_propval_by_name(module_nodeh, 773 PICL_PROP_NAC, val, sizeof (val)) != 774 PICL_SUCCESS) 775 continue; 776 else { 777 if (!flag) { 778 log_printf("%s\n", val); 779 flag = 1; 780 } else { 781 log_printf("%s%s\n", 782 " " 783 " ", 784 val); 785 } 786 } 787 } while (picl_get_propval_by_name(module_nodeh, PICL_PROP_PEER, 788 &module_nodeh, sizeof (picl_nodehdl_t)) == 789 PICL_SUCCESS); 790 } while (picl_get_propval_by_name(bank_nodeh, PICL_PROP_PEER, 791 &bank_nodeh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS); 792 } 793 794 /* 795 * Search node where _class=="memory-segment" 796 * print "Base Address", "Size", etc 797 */ 798 /*ARGSUSED*/ 799 static int 800 sun4v_memory_conf_callback(picl_nodehdl_t nodeh, void *args) 801 { 802 uint64_t base; 803 uint64_t size; 804 uint64_t ifactor; 805 picl_errno_t err = PICL_SUCCESS; 806 807 if (class_node_found == 0) { 808 class_node_found = 1; 809 return (PICL_WALK_TERMINATE); 810 } 811 while (err == PICL_SUCCESS) { 812 err = picl_get_propval_by_name(nodeh, PICL_PROP_BASEADDRESS, 813 &base, sizeof (base)); 814 if (err != PICL_SUCCESS) 815 break; 816 err = picl_get_propval_by_name(nodeh, PICL_PROP_SIZE, 817 &size, sizeof (size)); 818 if (err != PICL_SUCCESS) 819 break; 820 err = picl_get_propval_by_name(nodeh, 821 PICL_PROP_INTERLEAVE_FACTOR, &ifactor, 822 sizeof (ifactor)); 823 if (err != PICL_SUCCESS) 824 break; 825 log_printf("0x%-13llx", base); 826 print_memory_segment_size(size); 827 log_printf("%-12lld", ifactor); 828 err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD, 829 &nodeh, sizeof (nodeh)); 830 if (err == PICL_SUCCESS) 831 print_memory_segment_contain(nodeh); 832 log_printf("\n"); 833 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 834 sizeof (picl_nodehdl_t)); 835 } 836 837 return (PICL_WALK_CONTINUE); 838 } 839 840 /*ARGSUSED*/ 841 void 842 sun4v_display_memory_conf(picl_nodehdl_t plafh) 843 { 844 char *fmt = "%-14s %-8s %-11s %-8s %-s"; 845 (void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT, 846 NULL, sun4v_memory_conf_callback); 847 if (class_node_found == 0) 848 return; 849 log_printf("\n"); 850 log_printf("======================="); 851 log_printf(" Physical Memory Configuration "); 852 log_printf("========================"); 853 log_printf("\n"); 854 log_printf("Segment Table:\n"); 855 log_printf( 856 "--------------------------------------------------------------\n"); 857 log_printf(fmt, "Base", "Segment", "Interleave", "Bank", "Contains", 0); 858 log_printf("\n"); 859 log_printf(fmt, "Address", "Size", "Factor", "Size", "Modules", 0); 860 log_printf("\n"); 861 log_printf( 862 "--------------------------------------------------------------\n"); 863 (void) picl_walk_tree_by_class(plafh, PICL_CLASS_MEMORY_SEGMENT, 864 NULL, sun4v_memory_conf_callback); 865 } 866 867 void 868 sun4v_display_cpu_devices(picl_nodehdl_t plafh) 869 { 870 char *fmt = "%-6s %-9s %-22s %-6s"; 871 872 /* 873 * Display the table header for CPUs . Then display the CPU 874 * frequency, cache size, and processor revision of all cpus. 875 */ 876 log_printf(dgettext(TEXT_DOMAIN, 877 "\n" 878 "================================" 879 " Virtual CPUs " 880 "================================" 881 "\n" 882 "\n")); 883 log_printf("\n"); 884 log_printf(fmt, "CPU ID", "Frequency", "Implementation", 885 "Status", 0); 886 log_printf("\n"); 887 log_printf(fmt, "------", "---------", 888 "----------------------", "-------", 0); 889 log_printf("\n"); 890 891 (void) picl_walk_tree_by_class(plafh, PICL_CLASS_CPU, PICL_CLASS_CPU, 892 sun4v_display_cpus); 893 } 894 895 /* 896 * Display the CPUs present on this board. 897 */ 898 /*ARGSUSED*/ 899 int 900 sun4v_display_cpus(picl_nodehdl_t cpuh, void* args) 901 { 902 int status; 903 picl_prophdl_t proph; 904 picl_prophdl_t tblh; 905 picl_prophdl_t rowproph; 906 picl_propinfo_t propinfo; 907 int *int_value; 908 int cpuid; 909 char *comp_value; 910 char *no_prop_value = " "; 911 char freq_str[MAXSTRLEN]; 912 char state[MAXSTRLEN]; 913 914 /* 915 * Get cpuid property and print it and the NAC name 916 */ 917 status = picl_get_propinfo_by_name(cpuh, OBP_PROP_CPUID, &propinfo, 918 &proph); 919 if (status == PICL_SUCCESS) { 920 status = picl_get_propval(proph, &cpuid, sizeof (cpuid)); 921 if (status != PICL_SUCCESS) { 922 log_printf("%-7s", no_prop_value); 923 } else { 924 log_printf("%-7d", cpuid); 925 } 926 } else { 927 log_printf("%-7s", no_prop_value); 928 } 929 930 clock_freq: 931 status = picl_get_propinfo_by_name(cpuh, "clock-frequency", &propinfo, 932 &proph); 933 if (status == PICL_SUCCESS) { 934 int_value = malloc(propinfo.size); 935 if (int_value == NULL) { 936 log_printf("%-10s", no_prop_value); 937 goto compatible; 938 } 939 status = picl_get_propval(proph, int_value, propinfo.size); 940 if (status != PICL_SUCCESS) { 941 log_printf("%-10s", no_prop_value); 942 } else { 943 /* Running frequency */ 944 (void) snprintf(freq_str, sizeof (freq_str), "%d MHz", 945 CLK_FREQ_TO_MHZ(*int_value)); 946 log_printf("%-10s", freq_str); 947 } 948 free(int_value); 949 } else 950 log_printf("%-10s", no_prop_value); 951 952 compatible: 953 status = picl_get_propinfo_by_name(cpuh, "compatible", &propinfo, 954 &proph); 955 if (status == PICL_SUCCESS) { 956 if (propinfo.type == PICL_PTYPE_CHARSTRING) { 957 /* 958 * Compatible Property only has 1 value 959 */ 960 comp_value = malloc(propinfo.size); 961 if (comp_value == NULL) { 962 log_printf("%-23s", no_prop_value, 0); 963 goto state; 964 } 965 status = picl_get_propval(proph, comp_value, 966 propinfo.size); 967 if (status != PICL_SUCCESS) 968 log_printf("%-23s", no_prop_value, 0); 969 else 970 log_printf("%-23s", comp_value, 0); 971 free(comp_value); 972 } else if (propinfo.type == PICL_PTYPE_TABLE) { 973 /* 974 * Compatible Property has multiple values 975 */ 976 status = picl_get_propval(proph, &tblh, propinfo.size); 977 if (status != PICL_SUCCESS) { 978 log_printf("%-23s", no_prop_value, 0); 979 goto state; 980 } 981 status = picl_get_next_by_row(tblh, &rowproph); 982 if (status != PICL_SUCCESS) { 983 log_printf("%-23s", no_prop_value, 0); 984 goto state; 985 } 986 987 status = picl_get_propinfo(rowproph, &propinfo); 988 if (status != PICL_SUCCESS) { 989 log_printf("%-23s", no_prop_value, 0); 990 goto state; 991 } 992 993 comp_value = malloc(propinfo.size); 994 if (comp_value == NULL) { 995 log_printf("%-23s", no_prop_value, 0); 996 goto state; 997 } 998 status = picl_get_propval(rowproph, comp_value, 999 propinfo.size); 1000 if (status != PICL_SUCCESS) 1001 log_printf("%-23s", no_prop_value, 0); 1002 else 1003 log_printf("%-23s", comp_value, 0); 1004 free(comp_value); 1005 } 1006 } else 1007 log_printf("%-23s", no_prop_value, 0); 1008 1009 state: 1010 status = picl_get_propinfo_by_name(cpuh, PICL_PROP_STATE, 1011 &propinfo, &proph); 1012 if (status == PICL_SUCCESS) { 1013 status = picl_get_propval(proph, state, sizeof (state)); 1014 if (status != PICL_SUCCESS) { 1015 log_printf("%-9s", no_prop_value); 1016 } else { 1017 log_printf("%-9s", state); 1018 } 1019 } else 1020 log_printf("%-9s", no_prop_value); 1021 1022 done: 1023 log_printf("\n"); 1024 return (PICL_WALK_CONTINUE); 1025 } 1026 1027 void 1028 sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh) 1029 { 1030 #ifdef lint 1031 flag = flag; 1032 root = root; 1033 plafh = plafh; 1034 #endif 1035 /* 1036 * This function is intentionally empty 1037 */ 1038 } 1039 1040 void 1041 display_boardnum(int num) 1042 { 1043 log_printf("%2d ", num, 0); 1044 } 1045 1046 static int 1047 sun4v_disp_env_status() 1048 { 1049 int exit_code = 0; 1050 1051 if (phyplatformh == 0) 1052 return (0); 1053 log_printf("\n"); 1054 log_printf("============================"); 1055 log_printf(" Environmental Status "); 1056 log_printf("============================"); 1057 log_printf("\n"); 1058 1059 class_node_found = 0; 1060 all_status_ok = 1; 1061 sun4v_env_print_fan_sensors(); 1062 exit_code |= (!all_status_ok); 1063 1064 class_node_found = 0; 1065 all_status_ok = 1; 1066 sun4v_env_print_fan_indicators(); 1067 exit_code |= (!all_status_ok); 1068 1069 class_node_found = 0; 1070 all_status_ok = 1; 1071 sun4v_env_print_temp_sensors(); 1072 exit_code |= (!all_status_ok); 1073 1074 class_node_found = 0; 1075 all_status_ok = 1; 1076 sun4v_env_print_temp_indicators(); 1077 exit_code |= (!all_status_ok); 1078 1079 class_node_found = 0; 1080 all_status_ok = 1; 1081 sun4v_env_print_current_sensors(); 1082 exit_code |= (!all_status_ok); 1083 1084 class_node_found = 0; 1085 all_status_ok = 1; 1086 sun4v_env_print_current_indicators(); 1087 exit_code |= (!all_status_ok); 1088 1089 class_node_found = 0; 1090 all_status_ok = 1; 1091 sun4v_env_print_voltage_sensors(); 1092 exit_code |= (!all_status_ok); 1093 1094 class_node_found = 0; 1095 all_status_ok = 1; 1096 sun4v_env_print_voltage_indicators(); 1097 exit_code |= (!all_status_ok); 1098 1099 class_node_found = 0; 1100 all_status_ok = 1; 1101 sun4v_env_print_LEDs(); 1102 exit_code |= (!all_status_ok); 1103 1104 class_node_found = 0; 1105 all_status_ok = 1; 1106 sun4v_print_fru_status(); 1107 exit_code |= (!all_status_ok); 1108 1109 class_node_found = 0; 1110 sun4v_print_fw_rev(); 1111 1112 class_node_found = 0; 1113 sun4v_print_openprom_rev(); 1114 1115 sun4v_print_chassis_serial_no(); 1116 1117 return (exit_code); 1118 } 1119 1120 /*ARGSUSED*/ 1121 static int 1122 sun4v_env_print_sensor_callback(picl_nodehdl_t nodeh, void *args) 1123 { 1124 char val[PICL_PROPNAMELEN_MAX]; 1125 picl_nodehdl_t parenth; 1126 char *names[PARENT_NAMES]; 1127 char *base_units[PICL_PROPNAMELEN_MAX]; 1128 char *loc; 1129 int i; 1130 char *prop; 1131 picl_errno_t err; 1132 int32_t lo_warning, lo_shutdown, lo_poweroff; 1133 int32_t hi_warning, hi_shutdown, hi_poweroff; 1134 int32_t current_val; 1135 int32_t exponent; 1136 double display_val; 1137 typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED, 1138 SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t; 1139 sensor_status_t sensor_status = SENSOR_OK; 1140 1141 if (class_node_found == 0) { 1142 class_node_found = 1; 1143 return (PICL_WALK_TERMINATE); 1144 } 1145 1146 prop = (char *)args; 1147 if (!prop) { 1148 sensor_status = SENSOR_UNKNOWN; 1149 all_status_ok = 0; 1150 } else { 1151 err = picl_get_propval_by_name(nodeh, 1152 PICL_PROP_OPERATIONAL_STATUS, val, 1153 sizeof (val)); 1154 if (err == PICL_SUCCESS) { 1155 if (strcmp(val, "disabled") == 0) { 1156 sensor_status = SENSOR_DISABLED; 1157 } 1158 } 1159 } 1160 1161 if (sensor_status != SENSOR_DISABLED && 1162 sensor_status != SENSOR_UNKNOWN) { 1163 if (picl_get_propval_by_name(nodeh, prop, ¤t_val, 1164 sizeof (current_val)) != PICL_SUCCESS) { 1165 sensor_status = SENSOR_UNKNOWN; 1166 } else { 1167 if (picl_get_propval_by_name(nodeh, 1168 PICL_PROP_LOW_WARNING, 1169 &lo_warning, sizeof (lo_warning)) != PICL_SUCCESS) 1170 lo_warning = INVALID_THRESHOLD; 1171 if (picl_get_propval_by_name(nodeh, 1172 PICL_PROP_LOW_SHUTDOWN, 1173 &lo_shutdown, sizeof (lo_shutdown)) != PICL_SUCCESS) 1174 lo_shutdown = INVALID_THRESHOLD; 1175 if (picl_get_propval_by_name(nodeh, 1176 PICL_PROP_LOW_POWER_OFF, 1177 &lo_poweroff, sizeof (lo_poweroff)) != PICL_SUCCESS) 1178 lo_poweroff = INVALID_THRESHOLD; 1179 if (picl_get_propval_by_name(nodeh, 1180 PICL_PROP_HIGH_WARNING, 1181 &hi_warning, sizeof (hi_warning)) != PICL_SUCCESS) 1182 hi_warning = INVALID_THRESHOLD; 1183 if (picl_get_propval_by_name(nodeh, 1184 PICL_PROP_HIGH_SHUTDOWN, 1185 &hi_shutdown, sizeof (hi_shutdown)) != PICL_SUCCESS) 1186 hi_shutdown = INVALID_THRESHOLD; 1187 if (picl_get_propval_by_name(nodeh, 1188 PICL_PROP_HIGH_POWER_OFF, 1189 &hi_poweroff, sizeof (hi_poweroff)) != PICL_SUCCESS) 1190 hi_poweroff = INVALID_THRESHOLD; 1191 1192 if ((lo_poweroff != INVALID_THRESHOLD && 1193 current_val <= lo_poweroff) || 1194 (hi_poweroff != INVALID_THRESHOLD && 1195 current_val >= hi_poweroff)) { 1196 sensor_status = SENSOR_FAILED; 1197 } else if ((lo_shutdown != INVALID_THRESHOLD && 1198 current_val <= lo_shutdown) || 1199 (hi_shutdown != INVALID_THRESHOLD && 1200 current_val >= hi_shutdown)) { 1201 sensor_status = SENSOR_FAILED; 1202 } else if ((lo_warning != INVALID_THRESHOLD && 1203 current_val <= lo_warning) || 1204 (hi_warning != INVALID_THRESHOLD && 1205 current_val >= hi_warning)) { 1206 sensor_status = SENSOR_WARN; 1207 } else { 1208 sensor_status = SENSOR_OK; 1209 } 1210 } 1211 } 1212 1213 if (syserrlog == 0) { 1214 if (sensor_status != SENSOR_OK && all_status_ok == 1) { 1215 all_status_ok = 0; 1216 return (PICL_WALK_TERMINATE); 1217 } 1218 if (sensor_status == SENSOR_OK) { 1219 return (PICL_WALK_CONTINUE); 1220 } 1221 } else { 1222 if (sensor_status != SENSOR_OK && all_status_ok == 1) { 1223 all_status_ok = 0; 1224 } 1225 } 1226 1227 /* 1228 * If we're here then prtdiag was invoked with "-v" or we have 1229 * a sensor that is beyond a threshold, so give them a book to 1230 * read instead of the Cliff Notes. 1231 */ 1232 err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth, 1233 sizeof (parenth)); 1234 if (err != PICL_SUCCESS) { 1235 log_printf("\n"); 1236 return (PICL_WALK_CONTINUE); 1237 } 1238 1239 /* gather up the path name for the sensor */ 1240 if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) { 1241 for (i = 0; i < PARENT_NAMES; i++) { 1242 if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == 1243 NULL) { 1244 while (--i > -1) 1245 free(names[i]); 1246 free(loc); 1247 loc = NULL; 1248 } 1249 } 1250 } 1251 i = 0; 1252 if (loc != 0) { 1253 while (err == PICL_SUCCESS) { 1254 if (parenth == phyplatformh) 1255 break; 1256 err = picl_get_propval_by_name(parenth, PICL_PROP_NAME, 1257 names[i++], PICL_PROPNAMELEN_MAX); 1258 if (err != PICL_SUCCESS) { 1259 i--; 1260 break; 1261 } 1262 if (i == PARENT_NAMES) 1263 break; 1264 err = picl_get_propval_by_name(parenth, 1265 PICL_PROP_PARENT, &parenth, sizeof (parenth)); 1266 } 1267 loc[0] = '\0'; 1268 if (--i > -1) { 1269 (void) strlcat(loc, names[i], 1270 PICL_PROPNAMELEN_MAX * PARENT_NAMES); 1271 } 1272 while (--i > -1) { 1273 (void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * 1274 PARENT_NAMES); 1275 (void) strlcat(loc, names[i], 1276 PICL_PROPNAMELEN_MAX * PARENT_NAMES); 1277 } 1278 log_printf("%-35s", loc); 1279 for (i = 0; i < PARENT_NAMES; i++) 1280 free(names[i]); 1281 free(loc); 1282 } else { 1283 log_printf("%-35s", " "); 1284 } 1285 err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, val, 1286 sizeof (val)); 1287 if (err == PICL_SUCCESS) 1288 log_printf("%-19s", val); 1289 1290 /* 1291 * Get the exponent if present, and do a little math so that 1292 * if we need to we can print a normalized value for the 1293 * sensor reading. 1294 */ 1295 if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPONENT, 1296 &exponent, sizeof (exponent)) != PICL_SUCCESS) 1297 exponent = 0; 1298 if (exponent == 0) 1299 display_val = (double)current_val; 1300 else { 1301 display_val = (double)current_val * 1302 pow((double)10, (double)exponent); 1303 1304 /* 1305 * Sometimes ILOM will scale a sensor reading but 1306 * there will be nothing to the right of the decimal 1307 * once that value is normalized. Setting the 1308 * exponent to zero will prevent the printf below 1309 * from printing extraneous zeros. Otherwise a 1310 * negative exponent is used to set the precision 1311 * for the printf. 1312 */ 1313 if ((int)display_val == display_val || exponent > 0) 1314 exponent = 0; 1315 } 1316 1317 err = picl_get_propval_by_name(nodeh, PICL_PROP_BASE_UNITS, 1318 base_units, sizeof (base_units)); 1319 if (err != PICL_SUCCESS) 1320 base_units[0] = '\0'; 1321 1322 switch (sensor_status) { 1323 case SENSOR_FAILED: 1324 log_printf("%-s", "failed ("); 1325 log_printf("%-.*f", abs(exponent), display_val); 1326 log_printf("%-s %s", base_units, ")"); 1327 break; 1328 case SENSOR_WARN: 1329 log_printf("%-s", "warning ("); 1330 log_printf("%-.*f", abs(exponent), display_val); 1331 log_printf("%-s %s", base_units, ")"); 1332 break; 1333 case SENSOR_DISABLED: 1334 log_printf("%-s", "disabled"); 1335 break; 1336 case SENSOR_OK: 1337 log_printf("%-s", "ok"); 1338 break; 1339 default: 1340 log_printf("%-s", "unknown"); 1341 break; 1342 } 1343 1344 log_printf("\n"); 1345 return (PICL_WALK_CONTINUE); 1346 } 1347 1348 /*ARGSUSED*/ 1349 static int 1350 sun4v_env_print_indicator_callback(picl_nodehdl_t nodeh, void *args) 1351 { 1352 char current_val[PICL_PROPNAMELEN_MAX]; 1353 char expected_val[PICL_PROPNAMELEN_MAX]; 1354 char label[PICL_PROPNAMELEN_MAX]; 1355 picl_nodehdl_t parenth; 1356 char *names[PARENT_NAMES]; 1357 char *loc; 1358 int i = 0; 1359 char *prop = (char *)args; 1360 picl_errno_t err = PICL_SUCCESS; 1361 typedef enum {SENSOR_OK, SENSOR_WARN, SENSOR_FAILED, 1362 SENSOR_DISABLED, SENSOR_UNKNOWN} sensor_status_t; 1363 sensor_status_t sensor_status = SENSOR_OK; 1364 1365 if (class_node_found == 0) { 1366 class_node_found = 1; 1367 return (PICL_WALK_TERMINATE); 1368 } 1369 1370 prop = (char *)args; 1371 if (!prop) { 1372 sensor_status = SENSOR_UNKNOWN; 1373 all_status_ok = 0; 1374 } else { 1375 err = picl_get_propval_by_name(nodeh, 1376 PICL_PROP_OPERATIONAL_STATUS, current_val, 1377 sizeof (current_val)); 1378 if (err == PICL_SUCCESS) { 1379 if (strcmp(current_val, "disabled") == 0) { 1380 sensor_status = SENSOR_DISABLED; 1381 } 1382 } 1383 } 1384 1385 if (sensor_status != SENSOR_DISABLED && 1386 sensor_status != SENSOR_UNKNOWN) { 1387 if (picl_get_propval_by_name(nodeh, prop, ¤t_val, 1388 sizeof (current_val)) != PICL_SUCCESS) { 1389 (void) strlcpy(current_val, "unknown", 1390 sizeof (current_val)); 1391 sensor_status = SENSOR_UNKNOWN; 1392 } else { 1393 if (picl_get_propval_by_name(nodeh, PICL_PROP_EXPECTED, 1394 &expected_val, sizeof (expected_val)) == 1395 PICL_SUCCESS) { 1396 if (strncmp(current_val, expected_val, 1397 sizeof (current_val)) == 0) { 1398 sensor_status = SENSOR_OK; 1399 } else { 1400 sensor_status = SENSOR_FAILED; 1401 } 1402 } 1403 } 1404 } 1405 1406 if (syserrlog == 0) { 1407 if (sensor_status != SENSOR_OK && all_status_ok == 1) { 1408 all_status_ok = 0; 1409 return (PICL_WALK_TERMINATE); 1410 } 1411 if (sensor_status == SENSOR_OK) { 1412 return (PICL_WALK_CONTINUE); 1413 } 1414 } else { 1415 if (sensor_status != SENSOR_OK && all_status_ok == 1) { 1416 all_status_ok = 0; 1417 } 1418 } 1419 1420 /* 1421 * If we're here then prtdiag was invoked with "-v" or we have 1422 * a sensor that is beyond a threshold, so give them a book to 1423 * read instead of the Cliff Notes. 1424 */ 1425 err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth, 1426 sizeof (parenth)); 1427 if (err != PICL_SUCCESS) { 1428 log_printf("\n"); 1429 return (PICL_WALK_CONTINUE); 1430 } 1431 if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) != NULL) { 1432 for (i = 0; i < PARENT_NAMES; i++) { 1433 if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == 1434 NULL) { 1435 while (--i > -1) 1436 free(names[i]); 1437 free(loc); 1438 loc = NULL; 1439 } 1440 } 1441 } 1442 i = 0; 1443 if (loc) { 1444 while (err == PICL_SUCCESS) { 1445 if (parenth == phyplatformh) 1446 break; 1447 err = picl_get_propval_by_name(parenth, PICL_PROP_NAME, 1448 names[i++], PICL_PROPNAMELEN_MAX); 1449 if (err != PICL_SUCCESS) { 1450 i--; 1451 break; 1452 } 1453 if (i == PARENT_NAMES) 1454 break; 1455 err = picl_get_propval_by_name(parenth, 1456 PICL_PROP_PARENT, &parenth, sizeof (parenth)); 1457 } 1458 loc[0] = '\0'; 1459 if (--i > -1) { 1460 (void) strlcat(loc, names[i], 1461 PICL_PROPNAMELEN_MAX * PARENT_NAMES); 1462 } 1463 while (--i > -1) { 1464 (void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * 1465 PARENT_NAMES); 1466 (void) strlcat(loc, names[i], 1467 PICL_PROPNAMELEN_MAX * PARENT_NAMES); 1468 } 1469 log_printf("%-35s", loc); 1470 for (i = 0; i < PARENT_NAMES; i++) 1471 free(names[i]); 1472 free(loc); 1473 } else { 1474 log_printf("%-35s", ""); 1475 } 1476 1477 err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label, 1478 sizeof (label)); 1479 if (err != PICL_SUCCESS) 1480 (void) strlcpy(label, "", sizeof (label)); 1481 log_printf("%-19s", label); 1482 1483 log_printf("%-8s", current_val); 1484 1485 log_printf("\n"); 1486 return (PICL_WALK_CONTINUE); 1487 } 1488 1489 static void 1490 sun4v_env_print_fan_sensors() 1491 { 1492 char *fmt = "%-34s %-18s %-10s\n"; 1493 /* 1494 * If there isn't any fan sensor node, return now. 1495 */ 1496 (void) picl_walk_tree_by_class(phyplatformh, 1497 PICL_CLASS_RPM_SENSOR, (void *)PICL_PROP_SPEED, 1498 sun4v_env_print_sensor_callback); 1499 if (!class_node_found) 1500 return; 1501 log_printf("Fan sensors:\n"); 1502 if (syserrlog == 0) { 1503 (void) picl_walk_tree_by_class(phyplatformh, 1504 PICL_CLASS_RPM_SENSOR, 1505 PICL_PROP_SPEED, sun4v_env_print_sensor_callback); 1506 if (all_status_ok) { 1507 log_printf("All fan sensors are OK.\n"); 1508 return; 1509 } 1510 } 1511 log_printf("-------------------------------------------------" 1512 "---------------\n"); 1513 log_printf(fmt, "Location", "Sensor", "Status", 0); 1514 log_printf("-------------------------------------------------" 1515 "---------------\n"); 1516 (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_SENSOR, 1517 PICL_PROP_SPEED, sun4v_env_print_sensor_callback); 1518 } 1519 1520 static void 1521 sun4v_env_print_fan_indicators() 1522 { 1523 char *fmt = "%-34s %-18s %-10s\n"; 1524 (void) picl_walk_tree_by_class(phyplatformh, 1525 PICL_CLASS_RPM_INDICATOR, (void *)PICL_PROP_CONDITION, 1526 sun4v_env_print_indicator_callback); 1527 if (!class_node_found) 1528 return; 1529 log_printf("\nFan indicators:\n"); 1530 if (syserrlog == 0) { 1531 (void) picl_walk_tree_by_class(phyplatformh, 1532 PICL_CLASS_RPM_INDICATOR, 1533 (void *)PICL_PROP_CONDITION, 1534 sun4v_env_print_indicator_callback); 1535 if (all_status_ok) { 1536 log_printf("All fan indicators are OK.\n"); 1537 return; 1538 } 1539 } 1540 log_printf("-------------------------------------------------" 1541 "---------------\n"); 1542 log_printf(fmt, "Location", "Sensor", "Condition", 0); 1543 log_printf("-------------------------------------------------" 1544 "---------------\n"); 1545 (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_RPM_INDICATOR, 1546 (void *)PICL_PROP_CONDITION, sun4v_env_print_indicator_callback); 1547 } 1548 1549 static void 1550 sun4v_env_print_temp_sensors() 1551 { 1552 char *fmt = "%-34s %-18s %-10s\n"; 1553 (void) picl_walk_tree_by_class(phyplatformh, 1554 PICL_CLASS_TEMPERATURE_SENSOR, 1555 (void *)PICL_PROP_TEMPERATURE, 1556 sun4v_env_print_sensor_callback); 1557 if (!class_node_found) 1558 return; 1559 1560 log_printf("\nTemperature sensors:\n"); 1561 if (syserrlog == 0) { 1562 (void) picl_walk_tree_by_class(phyplatformh, 1563 PICL_CLASS_TEMPERATURE_SENSOR, 1564 PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback); 1565 if (all_status_ok) { 1566 log_printf("All temperature sensors are OK.\n"); 1567 return; 1568 } 1569 } 1570 log_printf("-------------------------------------------------" 1571 "---------------\n"); 1572 log_printf(fmt, "Location", "Sensor", "Status", 0); 1573 log_printf("-------------------------------------------------" 1574 "---------------\n"); 1575 (void) picl_walk_tree_by_class(phyplatformh, 1576 PICL_CLASS_TEMPERATURE_SENSOR, 1577 (void *)PICL_PROP_TEMPERATURE, sun4v_env_print_sensor_callback); 1578 } 1579 1580 static void 1581 sun4v_env_print_temp_indicators() 1582 { 1583 char *fmt = "%-34s %-18s %-8s\n"; 1584 (void) picl_walk_tree_by_class(phyplatformh, 1585 PICL_CLASS_TEMPERATURE_INDICATOR, (void *)PICL_PROP_CONDITION, 1586 sun4v_env_print_indicator_callback); 1587 if (!class_node_found) 1588 return; 1589 log_printf("\nTemperature indicators:\n"); 1590 if (syserrlog == 0) { 1591 (void) picl_walk_tree_by_class(phyplatformh, 1592 PICL_CLASS_TEMPERATURE_INDICATOR, 1593 (void *)PICL_PROP_CONDITION, 1594 sun4v_env_print_indicator_callback); 1595 if (all_status_ok) { 1596 log_printf("All temperature indicators are OK.\n"); 1597 return; 1598 } 1599 } 1600 log_printf("-------------------------------------------------" 1601 "---------------\n"); 1602 log_printf(fmt, "Location", "Indicator", "Condition", 0); 1603 log_printf("-------------------------------------------------" 1604 "---------------\n"); 1605 (void) picl_walk_tree_by_class(phyplatformh, 1606 PICL_CLASS_TEMPERATURE_INDICATOR, 1607 (void *)PICL_PROP_CONDITION, 1608 sun4v_env_print_indicator_callback); 1609 } 1610 1611 static void 1612 sun4v_env_print_current_sensors() 1613 { 1614 char *fmt = "%-34s %-18s %-10s\n"; 1615 (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_CURRENT_SENSOR, 1616 (void *)PICL_PROP_CURRENT, sun4v_env_print_sensor_callback); 1617 if (!class_node_found) 1618 return; 1619 log_printf("\nCurrent sensors:\n"); 1620 if (syserrlog == 0) { 1621 (void) picl_walk_tree_by_class(phyplatformh, 1622 PICL_CLASS_CURRENT_SENSOR, 1623 PICL_PROP_CURRENT, sun4v_env_print_sensor_callback); 1624 if (all_status_ok) { 1625 log_printf("All current sensors are OK.\n"); 1626 return; 1627 } 1628 } 1629 log_printf("-------------------------------------------------" 1630 "---------------\n"); 1631 log_printf(fmt, "Location", "Sensor", "Status", 0); 1632 log_printf("-------------------------------------------------" 1633 "---------------\n"); 1634 (void) picl_walk_tree_by_class(phyplatformh, 1635 PICL_CLASS_CURRENT_SENSOR, (void *)PICL_PROP_CURRENT, 1636 sun4v_env_print_sensor_callback); 1637 } 1638 1639 static void 1640 sun4v_env_print_current_indicators() 1641 { 1642 char *fmt = "%-34s %-18s %-8s\n"; 1643 (void) picl_walk_tree_by_class(phyplatformh, 1644 PICL_CLASS_CURRENT_INDICATOR, 1645 (void *)PICL_PROP_CONDITION, 1646 sun4v_env_print_indicator_callback); 1647 if (!class_node_found) 1648 return; 1649 log_printf("\nCurrent indicators:\n"); 1650 if (syserrlog == 0) { 1651 (void) picl_walk_tree_by_class(phyplatformh, 1652 PICL_CLASS_CURRENT_INDICATOR, (void *)PICL_PROP_CONDITION, 1653 sun4v_env_print_indicator_callback); 1654 if (all_status_ok) { 1655 log_printf("All current indicators are OK.\n"); 1656 return; 1657 } 1658 } 1659 log_printf("-------------------------------------------------" 1660 "---------------\n"); 1661 log_printf(fmt, "Location", "Indicator", "Condition", 0); 1662 log_printf("-------------------------------------------------" 1663 "---------------\n"); 1664 (void) picl_walk_tree_by_class(phyplatformh, 1665 PICL_CLASS_CURRENT_INDICATOR, 1666 (void *)PICL_PROP_CONDITION, 1667 sun4v_env_print_indicator_callback); 1668 } 1669 1670 static void 1671 sun4v_env_print_voltage_sensors() 1672 { 1673 char *fmt = "%-34s %-18s %-10s\n"; 1674 (void) picl_walk_tree_by_class(phyplatformh, 1675 PICL_CLASS_VOLTAGE_SENSOR, 1676 PICL_PROP_VOLTAGE, 1677 sun4v_env_print_sensor_callback); 1678 if (!class_node_found) 1679 return; 1680 log_printf("\nVoltage sensors:\n"); 1681 if (syserrlog == 0) { 1682 (void) picl_walk_tree_by_class(phyplatformh, 1683 PICL_CLASS_VOLTAGE_SENSOR, 1684 PICL_PROP_VOLTAGE, sun4v_env_print_sensor_callback); 1685 if (all_status_ok) { 1686 log_printf("All voltage sensors are OK.\n"); 1687 return; 1688 } 1689 } 1690 log_printf("-------------------------------------------------" 1691 "---------------\n"); 1692 log_printf(fmt, "Location", "Sensor", "Status", 0); 1693 log_printf("-------------------------------------------------" 1694 "---------------\n"); 1695 (void) picl_walk_tree_by_class(phyplatformh, 1696 PICL_CLASS_VOLTAGE_SENSOR, 1697 (void *)PICL_PROP_VOLTAGE, 1698 sun4v_env_print_sensor_callback); 1699 } 1700 1701 static void 1702 sun4v_env_print_voltage_indicators() 1703 { 1704 char *fmt = "%-34s %-18s %-8s\n"; 1705 (void) picl_walk_tree_by_class(phyplatformh, 1706 PICL_CLASS_VOLTAGE_INDICATOR, 1707 (void *)PICL_PROP_CONDITION, 1708 sun4v_env_print_indicator_callback); 1709 if (!class_node_found) 1710 return; 1711 log_printf("\nVoltage indicators:\n"); 1712 if (syserrlog == 0) { 1713 (void) picl_walk_tree_by_class(phyplatformh, 1714 PICL_CLASS_VOLTAGE_INDICATOR, (void *)PICL_PROP_CONDITION, 1715 sun4v_env_print_indicator_callback); 1716 if (all_status_ok) { 1717 log_printf("All voltage indicators are OK.\n"); 1718 return; 1719 } 1720 } 1721 log_printf("-------------------------------------------------" 1722 "---------------\n"); 1723 log_printf(fmt, "Location", "Indicator", "Condition", 0); 1724 log_printf("-------------------------------------------------" 1725 "---------------\n"); 1726 (void) picl_walk_tree_by_class(phyplatformh, 1727 PICL_CLASS_VOLTAGE_INDICATOR, 1728 (void *)PICL_PROP_CONDITION, 1729 sun4v_env_print_indicator_callback); 1730 } 1731 1732 static void 1733 sun4v_env_print_LEDs() 1734 { 1735 char *fmt = "%-34s %-18s %-8s\n"; 1736 if (syserrlog == 0) 1737 return; 1738 (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED, 1739 (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback); 1740 if (!class_node_found) 1741 return; 1742 log_printf("\nLEDs:\n"); 1743 log_printf("-------------------------------------------------" 1744 "---------------\n"); 1745 log_printf(fmt, "Location", "LED", "State", 0); 1746 log_printf("-------------------------------------------------" 1747 "---------------\n"); 1748 (void) picl_walk_tree_by_class(phyplatformh, PICL_CLASS_LED, 1749 (void *)PICL_PROP_STATE, sun4v_env_print_indicator_callback); 1750 } 1751 1752 /*ARGSUSED*/ 1753 static int 1754 sun4v_print_fru_status_callback(picl_nodehdl_t nodeh, void *args) 1755 { 1756 char label[PICL_PROPNAMELEN_MAX]; 1757 char status[PICL_PROPNAMELEN_MAX]; 1758 picl_errno_t err; 1759 picl_prophdl_t proph; 1760 picl_nodehdl_t parenth; 1761 char *names[PARENT_NAMES]; 1762 char *loc; 1763 int i; 1764 1765 if (!class_node_found) { 1766 class_node_found = 1; 1767 return (PICL_WALK_TERMINATE); 1768 } 1769 err = picl_get_prop_by_name(nodeh, PICL_PROP_IS_FRU, &proph); 1770 if (err != PICL_SUCCESS) 1771 return (PICL_WALK_CONTINUE); 1772 err = picl_get_propval_by_name(nodeh, PICL_PROP_LABEL, label, 1773 sizeof (label)); 1774 if (err != PICL_SUCCESS) 1775 return (PICL_WALK_CONTINUE); 1776 err = picl_get_propval_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS, 1777 status, sizeof (status)); 1778 if (err != PICL_SUCCESS) 1779 return (PICL_WALK_CONTINUE); 1780 if (syserrlog == 0) { 1781 if (strcmp(status, "disabled") == 0) { 1782 if (all_status_ok) { 1783 all_status_ok = 0; 1784 return (PICL_WALK_TERMINATE); 1785 } 1786 } else 1787 return (PICL_WALK_CONTINUE); 1788 } else { 1789 if (all_status_ok && (strcmp(status, "disabled") == 0)) { 1790 all_status_ok = 0; 1791 } 1792 } 1793 1794 if (is_fru_absent(nodeh)) 1795 (void) strcpy(status, "Not present"); 1796 1797 err = picl_get_propval_by_name(nodeh, PICL_PROP_PARENT, &parenth, 1798 sizeof (parenth)); 1799 if (err != PICL_SUCCESS) { 1800 log_printf("\n"); 1801 return (PICL_WALK_CONTINUE); 1802 } 1803 if ((loc = (char *)malloc(PICL_PROPNAMELEN_MAX*PARENT_NAMES)) == NULL) 1804 return (PICL_WALK_TERMINATE); 1805 for (i = 0; i < PARENT_NAMES; i++) 1806 if ((names[i] = (char *)malloc(PICL_PROPNAMELEN_MAX)) == NULL) { 1807 while (--i > -1) 1808 free(names[i]); 1809 free(loc); 1810 return (PICL_WALK_TERMINATE); 1811 } 1812 i = 0; 1813 while (err == PICL_SUCCESS) { 1814 if (parenth == phyplatformh) 1815 break; 1816 err = picl_get_propval_by_name(parenth, PICL_PROP_NAME, 1817 names[i++], PICL_PROPNAMELEN_MAX); 1818 if (err != PICL_SUCCESS) { 1819 i--; 1820 break; 1821 } 1822 if (i == PARENT_NAMES) 1823 break; 1824 err = picl_get_propval_by_name(parenth, PICL_PROP_PARENT, 1825 &parenth, sizeof (parenth)); 1826 } 1827 loc[0] = '\0'; 1828 if (--i > -1) { 1829 (void) strlcat(loc, names[i], 1830 PICL_PROPNAMELEN_MAX * PARENT_NAMES); 1831 } 1832 while (--i > -1) { 1833 (void) strlcat(loc, "/", PICL_PROPNAMELEN_MAX * PARENT_NAMES); 1834 (void) strlcat(loc, names[i], 1835 PICL_PROPNAMELEN_MAX * PARENT_NAMES); 1836 } 1837 log_printf("%-35s", loc); 1838 for (i = 0; i < PARENT_NAMES; i++) 1839 free(names[i]); 1840 free(loc); 1841 log_printf("%-10s", label); 1842 log_printf("%-9s", status); 1843 log_printf("\n"); 1844 return (PICL_WALK_CONTINUE); 1845 } 1846 1847 static void 1848 sun4v_print_fru_status() 1849 { 1850 char *fmt = "%-34s %-9s %-8s\n"; 1851 1852 (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL, 1853 sun4v_print_fru_status_callback); 1854 if (!class_node_found) 1855 return; 1856 1857 log_printf("\n"); 1858 log_printf("============================"); 1859 log_printf(" FRU Status "); 1860 log_printf("============================"); 1861 log_printf("\n"); 1862 1863 if (syserrlog == 0) { 1864 (void) picl_walk_tree_by_class(phyplatformh, 1865 NULL, NULL, 1866 sun4v_print_fru_status_callback); 1867 if (all_status_ok) { 1868 log_printf("All FRUs are enabled.\n"); 1869 return; 1870 } 1871 } 1872 log_printf(fmt, "Location", "Name", "Status", 0); 1873 log_printf("------------------------------------------------------\n"); 1874 (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL, 1875 sun4v_print_fru_status_callback); 1876 } 1877 1878 /* Check the children of the FRU node for a presence indicator */ 1879 static int 1880 is_fru_absent(picl_nodehdl_t fruh) 1881 { 1882 char class [PICL_CLASSNAMELEN_MAX]; 1883 char condition [PICL_PROPNAMELEN_MAX]; 1884 picl_errno_t err; 1885 picl_nodehdl_t nodeh; 1886 1887 err = picl_get_propval_by_name(fruh, PICL_PROP_CHILD, &nodeh, 1888 sizeof (picl_nodehdl_t)); 1889 while (err == PICL_SUCCESS) { 1890 err = picl_get_propval_by_name(nodeh, 1891 PICL_PROP_CLASSNAME, class, sizeof (class)); 1892 if (err == PICL_SUCCESS && 1893 strcmp(class, "presence-indicator") == 0) { 1894 err = picl_get_propval_by_name(nodeh, 1895 PICL_PROP_CONDITION, condition, 1896 sizeof (condition)); 1897 if (err == PICL_SUCCESS) { 1898 if (strcmp(condition, "Absent") == 0) { 1899 return (1); 1900 } else { 1901 return (0); 1902 } 1903 } 1904 } 1905 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, 1906 &nodeh, sizeof (picl_nodehdl_t)); 1907 } 1908 return (0); 1909 } 1910 1911 /*ARGSUSED*/ 1912 static int 1913 sun4v_print_fw_rev_callback(picl_nodehdl_t nodeh, void *args) 1914 { 1915 char rev[PICL_PROPNAMELEN_MAX]; 1916 picl_errno_t err; 1917 1918 if (!class_node_found) { 1919 class_node_found = 1; 1920 return (PICL_WALK_TERMINATE); 1921 } 1922 1923 err = picl_get_propval_by_name(nodeh, PICL_PROP_FW_REVISION, rev, 1924 sizeof (rev)); 1925 if (err != PICL_SUCCESS) 1926 return (PICL_WALK_CONTINUE); 1927 if (strlen(rev) == 0) 1928 return (PICL_WALK_CONTINUE); 1929 log_printf("%s", rev); 1930 log_printf("\n"); 1931 return (PICL_WALK_CONTINUE); 1932 } 1933 1934 static void 1935 sun4v_print_fw_rev() 1936 { 1937 if (syserrlog == 0) 1938 return; 1939 1940 (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL, 1941 sun4v_print_fw_rev_callback); 1942 if (!class_node_found) 1943 return; 1944 1945 log_printf("\n"); 1946 log_printf("============================"); 1947 log_printf(" FW Version "); 1948 log_printf("============================"); 1949 log_printf("\n"); 1950 log_printf("Version\n"); 1951 log_printf("-------------------------------------------------" 1952 "-----------\n"); 1953 (void) picl_walk_tree_by_class(phyplatformh, NULL, NULL, 1954 sun4v_print_fw_rev_callback); 1955 } 1956 1957 static void 1958 sun4v_print_openprom_rev() 1959 { 1960 if (syserrlog == 0) 1961 return; 1962 1963 (void) picl_walk_tree_by_class(rooth, "openprom", NULL, 1964 openprom_callback); 1965 if (!class_node_found) 1966 return; 1967 1968 log_printf("\n"); 1969 log_printf("======================"); 1970 log_printf(" System PROM revisions "); 1971 log_printf("======================="); 1972 log_printf("\n"); 1973 log_printf("Version\n"); 1974 log_printf("-------------------------------------------------" 1975 "-----------\n"); 1976 (void) picl_walk_tree_by_class(rooth, "openprom", NULL, 1977 openprom_callback); 1978 } 1979 1980 /* 1981 * display the OBP and POST prom revisions (if present) 1982 */ 1983 /* ARGSUSED */ 1984 static int 1985 openprom_callback(picl_nodehdl_t openpromh, void *arg) 1986 { 1987 picl_prophdl_t proph; 1988 picl_prophdl_t tblh; 1989 picl_prophdl_t rowproph; 1990 picl_propinfo_t pinfo; 1991 char *prom_version = NULL; 1992 char *obp_version = NULL; 1993 int err; 1994 1995 if (!class_node_found) { 1996 class_node_found = 1; 1997 return (PICL_WALK_TERMINATE); 1998 } 1999 2000 err = picl_get_propinfo_by_name(openpromh, OBP_PROP_VERSION, 2001 &pinfo, &proph); 2002 if (err == PICL_PROPNOTFOUND) 2003 return (PICL_WALK_TERMINATE); 2004 else if (err != PICL_SUCCESS) 2005 return (err); 2006 2007 /* 2008 * If it's a table prop, the first element is OBP revision 2009 * The second one is POST revision. 2010 * If it's a charstring prop, the value will be only OBP revision 2011 */ 2012 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 2013 prom_version = (char *)alloca(pinfo.size); 2014 if (prom_version == NULL) 2015 return (PICL_FAILURE); 2016 err = picl_get_propval(proph, prom_version, pinfo.size); 2017 if (err != PICL_SUCCESS) 2018 return (err); 2019 log_printf("%s\n", prom_version); 2020 } 2021 2022 if (pinfo.type != PICL_PTYPE_TABLE) /* not supported type */ 2023 return (PICL_WALK_TERMINATE); 2024 2025 err = picl_get_propval(proph, &tblh, pinfo.size); 2026 if (err != PICL_SUCCESS) 2027 return (err); 2028 2029 err = picl_get_next_by_row(tblh, &rowproph); 2030 if (err == PICL_SUCCESS) { 2031 /* get first row */ 2032 err = picl_get_propinfo(rowproph, &pinfo); 2033 if (err != PICL_SUCCESS) 2034 return (err); 2035 2036 prom_version = (char *)alloca(pinfo.size); 2037 if (prom_version == NULL) 2038 return (PICL_FAILURE); 2039 2040 err = picl_get_propval(rowproph, prom_version, pinfo.size); 2041 if (err != PICL_SUCCESS) 2042 return (err); 2043 log_printf("%s\n", prom_version); 2044 2045 /* get second row */ 2046 err = picl_get_next_by_col(rowproph, &rowproph); 2047 if (err == PICL_SUCCESS) { 2048 err = picl_get_propinfo(rowproph, &pinfo); 2049 if (err != PICL_SUCCESS) 2050 return (err); 2051 2052 obp_version = (char *)alloca(pinfo.size); 2053 if (obp_version == NULL) 2054 return (PICL_FAILURE); 2055 err = picl_get_propval(rowproph, obp_version, 2056 pinfo.size); 2057 if (err != PICL_SUCCESS) 2058 return (err); 2059 log_printf("%s\n", obp_version); 2060 } 2061 } 2062 2063 return (PICL_WALK_TERMINATE); 2064 } 2065 2066 static void 2067 sun4v_print_chassis_serial_no() 2068 { 2069 char val[PICL_PROPNAMELEN_MAX]; 2070 picl_errno_t err; 2071 if (syserrlog == 0 || chassish == 0) 2072 return; 2073 2074 log_printf("\n"); 2075 log_printf("Chassis Serial Number"); 2076 log_printf("\n"); 2077 log_printf("---------------------\n"); 2078 err = picl_get_propval_by_name(chassish, PICL_PROP_SERIAL_NUMBER, 2079 val, sizeof (val)); 2080 if (err == PICL_SUCCESS) 2081 log_printf("%s", val); 2082 log_printf("\n"); 2083 } 2084