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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Sun4v Platform specific functions. 28 * 29 * called when : 30 * machine_type == ontario 31 * 32 */ 33 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <unistd.h> 39 #include <kstat.h> 40 #include <fcntl.h> 41 #include <string.h> 42 #include <assert.h> 43 #include <libintl.h> 44 #include <note.h> 45 #include <sys/systeminfo.h> 46 #include <sys/openpromio.h> 47 #include <sys/sysmacros.h> 48 #include <picl.h> 49 #include "picldefs.h" 50 #include <pdevinfo.h> 51 #include <display.h> 52 #include <display_sun4v.h> 53 #include <libprtdiag.h> 54 #include "ontario.h" 55 #include "erie.h" 56 #include "pelton.h" 57 58 #if !defined(TEXT_DOMAIN) 59 #define TEXT_DOMAIN "SYS_TEST" 60 #endif 61 62 /* 63 * these functions will overlay the symbol table of libprtdiag 64 * at runtime 65 */ 66 void sun4v_display_pci(picl_nodehdl_t plafh); 67 void sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh); 68 69 70 /* local functions */ 71 static void sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh); 72 static int ontario_pci_callback(picl_nodehdl_t pcih, void *args); 73 static int ontario_get_first_compatible_value(picl_nodehdl_t nodeh, 74 char **outbuf); 75 static int64_t ontario_get_int_propval(picl_nodehdl_t modh, char *prop_name, 76 int *ret); 77 78 static void 79 get_bus_type(char *path, struct io_card *card) 80 { 81 if (strncmp(path, PCIX_SLOT0, PCIX_COMP_NUM) == 0) { 82 (void) strcpy(card->bus_type, "PCIX"); 83 } else { 84 (void) strcpy(card->bus_type, "PCIE"); 85 } 86 } 87 88 static void 89 get_slot_number(char *path, struct io_card *card) 90 { 91 if (strncmp(path, PCIE_SLOT0, PCIE_COMP_NUM) == 0) { 92 (void) strcpy(card->slot_str, "0"); 93 card->slot = 0; 94 } else if (strncmp(path, PCIE_SLOT1, PCIE_COMP_NUM) == 0) { 95 (void) strcpy(card->slot_str, "1"); 96 card->slot = 1; 97 } else if (strncmp(path, PCIE_SLOT2, PCIE_COMP_NUM) == 0) { 98 (void) strcpy(card->slot_str, "2"); 99 card->slot = 2; 100 } else if (strncmp(path, PCIX_SLOT1, strlen(PCIX_SLOT1)) == 0) { 101 (void) strcpy(card->slot_str, "PCIX"); 102 card->slot = -1; 103 } else if (strncmp(path, PCIX_SLOT0, strlen(PCIX_SLOT0)) == 0) { 104 (void) strcpy(card->slot_str, "PCIX"); 105 card->slot = -1; 106 } else { 107 (void) strcpy(card->slot_str, IOBOARD); 108 card->slot = -1; 109 } 110 } 111 112 static int 113 ontario_get_network_instance(char *path) 114 { 115 if (strncmp(path, NETWORK_1_PATH, strlen(NETWORK_1_PATH)) == 0) { 116 return (1); 117 } else if (strncmp(path, NETWORK_3_PATH, strlen(NETWORK_3_PATH)) == 0) { 118 return (3); 119 } else if (strncmp(path, NETWORK_0_PATH, strlen(NETWORK_0_PATH)) == 0) { 120 return (0); 121 } else if (strncmp(path, NETWORK_2_PATH, strlen(NETWORK_2_PATH)) == 0) { 122 return (2); 123 } else { 124 return (-1); 125 } 126 } 127 /* 128 * add all io devices under pci in io list 129 */ 130 /* ARGSUSED */ 131 static int 132 ontario_pci_callback(picl_nodehdl_t pcih, void *args) 133 { 134 int err = PICL_SUCCESS; 135 picl_nodehdl_t nodeh; 136 char path[MAXSTRLEN]; 137 char parent_path[MAXSTRLEN]; 138 char piclclass[PICL_CLASSNAMELEN_MAX]; 139 char name[MAXSTRLEN]; 140 char model[MAXSTRLEN]; 141 char *compatible; 142 char binding_name[MAXSTRLEN]; 143 struct io_card pci_card; 144 int32_t instance; 145 146 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path, 147 sizeof (parent_path)); 148 if (err != PICL_SUCCESS) { 149 return (err); 150 } 151 152 /* Walk through the children */ 153 154 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 155 sizeof (picl_nodehdl_t)); 156 157 while (err == PICL_SUCCESS) { 158 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 159 piclclass, sizeof (piclclass)); 160 if (err != PICL_SUCCESS) 161 return (err); 162 163 if (strcmp(piclclass, "pciex") == 0) { 164 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, 165 &nodeh, sizeof (picl_nodehdl_t)); 166 continue; 167 } 168 169 if (strcmp(piclclass, PICL_CLASS_PCI) == 0) { 170 err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD, 171 &nodeh, sizeof (picl_nodehdl_t)); 172 continue; 173 } 174 175 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH, 176 path, sizeof (path)); 177 if (err != PICL_SUCCESS) { 178 return (err); 179 } 180 181 (void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes)); 182 183 get_bus_type(parent_path, &pci_card); 184 185 get_slot_number(parent_path, &pci_card); 186 187 err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name, 188 sizeof (name)); 189 if (err == PICL_PROPNOTFOUND) 190 (void) strcpy(name, ""); 191 else if (err != PICL_SUCCESS) 192 return (err); 193 194 /* Figure NAC name */ 195 if ((strcmp(name, NETWORK) == 0) && 196 (strcmp(pci_card.slot_str, IOBOARD) == 0)) { 197 instance = ontario_get_network_instance(path); 198 199 (void) snprintf(pci_card.status, 200 sizeof (pci_card.status), "%s/%s%d", IOBOARD, 201 "NET", instance); 202 } else { 203 if (pci_card.slot != -1) { 204 (void) snprintf(pci_card.status, 205 sizeof (pci_card.status), "%s/%s%d", 206 IOBOARD, pci_card.bus_type, pci_card.slot); 207 } else { 208 (void) snprintf(pci_card.status, 209 sizeof (pci_card.status), "%s/%s", IOBOARD, 210 pci_card.bus_type); 211 } 212 } 213 214 /* 215 * Get the name of this card. If binding_name is found, 216 * name will be <nodename>-<binding_name> 217 */ 218 219 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, 220 &binding_name, sizeof (binding_name)); 221 if (err == PICL_PROPNOTFOUND) { 222 /* 223 * if compatible prop is found, name will be 224 * <nodename>-<compatible> 225 */ 226 err = ontario_get_first_compatible_value(nodeh, 227 &compatible); 228 if (err == PICL_SUCCESS) { 229 (void) strlcat(name, "-", MAXSTRLEN); 230 (void) strlcat(name, compatible, MAXSTRLEN); 231 free(compatible); 232 } else if (err != PICL_PROPNOTFOUND) { 233 return (err); 234 } 235 } else if (err != PICL_SUCCESS) { 236 return (err); 237 } else if (strcmp(name, binding_name) != 0) { 238 (void) strlcat(name, "-", MAXSTRLEN); 239 (void) strlcat(name, binding_name, MAXSTRLEN); 240 } 241 242 (void) strlcpy(pci_card.name, name, sizeof (pci_card.name)); 243 244 /* Get the model of this card */ 245 246 err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL, 247 &model, sizeof (model)); 248 if (err == PICL_PROPNOTFOUND) 249 (void) strcpy(model, ""); 250 else if (err != PICL_SUCCESS) 251 return (err); 252 (void) strlcpy(pci_card.model, model, sizeof (pci_card.model)); 253 254 /* Print NAC name */ 255 log_printf("%-11s", pci_card.status); 256 /* Print IO Type */ 257 log_printf("%6s", pci_card.bus_type); 258 /* Print Slot # */ 259 log_printf("%5s", pci_card.slot_str); 260 /* Print Parent Path */ 261 log_printf("%46.45s", pci_card.notes); 262 /* Printf Card Name */ 263 if (strlen(pci_card.name) > 24) 264 log_printf("%25.24s+", pci_card.name); 265 else 266 log_printf("%26s", pci_card.name); 267 /* Print Card Model */ 268 if (strlen(pci_card.model) > 10) 269 log_printf("%10.9s+", pci_card.model); 270 else 271 log_printf("%10s", pci_card.model); 272 log_printf("\n"); 273 274 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 275 sizeof (picl_nodehdl_t)); 276 277 } 278 279 return (PICL_WALK_CONTINUE); 280 } 281 /* 282 * display_pci 283 * Display all the PCI IO cards on this board. 284 */ 285 void 286 sun4v_display_pci(picl_nodehdl_t plafh) 287 { 288 char platbuf[MAXSTRLEN]; 289 char *fmt = "%-11s %-5s %-4s %-45s %-25s %-8s"; 290 static int banner = FALSE; /* Have we printed the column headings? */ 291 292 if (banner == FALSE) { 293 log_printf("\n", 0); 294 log_printf("=========================", 0); 295 log_printf(dgettext(TEXT_DOMAIN, " IO Configuration "), 0); 296 log_printf("=========================", 0); 297 log_printf("\n", 0); 298 log_printf("\n", 0); 299 log_printf(fmt, "", "IO", "", "", "", "", 0); 300 log_printf("\n", 0); 301 log_printf(fmt, "Location", "Type", "Slot", "Path", 302 "Name", "Model", 0); 303 log_printf("\n"); 304 log_printf(fmt, "-----------", "-----", "----", 305 "---------------------------------------------", 306 "-------------------------", "---------", 0); 307 log_printf("\n"); 308 banner = TRUE; 309 } 310 311 /* Get platform name, if that fails, use ontario name by default */ 312 if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) { 313 (void) strcpy(platbuf, ONTARIO_PLATFORM); 314 } 315 316 /* 317 * Call functions based on appropriate platform 318 */ 319 if ((strncmp(platbuf, ONTARIO_PLATFORM, 320 strlen(ONTARIO_PLATFORM)) == 0) || 321 (strncmp(platbuf, ONTARIO_PLATFORM2, 322 strlen(ONTARIO_PLATFORM2)) == 0)) { 323 (void) picl_walk_tree_by_class(plafh, "pciex", 324 "pciex", ontario_pci_callback); 325 } else if ((strncmp(platbuf, PELTON_PLATFORM, 326 strlen(PELTON_PLATFORM))) == 0) { 327 (void) picl_walk_tree_by_class(plafh, "pciex", 328 "pciex", pelton_pci_callback); 329 } else { 330 (void) picl_walk_tree_by_class(plafh, "pciex", "pciex", 331 erie_pci_callback); 332 (void) picl_walk_tree_by_class(plafh, "pci", "pci", 333 erie_pci_callback); 334 } 335 } 336 337 /* 338 * ---------------------------------------------------------------------------- 339 */ 340 341 /* ARGSUSED */ 342 void 343 sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh) 344 { 345 /* NOTE(ARGUNUSED(kstats)) */ 346 /* 347 * Now display the last powerfail time and the fatal hardware 348 * reset information. We do this under a couple of conditions. 349 * First if the user asks for it. The second is if the user 350 * told us to do logging, and we found a system failure. 351 */ 352 if (flag) { 353 /* 354 * display time of latest powerfail. Not all systems 355 * have this capability. For those that do not, this 356 * is just a no-op. 357 */ 358 disp_powerfail(root); 359 360 /* platform_disp_prom_version(tree); */ 361 sun4v_display_hw_revisions(root, plafh); 362 } 363 } 364 365 /* 366 * local functions 367 */ 368 /* 369 * add all io devices under pci in io list 370 */ 371 /* ARGSUSED */ 372 static int 373 ontario_hw_rev_callback(picl_nodehdl_t pcih, void *args) 374 { 375 int err = PICL_SUCCESS; 376 char path[MAXSTRLEN] = ""; 377 char device_path[MAXSTRLEN]; 378 char NAC[MAXSTRLEN]; 379 char *compatible; 380 int32_t revision; 381 int device_found; 382 383 device_found = 0; 384 385 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path, 386 sizeof (path)); 387 if (err != PICL_SUCCESS) { 388 return (err); 389 } 390 391 if ((strcmp(path, NETWORK_0_PATH) == 0) || 392 (strcmp(path, NETWORK_1_PATH) == 0)) { 393 device_found = 1; 394 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR, 395 0); 396 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 397 &err); 398 } 399 400 if ((strcmp(path, NETWORK_2_PATH) == 0) || 401 (strcmp(path, NETWORK_3_PATH) == 0)) { 402 device_found = 1; 403 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR, 404 1); 405 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 406 &err); 407 } 408 409 if ((strcmp(path, FIRE_PATH0) == 0) || 410 (strcmp(path, FIRE_PATH1) == 0)) { 411 device_found = 1; 412 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, 413 "IO-BRIDGE"); 414 revision = ontario_get_int_propval(pcih, OBP_PROP_VERSION_NUM, 415 &err); 416 } 417 418 if ((strcmp(path, PCIX_SLOT0) == 0) || 419 (strcmp(path, PCIX_SLOT1) == 0)) { 420 device_found = 1; 421 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, 422 PCI_BRIDGE); 423 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 424 &err); 425 } 426 427 if (strcmp(path, SWITCH_A_PATH) == 0) { 428 device_found = 1; 429 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_A); 430 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 431 &err); 432 } 433 434 if (strcmp(path, SWITCH_B_PATH) == 0) { 435 device_found = 1; 436 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_B); 437 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 438 &err); 439 } 440 441 if (strcmp(path, ONT_LSI_PATH) == 0) { 442 device_found = 1; 443 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, 444 SAS_SATA_HBA); 445 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 446 &err); 447 } 448 if (device_found == 1) { 449 (void) strcpy(device_path, path); 450 err = ontario_get_first_compatible_value(pcih, &compatible); 451 452 /* Print NAC name */ 453 log_printf("%-20s", NAC); 454 /* Print Device Path */ 455 if (strlen(device_path) > 38) 456 log_printf("%38.37s+", device_path); 457 else 458 log_printf("%39s", device_path); 459 /* Print Compatible # */ 460 log_printf("%31s", compatible); 461 free(compatible); 462 /* Print Revision */ 463 log_printf("%6d", revision); 464 log_printf("\n"); 465 } 466 467 return (PICL_WALK_CONTINUE); 468 } 469 470 /*ARGSUSED*/ 471 static void 472 sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh) 473 { 474 Prom_node *pnode; 475 char *value; 476 char platbuf[MAXSTRLEN]; 477 char *fmt = "%-20s %-40s %-30s %-9s"; 478 479 log_printf(dgettext(TEXT_DOMAIN, "\n" 480 "========================= HW Revisions " 481 "=======================================\n\n")); 482 483 log_printf(dgettext(TEXT_DOMAIN, 484 "System PROM revisions:\n" 485 "----------------------\n")); 486 487 pnode = dev_find_node(root, "openprom"); 488 if (pnode != NULL) { 489 value = (char *)get_prop_val(find_prop(pnode, "version")); 490 log_printf(value); 491 } 492 493 log_printf(dgettext(TEXT_DOMAIN, "\n\n" 494 "IO ASIC revisions:\n" 495 "------------------\n")); 496 log_printf(fmt, "Location", "Path", "Device", "Revision\n", 0); 497 log_printf(fmt, "--------------------", 498 "----------------------------------------", 499 "------------------------------", 500 "---------\n", 0); 501 502 /* Get platform name, if that fails, use ontario name by default */ 503 if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) { 504 (void) strcpy(platbuf, ONTARIO_PLATFORM); 505 } 506 507 /* 508 * Walk tree based on platform 509 */ 510 if ((strncmp(platbuf, ONTARIO_PLATFORM, 511 strlen(ONTARIO_PLATFORM))) == 0) { 512 (void) picl_walk_tree_by_class(plafh, "pciex", 513 "pciex", ontario_hw_rev_callback); 514 (void) picl_walk_tree_by_class(plafh, "pci", 515 "pci", ontario_hw_rev_callback); 516 (void) picl_walk_tree_by_class(plafh, "network", 517 "network", ontario_hw_rev_callback); 518 (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2", 519 ontario_hw_rev_callback); 520 } else if ((strncmp(platbuf, PELTON_PLATFORM, 521 strlen(PELTON_PLATFORM))) == 0) { 522 (void) picl_walk_tree_by_class(plafh, "pciex", 523 "pciex", pelton_hw_rev_callback); 524 (void) picl_walk_tree_by_class(plafh, "pci", 525 "pci", pelton_hw_rev_callback); 526 (void) picl_walk_tree_by_class(plafh, "network", 527 "network", pelton_hw_rev_callback); 528 (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2", 529 pelton_hw_rev_callback); 530 } else { 531 (void) picl_walk_tree_by_class(plafh, "pciex", "pciex", 532 erie_hw_rev_callback); 533 (void) picl_walk_tree_by_class(plafh, "pci", "pci", 534 erie_hw_rev_callback); 535 (void) picl_walk_tree_by_class(plafh, "network", "network", 536 erie_hw_rev_callback); 537 (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2", 538 erie_hw_rev_callback); 539 } 540 } 541 542 /* 543 * return the first compatible value 544 */ 545 static int 546 ontario_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 547 { 548 int err; 549 picl_prophdl_t proph; 550 picl_propinfo_t pinfo; 551 picl_prophdl_t tblh; 552 picl_prophdl_t rowproph; 553 char *pval; 554 555 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 556 &pinfo, &proph); 557 if (err != PICL_SUCCESS) 558 return (err); 559 560 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 561 pval = malloc(pinfo.size); 562 if (pval == NULL) 563 return (PICL_FAILURE); 564 err = picl_get_propval(proph, pval, pinfo.size); 565 if (err != PICL_SUCCESS) { 566 free(pval); 567 return (err); 568 } 569 *outbuf = pval; 570 return (PICL_SUCCESS); 571 } 572 573 if (pinfo.type != PICL_PTYPE_TABLE) 574 return (PICL_FAILURE); 575 576 /* get first string from table */ 577 err = picl_get_propval(proph, &tblh, pinfo.size); 578 if (err != PICL_SUCCESS) 579 return (err); 580 581 err = picl_get_next_by_row(tblh, &rowproph); 582 if (err != PICL_SUCCESS) 583 return (err); 584 585 err = picl_get_propinfo(rowproph, &pinfo); 586 if (err != PICL_SUCCESS) 587 return (err); 588 589 pval = malloc(pinfo.size); 590 if (pval == NULL) 591 return (PICL_FAILURE); 592 593 err = picl_get_propval(rowproph, pval, pinfo.size); 594 if (err != PICL_SUCCESS) { 595 free(pval); 596 return (err); 597 } 598 599 *outbuf = pval; 600 return (PICL_SUCCESS); 601 } 602 603 static int64_t 604 ontario_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 605 { 606 int err; 607 picl_prophdl_t proph; 608 picl_propinfo_t pinfo; 609 int8_t int8v; 610 int16_t int16v; 611 int32_t int32v; 612 int64_t int64v; 613 614 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 615 if (err != PICL_SUCCESS) { 616 *ret = err; 617 return (0); 618 } 619 620 /* 621 * If it is not an int, uint or byte array prop, return failure 622 */ 623 if ((pinfo.type != PICL_PTYPE_INT) && 624 (pinfo.type != PICL_PTYPE_UNSIGNED_INT) && 625 (pinfo.type != PICL_PTYPE_BYTEARRAY)) { 626 *ret = PICL_FAILURE; 627 return (0); 628 } 629 630 switch (pinfo.size) { 631 case sizeof (int8_t): 632 err = picl_get_propval(proph, &int8v, sizeof (int8v)); 633 *ret = err; 634 return (int8v); 635 case sizeof (int16_t): 636 err = picl_get_propval(proph, &int16v, sizeof (int16v)); 637 *ret = err; 638 return (int16v); 639 case sizeof (int32_t): 640 err = picl_get_propval(proph, &int32v, sizeof (int32v)); 641 *ret = err; 642 return (int32v); 643 case sizeof (int64_t): 644 err = picl_get_propval(proph, &int64v, sizeof (int64v)); 645 *ret = err; 646 return (int64v); 647 default: /* not supported size */ 648 *ret = PICL_FAILURE; 649 return (0); 650 } 651 } 652