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