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_PCIEX, encode_pci_unitaddr, 0}, 254 {PICL_CLASS_UPA, encode_upa_unitaddr, 0}, 255 {PICL_CLASS_SCSI, encode_scsi_unitaddr, 0}, 256 {PICL_CLASS_SCSI2, encode_scsi_unitaddr, 0}, 257 {PICL_CLASS_EBUS, encode_default_unitaddr, 2}, 258 {PICL_CLASS_SBUS, encode_default_unitaddr, 2}, 259 {PICL_CLASS_I2C, encode_default_unitaddr, 2}, 260 {PICL_CLASS_USB, encode_default_unitaddr, 1}, 261 {PICL_CLASS_PMU, encode_optional_unitaddr, 2}, 262 {NULL, encode_default_unitaddr, 0} 263 }; 264 265 static int add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh); 266 static int get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, 267 char *unitaddr, size_t ualen); 268 static void set_pci_pciex_deviceid(picl_nodehdl_t plafh); 269 270 /* 271 * The mc event completion handler. 272 * The arguments are event name buffer and a packed nvlist buffer 273 * with the size specifying the size of unpacked nvlist. These 274 * buffers are deallcoated here. 275 * 276 * Also, if a memory controller node is being removed then destroy the 277 * PICL subtree associated with that memory controller. 278 */ 279 static void 280 mc_completion_handler(char *ename, void *earg, size_t size) 281 { 282 picl_nodehdl_t mch; 283 nvlist_t *unpack_nvl; 284 285 if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0 && 286 nvlist_unpack(earg, size, &unpack_nvl, NULL) == 0) { 287 mch = NULL; 288 (void) nvlist_lookup_uint64(unpack_nvl, 289 PICLEVENTARG_NODEHANDLE, &mch); 290 if (mch != NULL) { 291 if (picldevtree_debug) 292 syslog(LOG_INFO, 293 "picldevtree: destroying_node:%llx\n", 294 mch); 295 (void) ptree_destroy_node(mch); 296 } 297 nvlist_free(unpack_nvl); 298 } 299 300 free(ename); 301 free(earg); 302 } 303 304 /* 305 * Functions to post memory controller change event 306 */ 307 static int 308 post_mc_event(char *ename, picl_nodehdl_t mch) 309 { 310 nvlist_t *nvl; 311 size_t nvl_size; 312 char *pack_buf; 313 char *ev_name; 314 315 ev_name = strdup(ename); 316 if (ev_name == NULL) 317 return (-1); 318 319 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) { 320 free(ev_name); 321 return (-1); 322 } 323 324 pack_buf = NULL; 325 if (nvlist_add_uint64(nvl, PICLEVENTARG_NODEHANDLE, mch) || 326 nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE, NULL)) { 327 free(ev_name); 328 nvlist_free(nvl); 329 return (-1); 330 } 331 332 if (picldevtree_debug) 333 syslog(LOG_INFO, 334 "picldevtree: posting MC event ename:%s nodeh:%llx\n", 335 ev_name, mch); 336 if (ptree_post_event(ev_name, pack_buf, nvl_size, 337 mc_completion_handler) != PICL_SUCCESS) { 338 free(ev_name); 339 nvlist_free(nvl); 340 return (-1); 341 } 342 nvlist_free(nvl); 343 return (0); 344 } 345 346 /* 347 * Lookup a name in the name to class map tables 348 */ 349 static int 350 lookup_name_class_map(char *classbuf, const char *nm) 351 { 352 conf_entries_t *ptr; 353 int i; 354 355 /* 356 * check name to class mapping in conf file 357 */ 358 ptr = conf_name_class_map; 359 360 while (ptr != NULL) { 361 if (strcmp(ptr->name, nm) == 0) { 362 (void) strlcpy(classbuf, ptr->piclclass, 363 PICL_CLASSNAMELEN_MAX); 364 return (0); 365 } 366 ptr = ptr->next; 367 } 368 369 /* 370 * check name to class mapping in builtin table 371 */ 372 if (builtin_map_ptr == NULL) 373 return (-1); 374 375 for (i = 0; i < builtin_map_size; ++i) 376 if (strcmp(builtin_map_ptr[i].name, nm) == 0) { 377 (void) strlcpy(classbuf, builtin_map_ptr[i].piclclass, 378 PICL_CLASSNAMELEN_MAX); 379 return (0); 380 } 381 return (-1); 382 } 383 384 /* 385 * Lookup a prop name in the pname to class map table 386 */ 387 static int 388 lookup_pname_type_map(const char *pname, picl_prop_type_t *type) 389 { 390 int i; 391 392 for (i = 0; i < PNAME_MAP_SIZE; ++i) 393 if (strcmp(pname_type_map[i].pname, pname) == 0) { 394 *type = pname_type_map[i].type; 395 return (0); 396 } 397 398 return (-1); 399 } 400 401 /* 402 * Return the number of strings in the buffer 403 */ 404 static int 405 get_string_count(char *strdat, int length) 406 { 407 int count; 408 char *lastnull; 409 char *nullptr; 410 411 count = 1; 412 for (lastnull = &strdat[length - 1], nullptr = strchr(strdat, '\0'); 413 nullptr != lastnull; nullptr = strchr(nullptr+1, '\0')) 414 count++; 415 416 return (count); 417 } 418 419 /* 420 * Return 1 if the node has a "reg" property 421 */ 422 static int 423 has_reg_prop(di_node_t dn) 424 { 425 int *pdata; 426 int dret; 427 428 dret = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, OBP_REG, &pdata); 429 if (dret > 0) 430 return (1); 431 432 if (!ph) 433 return (0); 434 dret = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata); 435 return (dret < 0 ? 0 : 1); 436 } 437 438 /* 439 * This function copies a PROM node's device_type property value into the 440 * buffer given by outbuf. The buffer size is PICL_CLASSNAMELEN_MAX. 441 * 442 * We reclassify device_type 'fru-prom' to PICL class 'seeprom' 443 * for FRUID support. 444 */ 445 static int 446 get_device_type(char *outbuf, di_node_t dn) 447 { 448 char *pdata; 449 char *pdatap; 450 int dret; 451 int i; 452 453 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_DEVICETYPE, 454 &pdata); 455 if (dret <= 0) { 456 if (!ph) 457 return (-1); 458 459 dret = di_prom_prop_lookup_strings(ph, dn, OBP_DEVICETYPE, 460 &pdata); 461 if (dret <= 0) { 462 return (-1); 463 } 464 } 465 466 if (dret != 1) { 467 /* 468 * multiple strings 469 */ 470 pdatap = pdata; 471 for (i = 0; i < (dret - 1); ++i) { 472 pdatap += strlen(pdatap); 473 *pdatap = '-'; /* replace '\0' with '-' */ 474 pdatap++; 475 } 476 } 477 if (strcasecmp(pdata, "fru-prom") == 0) { 478 /* 479 * Use PICL 'seeprom' class for fru-prom device types 480 */ 481 (void) strlcpy(outbuf, PICL_CLASS_SEEPROM, 482 PICL_CLASSNAMELEN_MAX); 483 } else { 484 (void) strlcpy(outbuf, pdata, PICL_CLASSNAMELEN_MAX); 485 } 486 return (0); 487 } 488 489 /* 490 * Get the minor node name in the class buffer passed 491 */ 492 static int 493 get_minor_class(char *classbuf, di_node_t dn) 494 { 495 di_minor_t mi_node; 496 char *mi_nodetype; 497 char *mi_name; 498 499 /* get minor node type */ 500 mi_node = di_minor_next(dn, DI_MINOR_NIL); 501 if (mi_node == DI_MINOR_NIL) 502 return (-1); 503 504 mi_nodetype = di_minor_nodetype(mi_node); 505 if (mi_nodetype == NULL) { /* no type info, return name */ 506 mi_name = di_minor_name(mi_node); 507 if (mi_name == NULL) 508 return (-1); 509 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX); 510 return (0); 511 } 512 513 #define DDI_NODETYPE(x, y) (strncmp(x, y, (sizeof (y) - 1)) == 0) 514 515 /* 516 * convert the string to the picl class for non-peudo nodes 517 */ 518 if (DDI_NODETYPE(mi_nodetype, DDI_PSEUDO)) 519 return (-1); 520 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_WWN)) 521 (void) strcpy(classbuf, PICL_CLASS_BLOCK); 522 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_CHAN)) 523 (void) strcpy(classbuf, PICL_CLASS_BLOCK); 524 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD)) 525 (void) strcpy(classbuf, PICL_CLASS_CDROM); 526 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD_CHAN)) 527 (void) strcpy(classbuf, PICL_CLASS_CDROM); 528 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_FD)) 529 (void) strcpy(classbuf, PICL_CLASS_FLOPPY); 530 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_FABRIC)) 531 (void) strcpy(classbuf, PICL_CLASS_FABRIC); 532 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK)) 533 (void) strcpy(classbuf, PICL_CLASS_BLOCK); 534 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_MOUSE)) 535 (void) strcpy(classbuf, PICL_CLASS_MOUSE); 536 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_KEYBOARD)) 537 (void) strcpy(classbuf, PICL_CLASS_KEYBOARD); 538 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ATTACHMENT_POINT)) 539 (void) strcpy(classbuf, PICL_CLASS_ATTACHMENT_POINT); 540 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_TAPE)) 541 (void) strcpy(classbuf, PICL_CLASS_TAPE); 542 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_SCSI_ENCLOSURE)) 543 (void) strcpy(classbuf, PICL_CLASS_SCSI); 544 else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ENCLOSURE)) { 545 char *colon; 546 547 if ((colon = strchr(mi_nodetype, ':')) == NULL) 548 return (-1); 549 ++colon; 550 (void) strcpy(classbuf, colon); 551 } else { /* unrecognized type, return name */ 552 mi_name = di_minor_name(mi_node); 553 if (mi_name == NULL) 554 return (-1); 555 (void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX); 556 } 557 return (0); 558 } 559 560 /* 561 * Derive PICL class using the compatible property of the node 562 * We use the map table to map compatible property value to 563 * class. 564 */ 565 static int 566 get_compatible_class(char *outbuf, di_node_t dn) 567 { 568 char *pdata; 569 char *pdatap; 570 int dret; 571 int i; 572 573 dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_COMPATIBLE, 574 &pdata); 575 if (dret <= 0) { 576 if (!ph) 577 return (-1); 578 579 dret = di_prom_prop_lookup_strings(ph, dn, OBP_COMPATIBLE, 580 &pdata); 581 if (dret <= 0) { 582 return (-1); 583 } 584 } 585 586 pdatap = pdata; 587 for (i = 0; i < dret; ++i) { 588 if (lookup_name_class_map(outbuf, pdatap) == 0) 589 return (0); 590 pdatap += strlen(pdatap); 591 pdatap++; 592 } 593 return (-1); 594 } 595 596 /* 597 * For a given device node find the PICL class to use. Returns NULL 598 * for non device node 599 */ 600 static int 601 get_node_class(char *classbuf, di_node_t dn, const char *nodename) 602 { 603 if (get_device_type(classbuf, dn) == 0) { 604 if (di_nodeid(dn) == DI_PROM_NODEID) { 605 /* 606 * discard place holder nodes 607 */ 608 if ((strcmp(classbuf, DEVICE_TYPE_BLOCK) == 0) || 609 (strcmp(classbuf, DEVICE_TYPE_BYTE) == 0) || 610 (strcmp(classbuf, DEVICE_TYPE_SES) == 0) || 611 (strcmp(classbuf, DEVICE_TYPE_FP) == 0) || 612 (strcmp(classbuf, DEVICE_TYPE_DISK) == 0)) 613 return (-1); 614 615 return (0); 616 } 617 return (0); /* return device_type value */ 618 } 619 620 if (get_compatible_class(classbuf, dn) == 0) { 621 return (0); /* derive class using compatible prop */ 622 } 623 624 if (lookup_name_class_map(classbuf, nodename) == 0) 625 return (0); /* derive class using name prop */ 626 627 if (has_reg_prop(dn)) { /* use default obp-device */ 628 (void) strcpy(classbuf, PICL_CLASS_OBP_DEVICE); 629 return (0); 630 } 631 632 return (get_minor_class(classbuf, dn)); 633 } 634 635 /* 636 * Add a table property containing nrows with one column 637 */ 638 static int 639 add_string_list_prop(picl_nodehdl_t nodeh, char *name, char *strlist, 640 unsigned int nrows) 641 { 642 ptree_propinfo_t propinfo; 643 picl_prophdl_t proph; 644 picl_prophdl_t tblh; 645 int err; 646 unsigned int i; 647 unsigned int j; 648 picl_prophdl_t *proprow; 649 int len; 650 651 #define NCOLS_IN_STRING_TABLE 1 652 653 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 654 PICL_PTYPE_TABLE, PICL_READ, sizeof (picl_prophdl_t), name, 655 NULL, NULL); 656 if (err != PICL_SUCCESS) 657 return (err); 658 659 err = ptree_create_table(&tblh); 660 if (err != PICL_SUCCESS) 661 return (err); 662 663 err = ptree_create_and_add_prop(nodeh, &propinfo, &tblh, &proph); 664 if (err != PICL_SUCCESS) 665 return (err); 666 667 proprow = alloca(sizeof (picl_prophdl_t) * nrows); 668 if (proprow == NULL) { 669 (void) ptree_destroy_prop(proph); 670 return (PICL_FAILURE); 671 } 672 673 for (j = 0; j < nrows; ++j) { 674 len = strlen(strlist) + 1; 675 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 676 PICL_PTYPE_CHARSTRING, PICL_READ, len, name, 677 NULL, NULL); 678 if (err != PICL_SUCCESS) 679 break; 680 err = ptree_create_prop(&propinfo, strlist, &proprow[j]); 681 if (err != PICL_SUCCESS) 682 break; 683 strlist += len; 684 err = ptree_add_row_to_table(tblh, NCOLS_IN_STRING_TABLE, 685 &proprow[j]); 686 if (err != PICL_SUCCESS) 687 break; 688 } 689 690 if (err != PICL_SUCCESS) { 691 for (i = 0; i < j; ++i) 692 (void) ptree_destroy_prop(proprow[i]); 693 (void) ptree_delete_prop(proph); 694 (void) ptree_destroy_prop(proph); 695 return (err); 696 } 697 698 return (PICL_SUCCESS); 699 } 700 701 /* 702 * return 1 if this node has this property with the given value 703 */ 704 static int 705 compare_string_propval(picl_nodehdl_t nodeh, const char *pname, 706 const char *pval) 707 { 708 char *pvalbuf; 709 int err; 710 int len; 711 ptree_propinfo_t pinfo; 712 picl_prophdl_t proph; 713 714 err = ptree_get_prop_by_name(nodeh, pname, &proph); 715 if (err != PICL_SUCCESS) /* prop doesn't exist */ 716 return (0); 717 718 err = ptree_get_propinfo(proph, &pinfo); 719 if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING) 720 return (0); /* not string prop */ 721 722 len = strlen(pval) + 1; 723 724 pvalbuf = alloca(len); 725 if (pvalbuf == NULL) 726 return (0); 727 728 err = ptree_get_propval(proph, pvalbuf, len); 729 if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0)) 730 return (1); /* prop match */ 731 732 return (0); 733 } 734 735 /* 736 * This function recursively searches the tree for a node that has 737 * the specified string property name and value 738 */ 739 static int 740 find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname, 741 const char *pval, picl_nodehdl_t *nodeh) 742 { 743 picl_nodehdl_t childh; 744 int err; 745 746 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh, 747 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 748 err = ptree_get_propval_by_name(childh, PICL_PROP_PEER, &childh, 749 sizeof (picl_nodehdl_t))) { 750 if (err != PICL_SUCCESS) 751 return (err); 752 753 if (compare_string_propval(childh, pname, pval)) { 754 *nodeh = childh; 755 return (PICL_SUCCESS); 756 } 757 758 if (find_node_by_string_prop(childh, pname, pval, nodeh) == 759 PICL_SUCCESS) 760 return (PICL_SUCCESS); 761 } 762 763 return (PICL_FAILURE); 764 } 765 766 /* 767 * check if this is a string prop 768 * If the length is less than or equal to 4, assume it's not a string list. 769 * If there is any non-ascii or non-print char, it's not a string prop 770 * If \0 is in the first char or any two consecutive \0's exist, 771 * it's a bytearray prop. 772 * Return value: 0 means it's not a string prop, 1 means it's a string prop 773 */ 774 static int 775 is_string_propval(unsigned char *pdata, int len) 776 { 777 int i; 778 int lastindex; 779 int prevnull = -1; 780 781 switch (len) { 782 case 1: 783 if (!isascii(pdata[0]) || !isprint(pdata[0])) 784 return (0); 785 return (1); 786 case 2: 787 case 3: 788 case 4: 789 lastindex = len; 790 if (pdata[len-1] == '\0') 791 lastindex = len - 1; 792 793 for (i = 0; i < lastindex; i++) 794 if (!isascii(pdata[i]) || !isprint(pdata[i])) 795 return (0); 796 797 return (1); 798 799 default: 800 if (len <= 0) 801 return (0); 802 for (i = 0; i < len; i++) { 803 if (!isascii(pdata[i]) || !isprint(pdata[i])) { 804 if (pdata[i] != '\0') 805 return (0); 806 /* 807 * if the null char is in the first char 808 * or two consecutive nulls' exist, 809 * it's a bytearray prop 810 */ 811 if ((i == 0) || ((i - prevnull) == 1)) 812 return (0); 813 814 prevnull = i; 815 } 816 } 817 break; 818 } 819 820 return (1); 821 } 822 823 /* 824 * This function counts the number of strings in the value buffer pdata 825 * and creates a property. 826 * If there is only one string in the buffer, pdata, a charstring property 827 * type is created and added. 828 * If there are more than one string in the buffer, pdata, then a table 829 * of charstrings is added. 830 */ 831 static int 832 process_charstring_data(picl_nodehdl_t nodeh, char *pname, unsigned char *pdata, 833 int retval) 834 { 835 int err; 836 int strcount; 837 char *strdat; 838 ptree_propinfo_t propinfo; 839 840 /* 841 * append the null char at the end of string when there is 842 * no null terminator 843 */ 844 if (pdata[retval - 1] != '\0') { 845 strdat = alloca(retval + 1); 846 (void) memcpy(strdat, pdata, retval); 847 strdat[retval] = '\0'; 848 retval++; 849 } else { 850 strdat = alloca(retval); 851 (void) memcpy(strdat, pdata, retval); 852 } 853 854 /* 855 * If it's a string list, create a table prop 856 */ 857 strcount = get_string_count(strdat, retval); 858 if (strcount > 1) { 859 err = add_string_list_prop(nodeh, pname, 860 strdat, strcount); 861 if (err != PICL_SUCCESS) 862 return (err); 863 } else { 864 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 865 PICL_PTYPE_CHARSTRING, PICL_READ, 866 strlen(strdat) + 1, pname, NULL, 867 NULL); 868 if (err != PICL_SUCCESS) 869 return (err); 870 (void) ptree_create_and_add_prop(nodeh, &propinfo, 871 strdat, NULL); 872 } 873 return (PICL_SUCCESS); 874 } 875 876 /* 877 * Add the OBP properties as properties of the PICL node 878 */ 879 static int 880 add_openprom_props(picl_nodehdl_t nodeh, di_node_t di_node) 881 { 882 di_prom_prop_t promp; 883 char *pname; 884 unsigned char *pdata; 885 int retval; 886 ptree_propinfo_t propinfo; 887 int err; 888 picl_prop_type_t type; 889 890 if (!ph) 891 return (PICL_FAILURE); 892 893 for (promp = di_prom_prop_next(ph, di_node, DI_PROM_PROP_NIL); 894 promp != DI_PROM_PROP_NIL; 895 promp = di_prom_prop_next(ph, di_node, promp)) { 896 897 pname = di_prom_prop_name(promp); 898 899 retval = di_prom_prop_data(promp, &pdata); 900 if (retval < 0) { 901 return (PICL_SUCCESS); 902 } 903 if (retval == 0) { 904 err = ptree_init_propinfo(&propinfo, 905 PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID, 906 PICL_READ, (size_t)0, pname, NULL, NULL); 907 if (err != PICL_SUCCESS) { 908 return (err); 909 } 910 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, 911 NULL); 912 continue; 913 } 914 915 /* 916 * Get the prop type from pname map table 917 */ 918 if (lookup_pname_type_map(pname, &type) == 0) { 919 if (type == PICL_PTYPE_CHARSTRING) { 920 err = process_charstring_data(nodeh, pname, 921 pdata, retval); 922 if (err != PICL_SUCCESS) { 923 return (err); 924 } 925 continue; 926 } 927 928 err = ptree_init_propinfo(&propinfo, 929 PTREE_PROPINFO_VERSION, type, PICL_READ, 930 retval, pname, NULL, NULL); 931 if (err != PICL_SUCCESS) { 932 return (err); 933 } 934 (void) ptree_create_and_add_prop(nodeh, &propinfo, 935 pdata, NULL); 936 } else if (!is_string_propval(pdata, retval)) { 937 switch (retval) { 938 case sizeof (uint8_t): 939 /*FALLTHROUGH*/ 940 case sizeof (uint16_t): 941 /*FALLTHROUGH*/ 942 case sizeof (uint32_t): 943 type = PICL_PTYPE_UNSIGNED_INT; 944 break; 945 default: 946 type = PICL_PTYPE_BYTEARRAY; 947 break; 948 } 949 err = ptree_init_propinfo(&propinfo, 950 PTREE_PROPINFO_VERSION, type, PICL_READ, 951 retval, pname, NULL, NULL); 952 if (err != PICL_SUCCESS) { 953 return (err); 954 } 955 (void) ptree_create_and_add_prop(nodeh, &propinfo, 956 pdata, NULL); 957 } else { 958 err = process_charstring_data(nodeh, pname, pdata, 959 retval); 960 if (err != PICL_SUCCESS) { 961 return (err); 962 } 963 } 964 } 965 966 return (PICL_SUCCESS); 967 } 968 969 /* 970 * Add properties provided by libdevinfo 971 */ 972 static void 973 add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node) 974 { 975 int instance; 976 char *di_val; 977 di_prop_t di_prop; 978 int di_ptype; 979 ptree_propinfo_t propinfo; 980 981 instance = di_instance(di_node); 982 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 983 PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE, 984 NULL, NULL); 985 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL); 986 987 di_val = di_bus_addr(di_node); 988 if (di_val) { 989 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 990 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 991 PICL_PROP_BUS_ADDR, NULL, NULL); 992 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 993 NULL); 994 } 995 996 di_val = di_binding_name(di_node); 997 if (di_val) { 998 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 999 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1000 PICL_PROP_BINDING_NAME, NULL, NULL); 1001 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1002 NULL); 1003 } 1004 1005 di_val = di_driver_name(di_node); 1006 if (di_val) { 1007 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1008 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1009 PICL_PROP_DRIVER_NAME, NULL, NULL); 1010 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1011 NULL); 1012 } 1013 1014 di_val = di_devfs_path(di_node); 1015 if (di_val) { 1016 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1017 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1018 PICL_PROP_DEVFS_PATH, NULL, NULL); 1019 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1020 NULL); 1021 di_devfs_path_free(di_val); 1022 } 1023 1024 for (di_prop = di_prop_next(di_node, DI_PROP_NIL); 1025 di_prop != DI_PROP_NIL; 1026 di_prop = di_prop_next(di_node, di_prop)) { 1027 1028 di_val = di_prop_name(di_prop); 1029 di_ptype = di_prop_type(di_prop); 1030 switch (di_ptype) { 1031 case DI_PROP_TYPE_BOOLEAN: 1032 (void) ptree_init_propinfo(&propinfo, 1033 PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID, 1034 PICL_READ, (size_t)0, di_val, NULL, NULL); 1035 (void) ptree_create_and_add_prop(nodeh, &propinfo, 1036 NULL, NULL); 1037 break; 1038 case DI_PROP_TYPE_INT: { 1039 int *idata; 1040 int len; 1041 1042 len = di_prop_ints(di_prop, &idata); 1043 if (len < 0) 1044 /* Recieved error, so ignore prop */ 1045 break; 1046 1047 if (len == 1) 1048 (void) ptree_init_propinfo(&propinfo, 1049 PTREE_PROPINFO_VERSION, PICL_PTYPE_INT, 1050 PICL_READ, len * sizeof (int), di_val, 1051 NULL, NULL); 1052 else 1053 (void) ptree_init_propinfo(&propinfo, 1054 PTREE_PROPINFO_VERSION, 1055 PICL_PTYPE_BYTEARRAY, PICL_READ, 1056 len * sizeof (int), di_val, 1057 NULL, NULL); 1058 1059 (void) ptree_create_and_add_prop(nodeh, &propinfo, 1060 idata, NULL); 1061 } 1062 break; 1063 case DI_PROP_TYPE_STRING: { 1064 char *sdata; 1065 int len; 1066 1067 len = di_prop_strings(di_prop, &sdata); 1068 if (len < 0) 1069 break; 1070 1071 if (len == 1) { 1072 (void) ptree_init_propinfo(&propinfo, 1073 PTREE_PROPINFO_VERSION, 1074 PICL_PTYPE_CHARSTRING, PICL_READ, 1075 strlen(sdata) + 1, di_val, 1076 NULL, NULL); 1077 (void) ptree_create_and_add_prop(nodeh, 1078 &propinfo, sdata, NULL); 1079 } else { 1080 (void) add_string_list_prop(nodeh, di_val, 1081 sdata, len); 1082 } 1083 } 1084 break; 1085 case DI_PROP_TYPE_BYTE: { 1086 int len; 1087 unsigned char *bdata; 1088 1089 len = di_prop_bytes(di_prop, &bdata); 1090 if (len < 0) 1091 break; 1092 (void) ptree_init_propinfo(&propinfo, 1093 PTREE_PROPINFO_VERSION, PICL_PTYPE_BYTEARRAY, 1094 PICL_READ, len, di_val, NULL, NULL); 1095 (void) ptree_create_and_add_prop(nodeh, &propinfo, 1096 bdata, NULL); 1097 } 1098 break; 1099 case DI_PROP_TYPE_UNKNOWN: 1100 break; 1101 case DI_PROP_TYPE_UNDEF_IT: 1102 break; 1103 default: 1104 break; 1105 } 1106 } 1107 } 1108 1109 /* 1110 * This function creates the /obp node in the PICL tree for OBP nodes 1111 * without a device type class. 1112 */ 1113 static int 1114 construct_picl_openprom(picl_nodehdl_t rooth, picl_nodehdl_t *obph) 1115 { 1116 picl_nodehdl_t tmph; 1117 int err; 1118 1119 err = ptree_create_and_add_node(rooth, PICL_NODE_OBP, 1120 PICL_CLASS_PICL, &tmph); 1121 1122 if (err != PICL_SUCCESS) 1123 return (err); 1124 *obph = tmph; 1125 return (PICL_SUCCESS); 1126 } 1127 1128 /* 1129 * This function creates the /platform node in the PICL tree and 1130 * its properties. It sets the "platform-name" property to the 1131 * platform name 1132 */ 1133 static int 1134 construct_picl_platform(picl_nodehdl_t rooth, di_node_t di_root, 1135 picl_nodehdl_t *piclh) 1136 { 1137 int err; 1138 picl_nodehdl_t plafh; 1139 char *nodename; 1140 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1141 ptree_propinfo_t propinfo; 1142 picl_prophdl_t proph; 1143 1144 nodename = di_node_name(di_root); 1145 if (nodename == NULL) 1146 return (PICL_FAILURE); 1147 1148 err = 0; 1149 if (di_nodeid(di_root) == DI_PROM_NODEID || 1150 di_nodeid(di_root) == DI_SID_NODEID) 1151 err = get_device_type(nodeclass, di_root); 1152 1153 if (err < 0) 1154 (void) strcpy(nodeclass, PICL_CLASS_UPA); /* default */ 1155 1156 err = ptree_create_and_add_node(rooth, PICL_NODE_PLATFORM, 1157 nodeclass, &plafh); 1158 if (err != PICL_SUCCESS) 1159 return (err); 1160 1161 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1162 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(nodename) + 1, 1163 PICL_PROP_PLATFORM_NAME, NULL, NULL); 1164 err = ptree_create_and_add_prop(plafh, &propinfo, nodename, &proph); 1165 if (err != PICL_SUCCESS) 1166 return (err); 1167 1168 (void) add_devinfo_props(plafh, di_root); 1169 1170 (void) add_openprom_props(plafh, di_root); 1171 1172 *piclh = plafh; 1173 1174 return (PICL_SUCCESS); 1175 } 1176 1177 /* 1178 * This function creates a node in /obp tree for the libdevinfo handle. 1179 */ 1180 static int 1181 construct_obp_node(picl_nodehdl_t parh, di_node_t dn, picl_nodehdl_t *chdh) 1182 { 1183 int err; 1184 char *nodename; 1185 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1186 picl_nodehdl_t anodeh; 1187 1188 nodename = di_node_name(dn); /* PICL_PROP_NAME */ 1189 if (nodename == NULL) 1190 return (PICL_FAILURE); 1191 1192 if (strcmp(nodename, "pseudo") == 0) 1193 return (PICL_FAILURE); 1194 1195 if ((di_nodeid(dn) == DI_PROM_NODEID) && 1196 (get_device_type(nodeclass, dn) == 0)) 1197 return (PICL_FAILURE); 1198 1199 err = ptree_create_and_add_node(parh, nodename, nodename, &anodeh); 1200 if (err != PICL_SUCCESS) 1201 return (err); 1202 1203 add_devinfo_props(anodeh, dn); 1204 1205 (void) add_openprom_props(anodeh, dn); 1206 1207 *chdh = anodeh; 1208 1209 return (PICL_SUCCESS); 1210 } 1211 1212 /* 1213 * This function creates a PICL node in /platform tree for a device 1214 */ 1215 static int 1216 construct_devtype_node(picl_nodehdl_t parh, char *nodename, 1217 char *nodeclass, di_node_t dn, picl_nodehdl_t *chdh) 1218 { 1219 int err; 1220 picl_nodehdl_t anodeh; 1221 1222 err = ptree_create_and_add_node(parh, nodename, nodeclass, &anodeh); 1223 if (err != PICL_SUCCESS) 1224 return (err); 1225 1226 (void) add_devinfo_props(anodeh, dn); 1227 (void) add_openprom_props(anodeh, dn); 1228 1229 *chdh = anodeh; 1230 return (err); 1231 } 1232 1233 /* 1234 * Create a subtree of "picl" class nodes in /obp for these nodes 1235 */ 1236 static int 1237 construct_openprom_tree(picl_nodehdl_t nodeh, di_node_t dinode) 1238 { 1239 di_node_t cnode; 1240 picl_nodehdl_t chdh; 1241 int err; 1242 1243 err = construct_obp_node(nodeh, dinode, &chdh); 1244 if (err != PICL_SUCCESS) 1245 return (err); 1246 1247 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1248 cnode = di_sibling_node(cnode)) 1249 (void) construct_openprom_tree(chdh, cnode); 1250 1251 return (PICL_SUCCESS); 1252 1253 } 1254 1255 /* 1256 * Process the libdevinfo device tree and create nodes in /platform or /obp 1257 * PICL tree. 1258 * 1259 * This routine traverses the immediate children of "dinode" device and 1260 * determines the node class for that child. If it finds a valid class 1261 * name, then it builds a PICL node under /platform subtree and calls itself 1262 * recursively to construct the subtree for that child node. Otherwise, if 1263 * the parent_class is NULL, then it constructs a node and subtree under /obp 1264 * subtree. 1265 * 1266 * Note that we skip the children nodes that don't have a valid class name 1267 * and the parent_class is non NULL to prevent creation of any placeholder 1268 * nodes (such as sd,...). 1269 */ 1270 static int 1271 construct_devinfo_tree(picl_nodehdl_t plafh, picl_nodehdl_t obph, 1272 di_node_t dinode, char *parent_class) 1273 { 1274 di_node_t cnode; 1275 picl_nodehdl_t chdh; 1276 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1277 char *nodename; 1278 int err; 1279 1280 err = PICL_SUCCESS; 1281 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1282 cnode = di_sibling_node(cnode)) { 1283 nodename = di_node_name(cnode); /* PICL_PROP_NAME */ 1284 if (nodename == NULL) 1285 continue; 1286 1287 err = get_node_class(nodeclass, cnode, nodename); 1288 1289 if (err == 0) { 1290 err = construct_devtype_node(plafh, nodename, 1291 nodeclass, cnode, &chdh); 1292 if (err != PICL_SUCCESS) 1293 return (err); 1294 err = construct_devinfo_tree(chdh, obph, cnode, 1295 nodeclass); 1296 } else if (parent_class == NULL) 1297 err = construct_openprom_tree(obph, cnode); 1298 else 1299 continue; 1300 /* 1301 * if parent_class is non NULL, skip the children nodes 1302 * that don't have a valid device class - eliminates 1303 * placeholder nodes (sd,...) from being created. 1304 */ 1305 } 1306 1307 return (err); 1308 1309 } 1310 1311 /* 1312 * This function is called from the event handler called from the daemon 1313 * on PICL events. 1314 * 1315 * This routine traverses the children of the "dinode" device and 1316 * creates a PICL node for each child not found in the PICL tree and 1317 * invokes itself recursively to create a subtree for the newly created 1318 * child node. It also checks if the node being created is a meory 1319 * controller. If so, it posts PICLEVENT_MC_ADDED PICL event to the PICL 1320 * framework. 1321 */ 1322 static int 1323 update_subtree(picl_nodehdl_t nodeh, di_node_t dinode) 1324 { 1325 di_node_t cnode; 1326 picl_nodehdl_t chdh; 1327 picl_nodehdl_t nh; 1328 char *nodename; 1329 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1330 char *path_buf; 1331 char buf[MAX_UNIT_ADDRESS_LEN]; 1332 char unitaddr[MAX_UNIT_ADDRESS_LEN]; 1333 char path_w_ua[MAXPATHLEN]; 1334 char path_wo_ua[MAXPATHLEN]; 1335 char *strp; 1336 int gotit; 1337 int err; 1338 1339 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1340 cnode = di_sibling_node(cnode)) { 1341 path_buf = di_devfs_path(cnode); 1342 if (path_buf == NULL) 1343 continue; 1344 1345 nodename = di_node_name(cnode); 1346 if (nodename == NULL) { 1347 di_devfs_path_free(path_buf); 1348 continue; 1349 } 1350 1351 err = get_node_class(nodeclass, cnode, nodename); 1352 1353 if (err < 0) { 1354 di_devfs_path_free(path_buf); 1355 continue; 1356 } 1357 1358 /* 1359 * this is quite complicated - both path_buf and any nodes 1360 * already in the picl tree may, or may not, have the 1361 * @<unit_addr> at the end of their names. So we must 1362 * take path_buf and work out what the device path would 1363 * be both with and without the unit_address, then search 1364 * the picl tree for both forms. 1365 */ 1366 if (((strp = strrchr(path_buf, '/')) != NULL) && 1367 strchr(strp, '@') == NULL) { 1368 /* 1369 * this is an unattached node - so the path is not 1370 * unique. Need to find out which node it is. 1371 * Find the unit_address from the obp properties. 1372 */ 1373 err = ptree_create_node(nodename, nodeclass, &chdh); 1374 if (err != PICL_SUCCESS) 1375 return (err); 1376 (void) add_openprom_props(chdh, cnode); 1377 err = get_unitaddr(nodeh, chdh, unitaddr, 1378 sizeof (unitaddr)); 1379 if (err != PICL_SUCCESS) 1380 return (err); 1381 (void) ptree_destroy_node(chdh); 1382 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s@%s", 1383 path_buf, unitaddr); 1384 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1385 path_buf); 1386 } else { 1387 /* 1388 * this is an attached node - so the path is unique 1389 */ 1390 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s", 1391 path_buf); 1392 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1393 path_buf); 1394 strp = strrchr(path_wo_ua, '@'); 1395 *strp++ = '\0'; 1396 (void) snprintf(unitaddr, sizeof (unitaddr), "%s", 1397 strp); 1398 } 1399 /* 1400 * first look for node with unit address in devfs_path 1401 */ 1402 if (ptree_find_node(nodeh, PICL_PROP_DEVFS_PATH, 1403 PICL_PTYPE_CHARSTRING, path_w_ua, strlen(path_w_ua) + 1, 1404 &nh) == PICL_SUCCESS) { 1405 /* 1406 * node already there - there's nothing we need to do 1407 */ 1408 if (picldevtree_debug > 1) 1409 syslog(LOG_INFO, 1410 "update_subtree: path:%s node exists\n", 1411 path_buf); 1412 di_devfs_path_free(path_buf); 1413 continue; 1414 } 1415 /* 1416 * now look for node without unit address in devfs_path. 1417 * This might be just one out of several 1418 * nodes - need to check all siblings 1419 */ 1420 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, 1421 &chdh, sizeof (chdh)); 1422 if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND)) 1423 return (err); 1424 gotit = 0; 1425 while (err == PICL_SUCCESS) { 1426 err = ptree_get_propval_by_name(chdh, 1427 PICL_PROP_DEVFS_PATH, buf, sizeof (buf)); 1428 if (err != PICL_SUCCESS) 1429 return (err); 1430 if (strcmp(buf, path_wo_ua) == 0) { 1431 err = ptree_get_propval_by_name(chdh, 1432 PICL_PROP_UNIT_ADDRESS, buf, sizeof (buf)); 1433 if (err != PICL_SUCCESS) 1434 return (err); 1435 if (strcmp(buf, unitaddr) == 0) { 1436 gotit = 1; 1437 break; 1438 } 1439 } 1440 err = ptree_get_propval_by_name(chdh, 1441 PICL_PROP_PEER, &chdh, sizeof (chdh)); 1442 if (err != PICL_SUCCESS) 1443 break; 1444 } 1445 if (gotit) { 1446 /* 1447 * node already there - there's nothing we need to do 1448 */ 1449 if (picldevtree_debug > 1) 1450 syslog(LOG_INFO, 1451 "update_subtree: path:%s node exists\n", 1452 path_buf); 1453 di_devfs_path_free(path_buf); 1454 continue; 1455 } 1456 1457 #define IS_MC(x) (strcmp(x, PICL_CLASS_MEMORY_CONTROLLER) == 0 ? 1 : 0) 1458 1459 if (construct_devtype_node(nodeh, nodename, nodeclass, cnode, 1460 &chdh) == PICL_SUCCESS) { 1461 if (picldevtree_debug) 1462 syslog(LOG_INFO, 1463 "picldevtree: added node:%s path:%s\n", 1464 nodename, path_buf); 1465 if (IS_MC(nodeclass)) { 1466 if (post_mc_event(PICLEVENT_MC_ADDED, chdh) != 1467 PICL_SUCCESS) 1468 syslog(LOG_WARNING, PICL_EVENT_DROPPED, 1469 PICLEVENT_MC_ADDED); 1470 } 1471 1472 di_devfs_path_free(path_buf); 1473 (void) update_subtree(chdh, cnode); 1474 } 1475 } 1476 1477 return (PICL_SUCCESS); 1478 1479 } 1480 1481 /* 1482 * This function processes the data from libdevinfo and creates nodes 1483 * in the PICL tree. 1484 */ 1485 static int 1486 libdevinfo_init(picl_nodehdl_t rooth) 1487 { 1488 di_node_t di_root; 1489 picl_nodehdl_t plafh; 1490 picl_nodehdl_t obph; 1491 int err; 1492 1493 1494 if ((di_root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) 1495 return (PICL_FAILURE); 1496 1497 if ((ph = di_prom_init()) == NULL) 1498 return (PICL_FAILURE); 1499 /* 1500 * create platform PICL node using di_root node 1501 */ 1502 err = construct_picl_platform(rooth, di_root, &plafh); 1503 if (err != PICL_SUCCESS) { 1504 di_fini(di_root); 1505 return (PICL_FAILURE); 1506 } 1507 1508 err = construct_picl_openprom(rooth, &obph); 1509 if (err != PICL_SUCCESS) { 1510 di_fini(di_root); 1511 return (PICL_FAILURE); 1512 } 1513 1514 (void) construct_devinfo_tree(plafh, obph, di_root, NULL); 1515 if (ph) { 1516 di_prom_fini(ph); 1517 ph = NULL; 1518 } 1519 di_fini(di_root); 1520 return (err); 1521 } 1522 1523 /* 1524 * This function returns the integer property value 1525 */ 1526 static int 1527 get_int_propval_by_name(picl_nodehdl_t nodeh, char *pname, int *ival) 1528 { 1529 int err; 1530 1531 err = ptree_get_propval_by_name(nodeh, pname, ival, 1532 sizeof (int)); 1533 1534 return (err); 1535 } 1536 1537 /* 1538 * This function returns the port ID (or CPU ID in the case of CMP cores) 1539 * of the specific CPU node handle. If upa_portid exists, return its value. 1540 * Otherwise, return portid/cpuid. 1541 */ 1542 static int 1543 get_cpu_portid(picl_nodehdl_t modh, int *id) 1544 { 1545 int err; 1546 1547 if (strcmp(mach_name, "sun4u") == 0) { 1548 err = get_int_propval_by_name(modh, OBP_PROP_UPA_PORTID, id); 1549 if (err == PICL_SUCCESS) 1550 return (err); 1551 err = get_int_propval_by_name(modh, OBP_PROP_PORTID, id); 1552 if (err == PICL_SUCCESS) 1553 return (err); 1554 return (get_int_propval_by_name(modh, OBP_PROP_CPUID, id)); 1555 } 1556 if (strcmp(mach_name, "i86pc") == 0) 1557 return (get_int_propval_by_name(modh, PICL_PROP_INSTANCE, id)); 1558 1559 return (PICL_FAILURE); 1560 } 1561 1562 /* 1563 * This function is the volatile read access function of CPU state 1564 * property 1565 */ 1566 static int 1567 get_pi_state(ptree_rarg_t *rarg, void *vbuf) 1568 { 1569 int id; 1570 int err; 1571 1572 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1573 if (err != PICL_SUCCESS) 1574 return (err); 1575 1576 switch (p_online(id, P_STATUS)) { 1577 case P_ONLINE: 1578 (void) strlcpy(vbuf, PS_ONLINE, MAX_STATE_SIZE); 1579 break; 1580 case P_OFFLINE: 1581 (void) strlcpy(vbuf, PS_OFFLINE, MAX_STATE_SIZE); 1582 break; 1583 case P_NOINTR: 1584 (void) strlcpy(vbuf, PS_NOINTR, MAX_STATE_SIZE); 1585 break; 1586 case P_SPARE: 1587 (void) strlcpy(vbuf, PS_SPARE, MAX_STATE_SIZE); 1588 break; 1589 case P_FAULTED: 1590 (void) strlcpy(vbuf, PS_FAULTED, MAX_STATE_SIZE); 1591 break; 1592 case P_POWEROFF: 1593 (void) strlcpy(vbuf, PS_POWEROFF, MAX_STATE_SIZE); 1594 break; 1595 default: 1596 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE); 1597 break; 1598 } 1599 return (PICL_SUCCESS); 1600 } 1601 1602 /* 1603 * This function is the volatile read access function of CPU processor_type 1604 * property 1605 */ 1606 static int 1607 get_processor_type(ptree_rarg_t *rarg, void *vbuf) 1608 { 1609 processor_info_t cpu_info; 1610 int id; 1611 int err; 1612 1613 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1614 if (err != PICL_SUCCESS) 1615 return (err); 1616 1617 if (processor_info(id, &cpu_info) >= 0) { 1618 (void) strlcpy(vbuf, cpu_info.pi_processor_type, PI_TYPELEN); 1619 } 1620 return (PICL_SUCCESS); 1621 } 1622 1623 /* 1624 * This function is the volatile read access function of CPU fputypes 1625 * property 1626 */ 1627 static int 1628 get_fputypes(ptree_rarg_t *rarg, void *vbuf) 1629 { 1630 processor_info_t cpu_info; 1631 int id; 1632 int err; 1633 1634 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1635 if (err != PICL_SUCCESS) 1636 return (err); 1637 1638 if (processor_info(id, &cpu_info) >= 0) { 1639 (void) strlcpy(vbuf, cpu_info.pi_fputypes, PI_FPUTYPE); 1640 } 1641 return (PICL_SUCCESS); 1642 } 1643 1644 /* 1645 * This function is the volatile read access function of CPU StateBegin 1646 * property. To minimize overhead, use kstat_chain_update() to refresh 1647 * the kstat header info as opposed to invoking kstat_open() every time. 1648 */ 1649 static int 1650 get_pi_state_begin(ptree_rarg_t *rarg, void *vbuf) 1651 { 1652 int err; 1653 int cpu_id; 1654 static kstat_ctl_t *kc = NULL; 1655 static pthread_mutex_t kc_mutex = PTHREAD_MUTEX_INITIALIZER; 1656 kstat_t *kp; 1657 kstat_named_t *kn; 1658 1659 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &cpu_id); 1660 if (err != PICL_SUCCESS) 1661 return (err); 1662 1663 (void) pthread_mutex_lock(&kc_mutex); 1664 if (kc == NULL) 1665 kc = kstat_open(); 1666 else if (kstat_chain_update(kc) == -1) { 1667 (void) kstat_close(kc); 1668 kc = kstat_open(); 1669 } 1670 1671 if (kc == NULL) { 1672 (void) pthread_mutex_unlock(&kc_mutex); 1673 return (PICL_FAILURE); 1674 } 1675 1676 /* Get the state_begin from kstat */ 1677 if ((kp = kstat_lookup(kc, KSTAT_CPU_INFO, cpu_id, NULL)) == NULL || 1678 kp->ks_type != KSTAT_TYPE_NAMED || kstat_read(kc, kp, 0) < 0) { 1679 (void) pthread_mutex_unlock(&kc_mutex); 1680 return (PICL_FAILURE); 1681 } 1682 1683 kn = kstat_data_lookup(kp, KSTAT_STATE_BEGIN); 1684 if (kn) { 1685 *(uint64_t *)vbuf = (uint64_t)kn->value.l; 1686 err = PICL_SUCCESS; 1687 } else 1688 err = PICL_FAILURE; 1689 1690 (void) pthread_mutex_unlock(&kc_mutex); 1691 return (err); 1692 } 1693 1694 /* 1695 * This function adds CPU information to the CPU nodes 1696 */ 1697 /* ARGSUSED */ 1698 static int 1699 add_processor_info(picl_nodehdl_t cpuh, void *args) 1700 { 1701 int err; 1702 int cpu_id; 1703 ptree_propinfo_t propinfo; 1704 ptree_propinfo_t pinfo; 1705 1706 err = get_cpu_portid(cpuh, &cpu_id); 1707 if (err != PICL_SUCCESS) 1708 return (PICL_WALK_CONTINUE); 1709 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1710 PICL_PTYPE_INT, PICL_READ, sizeof (int), PICL_PROP_ID, NULL, NULL); 1711 err = ptree_create_and_add_prop(cpuh, &propinfo, &cpu_id, NULL); 1712 if (err != PICL_SUCCESS) 1713 return (PICL_WALK_CONTINUE); 1714 1715 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1716 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), MAX_STATE_SIZE, 1717 PICL_PROP_STATE, get_pi_state, NULL); 1718 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1719 1720 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1721 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_TYPELEN, 1722 PICL_PROP_PROCESSOR_TYPE, get_processor_type, NULL); 1723 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1724 1725 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1726 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_FPUTYPE, 1727 PICL_PROP_FPUTYPE, get_fputypes, NULL); 1728 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1729 1730 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 1731 PICL_PTYPE_TIMESTAMP, PICL_READ|PICL_VOLATILE, sizeof (uint64_t), 1732 PICL_PROP_STATE_BEGIN, get_pi_state_begin, NULL); 1733 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 1734 1735 return (PICL_WALK_CONTINUE); 1736 } 1737 1738 /* 1739 * This function sets up the "ID" property in every CPU nodes 1740 * and adds processor info 1741 */ 1742 static int 1743 setup_cpus(picl_nodehdl_t plafh) 1744 { 1745 int err; 1746 1747 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_CPU, NULL, 1748 add_processor_info); 1749 1750 return (err); 1751 } 1752 1753 /* 1754 * This function format's the manufacture's information for FFB display 1755 * devices 1756 */ 1757 static void 1758 fmt_manf_id(manuf_t manufid, int bufsz, char *outbuf) 1759 { 1760 /* 1761 * Format the manufacturer's info. Note a small inconsistency we 1762 * have to work around - Brooktree has it's part number in decimal, 1763 * while Mitsubishi has it's part number in hex. 1764 */ 1765 switch (manufid.fld.manf) { 1766 case MANF_BROOKTREE: 1767 (void) snprintf(outbuf, bufsz, "%s %d, version %d", 1768 "Brooktree", manufid.fld.partno, manufid.fld.version); 1769 break; 1770 1771 case MANF_MITSUBISHI: 1772 (void) snprintf(outbuf, bufsz, "%s %x, version %d", 1773 "Mitsubishi", manufid.fld.partno, manufid.fld.version); 1774 break; 1775 1776 default: 1777 (void) snprintf(outbuf, bufsz, 1778 "JED code %d, Part num 0x%x, version %d", 1779 manufid.fld.manf, manufid.fld.partno, manufid.fld.version); 1780 } 1781 } 1782 1783 /* 1784 * If it's an ffb device, open ffb devices and return PICL_SUCCESS 1785 */ 1786 static int 1787 open_ffb_device(picl_nodehdl_t ffbh, int *fd) 1788 { 1789 DIR *dirp; 1790 char devfs_path[PATH_MAX]; 1791 char dev_path[PATH_MAX]; 1792 char *devp; 1793 struct dirent *direntp; 1794 int err; 1795 int tmpfd; 1796 1797 /* Get the devfs_path of the ffb devices */ 1798 err = ptree_get_propval_by_name(ffbh, PICL_PROP_DEVFS_PATH, devfs_path, 1799 sizeof (devfs_path)); 1800 if (err != PICL_SUCCESS) 1801 return (err); 1802 1803 /* Get the device node name */ 1804 devp = strrchr(devfs_path, '/'); 1805 if (devp == NULL) 1806 return (PICL_FAILURE); 1807 *devp = '\0'; 1808 ++devp; 1809 1810 /* 1811 * Check if device node name has the ffb string 1812 * If not, assume it's not a ffb device. 1813 */ 1814 if (strstr(devp, FFB_NAME) == NULL) 1815 return (PICL_FAILURE); 1816 1817 /* 1818 * Get the parent path of the ffb device node. 1819 */ 1820 (void) snprintf(dev_path, sizeof (dev_path), "%s/%s", "/devices", 1821 devfs_path); 1822 1823 /* 1824 * Since we don't know ffb's minor nodename, 1825 * we need to search all the devices under its 1826 * parent dir by comparing the node name 1827 */ 1828 if ((dirp = opendir(dev_path)) == NULL) 1829 return (PICL_FAILURE); 1830 1831 while ((direntp = readdir(dirp)) != NULL) { 1832 if (strstr(direntp->d_name, devp) != NULL) { 1833 (void) strcat(dev_path, "/"); 1834 (void) strcat(dev_path, direntp->d_name); 1835 tmpfd = open(dev_path, O_RDWR); 1836 if (tmpfd < 0) 1837 continue; 1838 *fd = tmpfd; 1839 (void) closedir(dirp); 1840 return (PICL_SUCCESS); 1841 } 1842 } 1843 1844 (void) closedir(dirp); 1845 return (PICL_FAILURE); 1846 } 1847 1848 /* 1849 * This function recursively searches the tree for ffb display devices 1850 * and add ffb config information 1851 */ 1852 static int 1853 add_ffb_config_info(picl_nodehdl_t rooth) 1854 { 1855 picl_nodehdl_t nodeh; 1856 int err; 1857 char piclclass[PICL_CLASSNAMELEN_MAX]; 1858 char manfidbuf[FFB_MANUF_BUFSIZE]; 1859 int fd; 1860 int board_rev; 1861 ffb_sys_info_t fsi; 1862 ptree_propinfo_t pinfo; 1863 1864 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh, 1865 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 1866 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, 1867 &nodeh, sizeof (picl_nodehdl_t))) { 1868 1869 if (err != PICL_SUCCESS) 1870 return (err); 1871 1872 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 1873 piclclass, PICL_CLASSNAMELEN_MAX); 1874 1875 if ((err == PICL_SUCCESS) && 1876 (strcmp(piclclass, PICL_CLASS_DISPLAY) == 0)) { 1877 1878 err = open_ffb_device(nodeh, &fd); 1879 if ((err == PICL_SUCCESS) && 1880 (ioctl(fd, FFB_SYS_INFO, &fsi) >= 0)) { 1881 (void) ptree_init_propinfo(&pinfo, 1882 PTREE_PROPINFO_VERSION, 1883 PICL_PTYPE_UNSIGNED_INT, PICL_READ, 1884 sizeof (int), PICL_PROP_FFB_BOARD_REV, 1885 NULL, NULL); 1886 board_rev = fsi.ffb_strap_bits.fld.board_rev; 1887 (void) ptree_create_and_add_prop(nodeh, &pinfo, 1888 &board_rev, NULL); 1889 1890 fmt_manf_id(fsi.dac_version, 1891 sizeof (manfidbuf), manfidbuf); 1892 (void) ptree_init_propinfo(&pinfo, 1893 PTREE_PROPINFO_VERSION, 1894 PICL_PTYPE_CHARSTRING, PICL_READ, 1895 strlen(manfidbuf) + 1, 1896 PICL_PROP_FFB_DAC_VER, NULL, NULL); 1897 (void) ptree_create_and_add_prop(nodeh, &pinfo, 1898 manfidbuf, NULL); 1899 1900 fmt_manf_id(fsi.fbram_version, 1901 sizeof (manfidbuf), manfidbuf); 1902 (void) ptree_init_propinfo(&pinfo, 1903 PTREE_PROPINFO_VERSION, 1904 PICL_PTYPE_CHARSTRING, PICL_READ, 1905 strlen(manfidbuf) + 1, 1906 PICL_PROP_FFB_FBRAM_VER, NULL, 1907 NULL); 1908 (void) ptree_create_and_add_prop(nodeh, &pinfo, 1909 manfidbuf, NULL); 1910 (void) close(fd); 1911 } 1912 } else if (add_ffb_config_info(nodeh) != PICL_SUCCESS) 1913 return (PICL_FAILURE); 1914 } 1915 return (PICL_SUCCESS); 1916 } 1917 1918 static conf_entries_t * 1919 free_conf_entries(conf_entries_t *list) 1920 { 1921 conf_entries_t *el; 1922 conf_entries_t *del; 1923 1924 if (list == NULL) 1925 return (NULL); 1926 el = list; 1927 while (el != NULL) { 1928 del = el; 1929 el = el->next; 1930 free(del->name); 1931 free(del->piclclass); 1932 free(del); 1933 } 1934 return (el); 1935 } 1936 1937 /* 1938 * Reading config order: platform, common 1939 */ 1940 static conf_entries_t * 1941 read_conf_file(char *fname, conf_entries_t *list) 1942 { 1943 FILE *fp; 1944 char lbuf[CONFFILE_LINELEN_MAX]; 1945 char *nametok; 1946 char *classtok; 1947 conf_entries_t *el; 1948 conf_entries_t *ptr; 1949 1950 if (fname == NULL) 1951 return (list); 1952 1953 fp = fopen(fname, "r"); 1954 1955 if (fp == NULL) 1956 return (list); 1957 1958 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 1959 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 1960 continue; 1961 1962 nametok = strtok(lbuf, " \t\n"); 1963 if (nametok == NULL) 1964 continue; 1965 1966 classtok = strtok(NULL, " \t\n"); 1967 if (classtok == NULL) 1968 continue; 1969 1970 el = malloc(sizeof (conf_entries_t)); 1971 if (el == NULL) 1972 break; 1973 el->name = strdup(nametok); 1974 el->piclclass = strdup(classtok); 1975 if ((el->name == NULL) || (el->piclclass == NULL)) { 1976 free(el); 1977 return (list); 1978 } 1979 el->next = NULL; 1980 1981 /* 1982 * Add it to the end of list 1983 */ 1984 if (list == NULL) 1985 list = el; 1986 else { 1987 ptr = list; 1988 while (ptr->next != NULL) 1989 ptr = ptr->next; 1990 ptr->next = el; 1991 } 1992 1993 } 1994 (void) fclose(fp); 1995 return (list); 1996 } 1997 1998 /* 1999 * Process the devtree conf file and set up the conf_name_class_map list 2000 */ 2001 static void 2002 process_devtree_conf_file(void) 2003 { 2004 char nmbuf[SYS_NMLN]; 2005 char pname[PATH_MAX]; 2006 2007 conf_name_class_map = NULL; 2008 2009 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2010 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2011 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2012 conf_name_class_map = read_conf_file(pname, 2013 conf_name_class_map); 2014 } 2015 2016 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2017 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2018 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2019 conf_name_class_map = read_conf_file(pname, 2020 conf_name_class_map); 2021 } 2022 2023 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2024 DEVTREE_CONFFILE_NAME); 2025 conf_name_class_map = read_conf_file(pname, conf_name_class_map); 2026 } 2027 2028 static asr_conf_entries_t *conf_name_asr_map = NULL; 2029 2030 static void 2031 free_asr_conf_entries(asr_conf_entries_t *list) { 2032 asr_conf_entries_t *el; 2033 asr_conf_entries_t *del; 2034 2035 el = list; 2036 while (el != NULL) { 2037 del = el; 2038 el = el->next; 2039 if (del->name) 2040 free(del->name); 2041 if (del->address) 2042 free(del->address); 2043 if (del->status) 2044 free(del->status); 2045 if (del->piclclass) 2046 free(del->piclclass); 2047 if (del->props) 2048 free(del->props); 2049 free(del); 2050 } 2051 } 2052 2053 /* 2054 * Reading config order: platform, common 2055 */ 2056 static asr_conf_entries_t * 2057 read_asr_conf_file(char *fname, asr_conf_entries_t *list) 2058 { 2059 FILE *fp; 2060 char lbuf[CONFFILE_LINELEN_MAX]; 2061 char *nametok; 2062 char *classtok; 2063 char *statustok; 2064 char *addresstok; 2065 char *propstok; 2066 asr_conf_entries_t *el; 2067 asr_conf_entries_t *ptr; 2068 2069 if (fname == NULL) 2070 return (list); 2071 2072 fp = fopen(fname, "r"); 2073 if (fp == NULL) 2074 return (list); 2075 2076 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 2077 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 2078 continue; 2079 2080 nametok = strtok(lbuf, " \t\n"); 2081 if (nametok == NULL) 2082 continue; 2083 2084 classtok = strtok(NULL, " \t\n"); 2085 if (classtok == NULL) 2086 continue; 2087 2088 statustok = strtok(NULL, " \t\n"); 2089 if (statustok == NULL) 2090 continue; 2091 2092 addresstok = strtok(NULL, " \t\n"); 2093 if (addresstok == NULL) 2094 continue; 2095 2096 /* 2097 * props are optional 2098 */ 2099 propstok = strtok(NULL, " \t\n"); 2100 2101 el = malloc(sizeof (asr_conf_entries_t)); 2102 if (el == NULL) 2103 break; 2104 el->name = strdup(nametok); 2105 el->piclclass = strdup(classtok); 2106 el->status = strdup(statustok); 2107 el->address = strdup(addresstok); 2108 if (propstok != NULL) 2109 el->props = strdup(propstok); 2110 else 2111 el->props = NULL; 2112 if ((el->name == NULL) || (el->piclclass == NULL) || 2113 (el->address == NULL) || (el->status == NULL)) { 2114 if (el->name) 2115 free(el->name); 2116 if (el->address) 2117 free(el->address); 2118 if (el->status) 2119 free(el->status); 2120 if (el->piclclass) 2121 free(el->piclclass); 2122 if (el->props) 2123 free(el->props); 2124 free(el); 2125 break; 2126 } 2127 el->next = NULL; 2128 2129 /* 2130 * Add it to the end of list 2131 */ 2132 if (list == NULL) 2133 list = el; 2134 else { 2135 ptr = list; 2136 while (ptr->next != NULL) 2137 ptr = ptr->next; 2138 ptr->next = el; 2139 } 2140 2141 } 2142 (void) fclose(fp); 2143 return (list); 2144 } 2145 2146 /* 2147 * Process the asr conf file 2148 */ 2149 static void 2150 process_asrtree_conf_file(void) 2151 { 2152 char nmbuf[SYS_NMLN]; 2153 char pname[PATH_MAX]; 2154 2155 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2156 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2157 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2158 conf_name_asr_map = read_asr_conf_file(pname, 2159 conf_name_asr_map); 2160 } 2161 2162 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2163 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2164 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2165 conf_name_asr_map = read_asr_conf_file(pname, 2166 conf_name_asr_map); 2167 } 2168 2169 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2170 ASRTREE_CONFFILE_NAME); 2171 conf_name_asr_map = read_asr_conf_file(pname, conf_name_asr_map); 2172 } 2173 2174 /* 2175 * This function reads the export file list from ASR 2176 */ 2177 static int 2178 get_asr_export_list(char **exportlist, int *exportlistlen) 2179 { 2180 struct openpromio oppbuf; 2181 struct openpromio *opp = &oppbuf; 2182 int d; 2183 int listsize; 2184 2185 d = open("/dev/openprom", O_RDWR); 2186 if (d < 0) 2187 return (0); 2188 2189 if (ioctl(d, OPROMEXPORTLEN, opp) == -1) { 2190 (void) close(d); 2191 return (0); 2192 } 2193 listsize = opp->oprom_size; 2194 opp = (struct openpromio *)malloc(sizeof (struct openpromio) + 2195 listsize); 2196 if (opp == NULL) { 2197 (void) close(d); 2198 return (0); 2199 } 2200 (void) memset(opp, '\0', sizeof (struct openpromio) + listsize); 2201 opp->oprom_size = listsize; 2202 if (ioctl(d, OPROMEXPORT, opp) == -1) { 2203 free(opp); 2204 (void) close(d); 2205 return (0); 2206 } 2207 *exportlist = malloc(listsize); 2208 if (*exportlist == NULL) { 2209 free(opp); 2210 (void) close(d); 2211 return (0); 2212 } 2213 (void) memcpy(*exportlist, opp->oprom_array, opp->oprom_size); 2214 free(opp); 2215 *exportlistlen = opp->oprom_size; 2216 (void) close(d); 2217 return (1); 2218 } 2219 2220 /* 2221 * Parses properties string, fills in triplet structure with first 2222 * type, name, val triplet and returns pointer to next property. 2223 * Returns NULL if no valid triplet found 2224 * CAUTION: drops \0 characters over separator characters: if you 2225 * want to parse the string twice, you'll have to take a copy. 2226 */ 2227 static char * 2228 parse_props_string(char *props, asr_prop_triplet_t *triplet) 2229 { 2230 char *prop_name; 2231 char *prop_val; 2232 char *prop_next; 2233 2234 prop_name = strchr(props, '?'); 2235 if (prop_name == NULL) 2236 return (NULL); 2237 *prop_name++ = '\0'; 2238 prop_val = strchr(prop_name, '='); 2239 if (prop_val == NULL) 2240 return (NULL); 2241 *prop_val++ = '\0'; 2242 triplet->proptype = props; 2243 triplet->propname = prop_name; 2244 triplet->propval = prop_val; 2245 prop_next = strchr(prop_val, ':'); 2246 if (prop_next == NULL) 2247 return (prop_val - 1); 2248 *prop_next++ = '\0'; 2249 return (prop_next); 2250 } 2251 2252 static int 2253 add_status_prop(picl_nodehdl_t chdh, char *status) 2254 { 2255 ptree_propinfo_t propinfo; 2256 picl_prophdl_t proph; 2257 int err; 2258 2259 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2260 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(status) + 1, 2261 PICL_PROP_STATUS, NULL, NULL); 2262 if (err != PICL_SUCCESS) 2263 return (err); 2264 err = ptree_create_and_add_prop(chdh, &propinfo, status, &proph); 2265 return (err); 2266 } 2267 2268 static void 2269 create_asr_node(char *parent, char *child, char *unitaddr, char *class, 2270 char *status, char *props) 2271 { 2272 char ptreepath[PATH_MAX]; 2273 char nodename[PICL_PROPNAMELEN_MAX]; 2274 char ua[MAX_UNIT_ADDRESS_LEN]; 2275 char *props_copy = NULL; 2276 char *next; 2277 char *prop_string; 2278 boolean_t found = B_FALSE; 2279 picl_nodehdl_t nodeh; 2280 picl_nodehdl_t chdh; 2281 asr_prop_triplet_t triple; 2282 ptree_propinfo_t propinfo; 2283 picl_prophdl_t proph; 2284 int val; 2285 int err; 2286 2287 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX); 2288 (void) strlcat(ptreepath, parent, PATH_MAX); 2289 2290 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS) 2291 return; 2292 /* 2293 * see if the required child node already exists 2294 */ 2295 for (err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 2296 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2297 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 2298 sizeof (picl_nodehdl_t))) { 2299 if (err != PICL_SUCCESS) 2300 break; 2301 err = ptree_get_propval_by_name(chdh, PICL_PROP_NAME, 2302 (void *)nodename, PICL_PROPNAMELEN_MAX); 2303 if (err != PICL_SUCCESS) 2304 break; 2305 if (strcmp(nodename, child) != 0) 2306 continue; 2307 /* 2308 * found a candidate child node 2309 */ 2310 if (unitaddr) { 2311 /* 2312 * does it match the required unit address? 2313 */ 2314 err = ptree_get_propval_by_name(chdh, 2315 PICL_PROP_UNIT_ADDRESS, ua, sizeof (ua)); 2316 if (err == PICL_PROPNOTFOUND) 2317 continue; 2318 if (err != PICL_SUCCESS) 2319 break; 2320 if (strcmp(unitaddr, ua) != 0) 2321 continue; 2322 } 2323 if (props == NULL) { 2324 next = ""; 2325 } else if (props_copy == NULL) { 2326 props_copy = strdup(props); 2327 if (props_copy == NULL) 2328 return; 2329 next = props_copy; 2330 } 2331 while ((next = parse_props_string(next, &triple)) != NULL) { 2332 err = ptree_get_prop_by_name(chdh, triple.propname, 2333 &proph); 2334 if (err != PICL_SUCCESS) 2335 break; 2336 err = ptree_get_propinfo(proph, &propinfo); 2337 if (err != PICL_SUCCESS) 2338 break; 2339 err = PICL_FAILURE; 2340 switch (propinfo.piclinfo.type) { 2341 case PICL_PTYPE_INT: 2342 case PICL_PTYPE_UNSIGNED_INT: 2343 if (strcmp(triple.proptype, "I") != 0) 2344 break; 2345 err = ptree_get_propval(proph, (void *)&val, 2346 sizeof (val)); 2347 if (err != PICL_SUCCESS) 2348 break; 2349 if (val != atoi(triple.propval)) 2350 err = PICL_FAILURE; 2351 break; 2352 case PICL_PTYPE_CHARSTRING: 2353 if (strcmp(triple.proptype, "S") != 0) 2354 break; 2355 prop_string = malloc(propinfo.piclinfo.size); 2356 if (prop_string == NULL) 2357 break; 2358 err = ptree_get_propval(proph, 2359 (void *)prop_string, 2360 propinfo.piclinfo.size); 2361 if (err != PICL_SUCCESS) { 2362 free(prop_string); 2363 break; 2364 } 2365 if (strcmp(prop_string, triple.propval) != 0) 2366 err = PICL_FAILURE; 2367 free(prop_string); 2368 break; 2369 default: 2370 break; 2371 } 2372 if (err != PICL_SUCCESS) { 2373 break; 2374 } 2375 } 2376 if (next == NULL) { 2377 found = B_TRUE; 2378 break; 2379 } 2380 } 2381 if (props_copy) 2382 free(props_copy); 2383 if (found) { 2384 /* 2385 * does the pre-existing node have a status property? 2386 */ 2387 err = ptree_get_propval_by_name(chdh, PICL_PROP_STATUS, 2388 ua, sizeof (ua)); 2389 if (err == PICL_PROPNOTFOUND) 2390 (void) add_status_prop(chdh, status); 2391 if (err != PICL_SUCCESS) 2392 return; 2393 if ((strcmp(ua, ASR_DISABLED) == 0) || 2394 (strcmp(ua, ASR_FAILED) == 0) || 2395 ((strcmp(status, ASR_DISABLED) != 0) && 2396 (strcmp(status, ASR_FAILED) != 0))) { 2397 return; 2398 } 2399 /* 2400 * more urgent status now, so replace existing value 2401 */ 2402 err = ptree_get_prop_by_name(chdh, PICL_PROP_STATUS, &proph); 2403 if (err != PICL_SUCCESS) 2404 return; 2405 (void) ptree_delete_prop(proph); 2406 (void) ptree_destroy_prop(proph); 2407 err = add_status_prop(chdh, status); 2408 if (err != PICL_SUCCESS) 2409 return; 2410 return; 2411 } 2412 2413 /* 2414 * typical case, node needs adding together with a set of properties 2415 */ 2416 if (ptree_create_and_add_node(nodeh, child, class, &chdh) == 2417 PICL_SUCCESS) { 2418 (void) add_status_prop(chdh, status); 2419 if (unitaddr) { 2420 (void) ptree_init_propinfo(&propinfo, 2421 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2422 PICL_READ, strlen(unitaddr) + 1, 2423 PICL_PROP_UNIT_ADDRESS, NULL, NULL); 2424 (void) ptree_create_and_add_prop(chdh, &propinfo, 2425 unitaddr, &proph); 2426 (void) strlcpy(ptreepath, parent, PATH_MAX); 2427 (void) strlcat(ptreepath, "/", PATH_MAX); 2428 (void) strlcat(ptreepath, child, PATH_MAX); 2429 (void) strlcat(ptreepath, "@", PATH_MAX); 2430 (void) strlcat(ptreepath, unitaddr, PATH_MAX); 2431 (void) ptree_init_propinfo(&propinfo, 2432 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2433 PICL_READ, strlen(ptreepath) + 1, 2434 PICL_PROP_DEVFS_PATH, NULL, NULL); 2435 (void) ptree_create_and_add_prop(chdh, &propinfo, 2436 ptreepath, &proph); 2437 } 2438 next = props; 2439 while ((next = parse_props_string(next, &triple)) != NULL) { 2440 /* 2441 * only handle int and string properties for 2442 * simplicity 2443 */ 2444 if (strcmp(triple.proptype, "I") == 0) { 2445 (void) ptree_init_propinfo(&propinfo, 2446 PTREE_PROPINFO_VERSION, 2447 PICL_PTYPE_INT, PICL_READ, 2448 sizeof (int), triple.propname, NULL, NULL); 2449 val = atoi(triple.propval); 2450 (void) ptree_create_and_add_prop(chdh, 2451 &propinfo, &val, &proph); 2452 } else { 2453 (void) ptree_init_propinfo(&propinfo, 2454 PTREE_PROPINFO_VERSION, 2455 PICL_PTYPE_CHARSTRING, PICL_READ, 2456 strlen(triple.propval) + 1, 2457 triple.propname, NULL, NULL); 2458 (void) ptree_create_and_add_prop(chdh, 2459 &propinfo, triple.propval, &proph); 2460 } 2461 } 2462 } 2463 } 2464 2465 static void 2466 add_asr_nodes() 2467 { 2468 char *asrexport; 2469 int asrexportlen; 2470 asr_conf_entries_t *c = NULL; 2471 int i; 2472 char *key; 2473 char *child; 2474 char *unitaddr; 2475 uint16_t count; 2476 int disabled; 2477 2478 if (get_asr_export_list(&asrexport, &asrexportlen) == 0) 2479 return; 2480 process_asrtree_conf_file(); 2481 if (conf_name_asr_map == NULL) 2482 return; 2483 i = 0; 2484 while (i < asrexportlen) { 2485 key = &asrexport[i]; 2486 i += strlen(key) + 1; 2487 if (i >= asrexportlen) 2488 break; 2489 2490 /* 2491 * next byte tells us whether failed by diags or manually 2492 * disabled 2493 */ 2494 disabled = asrexport[i]; 2495 i++; 2496 if (i >= asrexportlen) 2497 break; 2498 2499 /* 2500 * only type 1 supported 2501 */ 2502 if (asrexport[i] != 1) 2503 break; 2504 i++; 2505 if (i >= asrexportlen) 2506 break; 2507 2508 /* 2509 * next two bytes give size of reason string 2510 */ 2511 count = (asrexport[i] << 8) | asrexport[i + 1]; 2512 i += count + 2; 2513 if (i > asrexportlen) 2514 break; 2515 2516 /* 2517 * now look for key in conf file info 2518 */ 2519 c = conf_name_asr_map; 2520 while (c != NULL) { 2521 if (strcmp(key, c->name) == 0) { 2522 child = strrchr(c->address, '/'); 2523 *child++ = '\0'; 2524 unitaddr = strchr(child, '@'); 2525 if (unitaddr) 2526 *unitaddr++ = '\0'; 2527 if (strcmp(c->status, ASR_DISABLED) == 0) { 2528 create_asr_node(c->address, child, 2529 unitaddr, c->piclclass, disabled ? 2530 ASR_DISABLED : ASR_FAILED, 2531 c->props); 2532 } else { 2533 create_asr_node(c->address, child, 2534 unitaddr, c->piclclass, c->status, 2535 c->props); 2536 } 2537 } 2538 c = c->next; 2539 } 2540 } 2541 2542 free_asr_conf_entries(conf_name_asr_map); 2543 free(asrexport); 2544 } 2545 2546 /* 2547 * This function adds information to the /platform node 2548 */ 2549 static int 2550 add_platform_info(picl_nodehdl_t plafh) 2551 { 2552 struct utsname uts_info; 2553 int err; 2554 ptree_propinfo_t propinfo; 2555 picl_prophdl_t proph; 2556 2557 if (uname(&uts_info) < 0) 2558 return (PICL_FAILURE); 2559 2560 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2561 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.sysname) + 1, 2562 PICL_PROP_SYSNAME, NULL, NULL); 2563 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.sysname, 2564 &proph); 2565 if (err != PICL_SUCCESS) 2566 return (err); 2567 2568 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2569 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.nodename) + 1, 2570 PICL_PROP_NODENAME, NULL, NULL); 2571 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.nodename, 2572 &proph); 2573 if (err != PICL_SUCCESS) 2574 return (err); 2575 2576 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2577 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.release) + 1, 2578 PICL_PROP_RELEASE, NULL, NULL); 2579 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.release, 2580 &proph); 2581 if (err != PICL_SUCCESS) 2582 return (err); 2583 2584 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2585 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.version) + 1, 2586 PICL_PROP_VERSION, NULL, NULL); 2587 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.version, 2588 &proph); 2589 if (err != PICL_SUCCESS) 2590 return (err); 2591 2592 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2593 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.machine) + 1, 2594 PICL_PROP_MACHINE, NULL, NULL); 2595 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.machine, 2596 &proph); 2597 return (err); 2598 } 2599 2600 /* 2601 * Get first 32-bit value from the reg property 2602 */ 2603 static int 2604 get_first_reg_word(picl_nodehdl_t nodeh, uint32_t *regval) 2605 { 2606 int err; 2607 uint32_t *regbuf; 2608 picl_prophdl_t regh; 2609 ptree_propinfo_t pinfo; 2610 2611 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 2612 if (err != PICL_SUCCESS) /* no reg property */ 2613 return (err); 2614 err = ptree_get_propinfo(regh, &pinfo); 2615 if (err != PICL_SUCCESS) 2616 return (err); 2617 if (pinfo.piclinfo.size < sizeof (uint32_t)) /* too small */ 2618 return (PICL_FAILURE); 2619 regbuf = alloca(pinfo.piclinfo.size); 2620 if (regbuf == NULL) 2621 return (PICL_FAILURE); 2622 err = ptree_get_propval(regh, regbuf, pinfo.piclinfo.size); 2623 if (err != PICL_SUCCESS) 2624 return (err); 2625 *regval = *regbuf; /* get first 32-bit value */ 2626 return (PICL_SUCCESS); 2627 } 2628 2629 /* 2630 * Get device ID from the reg property 2631 */ 2632 static int 2633 get_device_id(picl_nodehdl_t nodeh, uint32_t *dev_id) 2634 { 2635 int err; 2636 uint32_t regval; 2637 2638 err = get_first_reg_word(nodeh, ®val); 2639 if (err != PICL_SUCCESS) 2640 return (err); 2641 2642 *dev_id = PCI_DEVICE_ID(regval); 2643 return (PICL_SUCCESS); 2644 } 2645 2646 /* 2647 * add Slot property for children of SBUS node 2648 */ 2649 /* ARGSUSED */ 2650 static int 2651 add_sbus_slots(picl_nodehdl_t pcih, void *args) 2652 { 2653 picl_nodehdl_t nodeh; 2654 uint32_t slot; 2655 int err; 2656 ptree_propinfo_t pinfo; 2657 2658 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 2659 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2660 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 2661 sizeof (picl_nodehdl_t))) { 2662 if (err != PICL_SUCCESS) 2663 return (err); 2664 2665 if (get_first_reg_word(nodeh, &slot) != 0) 2666 continue; 2667 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2668 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 2669 PICL_PROP_SLOT, NULL, NULL); 2670 (void) ptree_create_and_add_prop(nodeh, &pinfo, &slot, NULL); 2671 } 2672 2673 return (PICL_WALK_CONTINUE); 2674 } 2675 2676 /* 2677 * This function creates a Slot property for SBUS child nodes 2678 * which can be correlated with the slot they are plugged into 2679 * on the motherboard. 2680 */ 2681 static int 2682 set_sbus_slot(picl_nodehdl_t plafh) 2683 { 2684 int err; 2685 2686 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_SBUS, NULL, 2687 add_sbus_slots); 2688 2689 return (err); 2690 } 2691 2692 /* 2693 * add DeviceID property for children of PCI/PCIEX node 2694 */ 2695 /* ARGSUSED */ 2696 static int 2697 add_pci_deviceids(picl_nodehdl_t pcih, void *args) 2698 { 2699 picl_nodehdl_t nodeh; 2700 uint32_t dev_id; 2701 int err; 2702 ptree_propinfo_t pinfo; 2703 2704 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 2705 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2706 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 2707 sizeof (picl_nodehdl_t))) { 2708 if (err != PICL_SUCCESS) 2709 return (err); 2710 2711 if (get_device_id(nodeh, &dev_id) != 0) 2712 continue; 2713 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2714 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 2715 PICL_PROP_DEVICE_ID, NULL, NULL); 2716 (void) ptree_create_and_add_prop(nodeh, &pinfo, &dev_id, NULL); 2717 } 2718 2719 return (PICL_WALK_CONTINUE); 2720 } 2721 2722 /* 2723 * This function creates a DeviceID property for PCI/PCIEX child nodes 2724 * which can be correlated with the slot they are plugged into 2725 * on the motherboard. 2726 */ 2727 static void 2728 set_pci_pciex_deviceid(picl_nodehdl_t plafh) 2729 { 2730 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCI, NULL, 2731 add_pci_deviceids); 2732 2733 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCIEX, NULL, 2734 add_pci_deviceids); 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 set_pci_pciex_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 set_pci_pciex_deviceid(plafh); 3430 (void) set_sbus_slot(plafh); 3431 if (picldevtree_debug > 1) 3432 syslog(LOG_INFO, "picldevtree: event handler done\n"); 3433 } 3434