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