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