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