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