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