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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * PICL plug-in that creates device tree nodes for all platforms 31 */ 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <ctype.h> 36 #include <limits.h> 37 #include <stdlib.h> 38 #include <assert.h> 39 #include <alloca.h> 40 #include <unistd.h> 41 #include <stropts.h> 42 #include <syslog.h> 43 #include <libdevinfo.h> 44 #include <sys/dkio.h> 45 #include <sys/vtoc.h> 46 #include <sys/time.h> 47 #include <fcntl.h> 48 #include <picl.h> 49 #include <picltree.h> 50 #include <sys/types.h> 51 #include <sys/processor.h> 52 #include <kstat.h> 53 #include <sys/sysinfo.h> 54 #include <dirent.h> 55 #include <libintl.h> 56 #include <pthread.h> 57 #include <libnvpair.h> 58 #include <sys/utsname.h> 59 #include <sys/systeminfo.h> 60 #include <sys/obpdefs.h> 61 #include <sys/openpromio.h> 62 #include "picldevtree.h" 63 64 /* 65 * Plugin registration entry points 66 */ 67 static void picldevtree_register(void); 68 static void picldevtree_init(void); 69 static void picldevtree_fini(void); 70 71 static void picldevtree_evhandler(const char *ename, const void *earg, 72 size_t size, void *cookie); 73 74 #pragma init(picldevtree_register) 75 76 /* 77 * Log message texts 78 */ 79 #define DEVINFO_PLUGIN_INIT_FAILED gettext("SUNW_picldevtree failed!\n") 80 #define PICL_EVENT_DROPPED \ 81 gettext("SUNW_picldevtree '%s' event dropped.\n") 82 83 /* 84 * Macro to get PCI device id (from IEEE 1275 spec) 85 */ 86 #define PCI_DEVICE_ID(x) (((x) >> 11) & 0x1f) 87 /* 88 * Local variables 89 */ 90 static picld_plugin_reg_t my_reg_info = { 91 PICLD_PLUGIN_VERSION_1, 92 PICLD_PLUGIN_CRITICAL, 93 "SUNW_picldevtree", 94 picldevtree_init, 95 picldevtree_fini 96 }; 97 98 /* 99 * Debug enabling environment variable 100 */ 101 #define SUNW_PICLDEVTREE_PLUGIN_DEBUG "SUNW_PICLDEVTREE_PLUGIN_DEBUG" 102 static int picldevtree_debug = 0; 103 104 static conf_entries_t *conf_name_class_map = NULL; 105 static builtin_map_t sun4u_map[] = { 106 /* MAX_NAMEVAL_SIZE */ 107 { "SUNW,bpp", PICL_CLASS_PARALLEL}, 108 { "parallel", PICL_CLASS_PARALLEL}, 109 { "floppy", PICL_CLASS_FLOPPY}, 110 { "memory", PICL_CLASS_MEMORY}, 111 { "ebus", PICL_CLASS_EBUS}, 112 { "i2c", PICL_CLASS_I2C}, 113 { "usb", PICL_CLASS_USB}, 114 { "isa", PICL_CLASS_ISA}, 115 { "dma", PICL_CLASS_DMA}, 116 { "keyboard", PICL_CLASS_KEYBOARD}, 117 { "mouse", PICL_CLASS_MOUSE}, 118 { "fan-control", PICL_CLASS_FAN_CONTROL}, 119 { "sc", PICL_CLASS_SYSTEM_CONTROLLER}, 120 { "dimm", PICL_CLASS_SEEPROM}, 121 { "dimm-fru", PICL_CLASS_SEEPROM}, 122 { "cpu", PICL_CLASS_SEEPROM}, 123 { "cpu-fru", PICL_CLASS_SEEPROM}, 124 { "flashprom", PICL_CLASS_FLASHPROM}, 125 { "temperature", PICL_CLASS_TEMPERATURE_DEVICE}, 126 { "motherboard", PICL_CLASS_SEEPROM}, 127 { "motherboard-fru", PICL_CLASS_SEEPROM}, 128 { "motherboard-fru-prom", PICL_CLASS_SEEPROM}, 129 { "pmu", PICL_CLASS_PMU}, 130 { "sound", PICL_CLASS_SOUND}, 131 { "firewire", PICL_CLASS_FIREWIRE}, 132 { "i2c-at34c02", PICL_CLASS_SEEPROM}, 133 { "hardware-monitor", PICL_CLASS_HARDWARE_MONITOR}, 134 { "", ""} 135 }; 136 static builtin_map_t i86pc_map[] = { 137 /* MAX_NAMEVAL_SIZE */ 138 { "cpus", PICL_CLASS_I86CPUS}, 139 { "cpu", PICL_CLASS_CPU}, 140 { "memory", PICL_CLASS_MEMORY}, 141 { "asy", PICL_CLASS_SERIAL}, 142 { "", ""} 143 }; 144 static pname_type_map_t pname_type_map[] = { 145 { "reg", PICL_PTYPE_BYTEARRAY}, 146 { "device_type", PICL_PTYPE_CHARSTRING}, 147 { "ranges", PICL_PTYPE_BYTEARRAY}, 148 { "status", PICL_PTYPE_CHARSTRING}, 149 { "compatible", PICL_PTYPE_CHARSTRING}, 150 { "interrupts", PICL_PTYPE_BYTEARRAY}, 151 { "model", PICL_PTYPE_CHARSTRING}, 152 { "address", PICL_PTYPE_BYTEARRAY}, 153 { "vendor-id", PICL_PTYPE_UNSIGNED_INT}, 154 { "device-id", PICL_PTYPE_UNSIGNED_INT}, 155 { "revision-id", PICL_PTYPE_UNSIGNED_INT}, 156 { "class-code", PICL_PTYPE_UNSIGNED_INT}, 157 { "min-grant", PICL_PTYPE_UNSIGNED_INT}, 158 { "max-latency", PICL_PTYPE_UNSIGNED_INT}, 159 { "devsel-speed", PICL_PTYPE_UNSIGNED_INT}, 160 { "subsystem-id", PICL_PTYPE_UNSIGNED_INT}, 161 { "subsystem-vendor-id", PICL_PTYPE_UNSIGNED_INT}, 162 { "assigned-addresses", PICL_PTYPE_BYTEARRAY}, 163 { "configuration#", PICL_PTYPE_UNSIGNED_INT}, 164 { "assigned-address", PICL_PTYPE_UNSIGNED_INT}, 165 { "#address-cells", PICL_PTYPE_UNSIGNED_INT}, 166 { "#size-cells", PICL_PTYPE_UNSIGNED_INT}, 167 { "clock-frequency", PICL_PTYPE_UNSIGNED_INT}, 168 { "scsi-initiator-id", PICL_PTYPE_UNSIGNED_INT}, 169 { "differential", PICL_PTYPE_UNSIGNED_INT}, 170 { "idprom", PICL_PTYPE_BYTEARRAY}, 171 { "bus-range", PICL_PTYPE_BYTEARRAY}, 172 { "alternate-reg", PICL_PTYPE_BYTEARRAY}, 173 { "power-consumption", PICL_PTYPE_BYTEARRAY}, 174 { "slot-names", PICL_PTYPE_BYTEARRAY}, 175 { "burst-sizes", PICL_PTYPE_UNSIGNED_INT}, 176 { "up-burst-sizes", PICL_PTYPE_UNSIGNED_INT}, 177 { "slot-address-bits", PICL_PTYPE_UNSIGNED_INT}, 178 { "eisa-slots", PICL_PTYPE_BYTEARRAY}, 179 { "dma", PICL_PTYPE_BYTEARRAY}, 180 { "slot-names-index", PICL_PTYPE_UNSIGNED_INT}, 181 { "pnp-csn", PICL_PTYPE_UNSIGNED_INT}, 182 { "pnp-data", PICL_PTYPE_BYTEARRAY}, 183 { "description", PICL_PTYPE_CHARSTRING}, 184 { "pnp-id", PICL_PTYPE_CHARSTRING}, 185 { "max-frame-size", PICL_PTYPE_UNSIGNED_INT}, 186 { "address-bits", PICL_PTYPE_UNSIGNED_INT}, 187 { "local-mac-address", PICL_PTYPE_BYTEARRAY}, 188 { "mac-address", PICL_PTYPE_BYTEARRAY}, 189 { "character-set", PICL_PTYPE_CHARSTRING}, 190 { "available", PICL_PTYPE_BYTEARRAY}, 191 { "port-wwn", PICL_PTYPE_BYTEARRAY}, 192 { "node-wwn", PICL_PTYPE_BYTEARRAY}, 193 { "width", PICL_PTYPE_UNSIGNED_INT}, 194 { "linebytes", PICL_PTYPE_UNSIGNED_INT}, 195 { "height", PICL_PTYPE_UNSIGNED_INT}, 196 { "banner-name", PICL_PTYPE_CHARSTRING}, 197 { "reset-reason", PICL_PTYPE_CHARSTRING}, 198 { "implementation#", PICL_PTYPE_UNSIGNED_INT}, 199 { "version#", PICL_PTYPE_UNSIGNED_INT}, 200 { "icache-size", PICL_PTYPE_UNSIGNED_INT}, 201 { "icache-line-size", PICL_PTYPE_UNSIGNED_INT}, 202 { "icache-associativity", PICL_PTYPE_UNSIGNED_INT}, 203 { "l1-icache-size", PICL_PTYPE_UNSIGNED_INT}, 204 { "l1-icache-line-size", PICL_PTYPE_UNSIGNED_INT}, 205 { "l1-icache-associativity", PICL_PTYPE_UNSIGNED_INT}, 206 { "#itlb-entries", PICL_PTYPE_UNSIGNED_INT}, 207 { "dcache-size", PICL_PTYPE_UNSIGNED_INT}, 208 { "dcache-line-size", PICL_PTYPE_UNSIGNED_INT}, 209 { "dcache-associativity", PICL_PTYPE_UNSIGNED_INT}, 210 { "l1-dcache-size", PICL_PTYPE_UNSIGNED_INT}, 211 { "l1-dcache-line-size", PICL_PTYPE_UNSIGNED_INT}, 212 { "l1-dcache-associativity", PICL_PTYPE_UNSIGNED_INT}, 213 { "#dtlb-entries", PICL_PTYPE_UNSIGNED_INT}, 214 { "ecache-size", PICL_PTYPE_UNSIGNED_INT}, 215 { "ecache-line-size", PICL_PTYPE_UNSIGNED_INT}, 216 { "ecache-associativity", PICL_PTYPE_UNSIGNED_INT}, 217 { "l2-cache-size", PICL_PTYPE_UNSIGNED_INT}, 218 { "l2-cache-line-size", PICL_PTYPE_UNSIGNED_INT}, 219 { "l2-cache-associativity", PICL_PTYPE_UNSIGNED_INT}, 220 { "l2-cache-sharing", PICL_PTYPE_BYTEARRAY}, 221 { "mask#", PICL_PTYPE_UNSIGNED_INT}, 222 { "manufacturer#", PICL_PTYPE_UNSIGNED_INT}, 223 { "sparc-version", PICL_PTYPE_UNSIGNED_INT}, 224 { "version", PICL_PTYPE_CHARSTRING}, 225 { "cpu-model", PICL_PTYPE_UNSIGNED_INT}, 226 { "memory-layout", PICL_PTYPE_BYTEARRAY}, 227 { "#interrupt-cells", PICL_PTYPE_UNSIGNED_INT}, 228 { "interrupt-map", PICL_PTYPE_BYTEARRAY}, 229 { "interrupt-map-mask", PICL_PTYPE_BYTEARRAY} 230 }; 231 232 #define PNAME_MAP_SIZE sizeof (pname_type_map) / sizeof (pname_type_map_t) 233 234 static builtin_map_t *builtin_map_ptr = NULL; 235 static int builtin_map_size = 0; 236 static char mach_name[SYS_NMLN]; 237 static di_prom_handle_t ph = DI_PROM_HANDLE_NIL; 238 239 /* 240 * UnitAddress mapping table 241 */ 242 static unitaddr_func_t encode_default_unitaddr; 243 static unitaddr_func_t encode_optional_unitaddr; 244 static unitaddr_func_t encode_scsi_unitaddr; 245 static unitaddr_func_t encode_upa_unitaddr; 246 static unitaddr_func_t encode_gptwo_jbus_unitaddr; 247 static unitaddr_func_t encode_pci_unitaddr; 248 249 static unitaddr_map_t unitaddr_map_table[] = { 250 {PICL_CLASS_JBUS, encode_gptwo_jbus_unitaddr, 0}, 251 {PICL_CLASS_GPTWO, encode_gptwo_jbus_unitaddr, 0}, 252 {PICL_CLASS_PCI, 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 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 /* 969 * Add properties provided by libdevinfo 970 */ 971 static void 972 add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node) 973 { 974 int instance; 975 char *di_val; 976 di_prop_t di_prop; 977 int di_ptype; 978 ptree_propinfo_t propinfo; 979 980 instance = di_instance(di_node); 981 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 982 PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE, 983 NULL, NULL); 984 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL); 985 986 di_val = di_bus_addr(di_node); 987 if (di_val) { 988 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 989 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 990 PICL_PROP_BUS_ADDR, NULL, NULL); 991 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 992 NULL); 993 } 994 995 di_val = di_binding_name(di_node); 996 if (di_val) { 997 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 998 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 999 PICL_PROP_BINDING_NAME, NULL, NULL); 1000 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1001 NULL); 1002 } 1003 1004 di_val = di_driver_name(di_node); 1005 if (di_val) { 1006 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1007 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1008 PICL_PROP_DRIVER_NAME, NULL, NULL); 1009 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1010 NULL); 1011 } 1012 1013 di_val = di_devfs_path(di_node); 1014 if (di_val) { 1015 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1016 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1017 PICL_PROP_DEVFS_PATH, NULL, NULL); 1018 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1019 NULL); 1020 di_devfs_path_free(di_val); 1021 } 1022 1023 for (di_prop = di_prop_next(di_node, DI_PROP_NIL); 1024 di_prop != DI_PROP_NIL; 1025 di_prop = di_prop_next(di_node, di_prop)) { 1026 1027 di_val = di_prop_name(di_prop); 1028 di_ptype = di_prop_type(di_prop); 1029 switch (di_ptype) { 1030 case DI_PROP_TYPE_BOOLEAN: 1031 (void) ptree_init_propinfo(&propinfo, 1032 PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID, 1033 PICL_READ, (size_t)0, di_val, NULL, NULL); 1034 (void) ptree_create_and_add_prop(nodeh, &propinfo, 1035 NULL, NULL); 1036 break; 1037 case DI_PROP_TYPE_INT: { 1038 int *idata; 1039 int len; 1040 1041 len = di_prop_ints(di_prop, &idata); 1042 if (len < 0) 1043 /* Recieved error, so ignore prop */ 1044 break; 1045 1046 if (len == 1) 1047 (void) ptree_init_propinfo(&propinfo, 1048 PTREE_PROPINFO_VERSION, PICL_PTYPE_INT, 1049 PICL_READ, len * sizeof (int), di_val, 1050 NULL, NULL); 1051 else 1052 (void) ptree_init_propinfo(&propinfo, 1053 PTREE_PROPINFO_VERSION, 1054 PICL_PTYPE_BYTEARRAY, PICL_READ, 1055 len * sizeof (int), di_val, 1056 NULL, NULL); 1057 1058 (void) ptree_create_and_add_prop(nodeh, &propinfo, 1059 idata, NULL); 1060 } 1061 break; 1062 case DI_PROP_TYPE_STRING: { 1063 char *sdata; 1064 int len; 1065 1066 len = di_prop_strings(di_prop, &sdata); 1067 if (len < 0) 1068 break; 1069 1070 if (len == 1) { 1071 (void) ptree_init_propinfo(&propinfo, 1072 PTREE_PROPINFO_VERSION, 1073 PICL_PTYPE_CHARSTRING, PICL_READ, 1074 strlen(sdata) + 1, di_val, 1075 NULL, NULL); 1076 (void) ptree_create_and_add_prop(nodeh, 1077 &propinfo, sdata, NULL); 1078 } else { 1079 (void) add_string_list_prop(nodeh, di_val, 1080 sdata, len); 1081 } 1082 } 1083 break; 1084 case DI_PROP_TYPE_BYTE: { 1085 int len; 1086 unsigned char *bdata; 1087 1088 len = di_prop_bytes(di_prop, &bdata); 1089 if (len < 0) 1090 break; 1091 (void) ptree_init_propinfo(&propinfo, 1092 PTREE_PROPINFO_VERSION, PICL_PTYPE_BYTEARRAY, 1093 PICL_READ, len, di_val, NULL, NULL); 1094 (void) ptree_create_and_add_prop(nodeh, &propinfo, 1095 bdata, NULL); 1096 } 1097 break; 1098 case DI_PROP_TYPE_UNKNOWN: 1099 break; 1100 case DI_PROP_TYPE_UNDEF_IT: 1101 break; 1102 default: 1103 break; 1104 } 1105 } 1106 } 1107 1108 /* 1109 * This function creates the /obp node in the PICL tree for OBP nodes 1110 * without a device type class. 1111 */ 1112 static int 1113 construct_picl_openprom(picl_nodehdl_t rooth, picl_nodehdl_t *obph) 1114 { 1115 picl_nodehdl_t tmph; 1116 int err; 1117 1118 err = ptree_create_and_add_node(rooth, PICL_NODE_OBP, 1119 PICL_CLASS_PICL, &tmph); 1120 1121 if (err != PICL_SUCCESS) 1122 return (err); 1123 *obph = tmph; 1124 return (PICL_SUCCESS); 1125 } 1126 1127 /* 1128 * This function creates the /platform node in the PICL tree and 1129 * its properties. It sets the "platform-name" property to the 1130 * platform name 1131 */ 1132 static int 1133 construct_picl_platform(picl_nodehdl_t rooth, di_node_t di_root, 1134 picl_nodehdl_t *piclh) 1135 { 1136 int err; 1137 picl_nodehdl_t plafh; 1138 char *nodename; 1139 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1140 ptree_propinfo_t propinfo; 1141 picl_prophdl_t proph; 1142 1143 nodename = di_node_name(di_root); 1144 if (nodename == NULL) 1145 return (PICL_FAILURE); 1146 1147 err = 0; 1148 if (di_nodeid(di_root) == DI_PROM_NODEID || 1149 di_nodeid(di_root) == DI_SID_NODEID) 1150 err = get_device_type(nodeclass, di_root); 1151 1152 if (err < 0) 1153 (void) strcpy(nodeclass, PICL_CLASS_UPA); /* default */ 1154 1155 err = ptree_create_and_add_node(rooth, PICL_NODE_PLATFORM, 1156 nodeclass, &plafh); 1157 if (err != PICL_SUCCESS) 1158 return (err); 1159 1160 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1161 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(nodename) + 1, 1162 PICL_PROP_PLATFORM_NAME, NULL, NULL); 1163 err = ptree_create_and_add_prop(plafh, &propinfo, nodename, &proph); 1164 if (err != PICL_SUCCESS) 1165 return (err); 1166 1167 (void) add_devinfo_props(plafh, di_root); 1168 1169 (void) add_openprom_props(plafh, di_root); 1170 1171 *piclh = plafh; 1172 1173 return (PICL_SUCCESS); 1174 } 1175 1176 /* 1177 * This function creates a node in /obp tree for the libdevinfo handle. 1178 */ 1179 static int 1180 construct_obp_node(picl_nodehdl_t parh, di_node_t dn, picl_nodehdl_t *chdh) 1181 { 1182 int err; 1183 char *nodename; 1184 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1185 picl_nodehdl_t anodeh; 1186 1187 nodename = di_node_name(dn); /* PICL_PROP_NAME */ 1188 if (nodename == NULL) 1189 return (PICL_FAILURE); 1190 1191 if (strcmp(nodename, "pseudo") == 0) 1192 return (PICL_FAILURE); 1193 1194 if ((di_nodeid(dn) == DI_PROM_NODEID) && 1195 (get_device_type(nodeclass, dn) == 0)) 1196 return (PICL_FAILURE); 1197 1198 err = ptree_create_and_add_node(parh, nodename, nodename, &anodeh); 1199 if (err != PICL_SUCCESS) 1200 return (err); 1201 1202 add_devinfo_props(anodeh, dn); 1203 1204 (void) add_openprom_props(anodeh, dn); 1205 1206 *chdh = anodeh; 1207 1208 return (PICL_SUCCESS); 1209 } 1210 1211 /* 1212 * This function creates a PICL node in /platform tree for a device 1213 */ 1214 static int 1215 construct_devtype_node(picl_nodehdl_t parh, char *nodename, 1216 char *nodeclass, di_node_t dn, picl_nodehdl_t *chdh) 1217 { 1218 int err; 1219 picl_nodehdl_t anodeh; 1220 1221 err = ptree_create_and_add_node(parh, nodename, nodeclass, &anodeh); 1222 if (err != PICL_SUCCESS) 1223 return (err); 1224 1225 (void) add_devinfo_props(anodeh, dn); 1226 (void) add_openprom_props(anodeh, dn); 1227 1228 *chdh = anodeh; 1229 return (err); 1230 } 1231 1232 /* 1233 * Create a subtree of "picl" class nodes in /obp for these nodes 1234 */ 1235 static int 1236 construct_openprom_tree(picl_nodehdl_t nodeh, di_node_t dinode) 1237 { 1238 di_node_t cnode; 1239 picl_nodehdl_t chdh; 1240 int err; 1241 1242 err = construct_obp_node(nodeh, dinode, &chdh); 1243 if (err != PICL_SUCCESS) 1244 return (err); 1245 1246 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1247 cnode = di_sibling_node(cnode)) 1248 (void) construct_openprom_tree(chdh, cnode); 1249 1250 return (PICL_SUCCESS); 1251 1252 } 1253 1254 /* 1255 * Process the libdevinfo device tree and create nodes in /platform or /obp 1256 * PICL tree. 1257 * 1258 * This routine traverses the immediate children of "dinode" device and 1259 * determines the node class for that child. If it finds a valid class 1260 * name, then it builds a PICL node under /platform subtree and calls itself 1261 * recursively to construct the subtree for that child node. Otherwise, if 1262 * the parent_class is NULL, then it constructs a node and subtree under /obp 1263 * subtree. 1264 * 1265 * Note that we skip the children nodes that don't have a valid class name 1266 * and the parent_class is non NULL to prevent creation of any placeholder 1267 * nodes (such as sd,...). 1268 */ 1269 static int 1270 construct_devinfo_tree(picl_nodehdl_t plafh, picl_nodehdl_t obph, 1271 di_node_t dinode, char *parent_class) 1272 { 1273 di_node_t cnode; 1274 picl_nodehdl_t chdh; 1275 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1276 char *nodename; 1277 int err; 1278 1279 err = PICL_SUCCESS; 1280 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1281 cnode = di_sibling_node(cnode)) { 1282 nodename = di_node_name(cnode); /* PICL_PROP_NAME */ 1283 if (nodename == NULL) 1284 continue; 1285 1286 err = get_node_class(nodeclass, cnode, nodename); 1287 1288 if (err == 0) { 1289 err = construct_devtype_node(plafh, nodename, 1290 nodeclass, cnode, &chdh); 1291 if (err != PICL_SUCCESS) 1292 return (err); 1293 err = construct_devinfo_tree(chdh, obph, cnode, 1294 nodeclass); 1295 } else if (parent_class == NULL) 1296 err = construct_openprom_tree(obph, cnode); 1297 else 1298 continue; 1299 /* 1300 * if parent_class is non NULL, skip the children nodes 1301 * that don't have a valid device class - eliminates 1302 * placeholder nodes (sd,...) from being created. 1303 */ 1304 } 1305 1306 return (err); 1307 1308 } 1309 1310 /* 1311 * This function is called from the event handler called from the daemon 1312 * on PICL events. 1313 * 1314 * This routine traverses the children of the "dinode" device and 1315 * creates a PICL node for each child not found in the PICL tree and 1316 * invokes itself recursively to create a subtree for the newly created 1317 * child node. It also checks if the node being created is a meory 1318 * controller. If so, it posts PICLEVENT_MC_ADDED PICL event to the PICL 1319 * framework. 1320 */ 1321 static int 1322 update_subtree(picl_nodehdl_t nodeh, di_node_t dinode) 1323 { 1324 di_node_t cnode; 1325 picl_nodehdl_t chdh; 1326 picl_nodehdl_t nh; 1327 char *nodename; 1328 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1329 char *path_buf; 1330 char buf[MAX_UNIT_ADDRESS_LEN]; 1331 char unitaddr[MAX_UNIT_ADDRESS_LEN]; 1332 char path_w_ua[MAXPATHLEN]; 1333 char path_wo_ua[MAXPATHLEN]; 1334 char *strp; 1335 int gotit; 1336 int err; 1337 1338 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1339 cnode = di_sibling_node(cnode)) { 1340 path_buf = di_devfs_path(cnode); 1341 if (path_buf == NULL) 1342 continue; 1343 1344 nodename = di_node_name(cnode); 1345 if (nodename == NULL) { 1346 di_devfs_path_free(path_buf); 1347 continue; 1348 } 1349 1350 err = get_node_class(nodeclass, cnode, nodename); 1351 1352 if (err < 0) { 1353 di_devfs_path_free(path_buf); 1354 continue; 1355 } 1356 1357 /* 1358 * this is quite complicated - both path_buf and any nodes 1359 * already in the picl tree may, or may not, have the 1360 * @<unit_addr> at the end of their names. So we must 1361 * take path_buf and work out what the device path would 1362 * be both with and without the unit_address, then search 1363 * the picl tree for both forms. 1364 */ 1365 if (((strp = strrchr(path_buf, '/')) != NULL) && 1366 strchr(strp, '@') == NULL) { 1367 /* 1368 * this is an unattached node - so the path is not 1369 * unique. Need to find out which node it is. 1370 * Find the unit_address from the obp properties. 1371 */ 1372 err = ptree_create_node(nodename, nodeclass, &chdh); 1373 if (err != PICL_SUCCESS) 1374 return (err); 1375 (void) add_openprom_props(chdh, cnode); 1376 err = get_unitaddr(nodeh, chdh, unitaddr, 1377 sizeof (unitaddr)); 1378 if (err != PICL_SUCCESS) 1379 return (err); 1380 (void) ptree_destroy_node(chdh); 1381 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s@%s", 1382 path_buf, unitaddr); 1383 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1384 path_buf); 1385 } else { 1386 /* 1387 * this is an attached node - so the path is unique 1388 */ 1389 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s", 1390 path_buf); 1391 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1392 path_buf); 1393 strp = strrchr(path_wo_ua, '@'); 1394 *strp++ = '\0'; 1395 (void) snprintf(unitaddr, sizeof (unitaddr), "%s", 1396 strp); 1397 } 1398 /* 1399 * first look for node with unit address in devfs_path 1400 */ 1401 if (ptree_find_node(nodeh, PICL_PROP_DEVFS_PATH, 1402 PICL_PTYPE_CHARSTRING, path_w_ua, strlen(path_w_ua) + 1, 1403 &nh) == PICL_SUCCESS) { 1404 /* 1405 * node already there - there's nothing we need to do 1406 */ 1407 if (picldevtree_debug > 1) 1408 syslog(LOG_INFO, 1409 "update_subtree: path:%s node exists\n", 1410 path_buf); 1411 di_devfs_path_free(path_buf); 1412 continue; 1413 } 1414 /* 1415 * now look for node without unit address in devfs_path. 1416 * This might be just one out of several 1417 * nodes - need to check all siblings 1418 */ 1419 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, 1420 &chdh, sizeof (chdh)); 1421 if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND)) 1422 return (err); 1423 gotit = 0; 1424 while (err == PICL_SUCCESS) { 1425 err = ptree_get_propval_by_name(chdh, 1426 PICL_PROP_DEVFS_PATH, buf, sizeof (buf)); 1427 if (err != PICL_SUCCESS) 1428 return (err); 1429 if (strcmp(buf, path_wo_ua) == 0) { 1430 err = ptree_get_propval_by_name(chdh, 1431 PICL_PROP_UNIT_ADDRESS, buf, sizeof (buf)); 1432 if (err != PICL_SUCCESS) 1433 return (err); 1434 if (strcmp(buf, unitaddr) == 0) { 1435 gotit = 1; 1436 break; 1437 } 1438 } 1439 err = ptree_get_propval_by_name(chdh, 1440 PICL_PROP_PEER, &chdh, sizeof (chdh)); 1441 if (err != PICL_SUCCESS) 1442 break; 1443 } 1444 if (gotit) { 1445 /* 1446 * node already there - there's nothing we need to do 1447 */ 1448 if (picldevtree_debug > 1) 1449 syslog(LOG_INFO, 1450 "update_subtree: path:%s node exists\n", 1451 path_buf); 1452 di_devfs_path_free(path_buf); 1453 continue; 1454 } 1455 1456 #define IS_MC(x) (strcmp(x, PICL_CLASS_MEMORY_CONTROLLER) == 0 ? 1 : 0) 1457 1458 if (construct_devtype_node(nodeh, nodename, nodeclass, cnode, 1459 &chdh) == PICL_SUCCESS) { 1460 if (picldevtree_debug) 1461 syslog(LOG_INFO, 1462 "picldevtree: added node:%s path:%s\n", 1463 nodename, path_buf); 1464 if (IS_MC(nodeclass)) { 1465 if (post_mc_event(PICLEVENT_MC_ADDED, chdh) != 1466 PICL_SUCCESS) 1467 syslog(LOG_WARNING, PICL_EVENT_DROPPED, 1468 PICLEVENT_MC_ADDED); 1469 } 1470 1471 di_devfs_path_free(path_buf); 1472 (void) update_subtree(chdh, cnode); 1473 } 1474 } 1475 1476 return (PICL_SUCCESS); 1477 1478 } 1479 1480 /* 1481 * This function processes the data from libdevinfo and creates nodes 1482 * in the PICL tree. 1483 */ 1484 static int 1485 libdevinfo_init(picl_nodehdl_t rooth) 1486 { 1487 di_node_t di_root; 1488 picl_nodehdl_t plafh; 1489 picl_nodehdl_t obph; 1490 int err; 1491 1492 1493 if ((di_root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) 1494 return (PICL_FAILURE); 1495 1496 if ((ph = di_prom_init()) == NULL) 1497 return (PICL_FAILURE); 1498 /* 1499 * create platform PICL node using di_root node 1500 */ 1501 err = construct_picl_platform(rooth, di_root, &plafh); 1502 if (err != PICL_SUCCESS) { 1503 di_fini(di_root); 1504 return (PICL_FAILURE); 1505 } 1506 1507 err = construct_picl_openprom(rooth, &obph); 1508 if (err != PICL_SUCCESS) { 1509 di_fini(di_root); 1510 return (PICL_FAILURE); 1511 } 1512 1513 (void) construct_devinfo_tree(plafh, obph, di_root, NULL); 1514 if (ph) { 1515 di_prom_fini(ph); 1516 ph = NULL; 1517 } 1518 di_fini(di_root); 1519 return (err); 1520 } 1521 1522 /* 1523 * This function returns the integer property value 1524 */ 1525 static int 1526 get_int_propval_by_name(picl_nodehdl_t nodeh, char *pname, int *ival) 1527 { 1528 int err; 1529 1530 err = ptree_get_propval_by_name(nodeh, pname, ival, 1531 sizeof (int)); 1532 1533 return (err); 1534 } 1535 1536 /* 1537 * This function returns the port ID (or CPU ID in the case of CMP cores) 1538 * of the specific CPU node handle. If upa_portid exists, return its value. 1539 * Otherwise, return portid/cpuid. 1540 */ 1541 static int 1542 get_cpu_portid(picl_nodehdl_t modh, int *id) 1543 { 1544 int err; 1545 1546 if (strcmp(mach_name, "sun4u") == 0) { 1547 err = get_int_propval_by_name(modh, OBP_PROP_UPA_PORTID, id); 1548 if (err == PICL_SUCCESS) 1549 return (err); 1550 err = get_int_propval_by_name(modh, OBP_PROP_PORTID, id); 1551 if (err == PICL_SUCCESS) 1552 return (err); 1553 return (get_int_propval_by_name(modh, OBP_PROP_CPUID, id)); 1554 } 1555 if (strcmp(mach_name, "i86pc") == 0) 1556 return (get_int_propval_by_name(modh, PICL_PROP_INSTANCE, id)); 1557 1558 return (PICL_FAILURE); 1559 } 1560 1561 /* 1562 * This function is the volatile read access function of CPU state 1563 * property 1564 */ 1565 static int 1566 get_pi_state(ptree_rarg_t *rarg, void *vbuf) 1567 { 1568 int id; 1569 int err; 1570 1571 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1572 if (err != PICL_SUCCESS) 1573 return (err); 1574 1575 switch (p_online(id, P_STATUS)) { 1576 case P_ONLINE: 1577 (void) strlcpy(vbuf, PS_ONLINE, MAX_STATE_SIZE); 1578 break; 1579 case P_OFFLINE: 1580 (void) strlcpy(vbuf, PS_OFFLINE, MAX_STATE_SIZE); 1581 break; 1582 case P_NOINTR: 1583 (void) strlcpy(vbuf, PS_NOINTR, MAX_STATE_SIZE); 1584 break; 1585 case P_SPARE: 1586 (void) strlcpy(vbuf, PS_SPARE, MAX_STATE_SIZE); 1587 break; 1588 case P_FAULTED: 1589 (void) strlcpy(vbuf, PS_FAULTED, MAX_STATE_SIZE); 1590 break; 1591 case P_POWEROFF: 1592 (void) strlcpy(vbuf, PS_POWEROFF, MAX_STATE_SIZE); 1593 break; 1594 default: 1595 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE); 1596 break; 1597 } 1598 return (PICL_SUCCESS); 1599 } 1600 1601 /* 1602 * This function is the volatile read access function of CPU processor_type 1603 * property 1604 */ 1605 static int 1606 get_processor_type(ptree_rarg_t *rarg, void *vbuf) 1607 { 1608 processor_info_t cpu_info; 1609 int id; 1610 int err; 1611 1612 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1613 if (err != PICL_SUCCESS) 1614 return (err); 1615 1616 if (processor_info(id, &cpu_info) >= 0) { 1617 (void) strlcpy(vbuf, cpu_info.pi_processor_type, PI_TYPELEN); 1618 } 1619 return (PICL_SUCCESS); 1620 } 1621 1622 /* 1623 * This function is the volatile read access function of CPU fputypes 1624 * property 1625 */ 1626 static int 1627 get_fputypes(ptree_rarg_t *rarg, void *vbuf) 1628 { 1629 processor_info_t cpu_info; 1630 int id; 1631 int err; 1632 1633 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1634 if (err != PICL_SUCCESS) 1635 return (err); 1636 1637 if (processor_info(id, &cpu_info) >= 0) { 1638 (void) strlcpy(vbuf, cpu_info.pi_fputypes, PI_FPUTYPE); 1639 } 1640 return (PICL_SUCCESS); 1641 } 1642 1643 /* 1644 * This function is the volatile read access function of CPU StateBegin 1645 * property. To minimize overhead, use kstat_chain_update() to refresh 1646 * the kstat header info as opposed to invoking kstat_open() every time. 1647 */ 1648 static int 1649 get_pi_state_begin(ptree_rarg_t *rarg, void *vbuf) 1650 { 1651 int err; 1652 int cpu_id; 1653 static kstat_ctl_t *kc = NULL; 1654 static pthread_mutex_t kc_mutex = PTHREAD_MUTEX_INITIALIZER; 1655 kstat_t *kp; 1656 kstat_named_t *kn; 1657 1658 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &cpu_id); 1659 if (err != PICL_SUCCESS) 1660 return (err); 1661 1662 (void) pthread_mutex_lock(&kc_mutex); 1663 if (kc == NULL) 1664 kc = kstat_open(); 1665 else if (kstat_chain_update(kc) == -1) { 1666 (void) kstat_close(kc); 1667 kc = kstat_open(); 1668 } 1669 1670 if (kc == NULL) { 1671 (void) pthread_mutex_unlock(&kc_mutex); 1672 return (PICL_FAILURE); 1673 } 1674 1675 /* Get the state_begin from kstat */ 1676 if ((kp = kstat_lookup(kc, KSTAT_CPU_INFO, cpu_id, NULL)) == NULL || 1677 kp->ks_type != KSTAT_TYPE_NAMED || kstat_read(kc, kp, 0) < 0) { 1678 (void) pthread_mutex_unlock(&kc_mutex); 1679 return (PICL_FAILURE); 1680 } 1681 1682 kn = kstat_data_lookup(kp, KSTAT_STATE_BEGIN); 1683 if (kn) { 1684 *(uint64_t *)vbuf = (uint64_t)kn->value.l; 1685 err = PICL_SUCCESS; 1686 } else 1687 err = PICL_FAILURE; 1688 1689 (void) pthread_mutex_unlock(&kc_mutex); 1690 return (err); 1691 } 1692 1693 /* 1694 * This function adds CPU information to the CPU nodes 1695 */ 1696 /* ARGSUSED */ 1697 static int 1698 add_processor_info(picl_nodehdl_t cpuh, void *args) 1699 { 1700 int err; 1701 int cpu_id; 1702 ptree_propinfo_t propinfo; 1703 ptree_propinfo_t pinfo; 1704 1705 err = get_cpu_portid(cpuh, &cpu_id); 1706 if (err != PICL_SUCCESS) 1707 return (PICL_WALK_CONTINUE); 1708 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1709 PICL_PTYPE_INT, PICL_READ, sizeof (int), PICL_PROP_ID, NULL, NULL); 1710 err = ptree_create_and_add_prop(cpuh, &propinfo, &cpu_id, NULL); 1711 if (err != PICL_SUCCESS) 1712 return (PICL_WALK_CONTINUE); 1713 1714 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1715 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), MAX_STATE_SIZE, 1716 PICL_PROP_STATE, get_pi_state, NULL); 1717 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1718 1719 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1720 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_TYPELEN, 1721 PICL_PROP_PROCESSOR_TYPE, get_processor_type, NULL); 1722 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1723 1724 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1725 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_FPUTYPE, 1726 PICL_PROP_FPUTYPE, get_fputypes, NULL); 1727 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1728 1729 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1730 PICL_PTYPE_TIMESTAMP, PICL_READ|PICL_VOLATILE, sizeof (uint64_t), 1731 PICL_PROP_STATE_BEGIN, get_pi_state_begin, NULL); 1732 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1733 1734 return (PICL_WALK_CONTINUE); 1735 } 1736 1737 /* 1738 * This function sets up the "ID" property in every CPU nodes 1739 * and adds processor info 1740 */ 1741 static int 1742 setup_cpus(picl_nodehdl_t plafh) 1743 { 1744 int err; 1745 1746 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_CPU, NULL, 1747 add_processor_info); 1748 1749 return (err); 1750 } 1751 1752 /* 1753 * This function format's the manufacture's information for FFB display 1754 * devices 1755 */ 1756 static void 1757 fmt_manf_id(manuf_t manufid, int bufsz, char *outbuf) 1758 { 1759 /* 1760 * Format the manufacturer's info. Note a small inconsistency we 1761 * have to work around - Brooktree has it's part number in decimal, 1762 * while Mitsubishi has it's part number in hex. 1763 */ 1764 switch (manufid.fld.manf) { 1765 case MANF_BROOKTREE: 1766 (void) snprintf(outbuf, bufsz, "%s %d, version %d", 1767 "Brooktree", manufid.fld.partno, manufid.fld.version); 1768 break; 1769 1770 case MANF_MITSUBISHI: 1771 (void) snprintf(outbuf, bufsz, "%s %x, version %d", 1772 "Mitsubishi", manufid.fld.partno, manufid.fld.version); 1773 break; 1774 1775 default: 1776 (void) snprintf(outbuf, bufsz, 1777 "JED code %d, Part num 0x%x, version %d", 1778 manufid.fld.manf, manufid.fld.partno, manufid.fld.version); 1779 } 1780 } 1781 1782 /* 1783 * If it's an ffb device, open ffb devices and return PICL_SUCCESS 1784 */ 1785 static int 1786 open_ffb_device(picl_nodehdl_t ffbh, int *fd) 1787 { 1788 DIR *dirp; 1789 char devfs_path[PATH_MAX]; 1790 char dev_path[PATH_MAX]; 1791 char *devp; 1792 struct dirent *direntp; 1793 int err; 1794 int tmpfd; 1795 1796 /* Get the devfs_path of the ffb devices */ 1797 err = ptree_get_propval_by_name(ffbh, PICL_PROP_DEVFS_PATH, devfs_path, 1798 sizeof (devfs_path)); 1799 if (err != PICL_SUCCESS) 1800 return (err); 1801 1802 /* Get the device node name */ 1803 devp = strrchr(devfs_path, '/'); 1804 if (devp == NULL) 1805 return (PICL_FAILURE); 1806 *devp = '\0'; 1807 ++devp; 1808 1809 /* 1810 * Check if device node name has the ffb string 1811 * If not, assume it's not a ffb device. 1812 */ 1813 if (strstr(devp, FFB_NAME) == NULL) 1814 return (PICL_FAILURE); 1815 1816 /* 1817 * Get the parent path of the ffb device node. 1818 */ 1819 (void) snprintf(dev_path, sizeof (dev_path), "%s/%s", "/devices", 1820 devfs_path); 1821 1822 /* 1823 * Since we don't know ffb's minor nodename, 1824 * we need to search all the devices under its 1825 * parent dir by comparing the node name 1826 */ 1827 if ((dirp = opendir(dev_path)) == NULL) 1828 return (PICL_FAILURE); 1829 1830 while ((direntp = readdir(dirp)) != NULL) { 1831 if (strstr(direntp->d_name, devp) != NULL) { 1832 (void) strcat(dev_path, "/"); 1833 (void) strcat(dev_path, direntp->d_name); 1834 tmpfd = open(dev_path, O_RDWR); 1835 if (tmpfd < 0) 1836 continue; 1837 *fd = tmpfd; 1838 (void) closedir(dirp); 1839 return (PICL_SUCCESS); 1840 } 1841 } 1842 1843 (void) closedir(dirp); 1844 return (PICL_FAILURE); 1845 } 1846 1847 /* 1848 * This function recursively searches the tree for ffb display devices 1849 * and add ffb config information 1850 */ 1851 static int 1852 add_ffb_config_info(picl_nodehdl_t rooth) 1853 { 1854 picl_nodehdl_t nodeh; 1855 int err; 1856 char piclclass[PICL_CLASSNAMELEN_MAX]; 1857 char manfidbuf[FFB_MANUF_BUFSIZE]; 1858 int fd; 1859 int board_rev; 1860 ffb_sys_info_t fsi; 1861 ptree_propinfo_t pinfo; 1862 1863 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh, 1864 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 1865 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, 1866 &nodeh, sizeof (picl_nodehdl_t))) { 1867 1868 if (err != PICL_SUCCESS) 1869 return (err); 1870 1871 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 1872 piclclass, PICL_CLASSNAMELEN_MAX); 1873 1874 if ((err == PICL_SUCCESS) && 1875 (strcmp(piclclass, PICL_CLASS_DISPLAY) == 0)) { 1876 1877 err = open_ffb_device(nodeh, &fd); 1878 if ((err == PICL_SUCCESS) && 1879 (ioctl(fd, FFB_SYS_INFO, &fsi) >= 0)) { 1880 (void) ptree_init_propinfo(&pinfo, 1881 PTREE_PROPINFO_VERSION, 1882 PICL_PTYPE_UNSIGNED_INT, PICL_READ, 1883 sizeof (int), PICL_PROP_FFB_BOARD_REV, 1884 NULL, NULL); 1885 board_rev = fsi.ffb_strap_bits.fld.board_rev; 1886 (void) ptree_create_and_add_prop(nodeh, &pinfo, 1887 &board_rev, NULL); 1888 1889 fmt_manf_id(fsi.dac_version, 1890 sizeof (manfidbuf), manfidbuf); 1891 (void) ptree_init_propinfo(&pinfo, 1892 PTREE_PROPINFO_VERSION, 1893 PICL_PTYPE_CHARSTRING, PICL_READ, 1894 strlen(manfidbuf) + 1, 1895 PICL_PROP_FFB_DAC_VER, NULL, NULL); 1896 (void) ptree_create_and_add_prop(nodeh, &pinfo, 1897 manfidbuf, NULL); 1898 1899 fmt_manf_id(fsi.fbram_version, 1900 sizeof (manfidbuf), manfidbuf); 1901 (void) ptree_init_propinfo(&pinfo, 1902 PTREE_PROPINFO_VERSION, 1903 PICL_PTYPE_CHARSTRING, PICL_READ, 1904 strlen(manfidbuf) + 1, 1905 PICL_PROP_FFB_FBRAM_VER, NULL, 1906 NULL); 1907 (void) ptree_create_and_add_prop(nodeh, &pinfo, 1908 manfidbuf, NULL); 1909 (void) close(fd); 1910 } 1911 } else if (add_ffb_config_info(nodeh) != PICL_SUCCESS) 1912 return (PICL_FAILURE); 1913 } 1914 return (PICL_SUCCESS); 1915 } 1916 1917 static conf_entries_t * 1918 free_conf_entries(conf_entries_t *list) 1919 { 1920 conf_entries_t *el; 1921 conf_entries_t *del; 1922 1923 if (list == NULL) 1924 return (NULL); 1925 el = list; 1926 while (el != NULL) { 1927 del = el; 1928 el = el->next; 1929 free(del->name); 1930 free(del->piclclass); 1931 free(del); 1932 } 1933 return (el); 1934 } 1935 1936 /* 1937 * Reading config order: platform, common 1938 */ 1939 static conf_entries_t * 1940 read_conf_file(char *fname, conf_entries_t *list) 1941 { 1942 FILE *fp; 1943 char lbuf[CONFFILE_LINELEN_MAX]; 1944 char *nametok; 1945 char *classtok; 1946 conf_entries_t *el; 1947 conf_entries_t *ptr; 1948 1949 if (fname == NULL) 1950 return (list); 1951 1952 fp = fopen(fname, "r"); 1953 1954 if (fp == NULL) 1955 return (list); 1956 1957 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 1958 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 1959 continue; 1960 1961 nametok = strtok(lbuf, " \t\n"); 1962 if (nametok == NULL) 1963 continue; 1964 1965 classtok = strtok(NULL, " \t\n"); 1966 if (classtok == NULL) 1967 continue; 1968 1969 el = malloc(sizeof (conf_entries_t)); 1970 if (el == NULL) 1971 break; 1972 el->name = strdup(nametok); 1973 el->piclclass = strdup(classtok); 1974 if ((el->name == NULL) || (el->piclclass == NULL)) { 1975 free(el); 1976 return (list); 1977 } 1978 el->next = NULL; 1979 1980 /* 1981 * Add it to the end of list 1982 */ 1983 if (list == NULL) 1984 list = el; 1985 else { 1986 ptr = list; 1987 while (ptr->next != NULL) 1988 ptr = ptr->next; 1989 ptr->next = el; 1990 } 1991 1992 } 1993 (void) fclose(fp); 1994 return (list); 1995 } 1996 1997 /* 1998 * Process the devtree conf file and set up the conf_name_class_map list 1999 */ 2000 static void 2001 process_devtree_conf_file(void) 2002 { 2003 char nmbuf[SYS_NMLN]; 2004 char pname[PATH_MAX]; 2005 2006 conf_name_class_map = NULL; 2007 2008 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2009 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2010 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2011 conf_name_class_map = read_conf_file(pname, 2012 conf_name_class_map); 2013 } 2014 2015 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2016 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2017 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2018 conf_name_class_map = read_conf_file(pname, 2019 conf_name_class_map); 2020 } 2021 2022 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2023 DEVTREE_CONFFILE_NAME); 2024 conf_name_class_map = read_conf_file(pname, conf_name_class_map); 2025 } 2026 2027 static asr_conf_entries_t *conf_name_asr_map = NULL; 2028 2029 static void 2030 free_asr_conf_entries(asr_conf_entries_t *list) { 2031 asr_conf_entries_t *el; 2032 asr_conf_entries_t *del; 2033 2034 el = list; 2035 while (el != NULL) { 2036 del = el; 2037 el = el->next; 2038 if (del->name) 2039 free(del->name); 2040 if (del->address) 2041 free(del->address); 2042 if (del->status) 2043 free(del->status); 2044 if (del->piclclass) 2045 free(del->piclclass); 2046 if (del->props) 2047 free(del->props); 2048 free(del); 2049 } 2050 } 2051 2052 /* 2053 * Reading config order: platform, common 2054 */ 2055 static asr_conf_entries_t * 2056 read_asr_conf_file(char *fname, asr_conf_entries_t *list) 2057 { 2058 FILE *fp; 2059 char lbuf[CONFFILE_LINELEN_MAX]; 2060 char *nametok; 2061 char *classtok; 2062 char *statustok; 2063 char *addresstok; 2064 char *propstok; 2065 asr_conf_entries_t *el; 2066 asr_conf_entries_t *ptr; 2067 2068 if (fname == NULL) 2069 return (list); 2070 2071 fp = fopen(fname, "r"); 2072 if (fp == NULL) 2073 return (list); 2074 2075 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 2076 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 2077 continue; 2078 2079 nametok = strtok(lbuf, " \t\n"); 2080 if (nametok == NULL) 2081 continue; 2082 2083 classtok = strtok(NULL, " \t\n"); 2084 if (classtok == NULL) 2085 continue; 2086 2087 statustok = strtok(NULL, " \t\n"); 2088 if (statustok == NULL) 2089 continue; 2090 2091 addresstok = strtok(NULL, " \t\n"); 2092 if (addresstok == NULL) 2093 continue; 2094 2095 /* 2096 * props are optional 2097 */ 2098 propstok = strtok(NULL, " \t\n"); 2099 2100 el = malloc(sizeof (asr_conf_entries_t)); 2101 if (el == NULL) 2102 break; 2103 el->name = strdup(nametok); 2104 el->piclclass = strdup(classtok); 2105 el->status = strdup(statustok); 2106 el->address = strdup(addresstok); 2107 if (propstok != NULL) 2108 el->props = strdup(propstok); 2109 else 2110 el->props = NULL; 2111 if ((el->name == NULL) || (el->piclclass == NULL) || 2112 (el->address == NULL) || (el->status == NULL)) { 2113 if (el->name) 2114 free(el->name); 2115 if (el->address) 2116 free(el->address); 2117 if (el->status) 2118 free(el->status); 2119 if (el->piclclass) 2120 free(el->piclclass); 2121 if (el->props) 2122 free(el->props); 2123 free(el); 2124 break; 2125 } 2126 el->next = NULL; 2127 2128 /* 2129 * Add it to the end of list 2130 */ 2131 if (list == NULL) 2132 list = el; 2133 else { 2134 ptr = list; 2135 while (ptr->next != NULL) 2136 ptr = ptr->next; 2137 ptr->next = el; 2138 } 2139 2140 } 2141 (void) fclose(fp); 2142 return (list); 2143 } 2144 2145 /* 2146 * Process the asr conf file 2147 */ 2148 static void 2149 process_asrtree_conf_file(void) 2150 { 2151 char nmbuf[SYS_NMLN]; 2152 char pname[PATH_MAX]; 2153 2154 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2155 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2156 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2157 conf_name_asr_map = read_asr_conf_file(pname, 2158 conf_name_asr_map); 2159 } 2160 2161 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2162 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2163 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2164 conf_name_asr_map = read_asr_conf_file(pname, 2165 conf_name_asr_map); 2166 } 2167 2168 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2169 ASRTREE_CONFFILE_NAME); 2170 conf_name_asr_map = read_asr_conf_file(pname, conf_name_asr_map); 2171 } 2172 2173 /* 2174 * This function reads the export file list from ASR 2175 */ 2176 static int 2177 get_asr_export_list(char **exportlist, int *exportlistlen) 2178 { 2179 struct openpromio oppbuf; 2180 struct openpromio *opp = &oppbuf; 2181 int d; 2182 int listsize; 2183 2184 d = open("/dev/openprom", O_RDWR); 2185 if (d < 0) 2186 return (0); 2187 2188 if (ioctl(d, OPROMEXPORTLEN, opp) == -1) { 2189 (void) close(d); 2190 return (0); 2191 } 2192 listsize = opp->oprom_size; 2193 opp = (struct openpromio *)malloc(sizeof (struct openpromio) + 2194 listsize); 2195 if (opp == NULL) { 2196 (void) close(d); 2197 return (0); 2198 } 2199 (void) memset(opp, '\0', sizeof (struct openpromio) + listsize); 2200 opp->oprom_size = listsize; 2201 if (ioctl(d, OPROMEXPORT, opp) == -1) { 2202 free(opp); 2203 (void) close(d); 2204 return (0); 2205 } 2206 *exportlist = malloc(listsize); 2207 if (*exportlist == NULL) { 2208 free(opp); 2209 (void) close(d); 2210 return (0); 2211 } 2212 (void) memcpy(*exportlist, opp->oprom_array, opp->oprom_size); 2213 free(opp); 2214 *exportlistlen = opp->oprom_size; 2215 (void) close(d); 2216 return (1); 2217 } 2218 2219 /* 2220 * Parses properties string, fills in triplet structure with first 2221 * type, name, val triplet and returns pointer to next property. 2222 * Returns NULL if no valid triplet found 2223 * CAUTION: drops \0 characters over separator characters: if you 2224 * want to parse the string twice, you'll have to take a copy. 2225 */ 2226 static char * 2227 parse_props_string(char *props, asr_prop_triplet_t *triplet) 2228 { 2229 char *prop_name; 2230 char *prop_val; 2231 char *prop_next; 2232 2233 prop_name = strchr(props, '?'); 2234 if (prop_name == NULL) 2235 return (NULL); 2236 *prop_name++ = '\0'; 2237 prop_val = strchr(prop_name, '='); 2238 if (prop_val == NULL) 2239 return (NULL); 2240 *prop_val++ = '\0'; 2241 triplet->proptype = props; 2242 triplet->propname = prop_name; 2243 triplet->propval = prop_val; 2244 prop_next = strchr(prop_val, ':'); 2245 if (prop_next == NULL) 2246 return (prop_val - 1); 2247 *prop_next++ = '\0'; 2248 return (prop_next); 2249 } 2250 2251 static int 2252 add_status_prop(picl_nodehdl_t chdh, char *status) 2253 { 2254 ptree_propinfo_t propinfo; 2255 picl_prophdl_t proph; 2256 int err; 2257 2258 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2259 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(status) + 1, 2260 PICL_PROP_STATUS, NULL, NULL); 2261 if (err != PICL_SUCCESS) 2262 return (err); 2263 err = ptree_create_and_add_prop(chdh, &propinfo, status, &proph); 2264 return (err); 2265 } 2266 2267 static void 2268 create_asr_node(char *parent, char *child, char *unitaddr, char *class, 2269 char *status, char *props) 2270 { 2271 char ptreepath[PATH_MAX]; 2272 char nodename[PICL_PROPNAMELEN_MAX]; 2273 char ua[MAX_UNIT_ADDRESS_LEN]; 2274 char *props_copy = NULL; 2275 char *next; 2276 char *prop_string; 2277 boolean_t found = B_FALSE; 2278 picl_nodehdl_t nodeh; 2279 picl_nodehdl_t chdh; 2280 asr_prop_triplet_t triple; 2281 ptree_propinfo_t propinfo; 2282 picl_prophdl_t proph; 2283 int val; 2284 int err; 2285 2286 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX); 2287 (void) strlcat(ptreepath, parent, PATH_MAX); 2288 2289 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS) 2290 return; 2291 /* 2292 * see if the required child node already exists 2293 */ 2294 for (err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 2295 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2296 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 2297 sizeof (picl_nodehdl_t))) { 2298 if (err != PICL_SUCCESS) 2299 break; 2300 err = ptree_get_propval_by_name(chdh, PICL_PROP_NAME, 2301 (void *)nodename, PICL_PROPNAMELEN_MAX); 2302 if (err != PICL_SUCCESS) 2303 break; 2304 if (strcmp(nodename, child) != 0) 2305 continue; 2306 /* 2307 * found a candidate child node 2308 */ 2309 if (unitaddr) { 2310 /* 2311 * does it match the required unit address? 2312 */ 2313 err = ptree_get_propval_by_name(chdh, 2314 PICL_PROP_UNIT_ADDRESS, ua, sizeof (ua)); 2315 if (err == PICL_PROPNOTFOUND) 2316 continue; 2317 if (err != PICL_SUCCESS) 2318 break; 2319 if (strcmp(unitaddr, ua) != 0) 2320 continue; 2321 } 2322 if (props == NULL) { 2323 next = ""; 2324 } else if (props_copy == NULL) { 2325 props_copy = strdup(props); 2326 if (props_copy == NULL) 2327 return; 2328 next = props_copy; 2329 } 2330 while ((next = parse_props_string(next, &triple)) != NULL) { 2331 err = ptree_get_prop_by_name(chdh, triple.propname, 2332 &proph); 2333 if (err != PICL_SUCCESS) 2334 break; 2335 err = ptree_get_propinfo(proph, &propinfo); 2336 if (err != PICL_SUCCESS) 2337 break; 2338 err = PICL_FAILURE; 2339 switch (propinfo.piclinfo.type) { 2340 case PICL_PTYPE_INT: 2341 case PICL_PTYPE_UNSIGNED_INT: 2342 if (strcmp(triple.proptype, "I") != 0) 2343 break; 2344 err = ptree_get_propval(proph, (void *)&val, 2345 sizeof (val)); 2346 if (err != PICL_SUCCESS) 2347 break; 2348 if (val != atoi(triple.propval)) 2349 err = PICL_FAILURE; 2350 break; 2351 case PICL_PTYPE_CHARSTRING: 2352 if (strcmp(triple.proptype, "S") != 0) 2353 break; 2354 prop_string = malloc(propinfo.piclinfo.size); 2355 if (prop_string == NULL) 2356 break; 2357 err = ptree_get_propval(proph, 2358 (void *)prop_string, 2359 propinfo.piclinfo.size); 2360 if (err != PICL_SUCCESS) { 2361 free(prop_string); 2362 break; 2363 } 2364 if (strcmp(prop_string, triple.propval) != 0) 2365 err = PICL_FAILURE; 2366 free(prop_string); 2367 break; 2368 default: 2369 break; 2370 } 2371 if (err != PICL_SUCCESS) { 2372 break; 2373 } 2374 } 2375 if (next == NULL) { 2376 found = B_TRUE; 2377 break; 2378 } 2379 } 2380 if (props_copy) 2381 free(props_copy); 2382 if (found) { 2383 /* 2384 * does the pre-existing node have a status property? 2385 */ 2386 err = ptree_get_propval_by_name(chdh, PICL_PROP_STATUS, 2387 ua, sizeof (ua)); 2388 if (err == PICL_PROPNOTFOUND) 2389 (void) add_status_prop(chdh, status); 2390 if (err != PICL_SUCCESS) 2391 return; 2392 if ((strcmp(ua, ASR_DISABLED) == 0) || 2393 (strcmp(ua, ASR_FAILED) == 0) || 2394 ((strcmp(status, ASR_DISABLED) != 0) && 2395 (strcmp(status, ASR_FAILED) != 0))) { 2396 return; 2397 } 2398 /* 2399 * more urgent status now, so replace existing value 2400 */ 2401 err = ptree_get_prop_by_name(chdh, PICL_PROP_STATUS, &proph); 2402 if (err != PICL_SUCCESS) 2403 return; 2404 (void) ptree_delete_prop(proph); 2405 (void) ptree_destroy_prop(proph); 2406 err = add_status_prop(chdh, status); 2407 if (err != PICL_SUCCESS) 2408 return; 2409 return; 2410 } 2411 2412 /* 2413 * typical case, node needs adding together with a set of properties 2414 */ 2415 if (ptree_create_and_add_node(nodeh, child, class, &chdh) == 2416 PICL_SUCCESS) { 2417 (void) add_status_prop(chdh, status); 2418 if (unitaddr) { 2419 (void) ptree_init_propinfo(&propinfo, 2420 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2421 PICL_READ, strlen(unitaddr) + 1, 2422 PICL_PROP_UNIT_ADDRESS, NULL, NULL); 2423 (void) ptree_create_and_add_prop(chdh, &propinfo, 2424 unitaddr, &proph); 2425 (void) strlcpy(ptreepath, parent, PATH_MAX); 2426 (void) strlcat(ptreepath, "/", PATH_MAX); 2427 (void) strlcat(ptreepath, child, PATH_MAX); 2428 (void) strlcat(ptreepath, "@", PATH_MAX); 2429 (void) strlcat(ptreepath, unitaddr, PATH_MAX); 2430 (void) ptree_init_propinfo(&propinfo, 2431 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2432 PICL_READ, strlen(ptreepath) + 1, 2433 PICL_PROP_DEVFS_PATH, NULL, NULL); 2434 (void) ptree_create_and_add_prop(chdh, &propinfo, 2435 ptreepath, &proph); 2436 } 2437 next = props; 2438 while ((next = parse_props_string(next, &triple)) != NULL) { 2439 /* 2440 * only handle int and string properties for 2441 * simplicity 2442 */ 2443 if (strcmp(triple.proptype, "I") == 0) { 2444 (void) ptree_init_propinfo(&propinfo, 2445 PTREE_PROPINFO_VERSION, 2446 PICL_PTYPE_INT, PICL_READ, 2447 sizeof (int), triple.propname, NULL, NULL); 2448 val = atoi(triple.propval); 2449 (void) ptree_create_and_add_prop(chdh, 2450 &propinfo, &val, &proph); 2451 } else { 2452 (void) ptree_init_propinfo(&propinfo, 2453 PTREE_PROPINFO_VERSION, 2454 PICL_PTYPE_CHARSTRING, PICL_READ, 2455 strlen(triple.propval) + 1, 2456 triple.propname, NULL, NULL); 2457 (void) ptree_create_and_add_prop(chdh, 2458 &propinfo, triple.propval, &proph); 2459 } 2460 } 2461 } 2462 } 2463 2464 static void 2465 add_asr_nodes() 2466 { 2467 char *asrexport; 2468 int asrexportlen; 2469 asr_conf_entries_t *c = NULL; 2470 int i; 2471 char *key; 2472 char *child; 2473 char *unitaddr; 2474 uint16_t count; 2475 int disabled; 2476 2477 if (get_asr_export_list(&asrexport, &asrexportlen) == 0) 2478 return; 2479 process_asrtree_conf_file(); 2480 if (conf_name_asr_map == NULL) 2481 return; 2482 i = 0; 2483 while (i < asrexportlen) { 2484 key = &asrexport[i]; 2485 i += strlen(key) + 1; 2486 if (i >= asrexportlen) 2487 break; 2488 2489 /* 2490 * next byte tells us whether failed by diags or manually 2491 * disabled 2492 */ 2493 disabled = asrexport[i]; 2494 i++; 2495 if (i >= asrexportlen) 2496 break; 2497 2498 /* 2499 * only type 1 supported 2500 */ 2501 if (asrexport[i] != 1) 2502 break; 2503 i++; 2504 if (i >= asrexportlen) 2505 break; 2506 2507 /* 2508 * next two bytes give size of reason string 2509 */ 2510 count = (asrexport[i] << 8) | asrexport[i + 1]; 2511 i += count + 2; 2512 if (i > asrexportlen) 2513 break; 2514 2515 /* 2516 * now look for key in conf file info 2517 */ 2518 c = conf_name_asr_map; 2519 while (c != NULL) { 2520 if (strcmp(key, c->name) == 0) { 2521 child = strrchr(c->address, '/'); 2522 *child++ = '\0'; 2523 unitaddr = strchr(child, '@'); 2524 if (unitaddr) 2525 *unitaddr++ = '\0'; 2526 if (strcmp(c->status, ASR_DISABLED) == 0) { 2527 create_asr_node(c->address, child, 2528 unitaddr, c->piclclass, disabled ? 2529 ASR_DISABLED : ASR_FAILED, 2530 c->props); 2531 } else { 2532 create_asr_node(c->address, child, 2533 unitaddr, c->piclclass, c->status, 2534 c->props); 2535 } 2536 } 2537 c = c->next; 2538 } 2539 } 2540 2541 free_asr_conf_entries(conf_name_asr_map); 2542 free(asrexport); 2543 } 2544 2545 /* 2546 * This function adds information to the /platform node 2547 */ 2548 static int 2549 add_platform_info(picl_nodehdl_t plafh) 2550 { 2551 struct utsname uts_info; 2552 int err; 2553 ptree_propinfo_t propinfo; 2554 picl_prophdl_t proph; 2555 2556 if (uname(&uts_info) < 0) 2557 return (PICL_FAILURE); 2558 2559 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2560 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.sysname) + 1, 2561 PICL_PROP_SYSNAME, NULL, NULL); 2562 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.sysname, 2563 &proph); 2564 if (err != PICL_SUCCESS) 2565 return (err); 2566 2567 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2568 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.nodename) + 1, 2569 PICL_PROP_NODENAME, NULL, NULL); 2570 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.nodename, 2571 &proph); 2572 if (err != PICL_SUCCESS) 2573 return (err); 2574 2575 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2576 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.release) + 1, 2577 PICL_PROP_RELEASE, NULL, NULL); 2578 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.release, 2579 &proph); 2580 if (err != PICL_SUCCESS) 2581 return (err); 2582 2583 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2584 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.version) + 1, 2585 PICL_PROP_VERSION, NULL, NULL); 2586 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.version, 2587 &proph); 2588 if (err != PICL_SUCCESS) 2589 return (err); 2590 2591 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2592 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.machine) + 1, 2593 PICL_PROP_MACHINE, NULL, NULL); 2594 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.machine, 2595 &proph); 2596 return (err); 2597 } 2598 2599 /* 2600 * Get first 32-bit value from the reg property 2601 */ 2602 static int 2603 get_first_reg_word(picl_nodehdl_t nodeh, uint32_t *regval) 2604 { 2605 int err; 2606 uint32_t *regbuf; 2607 picl_prophdl_t regh; 2608 ptree_propinfo_t pinfo; 2609 2610 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 2611 if (err != PICL_SUCCESS) /* no reg property */ 2612 return (err); 2613 err = ptree_get_propinfo(regh, &pinfo); 2614 if (err != PICL_SUCCESS) 2615 return (err); 2616 if (pinfo.piclinfo.size < sizeof (uint32_t)) /* too small */ 2617 return (PICL_FAILURE); 2618 regbuf = alloca(pinfo.piclinfo.size); 2619 if (regbuf == NULL) 2620 return (PICL_FAILURE); 2621 err = ptree_get_propval(regh, regbuf, pinfo.piclinfo.size); 2622 if (err != PICL_SUCCESS) 2623 return (err); 2624 *regval = *regbuf; /* get first 32-bit value */ 2625 return (PICL_SUCCESS); 2626 } 2627 2628 /* 2629 * Get device ID from the reg property 2630 */ 2631 static int 2632 get_device_id(picl_nodehdl_t nodeh, uint32_t *dev_id) 2633 { 2634 int err; 2635 uint32_t regval; 2636 2637 err = get_first_reg_word(nodeh, ®val); 2638 if (err != PICL_SUCCESS) 2639 return (err); 2640 2641 *dev_id = PCI_DEVICE_ID(regval); 2642 return (PICL_SUCCESS); 2643 } 2644 2645 /* 2646 * add Slot property for children of SBUS node 2647 */ 2648 /* ARGSUSED */ 2649 static int 2650 add_sbus_slots(picl_nodehdl_t pcih, void *args) 2651 { 2652 picl_nodehdl_t nodeh; 2653 uint32_t slot; 2654 int err; 2655 ptree_propinfo_t pinfo; 2656 2657 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 2658 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2659 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 2660 sizeof (picl_nodehdl_t))) { 2661 if (err != PICL_SUCCESS) 2662 return (err); 2663 2664 if (get_first_reg_word(nodeh, &slot) != 0) 2665 continue; 2666 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2667 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 2668 PICL_PROP_SLOT, NULL, NULL); 2669 (void) ptree_create_and_add_prop(nodeh, &pinfo, &slot, NULL); 2670 } 2671 2672 return (PICL_WALK_CONTINUE); 2673 } 2674 2675 /* 2676 * This function creates a Slot property for SBUS child nodes 2677 * which can be correlated with the slot they are plugged into 2678 * on the motherboard. 2679 */ 2680 static int 2681 set_sbus_slot(picl_nodehdl_t plafh) 2682 { 2683 int err; 2684 2685 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_SBUS, NULL, 2686 add_sbus_slots); 2687 2688 return (err); 2689 } 2690 2691 /* 2692 * add DeviceID property for children of PCI node 2693 */ 2694 /* ARGSUSED */ 2695 static int 2696 add_pci_deviceids(picl_nodehdl_t pcih, void *args) 2697 { 2698 picl_nodehdl_t nodeh; 2699 uint32_t dev_id; 2700 int err; 2701 ptree_propinfo_t pinfo; 2702 2703 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 2704 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2705 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 2706 sizeof (picl_nodehdl_t))) { 2707 if (err != PICL_SUCCESS) 2708 return (err); 2709 2710 if (get_device_id(nodeh, &dev_id) != 0) 2711 continue; 2712 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2713 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 2714 PICL_PROP_DEVICE_ID, NULL, NULL); 2715 (void) ptree_create_and_add_prop(nodeh, &pinfo, &dev_id, NULL); 2716 } 2717 2718 return (PICL_WALK_CONTINUE); 2719 } 2720 2721 /* 2722 * This function creates a DeviceID property for PCI child nodes 2723 * which can be correlated with the slot they are plugged into 2724 * on the motherboard. 2725 */ 2726 static int 2727 set_pci_deviceid(picl_nodehdl_t plafh) 2728 { 2729 int err; 2730 2731 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_PCI, NULL, 2732 add_pci_deviceids); 2733 2734 return (err); 2735 } 2736 2737 /* 2738 * Default UnitAddress encode function 2739 */ 2740 static int 2741 encode_default_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 2742 { 2743 int i, len; 2744 2745 /* 2746 * Encode UnitAddress as %a,%b,%c,...,%n 2747 */ 2748 if (addrcells < 1) 2749 return (-1); 2750 2751 len = snprintf(buf, sz, "%x", *regprop); 2752 for (i = 1; i < addrcells && len < sz; i++) 2753 len += snprintf(&buf[len], sz-len, ",%x", regprop[i]); 2754 2755 return ((len >= sz) ? -1 : 0); 2756 } 2757 2758 /* 2759 * UnitAddress encode function where the last component is not printed 2760 * unless non-zero. 2761 */ 2762 static int 2763 encode_optional_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 2764 { 2765 int retval; 2766 2767 /* 2768 * Encode UnitAddress as %a,%b,%c,...,%n where the last component 2769 * is printed only if non-zero. 2770 */ 2771 if (addrcells > 1 && regprop[addrcells-1] == 0) 2772 retval = encode_default_unitaddr(buf, sz, regprop, addrcells-1); 2773 else 2774 retval = encode_default_unitaddr(buf, sz, regprop, addrcells); 2775 2776 return (retval); 2777 } 2778 2779 2780 /* 2781 * UnitAddress encode function for SCSI class of devices 2782 */ 2783 static int 2784 encode_scsi_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 2785 { 2786 int len, retval; 2787 2788 /* 2789 * #address-cells Format 2790 * 2 second component printed only if non-zero 2791 * 2792 * 4 regprop: phys_hi phys_lo lun_hi lun_lo 2793 * UnitAddr: w<phys_hi><phys_lo>,<lun_lo> 2794 */ 2795 2796 if (addrcells == 2) { 2797 retval = encode_optional_unitaddr(buf, sz, regprop, addrcells); 2798 } else if (addrcells == 4) { 2799 len = snprintf(buf, sz, "w%08x%08x,%x", regprop[0], regprop[1], 2800 regprop[3]); 2801 retval = (len >= sz) ? -1 : 0; 2802 } else 2803 retval = -1; 2804 2805 return (retval); 2806 } 2807 2808 /* 2809 * UnitAddress encode function for UPA devices 2810 */ 2811 static int 2812 encode_upa_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 2813 { 2814 int len; 2815 2816 if (addrcells != 2) 2817 return (-1); 2818 2819 len = snprintf(buf, sz, "%x,%x", (regprop[0]/2)&0x1f, regprop[1]); 2820 return ((len >= sz) ? -1 : 0); 2821 } 2822 2823 /* 2824 * UnitAddress encode function for GPTWO, JBUS devices 2825 */ 2826 static int 2827 encode_gptwo_jbus_unitaddr(char *buf, int sz, uint32_t *regprop, 2828 uint_t addrcells) 2829 { 2830 uint32_t hi, lo; 2831 int len, id, off; 2832 2833 if (addrcells != 2) 2834 return (-1); 2835 2836 hi = regprop[0]; 2837 lo = regprop[1]; 2838 2839 if (hi & 0x400) { 2840 id = ((hi & 0x1) << 9) | (lo >> 23); /* agent id */ 2841 off = lo & 0x7fffff; /* config offset */ 2842 len = snprintf(buf, sz, "%x,%x", id, off); 2843 } else { 2844 len = snprintf(buf, sz, "m%x,%x", hi, lo); 2845 } 2846 return ((len >= sz) ? -1 : 0); 2847 } 2848 2849 /* 2850 * UnitAddress encode function for PCI devices 2851 */ 2852 static int 2853 encode_pci_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 2854 { 2855 typedef struct { 2856 uint32_t n:1, /* relocatable */ 2857 p:1, /* prefetchable */ 2858 t:1, /* address region aliases */ 2859 zero:3, /* must be zero */ 2860 ss:2, /* address space type */ 2861 bus:8, /* bus number */ 2862 dev:5, /* device number */ 2863 fn:3, /* function number */ 2864 reg:8; /* register number */ 2865 uint32_t phys_hi; /* high physical address */ 2866 uint32_t phys_lo; /* low physical address */ 2867 } pci_addrcell_t; 2868 2869 pci_addrcell_t *p; 2870 int len; 2871 2872 if (addrcells != 3) 2873 return (-1); 2874 2875 p = (pci_addrcell_t *)regprop; 2876 switch (p->ss) { 2877 case 0: /* Config */ 2878 if (p->fn) 2879 len = snprintf(buf, sz, "%x,%x", p->dev, p->fn); 2880 else 2881 len = snprintf(buf, sz, "%x", p->dev); 2882 break; 2883 case 1: /* IO */ 2884 len = snprintf(buf, sz, "i%x,%x,%x,%x", p->dev, p->fn, p->reg, 2885 p->phys_lo); 2886 break; 2887 case 2: /* Mem32 */ 2888 len = snprintf(buf, sz, "m%x,%x,%x,%x", p->dev, p->fn, p->reg, 2889 p->phys_lo); 2890 break; 2891 case 3: /* Mem64 */ 2892 len = snprintf(buf, sz, "x%x,%x,%x,%x%08x", p->dev, p->fn, 2893 p->reg, p->phys_hi, p->phys_lo); 2894 break; 2895 } 2896 return ((len >= sz) ? -1 : 0); 2897 } 2898 2899 /* 2900 * Get #address-cells property value 2901 */ 2902 static uint_t 2903 get_addrcells_prop(picl_nodehdl_t nodeh) 2904 { 2905 int len, err; 2906 uint32_t addrcells; 2907 ptree_propinfo_t pinfo; 2908 picl_prophdl_t proph; 2909 2910 /* 2911 * Get #address-cells property. If not present, use default value. 2912 */ 2913 err = ptree_get_prop_by_name(nodeh, OBP_PROP_ADDRESS_CELLS, &proph); 2914 if (err == PICL_SUCCESS) 2915 err = ptree_get_propinfo(proph, &pinfo); 2916 2917 len = pinfo.piclinfo.size; 2918 if (err == PICL_SUCCESS && len >= sizeof (uint8_t) && 2919 len <= sizeof (addrcells)) { 2920 err = ptree_get_propval(proph, &addrcells, len); 2921 if (err == PICL_SUCCESS) { 2922 if (len == sizeof (uint8_t)) 2923 addrcells = *(uint8_t *)&addrcells; 2924 else if (len == sizeof (uint16_t)) 2925 addrcells = *(uint16_t *)&addrcells; 2926 } else 2927 addrcells = DEFAULT_ADDRESS_CELLS; 2928 } else 2929 addrcells = DEFAULT_ADDRESS_CELLS; 2930 2931 return (addrcells); 2932 } 2933 2934 /* 2935 * Get UnitAddress mapping entry for a node 2936 */ 2937 static unitaddr_map_t * 2938 get_unitaddr_mapping(picl_nodehdl_t nodeh) 2939 { 2940 int err; 2941 unitaddr_map_t *uamap; 2942 char clname[PICL_CLASSNAMELEN_MAX]; 2943 2944 /* 2945 * Get my classname and locate a function to translate "reg" prop 2946 * into "UnitAddress" prop for my children. 2947 */ 2948 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, clname, 2949 sizeof (clname)); 2950 if (err != PICL_SUCCESS) 2951 (void) strcpy(clname, ""); /* NULL class name */ 2952 2953 for (uamap = &unitaddr_map_table[0]; uamap->class != NULL; uamap++) 2954 if (strcmp(clname, uamap->class) == 0) 2955 break; 2956 2957 return (uamap); 2958 } 2959 2960 /* 2961 * Add UnitAddress property to the specified node 2962 */ 2963 static int 2964 add_unitaddr_prop(picl_nodehdl_t nodeh, unitaddr_map_t *uamap, uint_t addrcells) 2965 { 2966 int regproplen, err; 2967 uint32_t *regbuf; 2968 picl_prophdl_t regh; 2969 ptree_propinfo_t pinfo; 2970 char unitaddr[MAX_UNIT_ADDRESS_LEN]; 2971 2972 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 2973 if (err != PICL_SUCCESS) 2974 return (err); 2975 2976 err = ptree_get_propinfo(regh, &pinfo); 2977 if (err != PICL_SUCCESS) 2978 return (PICL_FAILURE); 2979 2980 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t))) 2981 return (PICL_FAILURE); 2982 2983 regproplen = pinfo.piclinfo.size; 2984 regbuf = alloca(regproplen); 2985 if (regbuf == NULL) 2986 return (PICL_FAILURE); 2987 2988 err = ptree_get_propval(regh, regbuf, regproplen); 2989 if (err != PICL_SUCCESS || uamap->func == NULL || 2990 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) || 2991 (uamap->func)(unitaddr, sizeof (unitaddr), regbuf, 2992 addrcells) != 0) { 2993 return (PICL_FAILURE); 2994 } 2995 2996 err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2997 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(unitaddr)+1, 2998 PICL_PROP_UNIT_ADDRESS, NULL, NULL); 2999 if (err == PICL_SUCCESS) 3000 err = ptree_create_and_add_prop(nodeh, &pinfo, unitaddr, NULL); 3001 3002 return (err); 3003 } 3004 3005 /* 3006 * work out UnitAddress property of the specified node 3007 */ 3008 static int 3009 get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, char *unitaddr, 3010 size_t ualen) 3011 { 3012 int regproplen, err; 3013 uint32_t *regbuf; 3014 picl_prophdl_t regh; 3015 ptree_propinfo_t pinfo; 3016 unitaddr_map_t *uamap; 3017 uint32_t addrcells; 3018 3019 addrcells = get_addrcells_prop(parh); 3020 uamap = get_unitaddr_mapping(parh); 3021 3022 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 3023 if (err != PICL_SUCCESS) 3024 return (err); 3025 3026 err = ptree_get_propinfo(regh, &pinfo); 3027 if (err != PICL_SUCCESS) 3028 return (err); 3029 3030 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t))) 3031 return (PICL_FAILURE); 3032 3033 regproplen = pinfo.piclinfo.size; 3034 regbuf = alloca(regproplen); 3035 if (regbuf == NULL) 3036 return (PICL_FAILURE); 3037 3038 err = ptree_get_propval(regh, regbuf, regproplen); 3039 if (err != PICL_SUCCESS || uamap->func == NULL || 3040 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) || 3041 (uamap->func)(unitaddr, ualen, regbuf, addrcells) != 0) { 3042 return (PICL_FAILURE); 3043 } 3044 return (PICL_SUCCESS); 3045 } 3046 3047 /* 3048 * Add UnitAddress property to all children of the specified node 3049 */ 3050 static int 3051 add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh) 3052 { 3053 int err; 3054 picl_nodehdl_t chdh; 3055 unitaddr_map_t *uamap; 3056 uint32_t addrcells; 3057 3058 /* 3059 * Get #address-cells and unit address mapping entry for my 3060 * node's class 3061 */ 3062 addrcells = get_addrcells_prop(nodeh); 3063 uamap = get_unitaddr_mapping(nodeh); 3064 3065 /* 3066 * Add UnitAddress property to my children and their subtree 3067 */ 3068 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 3069 sizeof (picl_nodehdl_t)); 3070 3071 while (err == PICL_SUCCESS) { 3072 (void) add_unitaddr_prop(chdh, uamap, addrcells); 3073 (void) add_unitaddr_prop_to_subtree(chdh); 3074 3075 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 3076 sizeof (picl_nodehdl_t)); 3077 } 3078 3079 return (PICL_SUCCESS); 3080 } 3081 3082 static int 3083 update_memory_size_prop(picl_nodehdl_t plafh) 3084 { 3085 picl_nodehdl_t memh; 3086 picl_prophdl_t proph; 3087 ptree_propinfo_t pinfo; 3088 int err, nspecs, snum, pval; 3089 char *regbuf; 3090 memspecs_t *mspecs; 3091 uint64_t memsize; 3092 3093 /* 3094 * check if the #size-cells of the platform node is 2 3095 */ 3096 err = ptree_get_propval_by_name(plafh, OBP_PROP_SIZE_CELLS, &pval, 3097 sizeof (pval)); 3098 3099 if (err == PICL_PROPNOTFOUND) 3100 pval = SUPPORTED_NUM_CELL_SIZE; 3101 else if (err != PICL_SUCCESS) 3102 return (err); 3103 3104 /* 3105 * don't know how to handle other vals 3106 */ 3107 if (pval != SUPPORTED_NUM_CELL_SIZE) 3108 return (PICL_FAILURE); 3109 3110 err = ptree_get_node_by_path(MEMORY_PATH, &memh); 3111 if (err != PICL_SUCCESS) 3112 return (err); 3113 3114 /* 3115 * Get the REG property to calculate the size of memory 3116 */ 3117 err = ptree_get_prop_by_name(memh, OBP_REG, &proph); 3118 if (err != PICL_SUCCESS) 3119 return (err); 3120 3121 err = ptree_get_propinfo(proph, &pinfo); 3122 if (err != PICL_SUCCESS) 3123 return (err); 3124 3125 regbuf = alloca(pinfo.piclinfo.size); 3126 if (regbuf == NULL) 3127 return (PICL_FAILURE); 3128 3129 err = ptree_get_propval(proph, regbuf, pinfo.piclinfo.size); 3130 if (err != PICL_SUCCESS) 3131 return (err); 3132 3133 mspecs = (memspecs_t *)regbuf; 3134 nspecs = pinfo.piclinfo.size / sizeof (memspecs_t); 3135 3136 memsize = 0; 3137 for (snum = 0; snum < nspecs; ++snum) 3138 memsize += mspecs[snum].size; 3139 3140 err = ptree_get_prop_by_name(memh, PICL_PROP_SIZE, &proph); 3141 if (err == PICL_SUCCESS) { 3142 err = ptree_update_propval(proph, &memsize, sizeof (memsize)); 3143 return (err); 3144 } 3145 3146 /* 3147 * Add the size property 3148 */ 3149 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3150 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (memsize), 3151 PICL_PROP_SIZE, NULL, NULL); 3152 err = ptree_create_and_add_prop(memh, &pinfo, &memsize, NULL); 3153 return (err); 3154 } 3155 3156 /* 3157 * This function is executed as part of .init when the plugin is 3158 * dlopen()ed 3159 */ 3160 static void 3161 picldevtree_register(void) 3162 { 3163 if (getenv(SUNW_PICLDEVTREE_PLUGIN_DEBUG)) 3164 picldevtree_debug = 1; 3165 (void) picld_plugin_register(&my_reg_info); 3166 } 3167 3168 /* 3169 * This function is the init entry point of the plugin. 3170 * It initializes the /platform tree based on libdevinfo 3171 */ 3172 static void 3173 picldevtree_init(void) 3174 { 3175 picl_nodehdl_t rhdl; 3176 int err; 3177 struct utsname utsname; 3178 picl_nodehdl_t plafh; 3179 3180 if (uname(&utsname) < 0) 3181 return; 3182 3183 (void) strcpy(mach_name, utsname.machine); 3184 3185 if (strcmp(mach_name, "sun4u") == 0) { 3186 builtin_map_ptr = sun4u_map; 3187 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t); 3188 } else if (strcmp(mach_name, "i86pc") == 0) { 3189 builtin_map_ptr = i86pc_map; 3190 builtin_map_size = sizeof (i86pc_map) / sizeof (builtin_map_t); 3191 } else { 3192 builtin_map_ptr = NULL; 3193 builtin_map_size = 0; 3194 } 3195 3196 err = ptree_get_root(&rhdl); 3197 if (err != PICL_SUCCESS) { 3198 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED); 3199 return; 3200 } 3201 3202 process_devtree_conf_file(); 3203 3204 if (libdevinfo_init(rhdl) != PICL_SUCCESS) { 3205 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED); 3206 return; 3207 } 3208 3209 err = ptree_get_node_by_path(PLATFORM_PATH, &plafh); 3210 if (err != PICL_SUCCESS) 3211 return; 3212 3213 (void) add_unitaddr_prop_to_subtree(plafh); 3214 3215 add_asr_nodes(); 3216 3217 (void) update_memory_size_prop(plafh); 3218 3219 (void) setup_cpus(plafh); 3220 3221 (void) add_ffb_config_info(plafh); 3222 3223 (void) add_platform_info(plafh); 3224 3225 (void) set_pci_deviceid(plafh); 3226 3227 (void) set_sbus_slot(plafh); 3228 3229 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 3230 picldevtree_evhandler, NULL); 3231 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 3232 picldevtree_evhandler, NULL); 3233 } 3234 3235 /* 3236 * This function is the fini entry point of the plugin 3237 */ 3238 static void 3239 picldevtree_fini(void) 3240 { 3241 /* First unregister the event handlers */ 3242 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 3243 picldevtree_evhandler, NULL); 3244 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 3245 picldevtree_evhandler, NULL); 3246 3247 conf_name_class_map = free_conf_entries(conf_name_class_map); 3248 } 3249 3250 /* 3251 * This function is the event handler of this plug-in. 3252 * 3253 * It processes the following events: 3254 * 3255 * PICLEVENT_SYSEVENT_DEVICE_ADDED 3256 * PICLEVENT_SYSEVENT_DEVICE_REMOVED 3257 */ 3258 /* ARGSUSED */ 3259 static void 3260 picldevtree_evhandler(const char *ename, const void *earg, size_t size, 3261 void *cookie) 3262 { 3263 char *devfs_path; 3264 char ptreepath[PATH_MAX]; 3265 char dipath[PATH_MAX]; 3266 picl_nodehdl_t plafh; 3267 picl_nodehdl_t nodeh; 3268 nvlist_t *nvlp; 3269 3270 if (earg == NULL) 3271 return; 3272 3273 nvlp = NULL; 3274 if (ptree_get_node_by_path(PLATFORM_PATH, &plafh) != PICL_SUCCESS || 3275 nvlist_unpack((char *)earg, size, &nvlp, NULL) || 3276 nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &devfs_path) || 3277 strlen(devfs_path) > (PATH_MAX - sizeof (PLATFORM_PATH))) { 3278 syslog(LOG_INFO, PICL_EVENT_DROPPED, ename); 3279 if (nvlp) 3280 nvlist_free(nvlp); 3281 return; 3282 } 3283 3284 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX); 3285 (void) strlcat(ptreepath, devfs_path, PATH_MAX); 3286 (void) strlcpy(dipath, devfs_path, PATH_MAX); 3287 nvlist_free(nvlp); 3288 3289 if (picldevtree_debug) 3290 syslog(LOG_INFO, "picldevtree: event handler invoked ename:%s " 3291 "ptreepath:%s\n", ename, ptreepath); 3292 3293 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) { 3294 di_node_t devnode; 3295 char *strp; 3296 picl_nodehdl_t parh; 3297 char nodeclass[PICL_CLASSNAMELEN_MAX]; 3298 char *nodename; 3299 int err; 3300 3301 /* If the node already exist, then nothing else to do here */ 3302 if (ptree_get_node_by_path(ptreepath, &nodeh) == PICL_SUCCESS) 3303 return; 3304 3305 /* Skip if unable to find parent PICL node handle */ 3306 parh = plafh; 3307 if (((strp = strrchr(ptreepath, '/')) != NULL) && 3308 (strp != strchr(ptreepath, '/'))) { 3309 *strp = '\0'; 3310 if (ptree_get_node_by_path(ptreepath, &parh) != 3311 PICL_SUCCESS) 3312 return; 3313 } 3314 3315 /* 3316 * If parent is the root node 3317 */ 3318 if (parh == plafh) { 3319 ph = di_prom_init(); 3320 devnode = di_init(dipath, DINFOCPYALL); 3321 if (devnode == DI_NODE_NIL) { 3322 if (ph != NULL) { 3323 di_prom_fini(ph); 3324 ph = NULL; 3325 } 3326 return; 3327 } 3328 nodename = di_node_name(devnode); 3329 if (nodename == NULL) { 3330 di_fini(devnode); 3331 if (ph != NULL) { 3332 di_prom_fini(ph); 3333 ph = NULL; 3334 } 3335 return; 3336 } 3337 3338 err = get_node_class(nodeclass, devnode, nodename); 3339 if (err < 0) { 3340 di_fini(devnode); 3341 if (ph != NULL) { 3342 di_prom_fini(ph); 3343 ph = NULL; 3344 } 3345 return; 3346 } 3347 err = construct_devtype_node(plafh, nodename, 3348 nodeclass, devnode, &nodeh); 3349 if (err != PICL_SUCCESS) { 3350 di_fini(devnode); 3351 if (ph != NULL) { 3352 di_prom_fini(ph); 3353 ph = NULL; 3354 } 3355 return; 3356 } 3357 (void) update_subtree(nodeh, devnode); 3358 (void) add_unitaddr_prop_to_subtree(nodeh); 3359 if (ph != NULL) { 3360 di_prom_fini(ph); 3361 ph = NULL; 3362 } 3363 di_fini(devnode); 3364 goto done; 3365 } 3366 3367 /* kludge ... try without bus-addr first */ 3368 if ((strp = strrchr(dipath, '@')) != NULL) { 3369 char *p; 3370 3371 p = strrchr(dipath, '/'); 3372 if (p != NULL && strp > p) { 3373 *strp = '\0'; 3374 devnode = di_init(dipath, DINFOCPYALL); 3375 if (devnode != DI_NODE_NIL) 3376 di_fini(devnode); 3377 *strp = '@'; 3378 } 3379 } 3380 /* Get parent devnode */ 3381 if ((strp = strrchr(dipath, '/')) != NULL) 3382 *++strp = '\0'; 3383 devnode = di_init(dipath, DINFOCPYALL); 3384 if (devnode == DI_NODE_NIL) 3385 return; 3386 ph = di_prom_init(); 3387 (void) update_subtree(parh, devnode); 3388 (void) add_unitaddr_prop_to_subtree(parh); 3389 if (ph) { 3390 di_prom_fini(ph); 3391 ph = NULL; 3392 } 3393 di_fini(devnode); 3394 } else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) { 3395 char delclass[PICL_CLASSNAMELEN_MAX]; 3396 char *strp; 3397 3398 /* 3399 * if final element of path doesn't have a unit address 3400 * then it is not uniquely identifiable - cannot remove 3401 */ 3402 if (((strp = strrchr(ptreepath, '/')) != NULL) && 3403 strchr(strp, '@') == NULL) 3404 return; 3405 3406 /* skip if can't find the node */ 3407 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS) 3408 return; 3409 3410 if (ptree_delete_node(nodeh) != PICL_SUCCESS) 3411 return; 3412 3413 if (picldevtree_debug) 3414 syslog(LOG_INFO, 3415 "picldevtree: deleted node nodeh:%llx\n", nodeh); 3416 if ((ptree_get_propval_by_name(nodeh, 3417 PICL_PROP_CLASSNAME, delclass, PICL_CLASSNAMELEN_MAX) == 3418 PICL_SUCCESS) && IS_MC(delclass)) { 3419 if (post_mc_event(PICLEVENT_MC_REMOVED, nodeh) != 3420 PICL_SUCCESS) 3421 syslog(LOG_WARNING, PICL_EVENT_DROPPED, 3422 PICLEVENT_MC_REMOVED); 3423 } else 3424 (void) ptree_destroy_node(nodeh); 3425 } 3426 done: 3427 (void) setup_cpus(plafh); 3428 (void) add_ffb_config_info(plafh); 3429 (void) set_pci_deviceid(plafh); 3430 (void) set_sbus_slot(plafh); 3431 if (picldevtree_debug > 1) 3432 syslog(LOG_INFO, "picldevtree: event handler done\n"); 3433 } 3434