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