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