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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Sun4v Platform specific functions. 29 * 30 * called when : 31 * machine_type == StPaul 32 * 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <kstat.h> 41 #include <fcntl.h> 42 #include <string.h> 43 #include <assert.h> 44 #include <libintl.h> 45 #include <note.h> 46 #include <sys/systeminfo.h> 47 #include <sys/openpromio.h> 48 #include <sys/sysmacros.h> 49 #include <picl.h> 50 #include "picldefs.h" 51 #include <pdevinfo.h> 52 #include <display.h> 53 #include <display_sun4v.h> 54 #include <libprtdiag.h> 55 #include "stpaul.h" 56 57 /* prototypes for local functions */ 58 static void get_bus_type(char *path, struct io_card *card); 59 static void get_slot_number(char *path, struct io_card *card); 60 static int stpaul_get_network_instance(char *path); 61 static int stpaul_get_usb_instance(char *path); 62 static int stpaul_get_io_instance(char *path, char *type); 63 static int stpaul_get_first_compatible_value(picl_nodehdl_t nodeh, 64 char **outbuf); 65 static int64_t stpaul_get_int_propval(picl_nodehdl_t modh, char *prop_name, 66 int *ret); 67 68 /* ARGSUSED */ 69 int 70 stpaul_pci_callback(picl_nodehdl_t pcih, void *args) 71 { 72 int err = PICL_SUCCESS; 73 picl_nodehdl_t nodeh; 74 char path[MAXSTRLEN]; 75 char parent_path[MAXSTRLEN]; 76 char piclclass[PICL_CLASSNAMELEN_MAX]; 77 char name[MAXSTRLEN]; 78 char model[MAXSTRLEN]; 79 char *compatible; 80 char binding_name[MAXSTRLEN]; 81 struct io_card pci_card; 82 int32_t instance; 83 char pn_type; 84 85 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path, 86 sizeof (parent_path)); 87 if (err != PICL_SUCCESS) 88 return (err); 89 90 /* Walk through the children */ 91 92 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 93 sizeof (picl_nodehdl_t)); 94 95 while (err == PICL_SUCCESS) { 96 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 97 piclclass, sizeof (piclclass)); 98 if (err != PICL_SUCCESS) 99 return (err); 100 101 if (strcmp(piclclass, PICL_CLASS_PCIEX) == 0) { 102 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, 103 &nodeh, sizeof (picl_nodehdl_t)); 104 continue; 105 } 106 107 if (strcmp(piclclass, PICL_CLASS_PCI) == 0) { 108 err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD, 109 &nodeh, sizeof (picl_nodehdl_t)); 110 continue; 111 } 112 113 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH, 114 path, sizeof (path)); 115 if (err != PICL_SUCCESS) 116 return (err); 117 118 (void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes)); 119 120 get_bus_type(path, &pci_card); 121 122 get_slot_number(path, &pci_card); 123 124 err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name, 125 sizeof (name)); 126 if (err == PICL_PROPNOTFOUND) 127 (void) strlcpy(name, "", sizeof (name)); 128 else if (err != PICL_SUCCESS) 129 return (err); 130 131 /* Figure NAC name */ 132 if ((strcmp(name, NETWORK) == 0) && 133 (strcmp(pci_card.slot_str, MOTHERBOARD) == 0)) { 134 instance = stpaul_get_network_instance(path); 135 (void) snprintf(pci_card.status, 136 sizeof (pci_card.status), "%s/%s%d", 137 MOTHERBOARD, "NET", instance); 138 139 140 } else if ((strcmp(name, SCSI) == 0) && 141 (strcmp(pci_card.slot_str, MOTHERBOARD) == 0)) { 142 (void) snprintf(pci_card.status, 143 sizeof (pci_card.status), "%s/%s", 144 MOTHERBOARD, SPL_SCSI_TAG); 145 146 } else { 147 if (pci_card.slot != -1) { 148 (void) snprintf(pci_card.status, 149 sizeof (pci_card.status), "%s/%s%d", 150 MOTHERBOARD, pci_card.bus_type, 151 pci_card.slot); 152 } else { 153 (void) snprintf(pci_card.status, 154 sizeof (pci_card.status), "%s/%s", 155 MOTHERBOARD, pci_card.bus_type); 156 } 157 } 158 159 /* Special case for USB */ 160 if (strncmp(name, USB, strlen(USB)) == 0) { 161 instance = stpaul_get_usb_instance(path); 162 if (instance != -1) 163 (void) snprintf(pci_card.status, 164 sizeof (pci_card.status), "%s/%s%d", 165 MOTHERBOARD, "USB", instance); 166 } 167 168 /* PEM/NEM case is handled here */ 169 if ((instance = stpaul_get_io_instance(path, &pn_type)) != -1) { 170 if (pn_type == SPL_PEM_TYPE) 171 (void) snprintf(pci_card.status, 172 sizeof (pci_card.status), "%s/%s%d", 173 MOTHERBOARD, "PCI-EM", instance); 174 else if (pn_type == SPL_NEM_TYPE) 175 (void) snprintf(pci_card.status, 176 sizeof (pci_card.status), "%s/%s%d", 177 MOTHERBOARD, "NEM", instance); 178 } 179 /* 180 * Get the name of this card. If binding_name is found, 181 * name will be <nodename>-<binding_name> 182 */ 183 184 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, 185 &binding_name, sizeof (binding_name)); 186 if (err == PICL_PROPNOTFOUND) { 187 /* 188 * if compatible prop is found, name will be 189 * <nodename>-<compatible> 190 */ 191 err = stpaul_get_first_compatible_value(nodeh, 192 &compatible); 193 if (err == PICL_SUCCESS) { 194 (void) strlcat(name, "-", MAXSTRLEN); 195 (void) strlcat(name, compatible, MAXSTRLEN); 196 free(compatible); 197 } else if (err != PICL_PROPNOTFOUND) 198 return (err); 199 } else if (err != PICL_SUCCESS) 200 return (err); 201 else if (strcmp(name, binding_name) != 0) { 202 (void) strlcat(name, "-", MAXSTRLEN); 203 (void) strlcat(name, binding_name, MAXSTRLEN); 204 } 205 206 (void) strlcpy(pci_card.name, name, sizeof (pci_card.name)); 207 208 /* Get the model of this card */ 209 210 err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL, 211 &model, sizeof (model)); 212 if (err == PICL_PROPNOTFOUND) 213 (void) strlcpy(model, "", sizeof (model)); 214 else if (err != PICL_SUCCESS) 215 return (err); 216 (void) strlcpy(pci_card.model, model, sizeof (pci_card.model)); 217 218 /* Print NAC name */ 219 log_printf("%-11s", pci_card.status); 220 /* Print IO Type */ 221 log_printf("%6s", pci_card.bus_type); 222 /* Print Slot # */ 223 log_printf("%5s", pci_card.slot_str); 224 /* Print Parent Path */ 225 log_printf("%46.45s", pci_card.notes); 226 /* Printf Card Name */ 227 if (strlen(pci_card.name) > 24) 228 log_printf("%25.24s+", pci_card.name); 229 else 230 log_printf("%26s", pci_card.name); 231 /* Print Card Model */ 232 if (strlen(pci_card.model) > 10) 233 log_printf("%10.9s+", pci_card.model); 234 else 235 log_printf("%10s", pci_card.model); 236 log_printf("\n"); 237 238 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 239 sizeof (picl_nodehdl_t)); 240 241 } 242 243 return (PICL_WALK_CONTINUE); 244 } 245 246 /* ARGSUSED */ 247 int 248 stpaul_hw_rev_callback(picl_nodehdl_t pcih, void *args) 249 { 250 int err = PICL_SUCCESS; 251 char path[MAXSTRLEN]; 252 char device_path[MAXSTRLEN]; 253 char NAC[MAXSTRLEN]; 254 char *compatible; 255 int32_t revision; 256 int device_found = 0; 257 char name[MAXSTRLEN]; 258 picl_nodehdl_t nodeh; 259 260 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path, 261 sizeof (path)); 262 if (err != PICL_SUCCESS) 263 return (err); 264 265 /* usb is special as a child of PCIE2PCI bridge */ 266 if (strcmp(path, SPL_PCIE2PCI) == 0) { 267 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 268 sizeof (picl_nodehdl_t)); 269 if (err != PICL_SUCCESS) 270 return (err); 271 err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name, 272 sizeof (name)); 273 if (err != PICL_SUCCESS) 274 return (err); 275 if (strcmp(name, USB) == 0) { 276 err = stpaul_hw_rev_callback(nodeh, &nodeh); 277 if (err != PICL_SUCCESS) 278 return (err); 279 } 280 } 281 282 if ((strcmp(path, SPL_NETWORK_0_PATH) == 0) || 283 (strcmp(path, SPL_NETWORK_1_PATH) == 0)) { 284 device_found = 1; 285 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD, 286 OPHIR, 0); 287 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 288 &err); 289 } 290 291 if ((strcmp(path, SPL_USB0_PATH) == 0) || 292 (strcmp(path, SPL_USB1_PATH) == 0) || 293 (strcmp(path, SPL_USB2_PATH) == 0)) { 294 device_found = 1; 295 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD, 296 USB_TAG, 0); 297 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 298 &err); 299 } 300 301 if ((strcmp(path, FIRE_PATH0) == 0) || 302 (strcmp(path, FIRE_PATH1) == 0)) { 303 device_found = 1; 304 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 305 "IO-BRIDGE"); 306 revision = stpaul_get_int_propval(pcih, OBP_PROP_VERSION_NUM, 307 &err); 308 } 309 310 if (strcmp(path, SWITCH_A_PATH) == 0) { 311 device_found = 1; 312 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 313 SWITCH_A); 314 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 315 &err); 316 } 317 318 if (strcmp(path, SWITCH_B_PATH) == 0) { 319 device_found = 1; 320 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 321 SWITCH_B); 322 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 323 &err); 324 } 325 326 if (strcmp(path, SPL_LSI_PATH) == 0) { 327 device_found = 1; 328 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 329 SPL_SAS_HBA); 330 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 331 &err); 332 } 333 334 if (strcmp(path, SPL_PCIE2PCI) == 0) { 335 device_found = 1; 336 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 337 PCI_BRIDGE); 338 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 339 &err); 340 } 341 342 if (device_found == 1) { 343 344 (void) strlcpy(device_path, path, sizeof (device_path)); 345 err = stpaul_get_first_compatible_value(pcih, &compatible); 346 347 /* Print NAC name */ 348 log_printf("%-20s", NAC); 349 /* Print Device Path */ 350 if (strlen(device_path) > 38) 351 log_printf("%38.37s+", device_path); 352 else 353 log_printf("%39s", device_path); 354 /* Print Compatible # */ 355 if (err == PICL_SUCCESS) { 356 log_printf("%31s", compatible); 357 free(compatible); 358 } else 359 log_printf("%31s", " "); 360 /* Print Revision */ 361 log_printf("%6d", revision); 362 log_printf("\n"); 363 } 364 365 return (PICL_WALK_CONTINUE); 366 } 367 368 static void 369 get_bus_type(char *path, struct io_card *card) 370 { 371 if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) { 372 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 373 } else if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) { 374 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 375 } else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) { 376 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 377 } else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) { 378 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 379 } else if (strncmp(path, SWITCH_A_PATH, strlen(SWITCH_A_PATH)) == 0) { 380 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 381 } else if (strncmp(path, SWITCH_B_PATH, strlen(SWITCH_B_PATH)) == 0) { 382 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 383 } else { 384 (void) strlcpy(card->bus_type, "NONE", sizeof (card->bus_type)); 385 } 386 } 387 388 static void 389 get_slot_number(char *path, struct io_card *card) 390 { 391 if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) { 392 (void) strlcpy(card->slot_str, "0", sizeof (card->slot_str)); 393 card->slot = 0; 394 } else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) { 395 (void) strlcpy(card->slot_str, "0", sizeof (card->slot_str)); 396 card->slot = 0; 397 } else if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) { 398 (void) strlcpy(card->slot_str, "1", sizeof (card->slot_str)); 399 card->slot = 1; 400 } else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) { 401 (void) strlcpy(card->slot_str, "1", sizeof (card->slot_str)); 402 card->slot = 1; 403 } else { 404 (void) strlcpy(card->slot_str, MOTHERBOARD, 405 sizeof (card->slot_str)); 406 card->slot = -1; 407 } 408 } 409 410 static int 411 stpaul_get_network_instance(char *path) 412 { 413 if (strncmp(path, SPL_NETWORK_1_PATH, 414 strlen(SPL_NETWORK_1_PATH)) == 0) 415 return (1); 416 else if (strncmp(path, SPL_NETWORK_0_PATH, 417 strlen(SPL_NETWORK_0_PATH)) == 0) 418 return (0); 419 else 420 return (-1); 421 } 422 423 static int 424 stpaul_get_usb_instance(char *path) 425 { 426 if (strncmp(path, SPL_USB2_PATH, strlen(SPL_USB2_PATH)) == 0) 427 return (2); 428 else if (strncmp(path, SPL_USB1_PATH, strlen(SPL_USB1_PATH)) == 0) 429 return (1); 430 else if (strncmp(path, SPL_USB0_PATH, strlen(path)) == 0) 431 return (0); 432 else 433 return (-1); 434 } 435 436 static int 437 stpaul_get_io_instance(char *path, char *type) 438 { 439 if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) { 440 *type = SPL_PEM_TYPE; 441 return (1); 442 } else if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) { 443 *type = SPL_PEM_TYPE; 444 return (0); 445 } else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) { 446 *type = SPL_NEM_TYPE; 447 return (1); 448 } else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) { 449 *type = SPL_NEM_TYPE; 450 return (0); 451 } else 452 return (-1); 453 } 454 /* 455 * return the first compatible value 456 */ 457 static int 458 stpaul_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 459 { 460 int err; 461 picl_prophdl_t proph; 462 picl_propinfo_t pinfo; 463 picl_prophdl_t tblh; 464 picl_prophdl_t rowproph; 465 char *pval; 466 467 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 468 &pinfo, &proph); 469 if (err != PICL_SUCCESS) 470 return (err); 471 472 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 473 pval = malloc(pinfo.size); 474 if (pval == NULL) 475 return (PICL_FAILURE); 476 err = picl_get_propval(proph, pval, pinfo.size); 477 if (err != PICL_SUCCESS) { 478 free(pval); 479 return (err); 480 } 481 *outbuf = pval; 482 return (PICL_SUCCESS); 483 } 484 485 if (pinfo.type != PICL_PTYPE_TABLE) 486 return (PICL_FAILURE); 487 488 /* get first string from table */ 489 err = picl_get_propval(proph, &tblh, pinfo.size); 490 if (err != PICL_SUCCESS) 491 return (err); 492 493 err = picl_get_next_by_row(tblh, &rowproph); 494 if (err != PICL_SUCCESS) 495 return (err); 496 497 err = picl_get_propinfo(rowproph, &pinfo); 498 if (err != PICL_SUCCESS) 499 return (err); 500 501 pval = malloc(pinfo.size); 502 if (pval == NULL) 503 return (PICL_FAILURE); 504 505 err = picl_get_propval(rowproph, pval, pinfo.size); 506 if (err != PICL_SUCCESS) { 507 free(pval); 508 return (err); 509 } 510 511 *outbuf = pval; 512 return (PICL_SUCCESS); 513 } 514 515 static int64_t 516 stpaul_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 517 { 518 int err; 519 picl_prophdl_t proph; 520 picl_propinfo_t pinfo; 521 int8_t int8v; 522 int16_t int16v; 523 int32_t int32v; 524 int64_t int64v; 525 526 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 527 if (err != PICL_SUCCESS) { 528 *ret = err; 529 return (0); 530 } 531 532 /* 533 * If it is not an int, uint or byte array prop, return failure 534 */ 535 if ((pinfo.type != PICL_PTYPE_INT) && 536 (pinfo.type != PICL_PTYPE_UNSIGNED_INT) && 537 (pinfo.type != PICL_PTYPE_BYTEARRAY)) { 538 *ret = PICL_FAILURE; 539 return (0); 540 } 541 542 switch (pinfo.size) { 543 case sizeof (int8_t): 544 err = picl_get_propval(proph, &int8v, sizeof (int8v)); 545 *ret = err; 546 return (int8v); 547 case sizeof (int16_t): 548 err = picl_get_propval(proph, &int16v, sizeof (int16v)); 549 *ret = err; 550 return (int16v); 551 case sizeof (int32_t): 552 err = picl_get_propval(proph, &int32v, sizeof (int32v)); 553 *ret = err; 554 return (int32v); 555 case sizeof (int64_t): 556 err = picl_get_propval(proph, &int64v, sizeof (int64v)); 557 *ret = err; 558 return (int64v); 559 default: /* not supported size */ 560 *ret = PICL_FAILURE; 561 return (0); 562 } 563 } 564