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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.open2solaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 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 == erie 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 "erie.h" 56 57 #if !defined(TEXT_DOMAIN) 58 #define TEXT_DOMAIN "SYS_TEST" 59 #endif 60 61 62 63 /* 64 * Add all io picl nodes under pci in io list 65 */ 66 /* ARGSUSED */ 67 int 68 erie_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 nac[MAXSTRLEN]; 78 char bus_type[MAXSTRLEN]; 79 int slot = NO_SLOT; 80 81 /* Get the parent node's path - used to determine bus type of child */ 82 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, parent_path, 83 sizeof (parent_path)); 84 if (err != PICL_SUCCESS) { 85 return (err); 86 } 87 88 /* Walk through this node's children */ 89 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 90 sizeof (picl_nodehdl_t)); 91 while (err == PICL_SUCCESS) { 92 93 /* Get child's class */ 94 if ((err = erie_get_class(nodeh, piclclass, 95 sizeof (piclclass))) != PICL_SUCCESS) 96 return (err); 97 98 /* If this node is a pci bus or bridge, get node's sibling */ 99 if ((strcmp(piclclass, "pci") == 0 || 100 (strcmp(piclclass, "pciex") == 0))) { 101 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, 102 &nodeh, sizeof (picl_nodehdl_t)); 103 continue; 104 } 105 106 /* 107 * In order to get certain values, it's necessary 108 * to search the picl tree. If there's a problem 109 * with these searches, we'll return the err 110 */ 111 if ((err = erie_get_path(nodeh, path, sizeof (path))) 112 != PICL_SUCCESS) 113 return (err); 114 if ((err = erie_get_name(nodeh, name, sizeof (name))) 115 != PICL_SUCCESS) 116 return (err); 117 if ((err = erie_get_model(nodeh, model, sizeof (model))) 118 != PICL_SUCCESS) 119 return (err); 120 erie_get_bus_type(parent_path, bus_type); 121 slot = erie_get_slot_number(path); 122 erie_get_nac(bus_type, path, slot, name, nac, sizeof (nac)); 123 124 125 /* Print out the data */ 126 127 /* Print NAC */ 128 log_printf("%-11s", nac); 129 130 /* Print IO Type */ 131 log_printf("%-6s", bus_type); 132 133 /* Print Slot # */ 134 if (slot != NO_SLOT) { 135 log_printf("%5d", slot); 136 log_printf("%46s", path); 137 } else { 138 log_printf("%5s", MOTHERBOARD); 139 log_printf("%46s", path); 140 } 141 142 /* Printf Node Name */ 143 log_printf("%26s", name); 144 if (strlen(name) > 30) 145 log_printf(dgettext(TEXT_DOMAIN, "+ ")); 146 else 147 log_printf(dgettext(TEXT_DOMAIN, " ")); 148 149 /* Print Card Model */ 150 log_printf("%-8s", model); 151 if (strlen(model) > 8) 152 log_printf(dgettext(TEXT_DOMAIN, "+")); 153 log_printf("\n"); 154 155 /* Grab the next child under parent node and do it again */ 156 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 157 sizeof (picl_nodehdl_t)); 158 } 159 return (PICL_WALK_CONTINUE); 160 } 161 162 163 /* 164 * ---------------------------------------------------------------------------- 165 */ 166 167 /* 168 * Add all IO ASIC revisions to list 169 */ 170 /* ARGSUSED */ 171 int 172 erie_hw_rev_callback(picl_nodehdl_t pcih, void *args) 173 { 174 int err = PICL_SUCCESS; 175 char path[MAXSTRLEN] = ""; 176 char nac[MAXSTRLEN]; 177 char *compatible; 178 int32_t revision; 179 180 /* Get path of this device */ 181 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path, 182 sizeof (path)); 183 if (err != PICL_SUCCESS) { 184 return (err); 185 } 186 /* 187 * If it's a network dev, then print network info. 188 * Else if it's not a network dev, check for FIRE ASIC 189 * Else return PICL_WALK_CONTINUE 190 */ 191 if ((strcmp(path, ERIE_NETWORK_0) == 0) || 192 (strcmp(path, ERIE_NETWORK_1) == 0)) { 193 (void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD, 194 OPHIR, 0); 195 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID, 196 &err); 197 } else if ((strcmp(path, ERIE_NETWORK_2) == 0) || 198 (strcmp(path, ERIE_NETWORK_3) == 0)) { 199 (void) snprintf(nac, sizeof (nac), "%s/%s%d", MOTHERBOARD, 200 OPHIR, 1); 201 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID, 202 &err); 203 } else if ((strcmp(path, ERIE_LSI_PATH) == 0)) { 204 (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD, 205 SAS_SATA_HBA); 206 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID, 207 &err); 208 } else if ((strcmp(path, FIRE0) == 0) || (strcmp(path, FIRE1) == 0)) { 209 (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD, 210 IOBRIDGE); 211 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID, 212 &err); 213 } else if ((strcmp(path, PCIE_PCIX) == 0) || 214 (strcmp(path, PCIE_PCIE) == 0)) { 215 (void) snprintf(nac, sizeof (nac), "%s/%s", MOTHERBOARD, 216 PCI_BRIDGE); 217 revision = erie_get_int_propval(pcih, OBP_PROP_REVISION_ID, 218 &err); 219 } else { 220 return (PICL_WALK_CONTINUE); 221 } 222 223 /* Get first compatible value from picl compatible list */ 224 err = erie_get_first_compatible_value(pcih, &compatible); 225 if (err != PICL_SUCCESS) { 226 return (err); 227 } 228 229 /* Print nacation */ 230 log_printf("%-20s", nac); 231 232 /* Print Device Path */ 233 log_printf("%41s", path); 234 235 /* Print Compatible # */ 236 log_printf("%31s", compatible); 237 free(compatible); 238 239 /* Print Revision */ 240 log_printf("%6d", revision); 241 log_printf("\n"); 242 243 return (PICL_WALK_CONTINUE); 244 } 245 246 /* 247 * ---------------------------------------------------------------------------- 248 */ 249 250 /* 251 * Local functions 252 */ 253 254 255 /* 256 * This function returns the first picl compatible value 257 */ 258 int 259 erie_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 260 { 261 int err; 262 picl_prophdl_t proph; 263 picl_propinfo_t pinfo; 264 picl_prophdl_t tblh; 265 picl_prophdl_t rowproph; 266 char *pval; 267 268 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 269 &pinfo, &proph); 270 if (err != PICL_SUCCESS) 271 return (err); 272 273 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 274 pval = malloc(pinfo.size); 275 if (pval == NULL) 276 return (PICL_FAILURE); 277 err = picl_get_propval(proph, pval, pinfo.size); 278 if (err != PICL_SUCCESS) { 279 free(pval); 280 return (err); 281 } 282 *outbuf = pval; 283 return (PICL_SUCCESS); 284 } 285 286 if (pinfo.type != PICL_PTYPE_TABLE) 287 return (PICL_FAILURE); 288 289 /* get first string from table */ 290 err = picl_get_propval(proph, &tblh, pinfo.size); 291 if (err != PICL_SUCCESS) 292 return (err); 293 294 err = picl_get_next_by_row(tblh, &rowproph); 295 if (err != PICL_SUCCESS) 296 return (err); 297 298 err = picl_get_propinfo(rowproph, &pinfo); 299 if (err != PICL_SUCCESS) 300 return (err); 301 302 pval = malloc(pinfo.size); 303 if (pval == NULL) 304 return (PICL_FAILURE); 305 306 err = picl_get_propval(rowproph, pval, pinfo.size); 307 if (err != PICL_SUCCESS) { 308 free(pval); 309 return (err); 310 } 311 312 *outbuf = pval; 313 return (PICL_SUCCESS); 314 } 315 316 /* 317 * This function returns the revision of 318 * a device. 319 */ 320 int64_t 321 erie_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 322 { 323 int err; 324 picl_prophdl_t proph; 325 picl_propinfo_t pinfo; 326 int8_t int8v; 327 int16_t int16v; 328 int32_t int32v; 329 int64_t int64v; 330 331 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 332 if (err != PICL_SUCCESS) { 333 *ret = err; 334 return (0); 335 } 336 337 /* 338 * If it is not an int, uint or byte array prop, return failure 339 */ 340 if ((pinfo.type != PICL_PTYPE_INT) && 341 (pinfo.type != PICL_PTYPE_UNSIGNED_INT) && 342 (pinfo.type != PICL_PTYPE_BYTEARRAY)) { 343 *ret = PICL_FAILURE; 344 return (0); 345 } 346 347 switch (pinfo.size) { 348 case sizeof (int8_t): 349 err = picl_get_propval(proph, &int8v, sizeof (int8v)); 350 *ret = err; 351 return (int8v); 352 case sizeof (int16_t): 353 err = picl_get_propval(proph, &int16v, sizeof (int16v)); 354 *ret = err; 355 return (int16v); 356 case sizeof (int32_t): 357 err = picl_get_propval(proph, &int32v, sizeof (int32v)); 358 *ret = err; 359 return (int32v); 360 case sizeof (int64_t): 361 err = picl_get_propval(proph, &int64v, sizeof (int64v)); 362 *ret = err; 363 return (int64v); 364 default: /* not supported size */ 365 *ret = PICL_FAILURE; 366 return (0); 367 } 368 } 369 370 /* 371 * This function fills in the bus type for an IO device. 372 * If a device hangs off /pci@7c0/pci@0/pci@8, it's on 373 * the pci-x bus. Otherwise, it's on a pci-e bus. 374 * 375 */ 376 void 377 erie_get_bus_type(char path[], char bus_type[]) 378 { 379 if (strncmp(path, PCIX_BUS, ERIE_PCIX_COMP) == 0) { 380 (void) strcpy(bus_type, "PCIX"); 381 } else { 382 (void) strcpy(bus_type, "PCIE"); 383 } 384 } 385 386 /* 387 * Thie function indicates whether a device is in a pci-e slot 388 * or if it's on the motherboard. There's only one pci-e slot 389 * on erie, everything else is on the motherboard. 390 * 391 */ 392 int 393 erie_get_slot_number(char path[]) 394 { 395 if (strncmp(path, FIRE0, ERIE_PCIE_COMP) == 0) 396 return (0); 397 return (NO_SLOT); 398 } 399 400 /* 401 * This function takes a path to one of the on-board 402 * network devices and returns the instance# of that 403 * device. 404 * 405 */ 406 int 407 erie_get_network_instance(char path[]) 408 { 409 410 if (strncmp(path, ERIE_NETWORK_1, strlen(ERIE_NETWORK_1)) == 0) { 411 return (1); 412 } else if (strncmp(path, ERIE_NETWORK_3, strlen(ERIE_NETWORK_3)) == 0) { 413 return (3); 414 } else if (strncmp(path, ERIE_NETWORK_0, strlen(ERIE_NETWORK_0)) == 0) { 415 return (0); 416 } else if (strncmp(path, ERIE_NETWORK_2, strlen(ERIE_NETWORK_2)) == 0) { 417 return (2); 418 } else { 419 return (-1); 420 } 421 } 422 423 /* 424 * This function gets the path of a node and 425 * the error code from the picl API 426 * 427 */ 428 int 429 erie_get_path(picl_nodehdl_t nodeh, char path[], int size) 430 { 431 int err; 432 433 /* hardware path of this node */ 434 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH, 435 path, size); 436 return (err); 437 } 438 439 /* 440 * This function returns assings the string passed in 441 * the value of the picl node's name 442 * 443 */ 444 int 445 erie_get_name(picl_nodehdl_t nodeh, char name[], int size) 446 { 447 int err; 448 char *compatible; 449 char binding_name[MAXSTRLEN]; 450 char lname[MAXSTRLEN]; 451 452 /* Get this node's name */ 453 err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &lname, size); 454 if (err == PICL_PROPNOTFOUND) { 455 (void) strcpy(lname, ""); 456 err = PICL_SUCCESS; 457 } 458 459 /* 460 * If binding_name is found, 461 * name will be <nodename>-<binding_name> 462 */ 463 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, 464 &binding_name, sizeof (binding_name)); 465 if (err == PICL_SUCCESS) { 466 if (strcmp(lname, binding_name) != 0) { 467 (void) strlcat(lname, "-", MAXSTRLEN); 468 (void) strlcat(lname, binding_name, MAXSTRLEN); 469 } 470 /* 471 * if compatible prop is not found, name will be 472 * <nodename>-<compatible> 473 */ 474 } else if (err == PICL_PROPNOTFOUND) { 475 err = erie_get_first_compatible_value(nodeh, &compatible); 476 if (err == PICL_SUCCESS) { 477 (void) strlcat(lname, "-", MAXSTRLEN); 478 (void) strlcat(lname, compatible, MAXSTRLEN); 479 } 480 err = PICL_SUCCESS; 481 } else { 482 return (err); 483 } 484 485 /* The name was created fine, copy it to name var */ 486 (void) strcpy(name, lname); 487 return (err); 488 } 489 490 /* 491 * This functions assigns the string passed in the 492 * the value of the picl node's NAC name. 493 */ 494 void 495 erie_get_nac(char bus_type[], char path[], int slot, char name[], char nac[], 496 int size) 497 { 498 int instance; 499 500 /* Figure out NAC name and instance, if onboard network node */ 501 if (strncmp(name, NETWORK, NET_COMP_NUM) == 0) { 502 instance = erie_get_network_instance(path); 503 (void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD, 504 "NET", instance); 505 } else if (slot != NO_SLOT) { 506 (void) snprintf(nac, size, "%s/%s%d", MOTHERBOARD, bus_type, 507 slot); 508 } else { 509 (void) snprintf(nac, size, "%s/%s", MOTHERBOARD, bus_type); 510 } 511 } 512 513 /* 514 * This function copies the node's model into model string 515 * 516 */ 517 int 518 erie_get_model(picl_nodehdl_t nodeh, char model[], int size) 519 { 520 int err; 521 char tmp_model[MAXSTRLEN]; 522 523 /* Get the model of this node */ 524 err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL, 525 &tmp_model, size); 526 if (err == PICL_PROPNOTFOUND) { 527 (void) strcpy(model, ""); 528 err = PICL_SUCCESS; 529 } else { 530 (void) strcpy(model, tmp_model); 531 } 532 return (err); 533 } 534 535 /* 536 * This function copies the node's class into class string 537 * 538 */ 539 int 540 erie_get_class(picl_nodehdl_t nodeh, char piclclass[], int size) 541 { 542 int err; 543 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 544 piclclass, size); 545 return (err); 546 } 547