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