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_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 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 /* Walk through the children */ 88 89 err = picl_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 90 sizeof (picl_nodehdl_t)); 91 92 while (err == PICL_SUCCESS) { 93 err = picl_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 94 piclclass, sizeof (piclclass)); 95 if (err != PICL_SUCCESS) 96 return (err); 97 98 if (strcmp(piclclass, "pciex") == 0) { 99 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, 100 &nodeh, sizeof (picl_nodehdl_t)); 101 continue; 102 } 103 104 if (strcmp(piclclass, PICL_CLASS_PCI) == 0) { 105 err = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD, 106 &nodeh, sizeof (picl_nodehdl_t)); 107 continue; 108 } 109 110 err = picl_get_propval_by_name(nodeh, PICL_PROP_DEVFS_PATH, 111 path, sizeof (path)); 112 if (err != PICL_SUCCESS) 113 return (err); 114 115 (void) strlcpy(pci_card.notes, path, sizeof (pci_card.notes)); 116 117 get_bus_type(parent_path, &pci_card); 118 119 get_slot_number(parent_path, &pci_card); 120 121 err = picl_get_propval_by_name(nodeh, PICL_PROP_NAME, &name, 122 sizeof (name)); 123 if (err == PICL_PROPNOTFOUND) 124 (void) strcpy(name, ""); 125 else if (err != PICL_SUCCESS) 126 return (err); 127 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 134 (void) snprintf(pci_card.status, 135 sizeof (pci_card.status), "%s/%s%d", MOTHERBOARD, 136 "NET", instance); 137 } else { 138 if (pci_card.slot != -1) { 139 (void) snprintf(pci_card.status, 140 sizeof (pci_card.status), "%s/%s%d", 141 MOTHERBOARD, pci_card.bus_type, 142 pci_card.slot); 143 } else { 144 (void) snprintf(pci_card.status, 145 sizeof (pci_card.status), "%s/%s", 146 MOTHERBOARD, pci_card.bus_type); 147 } 148 } 149 150 /* 151 * Get the name of this card. If binding_name is found, 152 * name will be <nodename>-<binding_name> 153 */ 154 155 err = picl_get_propval_by_name(nodeh, PICL_PROP_BINDING_NAME, 156 &binding_name, sizeof (binding_name)); 157 if (err == PICL_PROPNOTFOUND) { 158 /* 159 * if compatible prop is found, name will be 160 * <nodename>-<compatible> 161 */ 162 err = stpaul_get_first_compatible_value(nodeh, 163 &compatible); 164 if (err == PICL_SUCCESS) { 165 (void) strlcat(name, "-", MAXSTRLEN); 166 (void) strlcat(name, compatible, MAXSTRLEN); 167 free(compatible); 168 } else if (err != PICL_PROPNOTFOUND) 169 return (err); 170 } else if (err != PICL_SUCCESS) 171 return (err); 172 else if (strcmp(name, binding_name) != 0) { 173 (void) strlcat(name, "-", MAXSTRLEN); 174 (void) strlcat(name, binding_name, MAXSTRLEN); 175 } 176 177 (void) strlcpy(pci_card.name, name, sizeof (pci_card.name)); 178 179 /* Get the model of this card */ 180 181 err = picl_get_propval_by_name(nodeh, OBP_PROP_MODEL, 182 &model, sizeof (model)); 183 if (err == PICL_PROPNOTFOUND) 184 (void) strcpy(model, ""); 185 else if (err != PICL_SUCCESS) 186 return (err); 187 (void) strlcpy(pci_card.model, model, sizeof (pci_card.model)); 188 189 /* Print NAC name */ 190 log_printf("%-11s", pci_card.status); 191 /* Print IO Type */ 192 log_printf("%6s", pci_card.bus_type); 193 /* Print Slot # */ 194 log_printf("%5s", pci_card.slot_str); 195 /* Print Parent Path */ 196 log_printf("%46.45s", pci_card.notes); 197 /* Printf Card Name */ 198 if (strlen(pci_card.name) > 24) 199 log_printf("%25.24s+", pci_card.name); 200 else 201 log_printf("%26s", pci_card.name); 202 /* Print Card Model */ 203 if (strlen(pci_card.model) > 10) 204 log_printf("%10.9s+", pci_card.model); 205 else 206 log_printf("%10s", pci_card.model); 207 log_printf("\n"); 208 209 err = picl_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 210 sizeof (picl_nodehdl_t)); 211 212 } 213 214 return (PICL_WALK_CONTINUE); 215 } 216 217 /* ARGSUSED */ 218 int 219 stpaul_hw_rev_callback(picl_nodehdl_t pcih, void *args) 220 { 221 int err = PICL_SUCCESS; 222 char path[MAXSTRLEN] = ""; 223 char device_path[MAXSTRLEN]; 224 char NAC[MAXSTRLEN]; 225 char *compatible; 226 int32_t revision; 227 int device_found = 0; 228 229 err = picl_get_propval_by_name(pcih, PICL_PROP_DEVFS_PATH, path, 230 sizeof (path)); 231 if (err != PICL_SUCCESS) 232 return (err); 233 234 if ((strcmp(path, SPL_NETWORK_0_PATH) == 0) || 235 (strcmp(path, SPL_NETWORK_1_PATH) == 0)) { 236 device_found = 1; 237 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD, 238 OPHIR, 0); 239 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 240 &err); 241 } 242 243 if ((strcmp(path, SPL_NSC_USB0_PATH) == 0) || 244 (strcmp(path, SPL_NSC_USB1_PATH) == 0) || 245 (strcmp(path, SPL_NSC_USB2_PATH) == 0) || 246 (strcmp(path, SPL_NSC_USB3_PATH) == 0)) { 247 device_found = 1; 248 (void) snprintf(NAC, sizeof (NAC), "%s/%s%d", MOTHERBOARD, 249 USB, 0); 250 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 251 &err); 252 } 253 254 if ((strcmp(path, FIRE_PATH0) == 0) || 255 (strcmp(path, FIRE_PATH1) == 0)) { 256 device_found = 1; 257 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 258 "IO-BRIDGE"); 259 revision = stpaul_get_int_propval(pcih, OBP_PROP_VERSION_NUM, 260 &err); 261 } 262 263 if ((strcmp(path, SPL_PCIE_SLOT0) == 0) || 264 (strcmp(path, SPL_PCIE_SLOT1) == 0) || 265 (strcmp(path, SPL_PCIE_SLOT2) == 0) || 266 (strcmp(path, SPL_PCIE_SLOT3) == 0)) { 267 device_found = 1; 268 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 269 PCI_BRIDGE); 270 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 271 &err); 272 } 273 274 if (strcmp(path, SWITCH_A_PATH) == 0) { 275 device_found = 1; 276 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 277 SWITCH_A); 278 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 279 &err); 280 } 281 282 if (strcmp(path, SWITCH_B_PATH) == 0) { 283 device_found = 1; 284 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 285 SWITCH_B); 286 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 287 &err); 288 } 289 290 if (strcmp(path, SPL_LSI_PATH) == 0) { 291 device_found = 1; 292 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 293 SPL_SAS_HBA); 294 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 295 &err); 296 } 297 298 if (strcmp(path, SPL_PCIE2PCI) == 0) { 299 device_found = 1; 300 (void) snprintf(NAC, sizeof (NAC), "%s/%s", MOTHERBOARD, 301 PCI_BRIDGE); 302 revision = stpaul_get_int_propval(pcih, OBP_PROP_REVISION_ID, 303 &err); 304 } 305 306 if (device_found == 1) { 307 308 (void) strcpy(device_path, path); 309 err = stpaul_get_first_compatible_value(pcih, &compatible); 310 311 /* Print NAC name */ 312 log_printf("%-20s", NAC); 313 /* Print Device Path */ 314 if (strlen(device_path) > 38) 315 log_printf("%38.37s+", device_path); 316 else 317 log_printf("%39s", device_path); 318 /* Print Compatible # */ 319 log_printf("%31s", compatible); 320 free(compatible); 321 /* Print Revision */ 322 log_printf("%6d", revision); 323 log_printf("\n"); 324 } 325 326 return (PICL_WALK_CONTINUE); 327 } 328 329 static void 330 get_bus_type(char *path, struct io_card *card) 331 { 332 if (strncmp(path, SPL_PCIE_SLOT0, strlen(SPL_PCIE_SLOT0)) == 0) { 333 (void) strcpy(card->bus_type, "PCIE"); 334 } else if (strncmp(path, SPL_PCIE_SLOT1, strlen(SPL_PCIE_SLOT1)) == 0) { 335 (void) strcpy(card->bus_type, "PCIE"); 336 } else if (strncmp(path, SPL_PCIE_SLOT2, strlen(SPL_PCIE_SLOT2)) == 0) { 337 (void) strcpy(card->bus_type, "PCIE"); 338 } else if (strncmp(path, SPL_PCIE_SLOT3, strlen(SPL_PCIE_SLOT3)) == 0) { 339 (void) strcpy(card->bus_type, "PCIE"); 340 } else if (strncmp(path, SWITCH_A_PATH, strlen(SWITCH_A_PATH)) == 0) { 341 (void) strcpy(card->bus_type, "PCIE"); 342 } else if (strncmp(path, SWITCH_B_PATH, strlen(SWITCH_B_PATH)) == 0) { 343 (void) strcpy(card->bus_type, "PCIE"); 344 } else { 345 (void) strcpy(card->bus_type, "NONE"); 346 } 347 } 348 349 static void 350 get_slot_number(char *path, struct io_card *card) 351 { 352 if (strncmp(path, SPL_PCIE_SLOT0, strlen(SPL_PCIE_SLOT0)) == 0) { 353 (void) strcpy(card->slot_str, "0"); 354 card->slot = 0; 355 } else if (strncmp(path, SPL_PCIE_SLOT1, strlen(SPL_PCIE_SLOT1)) == 0) { 356 (void) strcpy(card->slot_str, "1"); 357 card->slot = 1; 358 } else if (strncmp(path, SPL_PCIE_SLOT2, strlen(SPL_PCIE_SLOT2)) == 0) { 359 (void) strcpy(card->slot_str, "2"); 360 card->slot = 2; 361 } else if (strncmp(path, SPL_PCIE_SLOT3, strlen(SPL_PCIE_SLOT3)) == 0) { 362 (void) strcpy(card->slot_str, "3"); 363 card->slot = 3; 364 } else { 365 (void) strcpy(card->slot_str, MOTHERBOARD); 366 card->slot = -1; 367 } 368 } 369 370 static int 371 stpaul_get_network_instance(char *path) 372 { 373 if (strncmp(path, SPL_NETWORK_1_PATH, 374 strlen(SPL_NETWORK_1_PATH)) == 0) 375 return (1); 376 else if (strncmp(path, SPL_NETWORK_0_PATH, 377 strlen(SPL_NETWORK_0_PATH)) == 0) 378 return (0); 379 else 380 return (-1); 381 } 382 383 /* 384 * return the first compatible value 385 */ 386 static int 387 stpaul_get_first_compatible_value(picl_nodehdl_t nodeh, char **outbuf) 388 { 389 int err; 390 picl_prophdl_t proph; 391 picl_propinfo_t pinfo; 392 picl_prophdl_t tblh; 393 picl_prophdl_t rowproph; 394 char *pval; 395 396 err = picl_get_propinfo_by_name(nodeh, OBP_PROP_COMPATIBLE, 397 &pinfo, &proph); 398 if (err != PICL_SUCCESS) 399 return (err); 400 401 if (pinfo.type == PICL_PTYPE_CHARSTRING) { 402 pval = malloc(pinfo.size); 403 if (pval == NULL) 404 return (PICL_FAILURE); 405 err = picl_get_propval(proph, pval, pinfo.size); 406 if (err != PICL_SUCCESS) { 407 free(pval); 408 return (err); 409 } 410 *outbuf = pval; 411 return (PICL_SUCCESS); 412 } 413 414 if (pinfo.type != PICL_PTYPE_TABLE) 415 return (PICL_FAILURE); 416 417 /* get first string from table */ 418 err = picl_get_propval(proph, &tblh, pinfo.size); 419 if (err != PICL_SUCCESS) 420 return (err); 421 422 err = picl_get_next_by_row(tblh, &rowproph); 423 if (err != PICL_SUCCESS) 424 return (err); 425 426 err = picl_get_propinfo(rowproph, &pinfo); 427 if (err != PICL_SUCCESS) 428 return (err); 429 430 pval = malloc(pinfo.size); 431 if (pval == NULL) 432 return (PICL_FAILURE); 433 434 err = picl_get_propval(rowproph, pval, pinfo.size); 435 if (err != PICL_SUCCESS) { 436 free(pval); 437 return (err); 438 } 439 440 *outbuf = pval; 441 return (PICL_SUCCESS); 442 } 443 444 static int64_t 445 stpaul_get_int_propval(picl_nodehdl_t modh, char *prop_name, int *ret) 446 { 447 int err; 448 picl_prophdl_t proph; 449 picl_propinfo_t pinfo; 450 int8_t int8v; 451 int16_t int16v; 452 int32_t int32v; 453 int64_t int64v; 454 455 err = picl_get_propinfo_by_name(modh, prop_name, &pinfo, &proph); 456 if (err != PICL_SUCCESS) { 457 *ret = err; 458 return (0); 459 } 460 461 /* 462 * If it is not an int, uint or byte array prop, return failure 463 */ 464 if ((pinfo.type != PICL_PTYPE_INT) && 465 (pinfo.type != PICL_PTYPE_UNSIGNED_INT) && 466 (pinfo.type != PICL_PTYPE_BYTEARRAY)) { 467 *ret = PICL_FAILURE; 468 return (0); 469 } 470 471 switch (pinfo.size) { 472 case sizeof (int8_t): 473 err = picl_get_propval(proph, &int8v, sizeof (int8v)); 474 *ret = err; 475 return (int8v); 476 case sizeof (int16_t): 477 err = picl_get_propval(proph, &int16v, sizeof (int16v)); 478 *ret = err; 479 return (int16v); 480 case sizeof (int32_t): 481 err = picl_get_propval(proph, &int32v, sizeof (int32v)); 482 *ret = err; 483 return (int32v); 484 case sizeof (int64_t): 485 err = picl_get_propval(proph, &int64v, sizeof (int64v)); 486 *ret = err; 487 return (int64v); 488 default: /* not supported size */ 489 *ret = PICL_FAILURE; 490 return (0); 491 } 492 } 493