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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Copyright 2019 Joyent, Inc. 28 */ 29 30 /* 31 * PICL plug-in that creates device tree nodes for all platforms 32 */ 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <ctype.h> 37 #include <limits.h> 38 #include <stdlib.h> 39 #include <assert.h> 40 #include <alloca.h> 41 #include <unistd.h> 42 #include <stropts.h> 43 #include <syslog.h> 44 #include <libdevinfo.h> 45 #include <sys/dkio.h> 46 #include <sys/vtoc.h> 47 #include <sys/time.h> 48 #include <fcntl.h> 49 #include <picl.h> 50 #include <picltree.h> 51 #include <sys/types.h> 52 #include <sys/processor.h> 53 #include <kstat.h> 54 #include <sys/sysinfo.h> 55 #include <dirent.h> 56 #include <libintl.h> 57 #include <pthread.h> 58 #include <libnvpair.h> 59 #include <sys/utsname.h> 60 #include <sys/systeminfo.h> 61 #include <sys/obpdefs.h> 62 #include <sys/openpromio.h> 63 #include "picldevtree.h" 64 65 /* 66 * Plugin registration entry points 67 */ 68 static void picldevtree_register(void); 69 static void picldevtree_init(void); 70 static void picldevtree_fini(void); 71 72 static void picldevtree_evhandler(const char *ename, const void *earg, 73 size_t size, void *cookie); 74 75 #pragma init(picldevtree_register) 76 77 /* 78 * Log message texts 79 */ 80 #define DEVINFO_PLUGIN_INIT_FAILED gettext("SUNW_picldevtree failed!\n") 81 #define PICL_EVENT_DROPPED \ 82 gettext("SUNW_picldevtree '%s' event dropped.\n") 83 84 /* 85 * Macro to get PCI device id (from IEEE 1275 spec) 86 */ 87 #define PCI_DEVICE_ID(x) (((x) >> 11) & 0x1f) 88 /* 89 * Local variables 90 */ 91 static picld_plugin_reg_t my_reg_info = { 92 PICLD_PLUGIN_VERSION_1, 93 PICLD_PLUGIN_CRITICAL, 94 "SUNW_picldevtree", 95 picldevtree_init, 96 picldevtree_fini 97 }; 98 99 /* 100 * Debug enabling environment variable 101 */ 102 #define SUNW_PICLDEVTREE_PLUGIN_DEBUG "SUNW_PICLDEVTREE_PLUGIN_DEBUG" 103 static int picldevtree_debug = 0; 104 105 static conf_entries_t *conf_name_class_map = NULL; 106 static builtin_map_t sun4u_map[] = { 107 /* MAX_NAMEVAL_SIZE */ 108 { "SUNW,bpp", PICL_CLASS_PARALLEL}, 109 { "parallel", PICL_CLASS_PARALLEL}, 110 { "floppy", PICL_CLASS_FLOPPY}, 111 { "memory", PICL_CLASS_MEMORY}, 112 { "ebus", PICL_CLASS_EBUS}, 113 { "i2c", PICL_CLASS_I2C}, 114 { "usb", PICL_CLASS_USB}, 115 { "isa", PICL_CLASS_ISA}, 116 { "dma", PICL_CLASS_DMA}, 117 { "keyboard", PICL_CLASS_KEYBOARD}, 118 { "mouse", PICL_CLASS_MOUSE}, 119 { "fan-control", PICL_CLASS_FAN_CONTROL}, 120 { "sc", PICL_CLASS_SYSTEM_CONTROLLER}, 121 { "dimm", PICL_CLASS_SEEPROM}, 122 { "dimm-fru", PICL_CLASS_SEEPROM}, 123 { "cpu", PICL_CLASS_SEEPROM}, 124 { "cpu-fru", PICL_CLASS_SEEPROM}, 125 { "flashprom", PICL_CLASS_FLASHPROM}, 126 { "temperature", PICL_CLASS_TEMPERATURE_DEVICE}, 127 { "motherboard", PICL_CLASS_SEEPROM}, 128 { "motherboard-fru", PICL_CLASS_SEEPROM}, 129 { "motherboard-fru-prom", PICL_CLASS_SEEPROM}, 130 { "pmu", PICL_CLASS_PMU}, 131 { "sound", PICL_CLASS_SOUND}, 132 { "firewire", PICL_CLASS_FIREWIRE}, 133 { "i2c-at34c02", PICL_CLASS_SEEPROM}, 134 { "hardware-monitor", PICL_CLASS_HARDWARE_MONITOR}, 135 { "", ""} 136 }; 137 static builtin_map_t i86pc_map[] = { 138 /* MAX_NAMEVAL_SIZE */ 139 { "cpus", PICL_CLASS_I86CPUS}, 140 { "cpu", PICL_CLASS_CPU}, 141 { "memory", PICL_CLASS_MEMORY}, 142 { "asy", PICL_CLASS_SERIAL}, 143 { "", ""} 144 }; 145 static pname_type_map_t pname_type_map[] = { 146 { "reg", PICL_PTYPE_BYTEARRAY}, 147 { "device_type", PICL_PTYPE_CHARSTRING}, 148 { "ranges", PICL_PTYPE_BYTEARRAY}, 149 { "status", PICL_PTYPE_CHARSTRING}, 150 { "compatible", PICL_PTYPE_CHARSTRING}, 151 { "interrupts", PICL_PTYPE_BYTEARRAY}, 152 { "model", PICL_PTYPE_CHARSTRING}, 153 { "address", PICL_PTYPE_BYTEARRAY}, 154 { "vendor-id", PICL_PTYPE_UNSIGNED_INT}, 155 { "device-id", PICL_PTYPE_UNSIGNED_INT}, 156 { "revision-id", PICL_PTYPE_UNSIGNED_INT}, 157 { "class-code", PICL_PTYPE_UNSIGNED_INT}, 158 { "min-grant", PICL_PTYPE_UNSIGNED_INT}, 159 { "max-latency", PICL_PTYPE_UNSIGNED_INT}, 160 { "devsel-speed", PICL_PTYPE_UNSIGNED_INT}, 161 { "subsystem-id", PICL_PTYPE_UNSIGNED_INT}, 162 { "subsystem-vendor-id", PICL_PTYPE_UNSIGNED_INT}, 163 { "assigned-addresses", PICL_PTYPE_BYTEARRAY}, 164 { "configuration#", PICL_PTYPE_UNSIGNED_INT}, 165 { "assigned-address", PICL_PTYPE_UNSIGNED_INT}, 166 { "#address-cells", PICL_PTYPE_UNSIGNED_INT}, 167 { "#size-cells", PICL_PTYPE_UNSIGNED_INT}, 168 { "clock-frequency", PICL_PTYPE_UNSIGNED_INT}, 169 { "scsi-initiator-id", PICL_PTYPE_UNSIGNED_INT}, 170 { "differential", PICL_PTYPE_UNSIGNED_INT}, 171 { "idprom", PICL_PTYPE_BYTEARRAY}, 172 { "bus-range", PICL_PTYPE_BYTEARRAY}, 173 { "alternate-reg", PICL_PTYPE_BYTEARRAY}, 174 { "power-consumption", PICL_PTYPE_BYTEARRAY}, 175 { "slot-names", PICL_PTYPE_BYTEARRAY}, 176 { "burst-sizes", PICL_PTYPE_UNSIGNED_INT}, 177 { "up-burst-sizes", PICL_PTYPE_UNSIGNED_INT}, 178 { "slot-address-bits", PICL_PTYPE_UNSIGNED_INT}, 179 { "eisa-slots", PICL_PTYPE_BYTEARRAY}, 180 { "dma", PICL_PTYPE_BYTEARRAY}, 181 { "slot-names-index", PICL_PTYPE_UNSIGNED_INT}, 182 { "pnp-csn", PICL_PTYPE_UNSIGNED_INT}, 183 { "pnp-data", PICL_PTYPE_BYTEARRAY}, 184 { "description", PICL_PTYPE_CHARSTRING}, 185 { "pnp-id", PICL_PTYPE_CHARSTRING}, 186 { "max-frame-size", PICL_PTYPE_UNSIGNED_INT}, 187 { "address-bits", PICL_PTYPE_UNSIGNED_INT}, 188 { "local-mac-address", PICL_PTYPE_BYTEARRAY}, 189 { "mac-address", PICL_PTYPE_BYTEARRAY}, 190 { "character-set", PICL_PTYPE_CHARSTRING}, 191 { "available", PICL_PTYPE_BYTEARRAY}, 192 { "port-wwn", PICL_PTYPE_BYTEARRAY}, 193 { "node-wwn", PICL_PTYPE_BYTEARRAY}, 194 { "width", PICL_PTYPE_UNSIGNED_INT}, 195 { "linebytes", PICL_PTYPE_UNSIGNED_INT}, 196 { "height", PICL_PTYPE_UNSIGNED_INT}, 197 { "banner-name", PICL_PTYPE_CHARSTRING}, 198 { "reset-reason", PICL_PTYPE_CHARSTRING}, 199 { "implementation#", PICL_PTYPE_UNSIGNED_INT}, 200 { "version#", PICL_PTYPE_UNSIGNED_INT}, 201 { "icache-size", PICL_PTYPE_UNSIGNED_INT}, 202 { "icache-line-size", PICL_PTYPE_UNSIGNED_INT}, 203 { "icache-associativity", PICL_PTYPE_UNSIGNED_INT}, 204 { "l1-icache-size", PICL_PTYPE_UNSIGNED_INT}, 205 { "l1-icache-line-size", PICL_PTYPE_UNSIGNED_INT}, 206 { "l1-icache-associativity", PICL_PTYPE_UNSIGNED_INT}, 207 { "#itlb-entries", PICL_PTYPE_UNSIGNED_INT}, 208 { "dcache-size", PICL_PTYPE_UNSIGNED_INT}, 209 { "dcache-line-size", PICL_PTYPE_UNSIGNED_INT}, 210 { "dcache-associativity", PICL_PTYPE_UNSIGNED_INT}, 211 { "l1-dcache-size", PICL_PTYPE_UNSIGNED_INT}, 212 { "l1-dcache-line-size", PICL_PTYPE_UNSIGNED_INT}, 213 { "l1-dcache-associativity", PICL_PTYPE_UNSIGNED_INT}, 214 { "#dtlb-entries", PICL_PTYPE_UNSIGNED_INT}, 215 { "ecache-size", PICL_PTYPE_UNSIGNED_INT}, 216 { "ecache-line-size", PICL_PTYPE_UNSIGNED_INT}, 217 { "ecache-associativity", PICL_PTYPE_UNSIGNED_INT}, 218 { "l2-cache-size", PICL_PTYPE_UNSIGNED_INT}, 219 { "l2-cache-line-size", PICL_PTYPE_UNSIGNED_INT}, 220 { "l2-cache-associativity", PICL_PTYPE_UNSIGNED_INT}, 221 { "l2-cache-sharing", PICL_PTYPE_BYTEARRAY}, 222 { "mask#", PICL_PTYPE_UNSIGNED_INT}, 223 { "manufacturer#", PICL_PTYPE_UNSIGNED_INT}, 224 { "sparc-version", PICL_PTYPE_UNSIGNED_INT}, 225 { "version", PICL_PTYPE_CHARSTRING}, 226 { "cpu-model", PICL_PTYPE_UNSIGNED_INT}, 227 { "memory-layout", PICL_PTYPE_BYTEARRAY}, 228 { "#interrupt-cells", PICL_PTYPE_UNSIGNED_INT}, 229 { "interrupt-map", PICL_PTYPE_BYTEARRAY}, 230 { "interrupt-map-mask", PICL_PTYPE_BYTEARRAY} 231 }; 232 233 #define PNAME_MAP_SIZE sizeof (pname_type_map) / sizeof (pname_type_map_t) 234 235 static builtin_map_t *builtin_map_ptr = NULL; 236 static int builtin_map_size = 0; 237 static char mach_name[SYS_NMLN]; 238 static di_prom_handle_t ph = DI_PROM_HANDLE_NIL; 239 static int snapshot_stale; 240 241 /* 242 * UnitAddress mapping table 243 */ 244 static unitaddr_func_t encode_default_unitaddr; 245 static unitaddr_func_t encode_optional_unitaddr; 246 static unitaddr_func_t encode_scsi_unitaddr; 247 static unitaddr_func_t encode_upa_unitaddr; 248 static unitaddr_func_t encode_gptwo_jbus_unitaddr; 249 static unitaddr_func_t encode_pci_unitaddr; 250 251 static unitaddr_map_t unitaddr_map_table[] = { 252 {PICL_CLASS_JBUS, encode_gptwo_jbus_unitaddr, 0}, 253 {PICL_CLASS_GPTWO, encode_gptwo_jbus_unitaddr, 0}, 254 {PICL_CLASS_PCI, encode_pci_unitaddr, 0}, 255 {PICL_CLASS_PCIEX, encode_pci_unitaddr, 0}, 256 {PICL_CLASS_UPA, encode_upa_unitaddr, 0}, 257 {PICL_CLASS_SCSI, encode_scsi_unitaddr, 0}, 258 {PICL_CLASS_SCSI2, encode_scsi_unitaddr, 0}, 259 {PICL_CLASS_EBUS, encode_default_unitaddr, 2}, 260 {PICL_CLASS_SBUS, encode_default_unitaddr, 2}, 261 {PICL_CLASS_I2C, encode_default_unitaddr, 2}, 262 {PICL_CLASS_USB, encode_default_unitaddr, 1}, 263 {PICL_CLASS_PMU, encode_optional_unitaddr, 2}, 264 {NULL, encode_default_unitaddr, 0} 265 }; 266 267 static int add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh); 268 static int get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, 269 char *unitaddr, size_t ualen); 270 static void set_pci_pciex_deviceid(picl_nodehdl_t plafh); 271 272 /* 273 * The mc event completion handler. 274 * The arguments are event name buffer and a packed nvlist buffer 275 * with the size specifying the size of unpacked nvlist. These 276 * buffers are deallcoated here. 277 * 278 * Also, if a memory controller node is being removed then destroy the 279 * PICL subtree associated with that memory controller. 280 */ 281 static void 282 mc_completion_handler(char *ename, void *earg, size_t size) 283 { 284 picl_nodehdl_t mch; 285 nvlist_t *unpack_nvl; 286 287 if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0 && 288 nvlist_unpack(earg, size, &unpack_nvl, 0) == 0) { 289 mch = 0; 290 (void) nvlist_lookup_uint64(unpack_nvl, 291 PICLEVENTARG_NODEHANDLE, &mch); 292 if (mch != 0) { 293 if (picldevtree_debug) 294 syslog(LOG_INFO, 295 "picldevtree: destroying_node:%llx\n", 296 mch); 297 (void) ptree_destroy_node(mch); 298 } 299 nvlist_free(unpack_nvl); 300 } 301 302 free(ename); 303 free(earg); 304 } 305 306 /* 307 * Functions to post memory controller change event 308 */ 309 static int 310 post_mc_event(char *ename, picl_nodehdl_t mch) 311 { 312 nvlist_t *nvl; 313 size_t nvl_size; 314 char *pack_buf; 315 char *ev_name; 316 317 ev_name = strdup(ename); 318 if (ev_name == NULL) 319 return (-1); 320 321 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) { 322 free(ev_name); 323 return (-1); 324 } 325 326 pack_buf = NULL; 327 if (nvlist_add_uint64(nvl, PICLEVENTARG_NODEHANDLE, mch) || 328 nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE, 0)) { 329 free(ev_name); 330 nvlist_free(nvl); 331 return (-1); 332 } 333 334 if (picldevtree_debug) 335 syslog(LOG_INFO, 336 "picldevtree: posting MC event ename:%s nodeh:%llx\n", 337 ev_name, mch); 338 if (ptree_post_event(ev_name, pack_buf, nvl_size, 339 mc_completion_handler) != PICL_SUCCESS) { 340 free(ev_name); 341 nvlist_free(nvl); 342 return (-1); 343 } 344 nvlist_free(nvl); 345 return (0); 346 } 347 348 /* 349 * Lookup a name in the name to class map tables 350 */ 351 static int 352 lookup_name_class_map(char *classbuf, const char *nm) 353 { 354 conf_entries_t *ptr; 355 int i; 356 357 /* 358 * check name to class mapping in conf file 359 */ 360 ptr = conf_name_class_map; 361 362 while (ptr != NULL) { 363 if (strcmp(ptr->name, nm) == 0) { 364 (void) strlcpy(classbuf, ptr->piclclass, 365 PICL_CLASSNAMELEN_MAX); 366 return (0); 367 } 368 ptr = ptr->next; 369 } 370 371 /* 372 * check name to class mapping in builtin table 373 */ 374 if (builtin_map_ptr == NULL) 375 return (-1); 376 377 for (i = 0; i < builtin_map_size; ++i) 378 if (strcmp(builtin_map_ptr[i].name, nm) == 0) { 379 (void) strlcpy(classbuf, builtin_map_ptr[i].piclclass, 380 PICL_CLASSNAMELEN_MAX); 381 return (0); 382 } 383 return (-1); 384 } 385 386 /* 387 * Lookup a prop name in the pname to class map table 388 */ 389 static int 390 lookup_pname_type_map(const char *pname, picl_prop_type_t *type) 391 { 392 int i; 393 394 for (i = 0; i < PNAME_MAP_SIZE; ++i) 395 if (strcmp(pname_type_map[i].pname, pname) == 0) { 396 *type = pname_type_map[i].type; 397 return (0); 398 } 399 400 return (-1); 401 } 402 403 /* 404 * Return the number of strings in the buffer 405 */ 406 static int 407 get_string_count(char *strdat, int length) 408 { 409 int count; 410 char *lastnull; 411 char *nullptr; 412 413 count = 1; 414 for (lastnull = &strdat[length - 1], nullptr = strchr(strdat, '\0'); 415 nullptr != lastnull; nullptr = strchr(nullptr+1, '\0')) 416 count++; 417 418 return (count); 419 } 420 421 /* 422 * Return 1 if the node has a "reg" property 423 */ 424 static int 425 has_reg_prop(di_node_t dn) 426 { 427 int *pdata; 428 int dret; 429 430 dret = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, OBP_REG, &pdata); 431 if (dret > 0) 432 return (1); 433 434 if (!ph) 435 return (0); 436 dret = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata); 437 return (dret < 0 ? 0 : 1); 438 } 439 440 /* 441 * This function copies a PROM node's device_type property value into the 442 * buffer given by outbuf. The buffer size is PICL_CLASSNAMELEN_MAX. 443 * 444 * We reclassify device_type 'fru-prom' to PICL class 'seeprom' 445 * for FRUID support. 446 */ 447 static int 448 get_device_type(char *outbuf, di_node_t dn) 449 { 450 char *pdata; 451 char *pdatap; 452 int dret; 453 int i; 454 455 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_DEVICETYPE, 456 &pdata); 457 if (dret <= 0) { 458 if (!ph) 459 return (-1); 460 461 dret = di_prom_prop_lookup_strings(ph, dn, OBP_DEVICETYPE, 462 &pdata); 463 if (dret <= 0) { 464 return (-1); 465 } 466 } 467 468 if (dret != 1) { 469 /* 470 * multiple strings 471 */ 472 pdatap = pdata; 473 for (i = 0; i < (dret - 1); ++i) { 474 pdatap += strlen(pdatap); 475 *pdatap = '-'; /* replace '\0' with '-' */ 476 pdatap++; 477 } 478 } 479 if (strcasecmp(pdata, "fru-prom") == 0) { 480 /* 481 * Use PICL 'seeprom' class for fru-prom device types 482 */ 483 (void) strlcpy(outbuf, PICL_CLASS_SEEPROM, 484 PICL_CLASSNAMELEN_MAX); 485 } else { 486 (void) strlcpy(outbuf, pdata, PICL_CLASSNAMELEN_MAX); 487 } 488 return (0); 489 } 490 491 /* 492 * Get the minor node name in the class buffer passed 493 */ 494 static int 495 get_minor_class(char *classbuf, di_node_t dn) 496 { 497 di_minor_t mi_node; 498 char *mi_nodetype; 499 char *mi_name; 500 501 /* get minor node type */ 502 mi_node = di_minor_next(dn, DI_MINOR_NIL); 503 if (mi_node == DI_MINOR_NIL) 504 return (-1); 505 506 mi_nodetype = di_minor_nodetype(mi_node); 507 if (mi_nodetype == NULL) { /* no type info, return name */ 508 mi_name = di_minor_name(mi_node); 509 if (mi_name == NULL) 510 return (-1); 511 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX); 512 return (0); 513 } 514 515 #define DDI_NODETYPE(x, y) (strncmp(x, y, (sizeof (y) - 1)) == 0) 516 517 /* 518 * convert the string to the picl class for non-peudo nodes 519 */ 520 if (DDI_NODETYPE(mi_nodetype, DDI_PSEUDO)) 521 return (-1); 522 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_WWN)) 523 (void) strcpy(classbuf, PICL_CLASS_BLOCK); 524 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_CHAN)) 525 (void) strcpy(classbuf, PICL_CLASS_BLOCK); 526 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD)) 527 (void) strcpy(classbuf, PICL_CLASS_CDROM); 528 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD_CHAN)) 529 (void) strcpy(classbuf, PICL_CLASS_CDROM); 530 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_FD)) 531 (void) strcpy(classbuf, PICL_CLASS_FLOPPY); 532 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_FABRIC)) 533 (void) strcpy(classbuf, PICL_CLASS_FABRIC); 534 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_SAS)) 535 (void) strcpy(classbuf, PICL_CLASS_SAS); 536 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK)) 537 (void) strcpy(classbuf, PICL_CLASS_BLOCK); 538 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_MOUSE)) 539 (void) strcpy(classbuf, PICL_CLASS_MOUSE); 540 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_KEYBOARD)) 541 (void) strcpy(classbuf, PICL_CLASS_KEYBOARD); 542 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ATTACHMENT_POINT)) 543 (void) strcpy(classbuf, PICL_CLASS_ATTACHMENT_POINT); 544 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_TAPE)) 545 (void) strcpy(classbuf, PICL_CLASS_TAPE); 546 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_SCSI_ENCLOSURE)) 547 (void) strcpy(classbuf, PICL_CLASS_SCSI); 548 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ENCLOSURE)) { 549 char *colon; 550 551 if ((colon = strchr(mi_nodetype, ':')) == NULL) 552 return (-1); 553 ++colon; 554 (void) strcpy(classbuf, colon); 555 } else { /* unrecognized type, return name */ 556 mi_name = di_minor_name(mi_node); 557 if (mi_name == NULL) 558 return (-1); 559 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX); 560 } 561 return (0); 562 } 563 564 /* 565 * Derive PICL class using the compatible property of the node 566 * We use the map table to map compatible property value to 567 * class. 568 */ 569 static int 570 get_compatible_class(char *outbuf, di_node_t dn) 571 { 572 char *pdata; 573 char *pdatap; 574 int dret; 575 int i; 576 577 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_COMPATIBLE, 578 &pdata); 579 if (dret <= 0) { 580 if (!ph) 581 return (-1); 582 583 dret = di_prom_prop_lookup_strings(ph, dn, OBP_COMPATIBLE, 584 &pdata); 585 if (dret <= 0) { 586 return (-1); 587 } 588 } 589 590 pdatap = pdata; 591 for (i = 0; i < dret; ++i) { 592 if (lookup_name_class_map(outbuf, pdatap) == 0) 593 return (0); 594 pdatap += strlen(pdatap); 595 pdatap++; 596 } 597 return (-1); 598 } 599 600 /* 601 * For a given device node find the PICL class to use. Returns NULL 602 * for non device node 603 */ 604 static int 605 get_node_class(char *classbuf, di_node_t dn, const char *nodename) 606 { 607 if (get_device_type(classbuf, dn) == 0) { 608 if (di_nodeid(dn) == DI_PROM_NODEID) { 609 /* 610 * discard place holder nodes 611 */ 612 if ((strcmp(classbuf, DEVICE_TYPE_BLOCK) == 0) || 613 (strcmp(classbuf, DEVICE_TYPE_BYTE) == 0) || 614 (strcmp(classbuf, DEVICE_TYPE_SES) == 0) || 615 (strcmp(classbuf, DEVICE_TYPE_FP) == 0) || 616 (strcmp(classbuf, DEVICE_TYPE_DISK) == 0)) 617 return (-1); 618 619 return (0); 620 } 621 return (0); /* return device_type value */ 622 } 623 624 if (get_compatible_class(classbuf, dn) == 0) { 625 return (0); /* derive class using compatible prop */ 626 } 627 628 if (lookup_name_class_map(classbuf, nodename) == 0) 629 return (0); /* derive class using name prop */ 630 631 if (has_reg_prop(dn)) { /* use default obp-device */ 632 (void) strcpy(classbuf, PICL_CLASS_OBP_DEVICE); 633 return (0); 634 } 635 636 return (get_minor_class(classbuf, dn)); 637 } 638 639 /* 640 * Add a table property containing nrows with one column 641 */ 642 static int 643 add_string_list_prop(picl_nodehdl_t nodeh, char *name, char *strlist, 644 unsigned int nrows) 645 { 646 ptree_propinfo_t propinfo; 647 picl_prophdl_t proph; 648 picl_prophdl_t tblh; 649 int err; 650 unsigned int i; 651 unsigned int j; 652 picl_prophdl_t *proprow; 653 int len; 654 655 #define NCOLS_IN_STRING_TABLE 1 656 657 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 658 PICL_PTYPE_TABLE, PICL_READ, sizeof (picl_prophdl_t), name, 659 NULL, NULL); 660 if (err != PICL_SUCCESS) 661 return (err); 662 663 err = ptree_create_table(&tblh); 664 if (err != PICL_SUCCESS) 665 return (err); 666 667 err = ptree_create_and_add_prop(nodeh, &propinfo, &tblh, &proph); 668 if (err != PICL_SUCCESS) 669 return (err); 670 671 proprow = alloca(sizeof (picl_prophdl_t) * nrows); 672 if (proprow == NULL) { 673 (void) ptree_destroy_prop(proph); 674 return (PICL_FAILURE); 675 } 676 677 for (j = 0; j < nrows; ++j) { 678 len = strlen(strlist) + 1; 679 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 680 PICL_PTYPE_CHARSTRING, PICL_READ, len, name, 681 NULL, NULL); 682 if (err != PICL_SUCCESS) 683 break; 684 err = ptree_create_prop(&propinfo, strlist, &proprow[j]); 685 if (err != PICL_SUCCESS) 686 break; 687 strlist += len; 688 err = ptree_add_row_to_table(tblh, NCOLS_IN_STRING_TABLE, 689 &proprow[j]); 690 if (err != PICL_SUCCESS) 691 break; 692 } 693 694 if (err != PICL_SUCCESS) { 695 for (i = 0; i < j; ++i) 696 (void) ptree_destroy_prop(proprow[i]); 697 (void) ptree_delete_prop(proph); 698 (void) ptree_destroy_prop(proph); 699 return (err); 700 } 701 702 return (PICL_SUCCESS); 703 } 704 705 /* 706 * return 1 if this node has this property with the given value 707 */ 708 static int 709 compare_string_propval(picl_nodehdl_t nodeh, const char *pname, 710 const char *pval) 711 { 712 char *pvalbuf; 713 int err; 714 int len; 715 ptree_propinfo_t pinfo; 716 picl_prophdl_t proph; 717 718 err = ptree_get_prop_by_name(nodeh, pname, &proph); 719 if (err != PICL_SUCCESS) /* prop doesn't exist */ 720 return (0); 721 722 err = ptree_get_propinfo(proph, &pinfo); 723 if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING) 724 return (0); /* not string prop */ 725 726 len = strlen(pval) + 1; 727 728 pvalbuf = alloca(len); 729 if (pvalbuf == NULL) 730 return (0); 731 732 err = ptree_get_propval(proph, pvalbuf, len); 733 if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0)) 734 return (1); /* prop match */ 735 736 return (0); 737 } 738 739 /* 740 * This function recursively searches the tree for a node that has 741 * the specified string property name and value 742 */ 743 static int 744 find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname, 745 const char *pval, picl_nodehdl_t *nodeh) 746 { 747 picl_nodehdl_t childh; 748 int err; 749 750 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh, 751 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 752 err = ptree_get_propval_by_name(childh, PICL_PROP_PEER, &childh, 753 sizeof (picl_nodehdl_t))) { 754 if (err != PICL_SUCCESS) 755 return (err); 756 757 if (compare_string_propval(childh, pname, pval)) { 758 *nodeh = childh; 759 return (PICL_SUCCESS); 760 } 761 762 if (find_node_by_string_prop(childh, pname, pval, nodeh) == 763 PICL_SUCCESS) 764 return (PICL_SUCCESS); 765 } 766 767 return (PICL_FAILURE); 768 } 769 770 /* 771 * check if this is a string prop 772 * If the length is less than or equal to 4, assume it's not a string list. 773 * If there is any non-ascii or non-print char, it's not a string prop 774 * If \0 is in the first char or any two consecutive \0's exist, 775 * it's a bytearray prop. 776 * Return value: 0 means it's not a string prop, 1 means it's a string prop 777 */ 778 static int 779 is_string_propval(unsigned char *pdata, int len) 780 { 781 int i; 782 int lastindex; 783 int prevnull = -1; 784 785 switch (len) { 786 case 1: 787 if (!isascii(pdata[0]) || !isprint(pdata[0])) 788 return (0); 789 return (1); 790 case 2: 791 case 3: 792 case 4: 793 lastindex = len; 794 if (pdata[len-1] == '\0') 795 lastindex = len - 1; 796 797 for (i = 0; i < lastindex; i++) 798 if (!isascii(pdata[i]) || !isprint(pdata[i])) 799 return (0); 800 801 return (1); 802 803 default: 804 if (len <= 0) 805 return (0); 806 for (i = 0; i < len; i++) { 807 if (!isascii(pdata[i]) || !isprint(pdata[i])) { 808 if (pdata[i] != '\0') 809 return (0); 810 /* 811 * if the null char is in the first char 812 * or two consecutive nulls' exist, 813 * it's a bytearray prop 814 */ 815 if ((i == 0) || ((i - prevnull) == 1)) 816 return (0); 817 818 prevnull = i; 819 } 820 } 821 break; 822 } 823 824 return (1); 825 } 826 827 /* 828 * This function counts the number of strings in the value buffer pdata 829 * and creates a property. 830 * If there is only one string in the buffer, pdata, a charstring property 831 * type is created and added. 832 * If there are more than one string in the buffer, pdata, then a table 833 * of charstrings is added. 834 */ 835 static int 836 process_charstring_data(picl_nodehdl_t nodeh, char *pname, unsigned char *pdata, 837 int retval) 838 { 839 int err; 840 int strcount; 841 char *strdat; 842 ptree_propinfo_t propinfo; 843 844 /* 845 * append the null char at the end of string when there is 846 * no null terminator 847 */ 848 if (pdata[retval - 1] != '\0') { 849 strdat = alloca(retval + 1); 850 (void) memcpy(strdat, pdata, retval); 851 strdat[retval] = '\0'; 852 retval++; 853 } else { 854 strdat = alloca(retval); 855 (void) memcpy(strdat, pdata, retval); 856 } 857 858 /* 859 * If it's a string list, create a table prop 860 */ 861 strcount = get_string_count(strdat, retval); 862 if (strcount > 1) { 863 err = add_string_list_prop(nodeh, pname, 864 strdat, strcount); 865 if (err != PICL_SUCCESS) 866 return (err); 867 } else { 868 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 869 PICL_PTYPE_CHARSTRING, PICL_READ, 870 strlen(strdat) + 1, pname, NULL, 871 NULL); 872 if (err != PICL_SUCCESS) 873 return (err); 874 (void) ptree_create_and_add_prop(nodeh, &propinfo, 875 strdat, NULL); 876 } 877 return (PICL_SUCCESS); 878 } 879 880 /* 881 * Add the OBP properties as properties of the PICL node 882 */ 883 static int 884 add_openprom_props(picl_nodehdl_t nodeh, di_node_t di_node) 885 { 886 di_prom_prop_t promp; 887 char *pname; 888 unsigned char *pdata; 889 int retval; 890 ptree_propinfo_t propinfo; 891 int err; 892 picl_prop_type_t type; 893 894 if (!ph) 895 return (PICL_FAILURE); 896 897 for (promp = di_prom_prop_next(ph, di_node, DI_PROM_PROP_NIL); 898 promp != DI_PROM_PROP_NIL; 899 promp = di_prom_prop_next(ph, di_node, promp)) { 900 901 pname = di_prom_prop_name(promp); 902 903 retval = di_prom_prop_data(promp, &pdata); 904 if (retval < 0) { 905 return (PICL_SUCCESS); 906 } 907 if (retval == 0) { 908 err = ptree_init_propinfo(&propinfo, 909 PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID, 910 PICL_READ, (size_t)0, pname, NULL, NULL); 911 if (err != PICL_SUCCESS) { 912 return (err); 913 } 914 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, 915 NULL); 916 continue; 917 } 918 919 /* 920 * Get the prop type from pname map table 921 */ 922 if (lookup_pname_type_map(pname, &type) == 0) { 923 if (type == PICL_PTYPE_CHARSTRING) { 924 err = process_charstring_data(nodeh, pname, 925 pdata, retval); 926 if (err != PICL_SUCCESS) { 927 return (err); 928 } 929 continue; 930 } 931 932 err = ptree_init_propinfo(&propinfo, 933 PTREE_PROPINFO_VERSION, type, PICL_READ, 934 retval, pname, NULL, NULL); 935 if (err != PICL_SUCCESS) { 936 return (err); 937 } 938 (void) ptree_create_and_add_prop(nodeh, &propinfo, 939 pdata, NULL); 940 } else if (!is_string_propval(pdata, retval)) { 941 switch (retval) { 942 case sizeof (uint8_t): 943 /*FALLTHROUGH*/ 944 case sizeof (uint16_t): 945 /*FALLTHROUGH*/ 946 case sizeof (uint32_t): 947 type = PICL_PTYPE_UNSIGNED_INT; 948 break; 949 default: 950 type = PICL_PTYPE_BYTEARRAY; 951 break; 952 } 953 err = ptree_init_propinfo(&propinfo, 954 PTREE_PROPINFO_VERSION, type, PICL_READ, 955 retval, pname, NULL, NULL); 956 if (err != PICL_SUCCESS) { 957 return (err); 958 } 959 (void) ptree_create_and_add_prop(nodeh, &propinfo, 960 pdata, NULL); 961 } else { 962 err = process_charstring_data(nodeh, pname, pdata, 963 retval); 964 if (err != PICL_SUCCESS) { 965 return (err); 966 } 967 } 968 } 969 970 return (PICL_SUCCESS); 971 } 972 973 static void 974 add_boolean_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val) 975 { 976 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 977 PICL_PTYPE_VOID, PICL_READ, (size_t)0, di_val, NULL, NULL); 978 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL); 979 } 980 981 static void 982 add_uints_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val, 983 int *idata, int len) 984 { 985 if (len == 1) 986 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 987 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (int), di_val, 988 NULL, NULL); 989 else 990 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 991 PICL_PTYPE_BYTEARRAY, PICL_READ, len * sizeof (int), di_val, 992 NULL, NULL); 993 994 (void) ptree_create_and_add_prop(nodeh, &propinfo, idata, NULL); 995 } 996 997 static void 998 add_strings_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val, 999 char *sdata, int len) 1000 { 1001 if (len == 1) { 1002 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1003 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(sdata) + 1, di_val, 1004 NULL, NULL); 1005 (void) ptree_create_and_add_prop(nodeh, &propinfo, sdata, NULL); 1006 } else { 1007 (void) add_string_list_prop(nodeh, di_val, sdata, len); 1008 } 1009 } 1010 1011 static void 1012 add_bytes_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val, 1013 unsigned char *bdata, int len) 1014 { 1015 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1016 PICL_PTYPE_BYTEARRAY, PICL_READ, len, di_val, NULL, NULL); 1017 (void) ptree_create_and_add_prop(nodeh, &propinfo, bdata, NULL); 1018 } 1019 1020 static const char * 1021 path_state_name(di_path_state_t st) 1022 { 1023 switch (st) { 1024 case DI_PATH_STATE_ONLINE: 1025 return ("online"); 1026 case DI_PATH_STATE_STANDBY: 1027 return ("standby"); 1028 case DI_PATH_STATE_OFFLINE: 1029 return ("offline"); 1030 case DI_PATH_STATE_FAULT: 1031 return ("faulted"); 1032 } 1033 return ("unknown"); 1034 } 1035 1036 /* 1037 * This function is the volatile property handler for the multipath node 1038 * "State" property. It must locate the associated devinfo node in order to 1039 * determine the current state. Since the devinfo node can have multiple 1040 * paths the devfs_path is used to locate the correct path. 1041 */ 1042 static int 1043 get_path_state_name(ptree_rarg_t *rarg, void *vbuf) 1044 { 1045 int err; 1046 picl_nodehdl_t parh; 1047 char devfs_path[PATH_MAX]; 1048 di_node_t di_node; 1049 di_node_t di_root; 1050 di_path_t pi = DI_PATH_NIL; 1051 picl_nodehdl_t mpnode; 1052 1053 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE); 1054 1055 mpnode = rarg->nodeh; 1056 1057 /* 1058 * The parent node represents the vHCI. 1059 */ 1060 err = ptree_get_propval_by_name(mpnode, PICL_PROP_PARENT, &parh, 1061 sizeof (picl_nodehdl_t)); 1062 if (err != PICL_SUCCESS) { 1063 return (PICL_SUCCESS); 1064 } 1065 1066 /* 1067 * The PICL_PROP_DEVFS_PATH property will be used to locate the 1068 * devinfo node for the vHCI driver. 1069 */ 1070 err = ptree_get_propval_by_name(parh, PICL_PROP_DEVFS_PATH, devfs_path, 1071 sizeof (devfs_path)); 1072 if (err != PICL_SUCCESS) { 1073 return (PICL_SUCCESS); 1074 } 1075 /* 1076 * Find the di_node for the vHCI driver. It will be used to scan 1077 * the path information nodes. 1078 */ 1079 di_root = di_init("/", DINFOCACHE); 1080 if (di_root == DI_NODE_NIL) { 1081 return (PICL_SUCCESS); 1082 } 1083 di_node = di_lookup_node(di_root, devfs_path); 1084 if (di_node == DI_NODE_NIL) { 1085 di_fini(di_root); 1086 return (PICL_SUCCESS); 1087 } 1088 1089 /* 1090 * The devfs_path will be used below to match the 1091 * proper path information node. 1092 */ 1093 err = ptree_get_propval_by_name(mpnode, PICL_PROP_DEVFS_PATH, 1094 devfs_path, sizeof (devfs_path)); 1095 if (err != PICL_SUCCESS) { 1096 di_fini(di_root); 1097 return (PICL_SUCCESS); 1098 } 1099 1100 /* 1101 * Scan the path information nodes looking for the matching devfs 1102 * path. When found obtain the state information. 1103 */ 1104 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) { 1105 char *di_path; 1106 di_node_t phci_node = di_path_phci_node(pi); 1107 1108 if (phci_node == DI_PATH_NIL) 1109 continue; 1110 1111 di_path = di_devfs_path(phci_node); 1112 if (di_path) { 1113 if (strcmp(di_path, devfs_path) != 0) { 1114 di_devfs_path_free(di_path); 1115 continue; 1116 } 1117 (void) strlcpy(vbuf, path_state_name(di_path_state(pi)), 1118 MAX_STATE_SIZE); 1119 di_devfs_path_free(di_path); 1120 break; 1121 } 1122 } 1123 1124 di_fini(di_root); 1125 return (PICL_SUCCESS); 1126 } 1127 1128 static void 1129 add_di_path_prop(picl_nodehdl_t nodeh, di_path_prop_t di_path_prop) 1130 { 1131 int di_ptype; 1132 char *di_val; 1133 ptree_propinfo_t propinfo; 1134 int *idata; 1135 char *sdata; 1136 unsigned char *bdata; 1137 int len; 1138 1139 di_ptype = di_path_prop_type(di_path_prop); 1140 di_val = di_path_prop_name(di_path_prop); 1141 1142 switch (di_ptype) { 1143 case DI_PROP_TYPE_BOOLEAN: 1144 add_boolean_prop(nodeh, propinfo, di_val); 1145 break; 1146 case DI_PROP_TYPE_INT: 1147 case DI_PROP_TYPE_INT64: 1148 len = di_path_prop_ints(di_path_prop, &idata); 1149 if (len < 0) 1150 /* Received error, so ignore prop */ 1151 break; 1152 add_uints_prop(nodeh, propinfo, di_val, idata, len); 1153 break; 1154 case DI_PROP_TYPE_STRING: 1155 len = di_path_prop_strings(di_path_prop, &sdata); 1156 if (len <= 0) 1157 break; 1158 add_strings_prop(nodeh, propinfo, di_val, sdata, len); 1159 break; 1160 case DI_PROP_TYPE_BYTE: 1161 len = di_path_prop_bytes(di_path_prop, &bdata); 1162 if (len < 0) 1163 break; 1164 add_bytes_prop(nodeh, propinfo, di_val, bdata, len); 1165 break; 1166 case DI_PROP_TYPE_UNKNOWN: 1167 /* 1168 * Unknown type, we'll try and guess what it should be. 1169 */ 1170 len = di_path_prop_strings(di_path_prop, &sdata); 1171 if ((len > 0) && (sdata[0] != 0)) { 1172 add_strings_prop(nodeh, propinfo, di_val, sdata, 1173 len); 1174 break; 1175 } 1176 len = di_path_prop_ints(di_path_prop, &idata); 1177 if (len > 0) { 1178 add_uints_prop(nodeh, propinfo, di_val, 1179 idata, len); 1180 break; 1181 } 1182 len = di_path_prop_bytes(di_path_prop, &bdata); 1183 if (len > 0) 1184 add_bytes_prop(nodeh, propinfo, 1185 di_val, bdata, len); 1186 else if (len == 0) 1187 add_boolean_prop(nodeh, propinfo, 1188 di_val); 1189 break; 1190 case DI_PROP_TYPE_UNDEF_IT: 1191 break; 1192 default: 1193 break; 1194 } 1195 } 1196 1197 /* 1198 * Add nodes for path information (PSARC/1999/647, PSARC/2008/437) 1199 */ 1200 static void 1201 construct_mpath_node(picl_nodehdl_t parh, di_node_t di_node) 1202 { 1203 di_path_t pi = DI_PATH_NIL; 1204 1205 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) { 1206 di_node_t phci_node = di_path_phci_node(pi); 1207 di_path_prop_t di_path_prop; 1208 picl_nodehdl_t nodeh; 1209 ptree_propinfo_t propinfo; 1210 int err; 1211 int instance; 1212 char *di_val; 1213 1214 if (phci_node == DI_PATH_NIL) 1215 continue; 1216 1217 err = ptree_create_and_add_node(parh, PICL_CLASS_MULTIPATH, 1218 PICL_CLASS_MULTIPATH, &nodeh); 1219 if (err != PICL_SUCCESS) 1220 continue; 1221 1222 instance = di_instance(phci_node); 1223 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1224 PICL_PTYPE_INT, PICL_READ, sizeof (instance), 1225 PICL_PROP_INSTANCE, NULL, NULL); 1226 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, 1227 NULL); 1228 1229 di_val = di_devfs_path(phci_node); 1230 if (di_val) { 1231 (void) ptree_init_propinfo(&propinfo, 1232 PTREE_PROPINFO_VERSION, 1233 PICL_PTYPE_CHARSTRING, PICL_READ, 1234 strlen(di_val) + 1, PICL_PROP_DEVFS_PATH, 1235 NULL, NULL); 1236 (void) ptree_create_and_add_prop(nodeh, 1237 &propinfo, di_val, NULL); 1238 di_devfs_path_free(di_val); 1239 } 1240 1241 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1242 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), 1243 MAX_STATE_SIZE, PICL_PROP_STATE, get_path_state_name, NULL); 1244 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL); 1245 1246 for (di_path_prop = di_path_prop_next(pi, DI_PROP_NIL); 1247 di_path_prop != DI_PROP_NIL; 1248 di_path_prop = di_path_prop_next(pi, di_path_prop)) { 1249 add_di_path_prop(nodeh, di_path_prop); 1250 } 1251 } 1252 } 1253 1254 /* 1255 * Add properties provided by libdevinfo 1256 */ 1257 static void 1258 add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node) 1259 { 1260 int instance; 1261 char *di_val; 1262 di_prop_t di_prop; 1263 int di_ptype; 1264 ptree_propinfo_t propinfo; 1265 char *sdata; 1266 unsigned char *bdata; 1267 int *idata; 1268 int len; 1269 1270 instance = di_instance(di_node); 1271 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1272 PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE, 1273 NULL, NULL); 1274 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL); 1275 1276 di_val = di_bus_addr(di_node); 1277 if (di_val) { 1278 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1279 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1280 PICL_PROP_BUS_ADDR, NULL, NULL); 1281 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1282 NULL); 1283 } 1284 1285 di_val = di_binding_name(di_node); 1286 if (di_val) { 1287 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1288 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1289 PICL_PROP_BINDING_NAME, NULL, NULL); 1290 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1291 NULL); 1292 } 1293 1294 di_val = di_driver_name(di_node); 1295 if (di_val) { 1296 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1297 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1298 PICL_PROP_DRIVER_NAME, NULL, NULL); 1299 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1300 NULL); 1301 } 1302 1303 di_val = di_devfs_path(di_node); 1304 if (di_val) { 1305 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1306 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1307 PICL_PROP_DEVFS_PATH, NULL, NULL); 1308 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1309 NULL); 1310 di_devfs_path_free(di_val); 1311 } 1312 1313 for (di_prop = di_prop_next(di_node, DI_PROP_NIL); 1314 di_prop != DI_PROP_NIL; 1315 di_prop = di_prop_next(di_node, di_prop)) { 1316 1317 di_val = di_prop_name(di_prop); 1318 di_ptype = di_prop_type(di_prop); 1319 1320 switch (di_ptype) { 1321 case DI_PROP_TYPE_BOOLEAN: 1322 add_boolean_prop(nodeh, propinfo, di_val); 1323 break; 1324 case DI_PROP_TYPE_INT: 1325 len = di_prop_ints(di_prop, &idata); 1326 if (len < 0) 1327 /* Received error, so ignore prop */ 1328 break; 1329 add_uints_prop(nodeh, propinfo, di_val, idata, len); 1330 break; 1331 case DI_PROP_TYPE_STRING: 1332 len = di_prop_strings(di_prop, &sdata); 1333 if (len < 0) 1334 break; 1335 add_strings_prop(nodeh, propinfo, di_val, sdata, len); 1336 break; 1337 case DI_PROP_TYPE_BYTE: 1338 len = di_prop_bytes(di_prop, &bdata); 1339 if (len < 0) 1340 break; 1341 add_bytes_prop(nodeh, propinfo, di_val, bdata, len); 1342 break; 1343 case DI_PROP_TYPE_UNKNOWN: 1344 /* 1345 * Unknown type, we'll try and guess what it should be. 1346 */ 1347 len = di_prop_strings(di_prop, &sdata); 1348 if ((len > 0) && (sdata[0] != 0)) { 1349 add_strings_prop(nodeh, propinfo, di_val, sdata, 1350 len); 1351 break; 1352 } 1353 len = di_prop_ints(di_prop, &idata); 1354 if (len > 0) { 1355 add_uints_prop(nodeh, propinfo, di_val, 1356 idata, len); 1357 break; 1358 } 1359 len = di_prop_rawdata(di_prop, &bdata); 1360 if (len > 0) 1361 add_bytes_prop(nodeh, propinfo, 1362 di_val, bdata, len); 1363 else if (len == 0) 1364 add_boolean_prop(nodeh, propinfo, 1365 di_val); 1366 break; 1367 case DI_PROP_TYPE_UNDEF_IT: 1368 break; 1369 default: 1370 break; 1371 } 1372 } 1373 } 1374 1375 /* 1376 * This function creates the /obp node in the PICL tree for OBP nodes 1377 * without a device type class. 1378 */ 1379 static int 1380 construct_picl_openprom(picl_nodehdl_t rooth, picl_nodehdl_t *obph) 1381 { 1382 picl_nodehdl_t tmph; 1383 int err; 1384 1385 err = ptree_create_and_add_node(rooth, PICL_NODE_OBP, 1386 PICL_CLASS_PICL, &tmph); 1387 1388 if (err != PICL_SUCCESS) 1389 return (err); 1390 *obph = tmph; 1391 return (PICL_SUCCESS); 1392 } 1393 1394 /* 1395 * This function creates the /platform node in the PICL tree and 1396 * its properties. It sets the "platform-name" property to the 1397 * platform name 1398 */ 1399 static int 1400 construct_picl_platform(picl_nodehdl_t rooth, di_node_t di_root, 1401 picl_nodehdl_t *piclh) 1402 { 1403 int err; 1404 picl_nodehdl_t plafh; 1405 char *nodename; 1406 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1407 ptree_propinfo_t propinfo; 1408 picl_prophdl_t proph; 1409 1410 nodename = di_node_name(di_root); 1411 if (nodename == NULL) 1412 return (PICL_FAILURE); 1413 1414 err = 0; 1415 if (di_nodeid(di_root) == DI_PROM_NODEID || 1416 di_nodeid(di_root) == DI_SID_NODEID) 1417 err = get_device_type(nodeclass, di_root); 1418 1419 if (err < 0) 1420 (void) strcpy(nodeclass, PICL_CLASS_UPA); /* default */ 1421 1422 err = ptree_create_and_add_node(rooth, PICL_NODE_PLATFORM, 1423 nodeclass, &plafh); 1424 if (err != PICL_SUCCESS) 1425 return (err); 1426 1427 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1428 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(nodename) + 1, 1429 PICL_PROP_PLATFORM_NAME, NULL, NULL); 1430 err = ptree_create_and_add_prop(plafh, &propinfo, nodename, &proph); 1431 if (err != PICL_SUCCESS) 1432 return (err); 1433 1434 (void) add_devinfo_props(plafh, di_root); 1435 1436 (void) add_openprom_props(plafh, di_root); 1437 1438 *piclh = plafh; 1439 1440 return (PICL_SUCCESS); 1441 } 1442 1443 /* 1444 * This function creates a node in /obp tree for the libdevinfo handle. 1445 */ 1446 static int 1447 construct_obp_node(picl_nodehdl_t parh, di_node_t dn, picl_nodehdl_t *chdh) 1448 { 1449 int err; 1450 char *nodename; 1451 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1452 picl_nodehdl_t anodeh; 1453 1454 nodename = di_node_name(dn); /* PICL_PROP_NAME */ 1455 if (nodename == NULL) 1456 return (PICL_FAILURE); 1457 1458 if (strcmp(nodename, "pseudo") == 0) 1459 return (PICL_FAILURE); 1460 1461 if ((di_nodeid(dn) == DI_PROM_NODEID) && 1462 (get_device_type(nodeclass, dn) == 0)) 1463 return (PICL_FAILURE); 1464 1465 err = ptree_create_and_add_node(parh, nodename, nodename, &anodeh); 1466 if (err != PICL_SUCCESS) 1467 return (err); 1468 1469 add_devinfo_props(anodeh, dn); 1470 1471 (void) add_openprom_props(anodeh, dn); 1472 1473 *chdh = anodeh; 1474 1475 return (PICL_SUCCESS); 1476 } 1477 1478 /* 1479 * This function creates a PICL node in /platform tree for a device 1480 */ 1481 static int 1482 construct_devtype_node(picl_nodehdl_t parh, char *nodename, 1483 char *nodeclass, di_node_t dn, picl_nodehdl_t *chdh) 1484 { 1485 int err; 1486 picl_nodehdl_t anodeh; 1487 1488 err = ptree_create_and_add_node(parh, nodename, nodeclass, &anodeh); 1489 if (err != PICL_SUCCESS) 1490 return (err); 1491 1492 (void) add_devinfo_props(anodeh, dn); 1493 (void) add_openprom_props(anodeh, dn); 1494 construct_mpath_node(anodeh, dn); 1495 1496 *chdh = anodeh; 1497 return (err); 1498 } 1499 1500 /* 1501 * Create a subtree of "picl" class nodes in /obp for these nodes 1502 */ 1503 static int 1504 construct_openprom_tree(picl_nodehdl_t nodeh, di_node_t dinode) 1505 { 1506 di_node_t cnode; 1507 picl_nodehdl_t chdh; 1508 int err; 1509 1510 err = construct_obp_node(nodeh, dinode, &chdh); 1511 if (err != PICL_SUCCESS) 1512 return (err); 1513 1514 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1515 cnode = di_sibling_node(cnode)) 1516 (void) construct_openprom_tree(chdh, cnode); 1517 1518 return (PICL_SUCCESS); 1519 1520 } 1521 1522 /* 1523 * Process the libdevinfo device tree and create nodes in /platform or /obp 1524 * PICL tree. 1525 * 1526 * This routine traverses the immediate children of "dinode" device and 1527 * determines the node class for that child. If it finds a valid class 1528 * name, then it builds a PICL node under /platform subtree and calls itself 1529 * recursively to construct the subtree for that child node. Otherwise, if 1530 * the parent_class is NULL, then it constructs a node and subtree under /obp 1531 * subtree. 1532 * 1533 * Note that we skip the children nodes that don't have a valid class name 1534 * and the parent_class is non NULL to prevent creation of any placeholder 1535 * nodes (such as sd,...). 1536 */ 1537 static int 1538 construct_devinfo_tree(picl_nodehdl_t plafh, picl_nodehdl_t obph, 1539 di_node_t dinode, char *parent_class) 1540 { 1541 di_node_t cnode; 1542 picl_nodehdl_t chdh; 1543 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1544 char *nodename; 1545 int err; 1546 1547 err = PICL_SUCCESS; 1548 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1549 cnode = di_sibling_node(cnode)) { 1550 nodename = di_node_name(cnode); /* PICL_PROP_NAME */ 1551 if (nodename == NULL) 1552 continue; 1553 1554 err = get_node_class(nodeclass, cnode, nodename); 1555 1556 if (err == 0) { 1557 err = construct_devtype_node(plafh, nodename, 1558 nodeclass, cnode, &chdh); 1559 if (err != PICL_SUCCESS) 1560 return (err); 1561 err = construct_devinfo_tree(chdh, obph, cnode, 1562 nodeclass); 1563 } else if (parent_class == NULL) 1564 err = construct_openprom_tree(obph, cnode); 1565 else 1566 continue; 1567 /* 1568 * if parent_class is non NULL, skip the children nodes 1569 * that don't have a valid device class - eliminates 1570 * placeholder nodes (sd,...) from being created. 1571 */ 1572 } 1573 1574 return (err); 1575 1576 } 1577 1578 /* 1579 * This function is called from the event handler called from the daemon 1580 * on PICL events. 1581 * 1582 * This routine traverses the children of the "dinode" device and 1583 * creates a PICL node for each child not found in the PICL tree and 1584 * invokes itself recursively to create a subtree for the newly created 1585 * child node. It also checks if the node being created is a meory 1586 * controller. If so, it posts PICLEVENT_MC_ADDED PICL event to the PICL 1587 * framework. 1588 */ 1589 static int 1590 update_subtree(picl_nodehdl_t nodeh, di_node_t dinode) 1591 { 1592 di_node_t cnode; 1593 picl_nodehdl_t chdh; 1594 picl_nodehdl_t nh; 1595 char *nodename; 1596 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1597 char *path_buf; 1598 char buf[MAX_UNIT_ADDRESS_LEN]; 1599 char unitaddr[MAX_UNIT_ADDRESS_LEN]; 1600 char path_w_ua[MAXPATHLEN]; 1601 char path_wo_ua[MAXPATHLEN]; 1602 char *strp; 1603 int gotit; 1604 int err; 1605 1606 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1607 cnode = di_sibling_node(cnode)) { 1608 path_buf = di_devfs_path(cnode); 1609 if (path_buf == NULL) 1610 continue; 1611 1612 nodename = di_node_name(cnode); 1613 if (nodename == NULL) { 1614 di_devfs_path_free(path_buf); 1615 continue; 1616 } 1617 1618 err = get_node_class(nodeclass, cnode, nodename); 1619 1620 if (err < 0) { 1621 di_devfs_path_free(path_buf); 1622 continue; 1623 } 1624 1625 /* 1626 * this is quite complicated - both path_buf and any nodes 1627 * already in the picl tree may, or may not, have the 1628 * @<unit_addr> at the end of their names. So we must 1629 * take path_buf and work out what the device path would 1630 * be both with and without the unit_address, then search 1631 * the picl tree for both forms. 1632 */ 1633 if (((strp = strrchr(path_buf, '/')) != NULL) && 1634 strchr(strp, '@') == NULL) { 1635 /* 1636 * This is an unattached node - so the path is not 1637 * unique. Need to find out which node it is. 1638 * Find the unit_address from the OBP or devinfo 1639 * properties. 1640 */ 1641 err = ptree_create_node(nodename, nodeclass, &chdh); 1642 if (err != PICL_SUCCESS) 1643 return (err); 1644 1645 (void) add_devinfo_props(chdh, cnode); 1646 (void) add_openprom_props(chdh, cnode); 1647 1648 err = get_unitaddr(nodeh, chdh, unitaddr, 1649 sizeof (unitaddr)); 1650 if (err != PICL_SUCCESS) 1651 return (err); 1652 (void) ptree_destroy_node(chdh); 1653 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s@%s", 1654 path_buf, unitaddr); 1655 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1656 path_buf); 1657 } else { 1658 /* 1659 * this is an attached node - so the path is unique 1660 */ 1661 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s", 1662 path_buf); 1663 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1664 path_buf); 1665 strp = strrchr(path_wo_ua, '@'); 1666 *strp++ = '\0'; 1667 (void) snprintf(unitaddr, sizeof (unitaddr), "%s", 1668 strp); 1669 } 1670 /* 1671 * first look for node with unit address in devfs_path 1672 */ 1673 if (ptree_find_node(nodeh, PICL_PROP_DEVFS_PATH, 1674 PICL_PTYPE_CHARSTRING, path_w_ua, strlen(path_w_ua) + 1, 1675 &nh) == PICL_SUCCESS) { 1676 /* 1677 * node already there - there's nothing we need to do 1678 */ 1679 if (picldevtree_debug > 1) 1680 syslog(LOG_INFO, 1681 "update_subtree: path:%s node exists\n", 1682 path_buf); 1683 di_devfs_path_free(path_buf); 1684 continue; 1685 } 1686 /* 1687 * now look for node without unit address in devfs_path. 1688 * This might be just one out of several 1689 * nodes - need to check all siblings 1690 */ 1691 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, 1692 &chdh, sizeof (chdh)); 1693 if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND)) 1694 return (err); 1695 gotit = 0; 1696 while (err == PICL_SUCCESS) { 1697 err = ptree_get_propval_by_name(chdh, 1698 PICL_PROP_DEVFS_PATH, buf, sizeof (buf)); 1699 if (err != PICL_SUCCESS) 1700 return (err); 1701 if (strcmp(buf, path_wo_ua) == 0) { 1702 err = ptree_get_propval_by_name(chdh, 1703 PICL_PROP_UNIT_ADDRESS, buf, sizeof (buf)); 1704 if (err != PICL_SUCCESS) 1705 return (err); 1706 if (strcmp(buf, unitaddr) == 0) { 1707 gotit = 1; 1708 break; 1709 } 1710 } 1711 err = ptree_get_propval_by_name(chdh, 1712 PICL_PROP_PEER, &chdh, sizeof (chdh)); 1713 if (err != PICL_SUCCESS) 1714 break; 1715 } 1716 if (gotit) { 1717 /* 1718 * node already there - there's nothing we need to do 1719 */ 1720 if (picldevtree_debug > 1) 1721 syslog(LOG_INFO, 1722 "update_subtree: path:%s node exists\n", 1723 path_buf); 1724 di_devfs_path_free(path_buf); 1725 continue; 1726 } 1727 1728 #define IS_MC(x) (strcmp(x, PICL_CLASS_MEMORY_CONTROLLER) == 0 ? 1 : 0) 1729 1730 if (construct_devtype_node(nodeh, nodename, nodeclass, cnode, 1731 &chdh) == PICL_SUCCESS) { 1732 if (picldevtree_debug) 1733 syslog(LOG_INFO, 1734 "picldevtree: added node:%s path:%s\n", 1735 nodename, path_buf); 1736 if (IS_MC(nodeclass)) { 1737 if (post_mc_event(PICLEVENT_MC_ADDED, chdh) != 1738 PICL_SUCCESS) 1739 syslog(LOG_WARNING, PICL_EVENT_DROPPED, 1740 PICLEVENT_MC_ADDED); 1741 } 1742 1743 di_devfs_path_free(path_buf); 1744 (void) update_subtree(chdh, cnode); 1745 } 1746 } 1747 1748 return (PICL_SUCCESS); 1749 1750 } 1751 1752 /* 1753 * Check for a stale OBP node. EINVAL is returned from the openprom(7D) driver 1754 * if the nodeid stored in the snapshot is not valid. 1755 */ 1756 static int 1757 check_stale_node(di_node_t node, void *arg) 1758 { 1759 di_prom_prop_t promp; 1760 1761 errno = 0; 1762 promp = di_prom_prop_next(ph, node, DI_PROM_PROP_NIL); 1763 if (promp == DI_PROM_PROP_NIL && errno == EINVAL) { 1764 snapshot_stale = 1; 1765 return (DI_WALK_TERMINATE); 1766 } 1767 return (DI_WALK_CONTINUE); 1768 } 1769 1770 /* 1771 * Walk the snapshot and check the OBP properties of each node. 1772 */ 1773 static int 1774 is_snapshot_stale(di_node_t root) 1775 { 1776 snapshot_stale = 0; 1777 (void) di_walk_node(root, DI_WALK_CLDFIRST, NULL, check_stale_node); 1778 return (snapshot_stale); 1779 } 1780 1781 /* 1782 * This function processes the data from libdevinfo and creates nodes 1783 * in the PICL tree. 1784 */ 1785 static int 1786 libdevinfo_init(picl_nodehdl_t rooth) 1787 { 1788 di_node_t di_root; 1789 picl_nodehdl_t plafh; 1790 picl_nodehdl_t obph; 1791 int err; 1792 1793 /* 1794 * Use DINFOCACHE so that we obtain all attributes for all 1795 * device instances (without necessarily doing a load/attach 1796 * of all drivers). Once the (on-disk) cache file is built, it 1797 * exists over a reboot and can be read into memory at a very 1798 * low cost. 1799 */ 1800 if ((di_root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 1801 return (PICL_FAILURE); 1802 1803 if ((ph = di_prom_init()) == NULL) 1804 return (PICL_FAILURE); 1805 1806 /* 1807 * Check if the snapshot cache contains stale OBP nodeid references. 1808 * If it does release the snapshot and obtain a live snapshot from the 1809 * kernel. 1810 */ 1811 if (is_snapshot_stale(di_root)) { 1812 syslog(LOG_INFO, "picld detected stale snapshot cache"); 1813 di_fini(di_root); 1814 if ((di_root = di_init("/", DINFOCPYALL | DINFOFORCE)) == 1815 DI_NODE_NIL) { 1816 return (PICL_FAILURE); 1817 } 1818 } 1819 1820 /* 1821 * create platform PICL node using di_root node 1822 */ 1823 err = construct_picl_platform(rooth, di_root, &plafh); 1824 if (err != PICL_SUCCESS) { 1825 di_fini(di_root); 1826 return (PICL_FAILURE); 1827 } 1828 1829 err = construct_picl_openprom(rooth, &obph); 1830 if (err != PICL_SUCCESS) { 1831 di_fini(di_root); 1832 return (PICL_FAILURE); 1833 } 1834 1835 (void) construct_devinfo_tree(plafh, obph, di_root, NULL); 1836 if (ph) { 1837 di_prom_fini(ph); 1838 ph = NULL; 1839 } 1840 di_fini(di_root); 1841 return (err); 1842 } 1843 1844 /* 1845 * This function returns the integer property value 1846 */ 1847 static int 1848 get_int_propval_by_name(picl_nodehdl_t nodeh, char *pname, int *ival) 1849 { 1850 int err; 1851 1852 err = ptree_get_propval_by_name(nodeh, pname, ival, 1853 sizeof (int)); 1854 1855 return (err); 1856 } 1857 1858 /* 1859 * This function returns the port ID (or CPU ID in the case of CMP cores) 1860 * of the specific CPU node handle. If upa_portid exists, return its value. 1861 * Otherwise, return portid/cpuid. 1862 */ 1863 static int 1864 get_cpu_portid(picl_nodehdl_t modh, int *id) 1865 { 1866 int err; 1867 1868 if (strcmp(mach_name, "sun4u") == 0 || 1869 strcmp(mach_name, "sun4v") == 0) { 1870 err = get_int_propval_by_name(modh, OBP_PROP_UPA_PORTID, id); 1871 if (err == PICL_SUCCESS) 1872 return (err); 1873 err = get_int_propval_by_name(modh, OBP_PROP_PORTID, id); 1874 if (err == PICL_SUCCESS) 1875 return (err); 1876 return (get_int_propval_by_name(modh, OBP_PROP_CPUID, id)); 1877 } 1878 if (strcmp(mach_name, "i86pc") == 0) 1879 return (get_int_propval_by_name(modh, OBP_REG, id)); 1880 1881 return (PICL_FAILURE); 1882 } 1883 1884 /* 1885 * This function is the volatile read access function of CPU state 1886 * property 1887 */ 1888 static int 1889 get_pi_state(ptree_rarg_t *rarg, void *vbuf) 1890 { 1891 int id; 1892 int err; 1893 1894 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1895 if (err != PICL_SUCCESS) 1896 return (err); 1897 1898 switch (p_online(id, P_STATUS)) { 1899 case P_ONLINE: 1900 (void) strlcpy(vbuf, PS_ONLINE, MAX_STATE_SIZE); 1901 break; 1902 case P_OFFLINE: 1903 (void) strlcpy(vbuf, PS_OFFLINE, MAX_STATE_SIZE); 1904 break; 1905 case P_NOINTR: 1906 (void) strlcpy(vbuf, PS_NOINTR, MAX_STATE_SIZE); 1907 break; 1908 case P_SPARE: 1909 (void) strlcpy(vbuf, PS_SPARE, MAX_STATE_SIZE); 1910 break; 1911 case P_FAULTED: 1912 (void) strlcpy(vbuf, PS_FAULTED, MAX_STATE_SIZE); 1913 break; 1914 case P_POWEROFF: 1915 (void) strlcpy(vbuf, PS_POWEROFF, MAX_STATE_SIZE); 1916 break; 1917 case P_DISABLED: 1918 (void) strlcpy(vbuf, PS_DISABLED, MAX_STATE_SIZE); 1919 break; 1920 default: 1921 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE); 1922 break; 1923 } 1924 return (PICL_SUCCESS); 1925 } 1926 1927 /* 1928 * This function is the volatile read access function of CPU processor_type 1929 * property 1930 */ 1931 static int 1932 get_processor_type(ptree_rarg_t *rarg, void *vbuf) 1933 { 1934 processor_info_t cpu_info; 1935 int id; 1936 int err; 1937 1938 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1939 if (err != PICL_SUCCESS) 1940 return (err); 1941 1942 if (processor_info(id, &cpu_info) >= 0) { 1943 (void) strlcpy(vbuf, cpu_info.pi_processor_type, PI_TYPELEN); 1944 } 1945 return (PICL_SUCCESS); 1946 } 1947 1948 /* 1949 * This function is the volatile read access function of CPU fputypes 1950 * property 1951 */ 1952 static int 1953 get_fputypes(ptree_rarg_t *rarg, void *vbuf) 1954 { 1955 processor_info_t cpu_info; 1956 int id; 1957 int err; 1958 1959 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1960 if (err != PICL_SUCCESS) 1961 return (err); 1962 1963 if (processor_info(id, &cpu_info) >= 0) { 1964 (void) strlcpy(vbuf, cpu_info.pi_fputypes, PI_FPUTYPE); 1965 } 1966 return (PICL_SUCCESS); 1967 } 1968 1969 /* 1970 * This function is the volatile read access function of CPU StateBegin 1971 * property. To minimize overhead, use kstat_chain_update() to refresh 1972 * the kstat header info as opposed to invoking kstat_open() every time. 1973 */ 1974 static int 1975 get_pi_state_begin(ptree_rarg_t *rarg, void *vbuf) 1976 { 1977 int err; 1978 int cpu_id; 1979 static kstat_ctl_t *kc = NULL; 1980 static pthread_mutex_t kc_mutex = PTHREAD_MUTEX_INITIALIZER; 1981 kstat_t *kp; 1982 kstat_named_t *kn; 1983 1984 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &cpu_id); 1985 if (err != PICL_SUCCESS) 1986 return (err); 1987 1988 (void) pthread_mutex_lock(&kc_mutex); 1989 if (kc == NULL) 1990 kc = kstat_open(); 1991 else if (kstat_chain_update(kc) == -1) { 1992 (void) kstat_close(kc); 1993 kc = kstat_open(); 1994 } 1995 1996 if (kc == NULL) { 1997 (void) pthread_mutex_unlock(&kc_mutex); 1998 return (PICL_FAILURE); 1999 } 2000 2001 /* Get the state_begin from kstat */ 2002 if ((kp = kstat_lookup(kc, KSTAT_CPU_INFO, cpu_id, NULL)) == NULL || 2003 kp->ks_type != KSTAT_TYPE_NAMED || kstat_read(kc, kp, 0) < 0) { 2004 (void) pthread_mutex_unlock(&kc_mutex); 2005 return (PICL_FAILURE); 2006 } 2007 2008 kn = kstat_data_lookup(kp, KSTAT_STATE_BEGIN); 2009 if (kn) { 2010 *(uint64_t *)vbuf = (uint64_t)kn->value.l; 2011 err = PICL_SUCCESS; 2012 } else 2013 err = PICL_FAILURE; 2014 2015 (void) pthread_mutex_unlock(&kc_mutex); 2016 return (err); 2017 } 2018 2019 /* 2020 * This function adds CPU information to the CPU nodes 2021 */ 2022 /* ARGSUSED */ 2023 static int 2024 add_processor_info(picl_nodehdl_t cpuh, void *args) 2025 { 2026 int err; 2027 int cpu_id; 2028 ptree_propinfo_t propinfo; 2029 ptree_propinfo_t pinfo; 2030 2031 err = get_cpu_portid(cpuh, &cpu_id); 2032 if (err != PICL_SUCCESS) 2033 return (PICL_WALK_CONTINUE); 2034 2035 /* 2036 * Check to make sure that the CPU is still present, i.e. that it 2037 * has not been DR'ed out of the system. 2038 */ 2039 if (p_online(cpu_id, P_STATUS) == -1) { 2040 if (picldevtree_debug) 2041 syslog(LOG_INFO, 2042 "picldevtree: cpu %d (%llx) does not exist - " 2043 "deleting node\n", cpu_id, cpuh); 2044 2045 if (ptree_delete_node(cpuh) == PICL_SUCCESS) 2046 (void) ptree_destroy_node(cpuh); 2047 2048 return (PICL_WALK_CONTINUE); 2049 } 2050 2051 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2052 PICL_PTYPE_INT, PICL_READ, sizeof (int), PICL_PROP_ID, NULL, NULL); 2053 err = ptree_create_and_add_prop(cpuh, &propinfo, &cpu_id, NULL); 2054 if (err != PICL_SUCCESS) 2055 return (PICL_WALK_CONTINUE); 2056 2057 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2058 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), MAX_STATE_SIZE, 2059 PICL_PROP_STATE, get_pi_state, NULL); 2060 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2061 2062 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2063 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_TYPELEN, 2064 PICL_PROP_PROCESSOR_TYPE, get_processor_type, NULL); 2065 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2066 2067 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2068 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_FPUTYPE, 2069 PICL_PROP_FPUTYPE, get_fputypes, NULL); 2070 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2071 2072 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2073 PICL_PTYPE_TIMESTAMP, PICL_READ|PICL_VOLATILE, sizeof (uint64_t), 2074 PICL_PROP_STATE_BEGIN, get_pi_state_begin, NULL); 2075 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2076 2077 return (PICL_WALK_CONTINUE); 2078 } 2079 2080 /* 2081 * This function sets up the "ID" property in every CPU nodes 2082 * and adds processor info 2083 */ 2084 static int 2085 setup_cpus(picl_nodehdl_t plafh) 2086 { 2087 int err; 2088 2089 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_CPU, NULL, 2090 add_processor_info); 2091 2092 return (err); 2093 } 2094 2095 /* 2096 * This function format's the manufacture's information for FFB display 2097 * devices 2098 */ 2099 static void 2100 fmt_manf_id(manuf_t manufid, int bufsz, char *outbuf) 2101 { 2102 /* 2103 * Format the manufacturer's info. Note a small inconsistency we 2104 * have to work around - Brooktree has it's part number in decimal, 2105 * while Mitsubishi has it's part number in hex. 2106 */ 2107 switch (manufid.fld.manf) { 2108 case MANF_BROOKTREE: 2109 (void) snprintf(outbuf, bufsz, "%s %d, version %d", 2110 "Brooktree", manufid.fld.partno, manufid.fld.version); 2111 break; 2112 2113 case MANF_MITSUBISHI: 2114 (void) snprintf(outbuf, bufsz, "%s %x, version %d", 2115 "Mitsubishi", manufid.fld.partno, manufid.fld.version); 2116 break; 2117 2118 default: 2119 (void) snprintf(outbuf, bufsz, 2120 "JED code %d, Part num 0x%x, version %d", 2121 manufid.fld.manf, manufid.fld.partno, manufid.fld.version); 2122 } 2123 } 2124 2125 /* 2126 * If it's an ffb device, open ffb devices and return PICL_SUCCESS 2127 */ 2128 static int 2129 open_ffb_device(picl_nodehdl_t ffbh, int *fd) 2130 { 2131 DIR *dirp; 2132 char devfs_path[PATH_MAX]; 2133 char dev_path[PATH_MAX]; 2134 char *devp; 2135 struct dirent *direntp; 2136 int err; 2137 int tmpfd; 2138 2139 /* Get the devfs_path of the ffb devices */ 2140 err = ptree_get_propval_by_name(ffbh, PICL_PROP_DEVFS_PATH, devfs_path, 2141 sizeof (devfs_path)); 2142 if (err != PICL_SUCCESS) 2143 return (err); 2144 2145 /* Get the device node name */ 2146 devp = strrchr(devfs_path, '/'); 2147 if (devp == NULL) 2148 return (PICL_FAILURE); 2149 *devp = '\0'; 2150 ++devp; 2151 2152 /* 2153 * Check if device node name has the ffb string 2154 * If not, assume it's not a ffb device. 2155 */ 2156 if (strstr(devp, FFB_NAME) == NULL) 2157 return (PICL_FAILURE); 2158 2159 /* 2160 * Get the parent path of the ffb device node. 2161 */ 2162 (void) snprintf(dev_path, sizeof (dev_path), "%s/%s", "/devices", 2163 devfs_path); 2164 2165 /* 2166 * Since we don't know ffb's minor nodename, 2167 * we need to search all the devices under its 2168 * parent dir by comparing the node name 2169 */ 2170 if ((dirp = opendir(dev_path)) == NULL) 2171 return (PICL_FAILURE); 2172 2173 while ((direntp = readdir(dirp)) != NULL) { 2174 if (strstr(direntp->d_name, devp) != NULL) { 2175 (void) strcat(dev_path, "/"); 2176 (void) strcat(dev_path, direntp->d_name); 2177 tmpfd = open(dev_path, O_RDWR); 2178 if (tmpfd < 0) 2179 continue; 2180 *fd = tmpfd; 2181 (void) closedir(dirp); 2182 return (PICL_SUCCESS); 2183 } 2184 } 2185 2186 (void) closedir(dirp); 2187 return (PICL_FAILURE); 2188 } 2189 2190 /* 2191 * This function recursively searches the tree for ffb display devices 2192 * and add ffb config information 2193 */ 2194 static int 2195 add_ffb_config_info(picl_nodehdl_t rooth) 2196 { 2197 picl_nodehdl_t nodeh; 2198 int err; 2199 char piclclass[PICL_CLASSNAMELEN_MAX]; 2200 char manfidbuf[FFB_MANUF_BUFSIZE]; 2201 int fd; 2202 int board_rev; 2203 ffb_sys_info_t fsi; 2204 ptree_propinfo_t pinfo; 2205 2206 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh, 2207 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2208 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, 2209 &nodeh, sizeof (picl_nodehdl_t))) { 2210 2211 if (err != PICL_SUCCESS) 2212 return (err); 2213 2214 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 2215 piclclass, PICL_CLASSNAMELEN_MAX); 2216 2217 if ((err == PICL_SUCCESS) && 2218 (strcmp(piclclass, PICL_CLASS_DISPLAY) == 0)) { 2219 2220 err = open_ffb_device(nodeh, &fd); 2221 if ((err == PICL_SUCCESS) && 2222 (ioctl(fd, FFB_SYS_INFO, &fsi) >= 0)) { 2223 (void) ptree_init_propinfo(&pinfo, 2224 PTREE_PROPINFO_VERSION, 2225 PICL_PTYPE_UNSIGNED_INT, PICL_READ, 2226 sizeof (int), PICL_PROP_FFB_BOARD_REV, 2227 NULL, NULL); 2228 board_rev = fsi.ffb_strap_bits.fld.board_rev; 2229 (void) ptree_create_and_add_prop(nodeh, &pinfo, 2230 &board_rev, NULL); 2231 2232 fmt_manf_id(fsi.dac_version, 2233 sizeof (manfidbuf), manfidbuf); 2234 (void) ptree_init_propinfo(&pinfo, 2235 PTREE_PROPINFO_VERSION, 2236 PICL_PTYPE_CHARSTRING, PICL_READ, 2237 strlen(manfidbuf) + 1, 2238 PICL_PROP_FFB_DAC_VER, NULL, NULL); 2239 (void) ptree_create_and_add_prop(nodeh, &pinfo, 2240 manfidbuf, NULL); 2241 2242 fmt_manf_id(fsi.fbram_version, 2243 sizeof (manfidbuf), manfidbuf); 2244 (void) ptree_init_propinfo(&pinfo, 2245 PTREE_PROPINFO_VERSION, 2246 PICL_PTYPE_CHARSTRING, PICL_READ, 2247 strlen(manfidbuf) + 1, 2248 PICL_PROP_FFB_FBRAM_VER, NULL, 2249 NULL); 2250 (void) ptree_create_and_add_prop(nodeh, &pinfo, 2251 manfidbuf, NULL); 2252 (void) close(fd); 2253 } 2254 } else if (add_ffb_config_info(nodeh) != PICL_SUCCESS) 2255 return (PICL_FAILURE); 2256 } 2257 return (PICL_SUCCESS); 2258 } 2259 2260 static conf_entries_t * 2261 free_conf_entries(conf_entries_t *list) 2262 { 2263 conf_entries_t *el; 2264 conf_entries_t *del; 2265 2266 if (list == NULL) 2267 return (NULL); 2268 el = list; 2269 while (el != NULL) { 2270 del = el; 2271 el = el->next; 2272 free(del->name); 2273 free(del->piclclass); 2274 free(del); 2275 } 2276 return (el); 2277 } 2278 2279 /* 2280 * Reading config order: platform, common 2281 */ 2282 static conf_entries_t * 2283 read_conf_file(char *fname, conf_entries_t *list) 2284 { 2285 FILE *fp; 2286 char lbuf[CONFFILE_LINELEN_MAX]; 2287 char *nametok; 2288 char *classtok; 2289 conf_entries_t *el; 2290 conf_entries_t *ptr; 2291 2292 if (fname == NULL) 2293 return (list); 2294 2295 fp = fopen(fname, "r"); 2296 2297 if (fp == NULL) 2298 return (list); 2299 2300 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 2301 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 2302 continue; 2303 2304 nametok = strtok(lbuf, " \t\n"); 2305 if (nametok == NULL) 2306 continue; 2307 2308 classtok = strtok(NULL, " \t\n"); 2309 if (classtok == NULL) 2310 continue; 2311 2312 el = malloc(sizeof (conf_entries_t)); 2313 if (el == NULL) 2314 break; 2315 el->name = strdup(nametok); 2316 el->piclclass = strdup(classtok); 2317 if ((el->name == NULL) || (el->piclclass == NULL)) { 2318 free(el); 2319 return (list); 2320 } 2321 el->next = NULL; 2322 2323 /* 2324 * Add it to the end of list 2325 */ 2326 if (list == NULL) 2327 list = el; 2328 else { 2329 ptr = list; 2330 while (ptr->next != NULL) 2331 ptr = ptr->next; 2332 ptr->next = el; 2333 } 2334 2335 } 2336 (void) fclose(fp); 2337 return (list); 2338 } 2339 2340 /* 2341 * Process the devtree conf file and set up the conf_name_class_map list 2342 */ 2343 static void 2344 process_devtree_conf_file(void) 2345 { 2346 char nmbuf[SYS_NMLN]; 2347 char pname[PATH_MAX]; 2348 2349 conf_name_class_map = NULL; 2350 2351 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2352 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2353 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2354 conf_name_class_map = read_conf_file(pname, 2355 conf_name_class_map); 2356 } 2357 2358 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2359 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2360 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2361 conf_name_class_map = read_conf_file(pname, 2362 conf_name_class_map); 2363 } 2364 2365 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2366 DEVTREE_CONFFILE_NAME); 2367 conf_name_class_map = read_conf_file(pname, conf_name_class_map); 2368 } 2369 2370 static asr_conf_entries_t *conf_name_asr_map = NULL; 2371 2372 static void 2373 free_asr_conf_entries(asr_conf_entries_t *list) 2374 { 2375 asr_conf_entries_t *el; 2376 asr_conf_entries_t *del; 2377 2378 el = list; 2379 while (el != NULL) { 2380 del = el; 2381 el = el->next; 2382 if (del->name) 2383 free(del->name); 2384 if (del->address) 2385 free(del->address); 2386 if (del->status) 2387 free(del->status); 2388 if (del->piclclass) 2389 free(del->piclclass); 2390 if (del->props) 2391 free(del->props); 2392 free(del); 2393 } 2394 } 2395 2396 /* 2397 * Reading config order: platform, common 2398 */ 2399 static asr_conf_entries_t * 2400 read_asr_conf_file(char *fname, asr_conf_entries_t *list) 2401 { 2402 FILE *fp; 2403 char lbuf[CONFFILE_LINELEN_MAX]; 2404 char *nametok; 2405 char *classtok; 2406 char *statustok; 2407 char *addresstok; 2408 char *propstok; 2409 asr_conf_entries_t *el; 2410 asr_conf_entries_t *ptr; 2411 2412 if (fname == NULL) 2413 return (list); 2414 2415 fp = fopen(fname, "r"); 2416 if (fp == NULL) 2417 return (list); 2418 2419 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 2420 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 2421 continue; 2422 2423 nametok = strtok(lbuf, " \t\n"); 2424 if (nametok == NULL) 2425 continue; 2426 2427 classtok = strtok(NULL, " \t\n"); 2428 if (classtok == NULL) 2429 continue; 2430 2431 statustok = strtok(NULL, " \t\n"); 2432 if (statustok == NULL) 2433 continue; 2434 2435 addresstok = strtok(NULL, " \t\n"); 2436 if (addresstok == NULL) 2437 continue; 2438 2439 /* 2440 * props are optional 2441 */ 2442 propstok = strtok(NULL, " \t\n"); 2443 2444 el = malloc(sizeof (asr_conf_entries_t)); 2445 if (el == NULL) 2446 break; 2447 el->name = strdup(nametok); 2448 el->piclclass = strdup(classtok); 2449 el->status = strdup(statustok); 2450 el->address = strdup(addresstok); 2451 if (propstok != NULL) 2452 el->props = strdup(propstok); 2453 else 2454 el->props = NULL; 2455 if ((el->name == NULL) || (el->piclclass == NULL) || 2456 (el->address == NULL) || (el->status == NULL)) { 2457 if (el->name) 2458 free(el->name); 2459 if (el->address) 2460 free(el->address); 2461 if (el->status) 2462 free(el->status); 2463 if (el->piclclass) 2464 free(el->piclclass); 2465 if (el->props) 2466 free(el->props); 2467 free(el); 2468 break; 2469 } 2470 el->next = NULL; 2471 2472 /* 2473 * Add it to the end of list 2474 */ 2475 if (list == NULL) 2476 list = el; 2477 else { 2478 ptr = list; 2479 while (ptr->next != NULL) 2480 ptr = ptr->next; 2481 ptr->next = el; 2482 } 2483 2484 } 2485 (void) fclose(fp); 2486 return (list); 2487 } 2488 2489 /* 2490 * Process the asr conf file 2491 */ 2492 static void 2493 process_asrtree_conf_file(void) 2494 { 2495 char nmbuf[SYS_NMLN]; 2496 char pname[PATH_MAX]; 2497 2498 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2499 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2500 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2501 conf_name_asr_map = read_asr_conf_file(pname, 2502 conf_name_asr_map); 2503 } 2504 2505 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2506 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2507 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2508 conf_name_asr_map = read_asr_conf_file(pname, 2509 conf_name_asr_map); 2510 } 2511 2512 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2513 ASRTREE_CONFFILE_NAME); 2514 conf_name_asr_map = read_asr_conf_file(pname, conf_name_asr_map); 2515 } 2516 2517 /* 2518 * This function reads the export file list from ASR 2519 */ 2520 static int 2521 get_asr_export_list(char **exportlist, int *exportlistlen) 2522 { 2523 struct openpromio oppbuf; 2524 struct openpromio *opp = &oppbuf; 2525 int d; 2526 int listsize; 2527 2528 d = open("/dev/openprom", O_RDWR); 2529 if (d < 0) 2530 return (0); 2531 2532 if (ioctl(d, OPROMEXPORTLEN, opp) == -1) { 2533 (void) close(d); 2534 return (0); 2535 } 2536 listsize = opp->oprom_size; 2537 opp = (struct openpromio *)malloc(sizeof (struct openpromio) + 2538 listsize); 2539 if (opp == NULL) { 2540 (void) close(d); 2541 return (0); 2542 } 2543 (void) memset(opp, '\0', sizeof (struct openpromio) + listsize); 2544 opp->oprom_size = listsize; 2545 if (ioctl(d, OPROMEXPORT, opp) == -1) { 2546 free(opp); 2547 (void) close(d); 2548 return (0); 2549 } 2550 *exportlist = malloc(listsize); 2551 if (*exportlist == NULL) { 2552 free(opp); 2553 (void) close(d); 2554 return (0); 2555 } 2556 (void) memcpy(*exportlist, opp->oprom_array, opp->oprom_size); 2557 *exportlistlen = opp->oprom_size; 2558 free(opp); 2559 (void) close(d); 2560 return (1); 2561 } 2562 2563 /* 2564 * Parses properties string, fills in triplet structure with first 2565 * type, name, val triplet and returns pointer to next property. 2566 * Returns NULL if no valid triplet found 2567 * CAUTION: drops \0 characters over separator characters: if you 2568 * want to parse the string twice, you'll have to take a copy. 2569 */ 2570 static char * 2571 parse_props_string(char *props, asr_prop_triplet_t *triplet) 2572 { 2573 char *prop_name; 2574 char *prop_val; 2575 char *prop_next; 2576 2577 prop_name = strchr(props, '?'); 2578 if (prop_name == NULL) 2579 return (NULL); 2580 *prop_name++ = '\0'; 2581 prop_val = strchr(prop_name, '='); 2582 if (prop_val == NULL) 2583 return (NULL); 2584 *prop_val++ = '\0'; 2585 triplet->proptype = props; 2586 triplet->propname = prop_name; 2587 triplet->propval = prop_val; 2588 prop_next = strchr(prop_val, ':'); 2589 if (prop_next == NULL) 2590 return (prop_val - 1); 2591 *prop_next++ = '\0'; 2592 return (prop_next); 2593 } 2594 2595 static int 2596 add_status_prop(picl_nodehdl_t chdh, char *status) 2597 { 2598 ptree_propinfo_t propinfo; 2599 picl_prophdl_t proph; 2600 int err; 2601 2602 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2603 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(status) + 1, 2604 PICL_PROP_STATUS, NULL, NULL); 2605 if (err != PICL_SUCCESS) 2606 return (err); 2607 err = ptree_create_and_add_prop(chdh, &propinfo, status, &proph); 2608 return (err); 2609 } 2610 2611 static void 2612 create_asr_node(char *parent, char *child, char *unitaddr, char *class, 2613 char *status, char *props) 2614 { 2615 char ptreepath[PATH_MAX]; 2616 char nodename[PICL_PROPNAMELEN_MAX]; 2617 char ua[MAX_UNIT_ADDRESS_LEN]; 2618 char *props_copy = NULL; 2619 char *next; 2620 char *prop_string; 2621 boolean_t found = B_FALSE; 2622 picl_nodehdl_t nodeh; 2623 picl_nodehdl_t chdh; 2624 asr_prop_triplet_t triple; 2625 ptree_propinfo_t propinfo; 2626 picl_prophdl_t proph; 2627 int val; 2628 int err; 2629 2630 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX); 2631 (void) strlcat(ptreepath, parent, PATH_MAX); 2632 2633 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS) 2634 return; 2635 /* 2636 * see if the required child node already exists 2637 */ 2638 for (err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 2639 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2640 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 2641 sizeof (picl_nodehdl_t))) { 2642 if (err != PICL_SUCCESS) 2643 break; 2644 err = ptree_get_propval_by_name(chdh, PICL_PROP_NAME, 2645 (void *)nodename, PICL_PROPNAMELEN_MAX); 2646 if (err != PICL_SUCCESS) 2647 break; 2648 if (strcmp(nodename, child) != 0) 2649 continue; 2650 /* 2651 * found a candidate child node 2652 */ 2653 if (unitaddr) { 2654 /* 2655 * does it match the required unit address? 2656 */ 2657 err = ptree_get_propval_by_name(chdh, 2658 PICL_PROP_UNIT_ADDRESS, ua, sizeof (ua)); 2659 if (err == PICL_PROPNOTFOUND) 2660 continue; 2661 if (err != PICL_SUCCESS) 2662 break; 2663 if (strcmp(unitaddr, ua) != 0) 2664 continue; 2665 } 2666 if (props == NULL) { 2667 next = ""; 2668 } else if (props_copy == NULL) { 2669 props_copy = strdup(props); 2670 if (props_copy == NULL) 2671 return; 2672 next = props_copy; 2673 } 2674 while ((next = parse_props_string(next, &triple)) != NULL) { 2675 err = ptree_get_prop_by_name(chdh, triple.propname, 2676 &proph); 2677 if (err != PICL_SUCCESS) 2678 break; 2679 err = ptree_get_propinfo(proph, &propinfo); 2680 if (err != PICL_SUCCESS) 2681 break; 2682 err = PICL_FAILURE; 2683 switch (propinfo.piclinfo.type) { 2684 case PICL_PTYPE_INT: 2685 case PICL_PTYPE_UNSIGNED_INT: 2686 if (strcmp(triple.proptype, "I") != 0) 2687 break; 2688 err = ptree_get_propval(proph, (void *)&val, 2689 sizeof (val)); 2690 if (err != PICL_SUCCESS) 2691 break; 2692 if (val != atoi(triple.propval)) 2693 err = PICL_FAILURE; 2694 break; 2695 case PICL_PTYPE_CHARSTRING: 2696 if (strcmp(triple.proptype, "S") != 0) 2697 break; 2698 prop_string = malloc(propinfo.piclinfo.size); 2699 if (prop_string == NULL) 2700 break; 2701 err = ptree_get_propval(proph, 2702 (void *)prop_string, 2703 propinfo.piclinfo.size); 2704 if (err != PICL_SUCCESS) { 2705 free(prop_string); 2706 break; 2707 } 2708 if (strcmp(prop_string, triple.propval) != 0) 2709 err = PICL_FAILURE; 2710 free(prop_string); 2711 break; 2712 default: 2713 break; 2714 } 2715 if (err != PICL_SUCCESS) { 2716 break; 2717 } 2718 } 2719 if (next == NULL) { 2720 found = B_TRUE; 2721 break; 2722 } 2723 } 2724 if (props_copy) 2725 free(props_copy); 2726 if (found) { 2727 /* 2728 * does the pre-existing node have a status property? 2729 */ 2730 err = ptree_get_propval_by_name(chdh, PICL_PROP_STATUS, 2731 ua, sizeof (ua)); 2732 if (err == PICL_PROPNOTFOUND) 2733 (void) add_status_prop(chdh, status); 2734 if (err != PICL_SUCCESS) 2735 return; 2736 if ((strcmp(ua, ASR_DISABLED) == 0) || 2737 (strcmp(ua, ASR_FAILED) == 0) || 2738 ((strcmp(status, ASR_DISABLED) != 0) && 2739 (strcmp(status, ASR_FAILED) != 0))) { 2740 return; 2741 } 2742 /* 2743 * more urgent status now, so replace existing value 2744 */ 2745 err = ptree_get_prop_by_name(chdh, PICL_PROP_STATUS, &proph); 2746 if (err != PICL_SUCCESS) 2747 return; 2748 (void) ptree_delete_prop(proph); 2749 (void) ptree_destroy_prop(proph); 2750 err = add_status_prop(chdh, status); 2751 if (err != PICL_SUCCESS) 2752 return; 2753 return; 2754 } 2755 2756 /* 2757 * typical case, node needs adding together with a set of properties 2758 */ 2759 if (ptree_create_and_add_node(nodeh, child, class, &chdh) == 2760 PICL_SUCCESS) { 2761 (void) add_status_prop(chdh, status); 2762 if (unitaddr) { 2763 (void) ptree_init_propinfo(&propinfo, 2764 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2765 PICL_READ, strlen(unitaddr) + 1, 2766 PICL_PROP_UNIT_ADDRESS, NULL, NULL); 2767 (void) ptree_create_and_add_prop(chdh, &propinfo, 2768 unitaddr, &proph); 2769 (void) strlcpy(ptreepath, parent, PATH_MAX); 2770 (void) strlcat(ptreepath, "/", PATH_MAX); 2771 (void) strlcat(ptreepath, child, PATH_MAX); 2772 (void) strlcat(ptreepath, "@", PATH_MAX); 2773 (void) strlcat(ptreepath, unitaddr, PATH_MAX); 2774 (void) ptree_init_propinfo(&propinfo, 2775 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2776 PICL_READ, strlen(ptreepath) + 1, 2777 PICL_PROP_DEVFS_PATH, NULL, NULL); 2778 (void) ptree_create_and_add_prop(chdh, &propinfo, 2779 ptreepath, &proph); 2780 } 2781 next = props; 2782 while ((next = parse_props_string(next, &triple)) != NULL) { 2783 /* 2784 * only handle int and string properties for 2785 * simplicity 2786 */ 2787 if (strcmp(triple.proptype, "I") == 0) { 2788 (void) ptree_init_propinfo(&propinfo, 2789 PTREE_PROPINFO_VERSION, 2790 PICL_PTYPE_INT, PICL_READ, 2791 sizeof (int), triple.propname, NULL, NULL); 2792 val = atoi(triple.propval); 2793 (void) ptree_create_and_add_prop(chdh, 2794 &propinfo, &val, &proph); 2795 } else { 2796 (void) ptree_init_propinfo(&propinfo, 2797 PTREE_PROPINFO_VERSION, 2798 PICL_PTYPE_CHARSTRING, PICL_READ, 2799 strlen(triple.propval) + 1, 2800 triple.propname, NULL, NULL); 2801 (void) ptree_create_and_add_prop(chdh, 2802 &propinfo, triple.propval, &proph); 2803 } 2804 } 2805 } 2806 } 2807 2808 static void 2809 add_asr_nodes() 2810 { 2811 char *asrexport; 2812 int asrexportlen; 2813 asr_conf_entries_t *c = NULL; 2814 int i; 2815 char *key; 2816 char *child; 2817 char *unitaddr; 2818 uint16_t count; 2819 int disabled; 2820 2821 if (get_asr_export_list(&asrexport, &asrexportlen) == 0) 2822 return; 2823 process_asrtree_conf_file(); 2824 if (conf_name_asr_map == NULL) 2825 return; 2826 i = 0; 2827 while (i < asrexportlen) { 2828 key = &asrexport[i]; 2829 i += strlen(key) + 1; 2830 if (i >= asrexportlen) 2831 break; 2832 2833 /* 2834 * next byte tells us whether failed by diags or manually 2835 * disabled 2836 */ 2837 disabled = asrexport[i]; 2838 i++; 2839 if (i >= asrexportlen) 2840 break; 2841 2842 /* 2843 * only type 1 supported 2844 */ 2845 if (asrexport[i] != 1) 2846 break; 2847 i++; 2848 if (i >= asrexportlen) 2849 break; 2850 2851 /* 2852 * next two bytes give size of reason string 2853 */ 2854 count = (asrexport[i] << 8) | asrexport[i + 1]; 2855 i += count + 2; 2856 if (i > asrexportlen) 2857 break; 2858 2859 /* 2860 * now look for key in conf file info 2861 */ 2862 c = conf_name_asr_map; 2863 while (c != NULL) { 2864 if (strcmp(key, c->name) == 0) { 2865 child = strrchr(c->address, '/'); 2866 *child++ = '\0'; 2867 unitaddr = strchr(child, '@'); 2868 if (unitaddr) 2869 *unitaddr++ = '\0'; 2870 if (strcmp(c->status, ASR_DISABLED) == 0) { 2871 create_asr_node(c->address, child, 2872 unitaddr, c->piclclass, disabled ? 2873 ASR_DISABLED : ASR_FAILED, 2874 c->props); 2875 } else { 2876 create_asr_node(c->address, child, 2877 unitaddr, c->piclclass, c->status, 2878 c->props); 2879 } 2880 } 2881 c = c->next; 2882 } 2883 } 2884 2885 free_asr_conf_entries(conf_name_asr_map); 2886 free(asrexport); 2887 } 2888 2889 /* 2890 * This function adds information to the /platform node 2891 */ 2892 static int 2893 add_platform_info(picl_nodehdl_t plafh) 2894 { 2895 struct utsname uts_info; 2896 int err; 2897 ptree_propinfo_t propinfo; 2898 picl_prophdl_t proph; 2899 2900 if (uname(&uts_info) < 0) 2901 return (PICL_FAILURE); 2902 2903 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2904 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.sysname) + 1, 2905 PICL_PROP_SYSNAME, NULL, NULL); 2906 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.sysname, 2907 &proph); 2908 if (err != PICL_SUCCESS) 2909 return (err); 2910 2911 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2912 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.nodename) + 1, 2913 PICL_PROP_NODENAME, NULL, NULL); 2914 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.nodename, 2915 &proph); 2916 if (err != PICL_SUCCESS) 2917 return (err); 2918 2919 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2920 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.release) + 1, 2921 PICL_PROP_RELEASE, NULL, NULL); 2922 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.release, 2923 &proph); 2924 if (err != PICL_SUCCESS) 2925 return (err); 2926 2927 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2928 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.version) + 1, 2929 PICL_PROP_VERSION, NULL, NULL); 2930 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.version, 2931 &proph); 2932 if (err != PICL_SUCCESS) 2933 return (err); 2934 2935 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2936 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.machine) + 1, 2937 PICL_PROP_MACHINE, NULL, NULL); 2938 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.machine, 2939 &proph); 2940 return (err); 2941 } 2942 2943 /* 2944 * Get first 32-bit value from the reg property 2945 */ 2946 static int 2947 get_first_reg_word(picl_nodehdl_t nodeh, uint32_t *regval) 2948 { 2949 int err; 2950 uint32_t *regbuf; 2951 picl_prophdl_t regh; 2952 ptree_propinfo_t pinfo; 2953 2954 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 2955 if (err != PICL_SUCCESS) /* no reg property */ 2956 return (err); 2957 err = ptree_get_propinfo(regh, &pinfo); 2958 if (err != PICL_SUCCESS) 2959 return (err); 2960 if (pinfo.piclinfo.size < sizeof (uint32_t)) /* too small */ 2961 return (PICL_FAILURE); 2962 regbuf = alloca(pinfo.piclinfo.size); 2963 if (regbuf == NULL) 2964 return (PICL_FAILURE); 2965 err = ptree_get_propval(regh, regbuf, pinfo.piclinfo.size); 2966 if (err != PICL_SUCCESS) 2967 return (err); 2968 *regval = *regbuf; /* get first 32-bit value */ 2969 return (PICL_SUCCESS); 2970 } 2971 2972 /* 2973 * Get device ID from the reg property 2974 */ 2975 static int 2976 get_device_id(picl_nodehdl_t nodeh, uint32_t *dev_id) 2977 { 2978 int err; 2979 uint32_t regval; 2980 2981 err = get_first_reg_word(nodeh, ®val); 2982 if (err != PICL_SUCCESS) 2983 return (err); 2984 2985 *dev_id = PCI_DEVICE_ID(regval); 2986 return (PICL_SUCCESS); 2987 } 2988 2989 /* 2990 * add Slot property for children of SBUS node 2991 */ 2992 /* ARGSUSED */ 2993 static int 2994 add_sbus_slots(picl_nodehdl_t pcih, void *args) 2995 { 2996 picl_nodehdl_t nodeh; 2997 uint32_t slot; 2998 int err; 2999 ptree_propinfo_t pinfo; 3000 3001 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 3002 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 3003 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 3004 sizeof (picl_nodehdl_t))) { 3005 if (err != PICL_SUCCESS) 3006 return (err); 3007 3008 if (get_first_reg_word(nodeh, &slot) != 0) 3009 continue; 3010 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3011 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 3012 PICL_PROP_SLOT, NULL, NULL); 3013 (void) ptree_create_and_add_prop(nodeh, &pinfo, &slot, NULL); 3014 } 3015 3016 return (PICL_WALK_CONTINUE); 3017 } 3018 3019 /* 3020 * This function creates a Slot property for SBUS child nodes 3021 * which can be correlated with the slot they are plugged into 3022 * on the motherboard. 3023 */ 3024 static int 3025 set_sbus_slot(picl_nodehdl_t plafh) 3026 { 3027 int err; 3028 3029 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_SBUS, NULL, 3030 add_sbus_slots); 3031 3032 return (err); 3033 } 3034 3035 /* 3036 * add DeviceID property for children of PCI/PCIEX node 3037 */ 3038 /* ARGSUSED */ 3039 static int 3040 add_pci_deviceids(picl_nodehdl_t pcih, void *args) 3041 { 3042 picl_nodehdl_t nodeh; 3043 uint32_t dev_id; 3044 int err; 3045 ptree_propinfo_t pinfo; 3046 3047 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 3048 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 3049 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 3050 sizeof (picl_nodehdl_t))) { 3051 if (err != PICL_SUCCESS) 3052 return (err); 3053 3054 if (get_device_id(nodeh, &dev_id) != 0) 3055 continue; 3056 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3057 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 3058 PICL_PROP_DEVICE_ID, NULL, NULL); 3059 (void) ptree_create_and_add_prop(nodeh, &pinfo, &dev_id, NULL); 3060 } 3061 3062 return (PICL_WALK_CONTINUE); 3063 } 3064 3065 /* 3066 * This function creates a DeviceID property for PCI/PCIEX child nodes 3067 * which can be correlated with the slot they are plugged into 3068 * on the motherboard. 3069 */ 3070 static void 3071 set_pci_pciex_deviceid(picl_nodehdl_t plafh) 3072 { 3073 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCI, NULL, 3074 add_pci_deviceids); 3075 3076 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCIEX, NULL, 3077 add_pci_deviceids); 3078 } 3079 3080 /* 3081 * Default UnitAddress encode function 3082 */ 3083 static int 3084 encode_default_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3085 { 3086 int i, len; 3087 3088 /* 3089 * Encode UnitAddress as %a,%b,%c,...,%n 3090 */ 3091 if (addrcells < 1) 3092 return (-1); 3093 3094 len = snprintf(buf, sz, "%x", *regprop); 3095 for (i = 1; i < addrcells && len < sz; i++) 3096 len += snprintf(&buf[len], sz-len, ",%x", regprop[i]); 3097 3098 return ((len >= sz) ? -1 : 0); 3099 } 3100 3101 /* 3102 * UnitAddress encode function where the last component is not printed 3103 * unless non-zero. 3104 */ 3105 static int 3106 encode_optional_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3107 { 3108 int retval; 3109 3110 /* 3111 * Encode UnitAddress as %a,%b,%c,...,%n where the last component 3112 * is printed only if non-zero. 3113 */ 3114 if (addrcells > 1 && regprop[addrcells-1] == 0) 3115 retval = encode_default_unitaddr(buf, sz, regprop, addrcells-1); 3116 else 3117 retval = encode_default_unitaddr(buf, sz, regprop, addrcells); 3118 3119 return (retval); 3120 } 3121 3122 3123 /* 3124 * UnitAddress encode function for SCSI class of devices 3125 */ 3126 static int 3127 encode_scsi_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3128 { 3129 int len, retval; 3130 3131 /* 3132 * #address-cells Format 3133 * 2 second component printed only if non-zero 3134 * 3135 * 4 regprop: phys_hi phys_lo lun_hi lun_lo 3136 * UnitAddr: w<phys_hi><phys_lo>,<lun_lo> 3137 */ 3138 3139 if (addrcells == 2) { 3140 retval = encode_optional_unitaddr(buf, sz, regprop, addrcells); 3141 } else if (addrcells == 4) { 3142 len = snprintf(buf, sz, "w%08x%08x,%x", regprop[0], regprop[1], 3143 regprop[3]); 3144 retval = (len >= sz) ? -1 : 0; 3145 } else 3146 retval = -1; 3147 3148 return (retval); 3149 } 3150 3151 /* 3152 * UnitAddress encode function for UPA devices 3153 */ 3154 static int 3155 encode_upa_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3156 { 3157 int len; 3158 3159 if (addrcells != 2) 3160 return (-1); 3161 3162 len = snprintf(buf, sz, "%x,%x", (regprop[0]/2)&0x1f, regprop[1]); 3163 return ((len >= sz) ? -1 : 0); 3164 } 3165 3166 /* 3167 * UnitAddress encode function for GPTWO, JBUS devices 3168 */ 3169 static int 3170 encode_gptwo_jbus_unitaddr(char *buf, int sz, uint32_t *regprop, 3171 uint_t addrcells) 3172 { 3173 uint32_t hi, lo; 3174 int len, id, off; 3175 3176 if (addrcells != 2) 3177 return (-1); 3178 3179 hi = regprop[0]; 3180 lo = regprop[1]; 3181 3182 if (hi & 0x400) { 3183 id = ((hi & 0x1) << 9) | (lo >> 23); /* agent id */ 3184 off = lo & 0x7fffff; /* config offset */ 3185 len = snprintf(buf, sz, "%x,%x", id, off); 3186 } else { 3187 len = snprintf(buf, sz, "m%x,%x", hi, lo); 3188 } 3189 return ((len >= sz) ? -1 : 0); 3190 } 3191 3192 /* 3193 * UnitAddress encode function for PCI devices 3194 */ 3195 static int 3196 encode_pci_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3197 { 3198 typedef struct { 3199 uint32_t n:1, /* relocatable */ 3200 p:1, /* prefetchable */ 3201 t:1, /* address region aliases */ 3202 zero:3, /* must be zero */ 3203 ss:2, /* address space type */ 3204 bus:8, /* bus number */ 3205 dev:5, /* device number */ 3206 fn:3, /* function number */ 3207 reg:8; /* register number */ 3208 uint32_t phys_hi; /* high physical address */ 3209 uint32_t phys_lo; /* low physical address */ 3210 } pci_addrcell_t; 3211 3212 pci_addrcell_t *p; 3213 int len; 3214 3215 if (addrcells != 3) 3216 return (-1); 3217 3218 p = (pci_addrcell_t *)regprop; 3219 switch (p->ss) { 3220 case 0: /* Config */ 3221 if (p->fn) 3222 len = snprintf(buf, sz, "%x,%x", p->dev, p->fn); 3223 else 3224 len = snprintf(buf, sz, "%x", p->dev); 3225 break; 3226 case 1: /* IO */ 3227 len = snprintf(buf, sz, "i%x,%x,%x,%x", p->dev, p->fn, p->reg, 3228 p->phys_lo); 3229 break; 3230 case 2: /* Mem32 */ 3231 len = snprintf(buf, sz, "m%x,%x,%x,%x", p->dev, p->fn, p->reg, 3232 p->phys_lo); 3233 break; 3234 case 3: /* Mem64 */ 3235 len = snprintf(buf, sz, "x%x,%x,%x,%x%08x", p->dev, p->fn, 3236 p->reg, p->phys_hi, p->phys_lo); 3237 break; 3238 } 3239 return ((len >= sz) ? -1 : 0); 3240 } 3241 3242 /* 3243 * Get #address-cells property value 3244 */ 3245 static uint_t 3246 get_addrcells_prop(picl_nodehdl_t nodeh) 3247 { 3248 int len, err; 3249 uint32_t addrcells; 3250 ptree_propinfo_t pinfo; 3251 picl_prophdl_t proph; 3252 3253 /* 3254 * Get #address-cells property. If not present, use default value. 3255 */ 3256 err = ptree_get_prop_by_name(nodeh, OBP_PROP_ADDRESS_CELLS, &proph); 3257 if (err == PICL_SUCCESS) 3258 err = ptree_get_propinfo(proph, &pinfo); 3259 3260 len = pinfo.piclinfo.size; 3261 if (err == PICL_SUCCESS && len >= sizeof (uint8_t) && 3262 len <= sizeof (addrcells)) { 3263 err = ptree_get_propval(proph, &addrcells, len); 3264 if (err == PICL_SUCCESS) { 3265 if (len == sizeof (uint8_t)) 3266 addrcells = *(uint8_t *)&addrcells; 3267 else if (len == sizeof (uint16_t)) 3268 addrcells = *(uint16_t *)&addrcells; 3269 } else 3270 addrcells = DEFAULT_ADDRESS_CELLS; 3271 } else 3272 addrcells = DEFAULT_ADDRESS_CELLS; 3273 3274 return (addrcells); 3275 } 3276 3277 /* 3278 * Get UnitAddress mapping entry for a node 3279 */ 3280 static unitaddr_map_t * 3281 get_unitaddr_mapping(picl_nodehdl_t nodeh) 3282 { 3283 int err; 3284 unitaddr_map_t *uamap; 3285 char clname[PICL_CLASSNAMELEN_MAX]; 3286 3287 /* 3288 * Get my classname and locate a function to translate "reg" prop 3289 * into "UnitAddress" prop for my children. 3290 */ 3291 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, clname, 3292 sizeof (clname)); 3293 if (err != PICL_SUCCESS) 3294 (void) strcpy(clname, ""); /* NULL class name */ 3295 3296 for (uamap = &unitaddr_map_table[0]; uamap->class != NULL; uamap++) 3297 if (strcmp(clname, uamap->class) == 0) 3298 break; 3299 3300 return (uamap); 3301 } 3302 3303 /* 3304 * Add UnitAddress property to the specified node 3305 */ 3306 static int 3307 add_unitaddr_prop(picl_nodehdl_t nodeh, unitaddr_map_t *uamap, uint_t addrcells) 3308 { 3309 int regproplen, err; 3310 uint32_t *regbuf; 3311 picl_prophdl_t regh; 3312 ptree_propinfo_t pinfo; 3313 char unitaddr[MAX_UNIT_ADDRESS_LEN]; 3314 3315 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 3316 if (err != PICL_SUCCESS) 3317 return (err); 3318 3319 err = ptree_get_propinfo(regh, &pinfo); 3320 if (err != PICL_SUCCESS) 3321 return (PICL_FAILURE); 3322 3323 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t))) 3324 return (PICL_FAILURE); 3325 3326 regproplen = pinfo.piclinfo.size; 3327 regbuf = alloca(regproplen); 3328 if (regbuf == NULL) 3329 return (PICL_FAILURE); 3330 3331 err = ptree_get_propval(regh, regbuf, regproplen); 3332 if (err != PICL_SUCCESS || uamap->func == NULL || 3333 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) || 3334 (uamap->func)(unitaddr, sizeof (unitaddr), regbuf, 3335 addrcells) != 0) { 3336 return (PICL_FAILURE); 3337 } 3338 3339 err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3340 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(unitaddr)+1, 3341 PICL_PROP_UNIT_ADDRESS, NULL, NULL); 3342 if (err == PICL_SUCCESS) 3343 err = ptree_create_and_add_prop(nodeh, &pinfo, unitaddr, NULL); 3344 3345 return (err); 3346 } 3347 3348 /* 3349 * work out UnitAddress property of the specified node 3350 */ 3351 static int 3352 get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, char *unitaddr, 3353 size_t ualen) 3354 { 3355 int regproplen, err; 3356 uint32_t *regbuf; 3357 picl_prophdl_t regh; 3358 ptree_propinfo_t pinfo; 3359 unitaddr_map_t *uamap; 3360 uint32_t addrcells; 3361 3362 addrcells = get_addrcells_prop(parh); 3363 uamap = get_unitaddr_mapping(parh); 3364 3365 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 3366 if (err != PICL_SUCCESS) 3367 return (err); 3368 3369 err = ptree_get_propinfo(regh, &pinfo); 3370 if (err != PICL_SUCCESS) 3371 return (err); 3372 3373 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t))) 3374 return (PICL_FAILURE); 3375 3376 regproplen = pinfo.piclinfo.size; 3377 regbuf = alloca(regproplen); 3378 if (regbuf == NULL) 3379 return (PICL_FAILURE); 3380 3381 err = ptree_get_propval(regh, regbuf, regproplen); 3382 if (err != PICL_SUCCESS || uamap->func == NULL || 3383 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) || 3384 (uamap->func)(unitaddr, ualen, regbuf, addrcells) != 0) { 3385 return (PICL_FAILURE); 3386 } 3387 return (PICL_SUCCESS); 3388 } 3389 3390 /* 3391 * Add UnitAddress property to all children of the specified node 3392 */ 3393 static int 3394 add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh) 3395 { 3396 int err; 3397 picl_nodehdl_t chdh; 3398 unitaddr_map_t *uamap; 3399 uint32_t addrcells; 3400 3401 /* 3402 * Get #address-cells and unit address mapping entry for my 3403 * node's class 3404 */ 3405 addrcells = get_addrcells_prop(nodeh); 3406 uamap = get_unitaddr_mapping(nodeh); 3407 3408 /* 3409 * Add UnitAddress property to my children and their subtree 3410 */ 3411 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 3412 sizeof (picl_nodehdl_t)); 3413 3414 while (err == PICL_SUCCESS) { 3415 (void) add_unitaddr_prop(chdh, uamap, addrcells); 3416 (void) add_unitaddr_prop_to_subtree(chdh); 3417 3418 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 3419 sizeof (picl_nodehdl_t)); 3420 } 3421 3422 return (PICL_SUCCESS); 3423 } 3424 3425 static int 3426 update_memory_size_prop(picl_nodehdl_t plafh) 3427 { 3428 picl_nodehdl_t memh; 3429 picl_prophdl_t proph; 3430 ptree_propinfo_t pinfo; 3431 int err, nspecs, snum, pval; 3432 char *regbuf; 3433 memspecs_t *mspecs; 3434 uint64_t memsize; 3435 3436 /* 3437 * check if the #size-cells of the platform node is 2 3438 */ 3439 err = ptree_get_propval_by_name(plafh, OBP_PROP_SIZE_CELLS, &pval, 3440 sizeof (pval)); 3441 3442 if (err == PICL_PROPNOTFOUND) 3443 pval = SUPPORTED_NUM_CELL_SIZE; 3444 else if (err != PICL_SUCCESS) 3445 return (err); 3446 3447 /* 3448 * don't know how to handle other vals 3449 */ 3450 if (pval != SUPPORTED_NUM_CELL_SIZE) 3451 return (PICL_FAILURE); 3452 3453 err = ptree_get_node_by_path(MEMORY_PATH, &memh); 3454 if (err != PICL_SUCCESS) 3455 return (err); 3456 3457 /* 3458 * Get the REG property to calculate the size of memory 3459 */ 3460 err = ptree_get_prop_by_name(memh, OBP_REG, &proph); 3461 if (err != PICL_SUCCESS) 3462 return (err); 3463 3464 err = ptree_get_propinfo(proph, &pinfo); 3465 if (err != PICL_SUCCESS) 3466 return (err); 3467 3468 regbuf = alloca(pinfo.piclinfo.size); 3469 if (regbuf == NULL) 3470 return (PICL_FAILURE); 3471 3472 err = ptree_get_propval(proph, regbuf, pinfo.piclinfo.size); 3473 if (err != PICL_SUCCESS) 3474 return (err); 3475 3476 mspecs = (memspecs_t *)regbuf; 3477 nspecs = pinfo.piclinfo.size / sizeof (memspecs_t); 3478 3479 memsize = 0; 3480 for (snum = 0; snum < nspecs; ++snum) 3481 memsize += mspecs[snum].size; 3482 3483 err = ptree_get_prop_by_name(memh, PICL_PROP_SIZE, &proph); 3484 if (err == PICL_SUCCESS) { 3485 err = ptree_update_propval(proph, &memsize, sizeof (memsize)); 3486 return (err); 3487 } 3488 3489 /* 3490 * Add the size property 3491 */ 3492 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3493 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (memsize), 3494 PICL_PROP_SIZE, NULL, NULL); 3495 err = ptree_create_and_add_prop(memh, &pinfo, &memsize, NULL); 3496 return (err); 3497 } 3498 3499 /* 3500 * This function is executed as part of .init when the plugin is 3501 * dlopen()ed 3502 */ 3503 static void 3504 picldevtree_register(void) 3505 { 3506 if (getenv(SUNW_PICLDEVTREE_PLUGIN_DEBUG)) 3507 picldevtree_debug = 1; 3508 (void) picld_plugin_register(&my_reg_info); 3509 } 3510 3511 /* 3512 * This function is the init entry point of the plugin. 3513 * It initializes the /platform tree based on libdevinfo 3514 */ 3515 static void 3516 picldevtree_init(void) 3517 { 3518 picl_nodehdl_t rhdl; 3519 int err; 3520 struct utsname utsname; 3521 picl_nodehdl_t plafh; 3522 3523 if (uname(&utsname) < 0) 3524 return; 3525 3526 (void) strcpy(mach_name, utsname.machine); 3527 3528 if (strcmp(mach_name, "sun4u") == 0) { 3529 builtin_map_ptr = sun4u_map; 3530 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t); 3531 } else if (strcmp(mach_name, "sun4v") == 0) { 3532 builtin_map_ptr = sun4u_map; 3533 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t); 3534 } else if (strcmp(mach_name, "i86pc") == 0) { 3535 builtin_map_ptr = i86pc_map; 3536 builtin_map_size = sizeof (i86pc_map) / sizeof (builtin_map_t); 3537 } else { 3538 builtin_map_ptr = NULL; 3539 builtin_map_size = 0; 3540 } 3541 3542 err = ptree_get_root(&rhdl); 3543 if (err != PICL_SUCCESS) { 3544 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED); 3545 return; 3546 } 3547 3548 process_devtree_conf_file(); 3549 3550 if (libdevinfo_init(rhdl) != PICL_SUCCESS) { 3551 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED); 3552 return; 3553 } 3554 3555 err = ptree_get_node_by_path(PLATFORM_PATH, &plafh); 3556 if (err != PICL_SUCCESS) 3557 return; 3558 3559 (void) add_unitaddr_prop_to_subtree(plafh); 3560 3561 add_asr_nodes(); 3562 3563 (void) update_memory_size_prop(plafh); 3564 3565 (void) setup_cpus(plafh); 3566 3567 (void) add_ffb_config_info(plafh); 3568 3569 (void) add_platform_info(plafh); 3570 3571 set_pci_pciex_deviceid(plafh); 3572 3573 (void) set_sbus_slot(plafh); 3574 3575 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 3576 picldevtree_evhandler, NULL); 3577 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 3578 picldevtree_evhandler, NULL); 3579 (void) ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE, 3580 picldevtree_evhandler, NULL); 3581 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE, 3582 picldevtree_evhandler, NULL); 3583 } 3584 3585 /* 3586 * This function is the fini entry point of the plugin 3587 */ 3588 static void 3589 picldevtree_fini(void) 3590 { 3591 /* First unregister the event handlers */ 3592 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 3593 picldevtree_evhandler, NULL); 3594 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 3595 picldevtree_evhandler, NULL); 3596 (void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE, 3597 picldevtree_evhandler, NULL); 3598 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE, 3599 picldevtree_evhandler, NULL); 3600 3601 conf_name_class_map = free_conf_entries(conf_name_class_map); 3602 } 3603 3604 /* 3605 * This function is the event handler of this plug-in. 3606 * 3607 * It processes the following events: 3608 * 3609 * PICLEVENT_SYSEVENT_DEVICE_ADDED 3610 * PICLEVENT_SYSEVENT_DEVICE_REMOVED 3611 * PICLEVENT_CPU_STATE_CHANGE 3612 * PICLEVENT_DR_AP_STATE_CHANGE 3613 */ 3614 /* ARGSUSED */ 3615 static void 3616 picldevtree_evhandler(const char *ename, const void *earg, size_t size, 3617 void *cookie) 3618 { 3619 char *devfs_path; 3620 char ptreepath[PATH_MAX]; 3621 char dipath[PATH_MAX]; 3622 picl_nodehdl_t plafh; 3623 picl_nodehdl_t nodeh; 3624 nvlist_t *nvlp; 3625 3626 if ((earg == NULL) || 3627 (ptree_get_node_by_path(PLATFORM_PATH, &plafh) != PICL_SUCCESS)) 3628 return; 3629 3630 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) == 0) { 3631 (void) setup_cpus(plafh); 3632 if (picldevtree_debug > 1) 3633 syslog(LOG_INFO, "picldevtree: event handler done\n"); 3634 return; 3635 } 3636 3637 nvlp = NULL; 3638 if (nvlist_unpack((char *)earg, size, &nvlp, 0) || 3639 nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &devfs_path) || 3640 strlen(devfs_path) > (PATH_MAX - sizeof (PLATFORM_PATH))) { 3641 syslog(LOG_INFO, PICL_EVENT_DROPPED, ename); 3642 nvlist_free(nvlp); 3643 return; 3644 } 3645 3646 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX); 3647 (void) strlcat(ptreepath, devfs_path, PATH_MAX); 3648 (void) strlcpy(dipath, devfs_path, PATH_MAX); 3649 nvlist_free(nvlp); 3650 3651 if (picldevtree_debug) 3652 syslog(LOG_INFO, "picldevtree: event handler invoked ename:%s " 3653 "ptreepath:%s\n", ename, ptreepath); 3654 3655 if (strcmp(ename, PICLEVENT_CPU_STATE_CHANGE) == 0) { 3656 goto done; 3657 } 3658 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) { 3659 di_node_t devnode; 3660 char *strp; 3661 picl_nodehdl_t parh; 3662 char nodeclass[PICL_CLASSNAMELEN_MAX]; 3663 char *nodename; 3664 int err; 3665 3666 /* If the node already exist, then nothing else to do here */ 3667 if (ptree_get_node_by_path(ptreepath, &nodeh) == PICL_SUCCESS) 3668 return; 3669 3670 /* Skip if unable to find parent PICL node handle */ 3671 parh = plafh; 3672 if (((strp = strrchr(ptreepath, '/')) != NULL) && 3673 (strp != strchr(ptreepath, '/'))) { 3674 *strp = '\0'; 3675 if (ptree_get_node_by_path(ptreepath, &parh) != 3676 PICL_SUCCESS) 3677 return; 3678 } 3679 3680 /* 3681 * If parent is the root node 3682 */ 3683 if (parh == plafh) { 3684 ph = di_prom_init(); 3685 devnode = di_init(dipath, DINFOCPYALL); 3686 if (devnode == DI_NODE_NIL) { 3687 if (ph != NULL) { 3688 di_prom_fini(ph); 3689 ph = NULL; 3690 } 3691 return; 3692 } 3693 nodename = di_node_name(devnode); 3694 if (nodename == NULL) { 3695 di_fini(devnode); 3696 if (ph != NULL) { 3697 di_prom_fini(ph); 3698 ph = NULL; 3699 } 3700 return; 3701 } 3702 3703 err = get_node_class(nodeclass, devnode, nodename); 3704 if (err < 0) { 3705 di_fini(devnode); 3706 if (ph != NULL) { 3707 di_prom_fini(ph); 3708 ph = NULL; 3709 } 3710 return; 3711 } 3712 err = construct_devtype_node(plafh, nodename, 3713 nodeclass, devnode, &nodeh); 3714 if (err != PICL_SUCCESS) { 3715 di_fini(devnode); 3716 if (ph != NULL) { 3717 di_prom_fini(ph); 3718 ph = NULL; 3719 } 3720 return; 3721 } 3722 (void) update_subtree(nodeh, devnode); 3723 (void) add_unitaddr_prop_to_subtree(nodeh); 3724 if (ph != NULL) { 3725 di_prom_fini(ph); 3726 ph = NULL; 3727 } 3728 di_fini(devnode); 3729 goto done; 3730 } 3731 3732 /* kludge ... try without bus-addr first */ 3733 if ((strp = strrchr(dipath, '@')) != NULL) { 3734 char *p; 3735 3736 p = strrchr(dipath, '/'); 3737 if (p != NULL && strp > p) { 3738 *strp = '\0'; 3739 devnode = di_init(dipath, DINFOCPYALL); 3740 if (devnode != DI_NODE_NIL) 3741 di_fini(devnode); 3742 *strp = '@'; 3743 } 3744 } 3745 /* Get parent devnode */ 3746 if ((strp = strrchr(dipath, '/')) != NULL) 3747 *++strp = '\0'; 3748 devnode = di_init(dipath, DINFOCPYALL); 3749 if (devnode == DI_NODE_NIL) 3750 return; 3751 ph = di_prom_init(); 3752 (void) update_subtree(parh, devnode); 3753 (void) add_unitaddr_prop_to_subtree(parh); 3754 if (ph) { 3755 di_prom_fini(ph); 3756 ph = NULL; 3757 } 3758 di_fini(devnode); 3759 } else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) { 3760 char delclass[PICL_CLASSNAMELEN_MAX]; 3761 char *strp; 3762 3763 /* 3764 * if final element of path doesn't have a unit address 3765 * then it is not uniquely identifiable - cannot remove 3766 */ 3767 if (((strp = strrchr(ptreepath, '/')) != NULL) && 3768 strchr(strp, '@') == NULL) 3769 return; 3770 3771 /* skip if can't find the node */ 3772 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS) 3773 return; 3774 3775 if (ptree_delete_node(nodeh) != PICL_SUCCESS) 3776 return; 3777 3778 if (picldevtree_debug) 3779 syslog(LOG_INFO, 3780 "picldevtree: deleted node nodeh:%llx\n", nodeh); 3781 if ((ptree_get_propval_by_name(nodeh, 3782 PICL_PROP_CLASSNAME, delclass, PICL_CLASSNAMELEN_MAX) == 3783 PICL_SUCCESS) && IS_MC(delclass)) { 3784 if (post_mc_event(PICLEVENT_MC_REMOVED, nodeh) != 3785 PICL_SUCCESS) 3786 syslog(LOG_WARNING, PICL_EVENT_DROPPED, 3787 PICLEVENT_MC_REMOVED); 3788 } else 3789 (void) ptree_destroy_node(nodeh); 3790 } 3791 done: 3792 (void) setup_cpus(plafh); 3793 (void) add_ffb_config_info(plafh); 3794 set_pci_pciex_deviceid(plafh); 3795 (void) set_sbus_slot(plafh); 3796 if (picldevtree_debug > 1) 3797 syslog(LOG_INFO, "picldevtree: event handler done\n"); 3798 } 3799