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