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 2006 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 log_printf("%31s", compatible); 356 free(compatible); 357 /* Print Revision */ 358 log_printf("%6d", revision); 359 log_printf("\n"); 360 } 361 362 return (PICL_WALK_CONTINUE); 363 } 364 365 static void 366 get_bus_type(char *path, struct io_card *card) 367 { 368 if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) { 369 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 370 } else if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) { 371 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 372 } else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) { 373 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 374 } else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) { 375 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 376 } else if (strncmp(path, SWITCH_A_PATH, strlen(SWITCH_A_PATH)) == 0) { 377 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 378 } else if (strncmp(path, SWITCH_B_PATH, strlen(SWITCH_B_PATH)) == 0) { 379 (void) strlcpy(card->bus_type, "PCIE", sizeof (card->bus_type)); 380 } else { 381 (void) strlcpy(card->bus_type, "NONE", sizeof (card->bus_type)); 382 } 383 } 384 385 static void 386 get_slot_number(char *path, struct io_card *card) 387 { 388 if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) { 389 (void) strlcpy(card->slot_str, "0", sizeof (card->slot_str)); 390 card->slot = 0; 391 } else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) { 392 (void) strlcpy(card->slot_str, "0", sizeof (card->slot_str)); 393 card->slot = 0; 394 } else if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) { 395 (void) strlcpy(card->slot_str, "1", sizeof (card->slot_str)); 396 card->slot = 1; 397 } else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) { 398 (void) strlcpy(card->slot_str, "1", sizeof (card->slot_str)); 399 card->slot = 1; 400 } else { 401 (void) strlcpy(card->slot_str, MOTHERBOARD, 402 sizeof (card->slot_str)); 403 card->slot = -1; 404 } 405 } 406 407 static int 408 stpaul_get_network_instance(char *path) 409 { 410 if (strncmp(path, SPL_NETWORK_1_PATH, 411 strlen(SPL_NETWORK_1_PATH)) == 0) 412 return (1); 413 else if (strncmp(path, SPL_NETWORK_0_PATH, 414 strlen(SPL_NETWORK_0_PATH)) == 0) 415 return (0); 416 else 417 return (-1); 418 } 419 420 static int 421 stpaul_get_usb_instance(char *path) 422 { 423 if (strncmp(path, SPL_USB2_PATH, strlen(SPL_USB2_PATH)) == 0) 424 return (2); 425 else if (strncmp(path, SPL_USB1_PATH, strlen(SPL_USB1_PATH)) == 0) 426 return (1); 427 else if (strncmp(path, SPL_USB0_PATH, strlen(path)) == 0) 428 return (0); 429 else 430 return (-1); 431 } 432 433 static int 434 stpaul_get_io_instance(char *path, char *type) 435 { 436 if (strncmp(path, SPL_PCIE_PEM1, strlen(SPL_PCIE_PEM1)) == 0) { 437 *type = SPL_PEM_TYPE; 438 return (1); 439 } else if (strncmp(path, SPL_PCIE_PEM0, strlen(SPL_PCIE_PEM0)) == 0) { 440 *type = SPL_PEM_TYPE; 441 return (0); 442 } else if (strncmp(path, SPL_PCIE_NEM1, strlen(SPL_PCIE_NEM1)) == 0) { 443 *type = SPL_NEM_TYPE; 444 return (1); 445 } else if (strncmp(path, SPL_PCIE_NEM0, strlen(SPL_PCIE_NEM0)) == 0) { 446 *type = SPL_NEM_TYPE; 447 return (0); 448 } else 449 return (-1); 450 } 451 /* 452 * return the first compatible value 453 */ 454 static int 455 stpaul_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 456 { 457 int err; 458 picl_prophdl_t proph; 459 picl_propinfo_t pinfo; 460 picl_prophdl_t tblh; 461 picl_prophdl_t rowproph; 462 char *pval; 463 464 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 465 &pinfo, &proph); 466 if (err != PICL_SUCCESS) 467 return (err); 468 469 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 470 pval = malloc(pinfo.size); 471 if (pval == NULL) 472 return (PICL_FAILURE); 473 err = picl_get_propval(proph, pval, pinfo.size); 474 if (err != PICL_SUCCESS) { 475 free(pval); 476 return (err); 477 } 478 *outbuf = pval; 479 return (PICL_SUCCESS); 480 } 481 482 if (pinfo.type != PICL_PTYPE_TABLE) 483 return (PICL_FAILURE); 484 485 /* get first string from table */ 486 err = picl_get_propval(proph, &tblh, pinfo.size); 487 if (err != PICL_SUCCESS) 488 return (err); 489 490 err = picl_get_next_by_row(tblh, &rowproph); 491 if (err != PICL_SUCCESS) 492 return (err); 493 494 err = picl_get_propinfo(rowproph, &pinfo); 495 if (err != PICL_SUCCESS) 496 return (err); 497 498 pval = malloc(pinfo.size); 499 if (pval == NULL) 500 return (PICL_FAILURE); 501 502 err = picl_get_propval(rowproph, pval, pinfo.size); 503 if (err != PICL_SUCCESS) { 504 free(pval); 505 return (err); 506 } 507 508 *outbuf = pval; 509 return (PICL_SUCCESS); 510 } 511 512 static int64_t 513 stpaul_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 514 { 515 int err; 516 picl_prophdl_t proph; 517 picl_propinfo_t pinfo; 518 int8_t int8v; 519 int16_t int16v; 520 int32_t int32v; 521 int64_t int64v; 522 523 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 524 if (err != PICL_SUCCESS) { 525 *ret = err; 526 return (0); 527 } 528 529 /* 530 * If it is not an int, uint or byte array prop, return failure 531 */ 532 if ((pinfo.type != PICL_PTYPE_INT) && 533 (pinfo.type != PICL_PTYPE_UNSIGNED_INT) && 534 (pinfo.type != PICL_PTYPE_BYTEARRAY)) { 535 *ret = PICL_FAILURE; 536 return (0); 537 } 538 539 switch (pinfo.size) { 540 case sizeof (int8_t): 541 err = picl_get_propval(proph, &int8v, sizeof (int8v)); 542 *ret = err; 543 return (int8v); 544 case sizeof (int16_t): 545 err = picl_get_propval(proph, &int16v, sizeof (int16v)); 546 *ret = err; 547 return (int16v); 548 case sizeof (int32_t): 549 err = picl_get_propval(proph, &int32v, sizeof (int32v)); 550 *ret = err; 551 return (int32v); 552 case sizeof (int64_t): 553 err = picl_get_propval(proph, &int64v, sizeof (int64v)); 554 *ret = err; 555 return (int64v); 556 default: /* not supported size */ 557 *ret = PICL_FAILURE; 558 return (0); 559 } 560 } 561