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