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 (void) picl_walk_tree_by_class(plafh, "pciex", 322 "pciex", ontario_pci_callback); 323 } else if ((strncmp(platbuf, PELTON_PLATFORM, 324 strlen(PELTON_PLATFORM))) == 0) { 325 (void) picl_walk_tree_by_class(plafh, "pciex", 326 "pciex", pelton_pci_callback); 327 } else { 328 (void) picl_walk_tree_by_class(plafh, "pciex", "pciex", 329 erie_pci_callback); 330 (void) picl_walk_tree_by_class(plafh, "pci", "pci", 331 erie_pci_callback); 332 } 333 } 334 335 /* 336 * ---------------------------------------------------------------------------- 337 */ 338 339 /* ARGSUSED */ 340 void 341 sun4v_display_diaginfo(int flag, Prom_node *root, picl_nodehdl_t plafh) 342 { 343 /* NOTE(ARGUNUSED(kstats)) */ 344 /* 345 * Now display the last powerfail time and the fatal hardware 346 * reset information. We do this under a couple of conditions. 347 * First if the user asks for it. The second is if the user 348 * told us to do logging, and we found a system failure. 349 */ 350 if (flag) { 351 /* 352 * display time of latest powerfail. Not all systems 353 * have this capability. For those that do not, this 354 * is just a no-op. 355 */ 356 disp_powerfail(root); 357 358 /* platform_disp_prom_version(tree); */ 359 sun4v_display_hw_revisions(root, plafh); 360 } 361 } 362 363 /* 364 * local functions 365 */ 366 /* 367 * add all io devices under pci in io list 368 */ 369 /* ARGSUSED */ 370 static int 371 ontario_hw_rev_callback(picl_nodehdl_t pcih, void *args) 372 { 373 int err = PICL_SUCCESS; 374 char path[MAXSTRLEN] = ""; 375 char device_path[MAXSTRLEN]; 376 char NAC[MAXSTRLEN]; 377 char *compatible; 378 int32_t revision; 379 int device_found; 380 381 device_found = 0; 382 383 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path, 384 sizeof (path)); 385 if (err != PICL_SUCCESS) { 386 return (err); 387 } 388 389 if ((strcmp(path, NETWORK_0_PATH) == 0) || 390 (strcmp(path, NETWORK_1_PATH) == 0)) { 391 device_found = 1; 392 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR, 393 0); 394 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 395 &err); 396 } 397 398 if ((strcmp(path, NETWORK_2_PATH) == 0) || 399 (strcmp(path, NETWORK_3_PATH) == 0)) { 400 device_found = 1; 401 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", IOBOARD, OPHIR, 402 1); 403 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 404 &err); 405 } 406 407 if ((strcmp(path, FIRE_PATH0) == 0) || 408 (strcmp(path, FIRE_PATH1) == 0)) { 409 device_found = 1; 410 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, 411 "IO-BRIDGE"); 412 revision = ontario_get_int_propval(pcih, OBP_PROP_VERSION_NUM, 413 &err); 414 } 415 416 if ((strcmp(path, PCIX_SLOT0) == 0) || 417 (strcmp(path, PCIX_SLOT1) == 0)) { 418 device_found = 1; 419 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, 420 PCI_BRIDGE); 421 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 422 &err); 423 } 424 425 if (strcmp(path, SWITCH_A_PATH) == 0) { 426 device_found = 1; 427 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_A); 428 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 429 &err); 430 } 431 432 if (strcmp(path, SWITCH_B_PATH) == 0) { 433 device_found = 1; 434 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, SWITCH_B); 435 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 436 &err); 437 } 438 439 if (strcmp(path, ONT_LSI_PATH) == 0) { 440 device_found = 1; 441 (void) snprintf(NAC, sizeof (NAC), "%s/%s", IOBOARD, 442 SAS_SATA_HBA); 443 revision = ontario_get_int_propval(pcih, OBP_PROP_REVISION_ID, 444 &err); 445 } 446 if (device_found == 1) { 447 (void) strcpy(device_path, path); 448 err = ontario_get_first_compatible_value(pcih, &compatible); 449 450 /* Print NAC name */ 451 log_printf("%-20s", NAC); 452 /* Print Device Path */ 453 if (strlen(device_path) > 38) 454 log_printf("%38.37s+", device_path); 455 else 456 log_printf("%39s", device_path); 457 /* Print Compatible # */ 458 log_printf("%31s", compatible); 459 free(compatible); 460 /* Print Revision */ 461 log_printf("%6d", revision); 462 log_printf("\n"); 463 } 464 465 return (PICL_WALK_CONTINUE); 466 } 467 468 /*ARGSUSED*/ 469 static void 470 sun4v_display_hw_revisions(Prom_node *root, picl_nodehdl_t plafh) 471 { 472 Prom_node *pnode; 473 char *value; 474 char platbuf[MAXSTRLEN]; 475 char *fmt = "%-20s %-40s %-30s %-9s"; 476 477 log_printf(dgettext(TEXT_DOMAIN, "\n" 478 "========================= HW Revisions " 479 "=======================================\n\n")); 480 481 log_printf(dgettext(TEXT_DOMAIN, 482 "System PROM revisions:\n" 483 "----------------------\n")); 484 485 pnode = dev_find_node(root, "openprom"); 486 if (pnode != NULL) { 487 value = (char *)get_prop_val(find_prop(pnode, "version")); 488 log_printf(value); 489 } 490 491 log_printf(dgettext(TEXT_DOMAIN, "\n\n" 492 "IO ASIC revisions:\n" 493 "------------------\n")); 494 log_printf(fmt, "Location", "Path", "Device", "Revision\n", 0); 495 log_printf(fmt, "--------------------", 496 "----------------------------------------", 497 "------------------------------", 498 "---------\n", 0); 499 500 /* Get platform name, if that fails, use ontario name by default */ 501 if (sysinfo(SI_PLATFORM, platbuf, sizeof (platbuf)) == -1) { 502 (void) strcpy(platbuf, ONTARIO_PLATFORM); 503 } 504 505 /* 506 * Walk tree based on platform 507 */ 508 if ((strncmp(platbuf, ONTARIO_PLATFORM, 509 strlen(ONTARIO_PLATFORM))) == 0) { 510 (void) picl_walk_tree_by_class(plafh, "pciex", 511 "pciex", ontario_hw_rev_callback); 512 (void) picl_walk_tree_by_class(plafh, "pci", 513 "pci", ontario_hw_rev_callback); 514 (void) picl_walk_tree_by_class(plafh, "network", 515 "network", ontario_hw_rev_callback); 516 (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2", 517 ontario_hw_rev_callback); 518 } else if ((strncmp(platbuf, PELTON_PLATFORM, 519 strlen(PELTON_PLATFORM))) == 0) { 520 (void) picl_walk_tree_by_class(plafh, "pciex", 521 "pciex", pelton_hw_rev_callback); 522 (void) picl_walk_tree_by_class(plafh, "pci", 523 "pci", pelton_hw_rev_callback); 524 (void) picl_walk_tree_by_class(plafh, "network", 525 "network", pelton_hw_rev_callback); 526 (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2", 527 pelton_hw_rev_callback); 528 } else { 529 (void) picl_walk_tree_by_class(plafh, "pciex", "pciex", 530 erie_hw_rev_callback); 531 (void) picl_walk_tree_by_class(plafh, "pci", "pci", 532 erie_hw_rev_callback); 533 (void) picl_walk_tree_by_class(plafh, "network", "network", 534 erie_hw_rev_callback); 535 (void) picl_walk_tree_by_class(plafh, "scsi-2", "scsi-2", 536 erie_hw_rev_callback); 537 } 538 } 539 540 /* 541 * return the first compatible value 542 */ 543 static int 544 ontario_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 545 { 546 int err; 547 picl_prophdl_t proph; 548 picl_propinfo_t pinfo; 549 picl_prophdl_t tblh; 550 picl_prophdl_t rowproph; 551 char *pval; 552 553 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 554 &pinfo, &proph); 555 if (err != PICL_SUCCESS) 556 return (err); 557 558 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 559 pval = malloc(pinfo.size); 560 if (pval == NULL) 561 return (PICL_FAILURE); 562 err = picl_get_propval(proph, pval, pinfo.size); 563 if (err != PICL_SUCCESS) { 564 free(pval); 565 return (err); 566 } 567 *outbuf = pval; 568 return (PICL_SUCCESS); 569 } 570 571 if (pinfo.type != PICL_PTYPE_TABLE) 572 return (PICL_FAILURE); 573 574 /* get first string from table */ 575 err = picl_get_propval(proph, &tblh, pinfo.size); 576 if (err != PICL_SUCCESS) 577 return (err); 578 579 err = picl_get_next_by_row(tblh, &rowproph); 580 if (err != PICL_SUCCESS) 581 return (err); 582 583 err = picl_get_propinfo(rowproph, &pinfo); 584 if (err != PICL_SUCCESS) 585 return (err); 586 587 pval = malloc(pinfo.size); 588 if (pval == NULL) 589 return (PICL_FAILURE); 590 591 err = picl_get_propval(rowproph, pval, pinfo.size); 592 if (err != PICL_SUCCESS) { 593 free(pval); 594 return (err); 595 } 596 597 *outbuf = pval; 598 return (PICL_SUCCESS); 599 } 600 601 static int64_t 602 ontario_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 603 { 604 int err; 605 picl_prophdl_t proph; 606 picl_propinfo_t pinfo; 607 int8_t int8v; 608 int16_t int16v; 609 int32_t int32v; 610 int64_t int64v; 611 612 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 613 if (err != PICL_SUCCESS) { 614 *ret = err; 615 return (0); 616 } 617 618 /* 619 * If it is not an int, uint or byte array prop, return failure 620 */ 621 if ((pinfo.type != PICL_PTYPE_INT) && 622 (pinfo.type != PICL_PTYPE_UNSIGNED_INT) && 623 (pinfo.type != PICL_PTYPE_BYTEARRAY)) { 624 *ret = PICL_FAILURE; 625 return (0); 626 } 627 628 switch (pinfo.size) { 629 case sizeof (int8_t): 630 err = picl_get_propval(proph, &int8v, sizeof (int8v)); 631 *ret = err; 632 return (int8v); 633 case sizeof (int16_t): 634 err = picl_get_propval(proph, &int16v, sizeof (int16v)); 635 *ret = err; 636 return (int16v); 637 case sizeof (int32_t): 638 err = picl_get_propval(proph, &int32v, sizeof (int32v)); 639 *ret = err; 640 return (int32v); 641 case sizeof (int64_t): 642 err = picl_get_propval(proph, &int64v, sizeof (int64v)); 643 *ret = err; 644 return (int64v); 645 default: /* not supported size */ 646 *ret = PICL_FAILURE; 647 return (0); 648 } 649 } 650