1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * 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 static const char * 1015 path_state_name(di_path_state_t st) 1016 { 1017 switch (st) { 1018 case DI_PATH_STATE_ONLINE: 1019 return ("online"); 1020 case DI_PATH_STATE_STANDBY: 1021 return ("standby"); 1022 case DI_PATH_STATE_OFFLINE: 1023 return ("offline"); 1024 case DI_PATH_STATE_FAULT: 1025 return ("faulted"); 1026 } 1027 return ("unknown"); 1028 } 1029 1030 /* 1031 * This function is the volatile property handler for the multipath node 1032 * "State" property. It must locate the associated devinfo node in order to 1033 * determine the current state. Since the devinfo node can have multiple 1034 * paths the devfs_path is used to locate the correct path. 1035 */ 1036 static int 1037 get_path_state_name(ptree_rarg_t *rarg, void *vbuf) 1038 { 1039 int err; 1040 picl_nodehdl_t parh; 1041 char devfs_path[PATH_MAX]; 1042 di_node_t di_node; 1043 di_node_t di_root; 1044 di_path_t pi = DI_PATH_NIL; 1045 picl_nodehdl_t mpnode; 1046 1047 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE); 1048 1049 mpnode = rarg->nodeh; 1050 1051 /* 1052 * The parent node represents the vHCI. 1053 */ 1054 err = ptree_get_propval_by_name(mpnode, PICL_PROP_PARENT, &parh, 1055 sizeof (picl_nodehdl_t)); 1056 if (err != PICL_SUCCESS) { 1057 return (PICL_SUCCESS); 1058 } 1059 1060 /* 1061 * The PICL_PROP_DEVFS_PATH property will be used to locate the 1062 * devinfo node for the vHCI driver. 1063 */ 1064 err = ptree_get_propval_by_name(parh, PICL_PROP_DEVFS_PATH, devfs_path, 1065 sizeof (devfs_path)); 1066 if (err != PICL_SUCCESS) { 1067 return (PICL_SUCCESS); 1068 } 1069 /* 1070 * Find the di_node for the vHCI driver. It will be used to scan 1071 * the path information nodes. 1072 */ 1073 di_root = di_init("/", DINFOCACHE); 1074 if (di_root == DI_NODE_NIL) { 1075 return (PICL_SUCCESS); 1076 } 1077 di_node = di_lookup_node(di_root, devfs_path); 1078 if (di_node == DI_NODE_NIL) { 1079 di_fini(di_root); 1080 return (PICL_SUCCESS); 1081 } 1082 1083 /* 1084 * The devfs_path will be used below to match the 1085 * proper path information node. 1086 */ 1087 err = ptree_get_propval_by_name(mpnode, PICL_PROP_DEVFS_PATH, 1088 devfs_path, sizeof (devfs_path)); 1089 if (err != PICL_SUCCESS) { 1090 di_fini(di_root); 1091 return (PICL_SUCCESS); 1092 } 1093 1094 /* 1095 * Scan the path information nodes looking for the matching devfs 1096 * path. When found obtain the state information. 1097 */ 1098 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) { 1099 char *di_path; 1100 di_node_t phci_node = di_path_phci_node(pi); 1101 1102 if (phci_node == DI_PATH_NIL) 1103 continue; 1104 1105 di_path = di_devfs_path(phci_node); 1106 if (di_path) { 1107 if (strcmp(di_path, devfs_path) != 0) { 1108 di_devfs_path_free(di_path); 1109 continue; 1110 } 1111 (void) strlcpy(vbuf, path_state_name(di_path_state(pi)), 1112 MAX_STATE_SIZE); 1113 di_devfs_path_free(di_path); 1114 break; 1115 } 1116 } 1117 1118 di_fini(di_root); 1119 return (PICL_SUCCESS); 1120 } 1121 1122 static void 1123 add_di_path_prop(picl_nodehdl_t nodeh, di_path_prop_t di_path_prop) 1124 { 1125 int di_ptype; 1126 char *di_val; 1127 ptree_propinfo_t propinfo; 1128 int *idata; 1129 char *sdata; 1130 unsigned char *bdata; 1131 int len; 1132 1133 di_ptype = di_path_prop_type(di_path_prop); 1134 di_val = di_path_prop_name(di_path_prop); 1135 1136 switch (di_ptype) { 1137 case DI_PROP_TYPE_BOOLEAN: 1138 add_boolean_prop(nodeh, propinfo, di_val); 1139 break; 1140 case DI_PROP_TYPE_INT: 1141 case DI_PROP_TYPE_INT64: 1142 len = di_path_prop_ints(di_path_prop, &idata); 1143 if (len < 0) 1144 /* Received error, so ignore prop */ 1145 break; 1146 add_uints_prop(nodeh, propinfo, di_val, idata, len); 1147 break; 1148 case DI_PROP_TYPE_STRING: 1149 len = di_path_prop_strings(di_path_prop, &sdata); 1150 if (len <= 0) 1151 break; 1152 add_strings_prop(nodeh, propinfo, di_val, sdata, len); 1153 break; 1154 case DI_PROP_TYPE_BYTE: 1155 len = di_path_prop_bytes(di_path_prop, &bdata); 1156 if (len < 0) 1157 break; 1158 add_bytes_prop(nodeh, propinfo, di_val, bdata, len); 1159 break; 1160 case DI_PROP_TYPE_UNKNOWN: 1161 /* 1162 * Unknown type, we'll try and guess what it should be. 1163 */ 1164 len = di_path_prop_strings(di_path_prop, &sdata); 1165 if ((len > 0) && (sdata[0] != 0)) { 1166 add_strings_prop(nodeh, propinfo, di_val, sdata, 1167 len); 1168 break; 1169 } 1170 len = di_path_prop_ints(di_path_prop, &idata); 1171 if (len > 0) { 1172 add_uints_prop(nodeh, propinfo, di_val, 1173 idata, len); 1174 break; 1175 } 1176 len = di_path_prop_bytes(di_path_prop, &bdata); 1177 if (len > 0) 1178 add_bytes_prop(nodeh, propinfo, 1179 di_val, bdata, len); 1180 else if (len == 0) 1181 add_boolean_prop(nodeh, propinfo, 1182 di_val); 1183 break; 1184 case DI_PROP_TYPE_UNDEF_IT: 1185 break; 1186 default: 1187 break; 1188 } 1189 } 1190 1191 /* 1192 * Add nodes for path information (PSARC/1999/647, PSARC/2008/437) 1193 */ 1194 static void 1195 construct_mpath_node(picl_nodehdl_t parh, di_node_t di_node) 1196 { 1197 di_path_t pi = DI_PATH_NIL; 1198 1199 while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) { 1200 di_node_t phci_node = di_path_phci_node(pi); 1201 di_path_prop_t di_path_prop; 1202 picl_nodehdl_t nodeh; 1203 ptree_propinfo_t propinfo; 1204 int err; 1205 int instance; 1206 char *di_val; 1207 1208 if (phci_node == DI_PATH_NIL) 1209 continue; 1210 1211 err = ptree_create_and_add_node(parh, PICL_CLASS_MULTIPATH, 1212 PICL_CLASS_MULTIPATH, &nodeh); 1213 if (err != PICL_SUCCESS) 1214 continue; 1215 1216 instance = di_instance(phci_node); 1217 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1218 PICL_PTYPE_INT, PICL_READ, sizeof (instance), 1219 PICL_PROP_INSTANCE, NULL, NULL); 1220 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, 1221 NULL); 1222 1223 di_val = di_devfs_path(phci_node); 1224 if (di_val) { 1225 (void) ptree_init_propinfo(&propinfo, 1226 PTREE_PROPINFO_VERSION, 1227 PICL_PTYPE_CHARSTRING, PICL_READ, 1228 strlen(di_val) + 1, PICL_PROP_DEVFS_PATH, 1229 NULL, NULL); 1230 (void) ptree_create_and_add_prop(nodeh, 1231 &propinfo, di_val, NULL); 1232 di_devfs_path_free(di_val); 1233 } 1234 1235 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1236 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), 1237 MAX_STATE_SIZE, PICL_PROP_STATE, get_path_state_name, NULL); 1238 (void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL); 1239 1240 for (di_path_prop = di_path_prop_next(pi, DI_PROP_NIL); 1241 di_path_prop != DI_PROP_NIL; 1242 di_path_prop = di_path_prop_next(pi, di_path_prop)) { 1243 add_di_path_prop(nodeh, di_path_prop); 1244 } 1245 } 1246 } 1247 1248 /* 1249 * Add properties provided by libdevinfo 1250 */ 1251 static void 1252 add_devinfo_props(picl_nodehdl_t nodeh, di_node_t di_node) 1253 { 1254 int instance; 1255 char *di_val; 1256 di_prop_t di_prop; 1257 int di_ptype; 1258 ptree_propinfo_t propinfo; 1259 char *sdata; 1260 unsigned char *bdata; 1261 int *idata; 1262 int len; 1263 1264 instance = di_instance(di_node); 1265 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1266 PICL_PTYPE_INT, PICL_READ, sizeof (instance), PICL_PROP_INSTANCE, 1267 NULL, NULL); 1268 (void) ptree_create_and_add_prop(nodeh, &propinfo, &instance, NULL); 1269 1270 di_val = di_bus_addr(di_node); 1271 if (di_val) { 1272 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1273 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1274 PICL_PROP_BUS_ADDR, NULL, NULL); 1275 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1276 NULL); 1277 } 1278 1279 di_val = di_binding_name(di_node); 1280 if (di_val) { 1281 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1282 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1283 PICL_PROP_BINDING_NAME, NULL, NULL); 1284 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1285 NULL); 1286 } 1287 1288 di_val = di_driver_name(di_node); 1289 if (di_val) { 1290 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1291 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1292 PICL_PROP_DRIVER_NAME, NULL, NULL); 1293 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1294 NULL); 1295 } 1296 1297 di_val = di_devfs_path(di_node); 1298 if (di_val) { 1299 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1300 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(di_val) + 1, 1301 PICL_PROP_DEVFS_PATH, NULL, NULL); 1302 (void) ptree_create_and_add_prop(nodeh, &propinfo, di_val, 1303 NULL); 1304 di_devfs_path_free(di_val); 1305 } 1306 1307 for (di_prop = di_prop_next(di_node, DI_PROP_NIL); 1308 di_prop != DI_PROP_NIL; 1309 di_prop = di_prop_next(di_node, di_prop)) { 1310 1311 di_val = di_prop_name(di_prop); 1312 di_ptype = di_prop_type(di_prop); 1313 1314 switch (di_ptype) { 1315 case DI_PROP_TYPE_BOOLEAN: 1316 add_boolean_prop(nodeh, propinfo, di_val); 1317 break; 1318 case DI_PROP_TYPE_INT: 1319 len = di_prop_ints(di_prop, &idata); 1320 if (len < 0) 1321 /* Received error, so ignore prop */ 1322 break; 1323 add_uints_prop(nodeh, propinfo, di_val, idata, len); 1324 break; 1325 case DI_PROP_TYPE_STRING: 1326 len = di_prop_strings(di_prop, &sdata); 1327 if (len < 0) 1328 break; 1329 add_strings_prop(nodeh, propinfo, di_val, sdata, len); 1330 break; 1331 case DI_PROP_TYPE_BYTE: 1332 len = di_prop_bytes(di_prop, &bdata); 1333 if (len < 0) 1334 break; 1335 add_bytes_prop(nodeh, propinfo, di_val, bdata, len); 1336 break; 1337 case DI_PROP_TYPE_UNKNOWN: 1338 /* 1339 * Unknown type, we'll try and guess what it should be. 1340 */ 1341 len = di_prop_strings(di_prop, &sdata); 1342 if ((len > 0) && (sdata[0] != 0)) { 1343 add_strings_prop(nodeh, propinfo, di_val, sdata, 1344 len); 1345 break; 1346 } 1347 len = di_prop_ints(di_prop, &idata); 1348 if (len > 0) { 1349 add_uints_prop(nodeh, propinfo, di_val, 1350 idata, len); 1351 break; 1352 } 1353 len = di_prop_rawdata(di_prop, &bdata); 1354 if (len > 0) 1355 add_bytes_prop(nodeh, propinfo, 1356 di_val, bdata, len); 1357 else if (len == 0) 1358 add_boolean_prop(nodeh, propinfo, 1359 di_val); 1360 break; 1361 case DI_PROP_TYPE_UNDEF_IT: 1362 break; 1363 default: 1364 break; 1365 } 1366 } 1367 } 1368 1369 /* 1370 * This function creates the /obp node in the PICL tree for OBP nodes 1371 * without a device type class. 1372 */ 1373 static int 1374 construct_picl_openprom(picl_nodehdl_t rooth, picl_nodehdl_t *obph) 1375 { 1376 picl_nodehdl_t tmph; 1377 int err; 1378 1379 err = ptree_create_and_add_node(rooth, PICL_NODE_OBP, 1380 PICL_CLASS_PICL, &tmph); 1381 1382 if (err != PICL_SUCCESS) 1383 return (err); 1384 *obph = tmph; 1385 return (PICL_SUCCESS); 1386 } 1387 1388 /* 1389 * This function creates the /platform node in the PICL tree and 1390 * its properties. It sets the "platform-name" property to the 1391 * platform name 1392 */ 1393 static int 1394 construct_picl_platform(picl_nodehdl_t rooth, di_node_t di_root, 1395 picl_nodehdl_t *piclh) 1396 { 1397 int err; 1398 picl_nodehdl_t plafh; 1399 char *nodename; 1400 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1401 ptree_propinfo_t propinfo; 1402 picl_prophdl_t proph; 1403 1404 nodename = di_node_name(di_root); 1405 if (nodename == NULL) 1406 return (PICL_FAILURE); 1407 1408 err = 0; 1409 if (di_nodeid(di_root) == DI_PROM_NODEID || 1410 di_nodeid(di_root) == DI_SID_NODEID) 1411 err = get_device_type(nodeclass, di_root); 1412 1413 if (err < 0) 1414 (void) strcpy(nodeclass, PICL_CLASS_UPA); /* default */ 1415 1416 err = ptree_create_and_add_node(rooth, PICL_NODE_PLATFORM, 1417 nodeclass, &plafh); 1418 if (err != PICL_SUCCESS) 1419 return (err); 1420 1421 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1422 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(nodename) + 1, 1423 PICL_PROP_PLATFORM_NAME, NULL, NULL); 1424 err = ptree_create_and_add_prop(plafh, &propinfo, nodename, &proph); 1425 if (err != PICL_SUCCESS) 1426 return (err); 1427 1428 (void) add_devinfo_props(plafh, di_root); 1429 1430 (void) add_openprom_props(plafh, di_root); 1431 1432 *piclh = plafh; 1433 1434 return (PICL_SUCCESS); 1435 } 1436 1437 /* 1438 * This function creates a node in /obp tree for the libdevinfo handle. 1439 */ 1440 static int 1441 construct_obp_node(picl_nodehdl_t parh, di_node_t dn, picl_nodehdl_t *chdh) 1442 { 1443 int err; 1444 char *nodename; 1445 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1446 picl_nodehdl_t anodeh; 1447 1448 nodename = di_node_name(dn); /* PICL_PROP_NAME */ 1449 if (nodename == NULL) 1450 return (PICL_FAILURE); 1451 1452 if (strcmp(nodename, "pseudo") == 0) 1453 return (PICL_FAILURE); 1454 1455 if ((di_nodeid(dn) == DI_PROM_NODEID) && 1456 (get_device_type(nodeclass, dn) == 0)) 1457 return (PICL_FAILURE); 1458 1459 err = ptree_create_and_add_node(parh, nodename, nodename, &anodeh); 1460 if (err != PICL_SUCCESS) 1461 return (err); 1462 1463 add_devinfo_props(anodeh, dn); 1464 1465 (void) add_openprom_props(anodeh, dn); 1466 1467 *chdh = anodeh; 1468 1469 return (PICL_SUCCESS); 1470 } 1471 1472 /* 1473 * This function creates a PICL node in /platform tree for a device 1474 */ 1475 static int 1476 construct_devtype_node(picl_nodehdl_t parh, char *nodename, 1477 char *nodeclass, di_node_t dn, picl_nodehdl_t *chdh) 1478 { 1479 int err; 1480 picl_nodehdl_t anodeh; 1481 1482 err = ptree_create_and_add_node(parh, nodename, nodeclass, &anodeh); 1483 if (err != PICL_SUCCESS) 1484 return (err); 1485 1486 (void) add_devinfo_props(anodeh, dn); 1487 (void) add_openprom_props(anodeh, dn); 1488 construct_mpath_node(anodeh, dn); 1489 1490 *chdh = anodeh; 1491 return (err); 1492 } 1493 1494 /* 1495 * Create a subtree of "picl" class nodes in /obp for these nodes 1496 */ 1497 static int 1498 construct_openprom_tree(picl_nodehdl_t nodeh, di_node_t dinode) 1499 { 1500 di_node_t cnode; 1501 picl_nodehdl_t chdh; 1502 int err; 1503 1504 err = construct_obp_node(nodeh, dinode, &chdh); 1505 if (err != PICL_SUCCESS) 1506 return (err); 1507 1508 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1509 cnode = di_sibling_node(cnode)) 1510 (void) construct_openprom_tree(chdh, cnode); 1511 1512 return (PICL_SUCCESS); 1513 1514 } 1515 1516 /* 1517 * Process the libdevinfo device tree and create nodes in /platform or /obp 1518 * PICL tree. 1519 * 1520 * This routine traverses the immediate children of "dinode" device and 1521 * determines the node class for that child. If it finds a valid class 1522 * name, then it builds a PICL node under /platform subtree and calls itself 1523 * recursively to construct the subtree for that child node. Otherwise, if 1524 * the parent_class is NULL, then it constructs a node and subtree under /obp 1525 * subtree. 1526 * 1527 * Note that we skip the children nodes that don't have a valid class name 1528 * and the parent_class is non NULL to prevent creation of any placeholder 1529 * nodes (such as sd,...). 1530 */ 1531 static int 1532 construct_devinfo_tree(picl_nodehdl_t plafh, picl_nodehdl_t obph, 1533 di_node_t dinode, char *parent_class) 1534 { 1535 di_node_t cnode; 1536 picl_nodehdl_t chdh; 1537 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1538 char *nodename; 1539 int err; 1540 1541 err = PICL_SUCCESS; 1542 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1543 cnode = di_sibling_node(cnode)) { 1544 nodename = di_node_name(cnode); /* PICL_PROP_NAME */ 1545 if (nodename == NULL) 1546 continue; 1547 1548 err = get_node_class(nodeclass, cnode, nodename); 1549 1550 if (err == 0) { 1551 err = construct_devtype_node(plafh, nodename, 1552 nodeclass, cnode, &chdh); 1553 if (err != PICL_SUCCESS) 1554 return (err); 1555 err = construct_devinfo_tree(chdh, obph, cnode, 1556 nodeclass); 1557 } else if (parent_class == NULL) 1558 err = construct_openprom_tree(obph, cnode); 1559 else 1560 continue; 1561 /* 1562 * if parent_class is non NULL, skip the children nodes 1563 * that don't have a valid device class - eliminates 1564 * placeholder nodes (sd,...) from being created. 1565 */ 1566 } 1567 1568 return (err); 1569 1570 } 1571 1572 /* 1573 * This function is called from the event handler called from the daemon 1574 * on PICL events. 1575 * 1576 * This routine traverses the children of the "dinode" device and 1577 * creates a PICL node for each child not found in the PICL tree and 1578 * invokes itself recursively to create a subtree for the newly created 1579 * child node. It also checks if the node being created is a meory 1580 * controller. If so, it posts PICLEVENT_MC_ADDED PICL event to the PICL 1581 * framework. 1582 */ 1583 static int 1584 update_subtree(picl_nodehdl_t nodeh, di_node_t dinode) 1585 { 1586 di_node_t cnode; 1587 picl_nodehdl_t chdh; 1588 picl_nodehdl_t nh; 1589 char *nodename; 1590 char nodeclass[PICL_CLASSNAMELEN_MAX]; 1591 char *path_buf; 1592 char buf[MAX_UNIT_ADDRESS_LEN]; 1593 char unitaddr[MAX_UNIT_ADDRESS_LEN]; 1594 char path_w_ua[MAXPATHLEN]; 1595 char path_wo_ua[MAXPATHLEN]; 1596 char *strp; 1597 int gotit; 1598 int err; 1599 1600 for (cnode = di_child_node(dinode); cnode != DI_NODE_NIL; 1601 cnode = di_sibling_node(cnode)) { 1602 path_buf = di_devfs_path(cnode); 1603 if (path_buf == NULL) 1604 continue; 1605 1606 nodename = di_node_name(cnode); 1607 if (nodename == NULL) { 1608 di_devfs_path_free(path_buf); 1609 continue; 1610 } 1611 1612 err = get_node_class(nodeclass, cnode, nodename); 1613 1614 if (err < 0) { 1615 di_devfs_path_free(path_buf); 1616 continue; 1617 } 1618 1619 /* 1620 * this is quite complicated - both path_buf and any nodes 1621 * already in the picl tree may, or may not, have the 1622 * @<unit_addr> at the end of their names. So we must 1623 * take path_buf and work out what the device path would 1624 * be both with and without the unit_address, then search 1625 * the picl tree for both forms. 1626 */ 1627 if (((strp = strrchr(path_buf, '/')) != NULL) && 1628 strchr(strp, '@') == NULL) { 1629 /* 1630 * This is an unattached node - so the path is not 1631 * unique. Need to find out which node it is. 1632 * Find the unit_address from the OBP or devinfo 1633 * properties. 1634 */ 1635 err = ptree_create_node(nodename, nodeclass, &chdh); 1636 if (err != PICL_SUCCESS) 1637 return (err); 1638 1639 (void) add_devinfo_props(chdh, cnode); 1640 (void) add_openprom_props(chdh, cnode); 1641 1642 err = get_unitaddr(nodeh, chdh, unitaddr, 1643 sizeof (unitaddr)); 1644 if (err != PICL_SUCCESS) 1645 return (err); 1646 (void) ptree_destroy_node(chdh); 1647 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s@%s", 1648 path_buf, unitaddr); 1649 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1650 path_buf); 1651 } else { 1652 /* 1653 * this is an attached node - so the path is unique 1654 */ 1655 (void) snprintf(path_w_ua, sizeof (path_w_ua), "%s", 1656 path_buf); 1657 (void) snprintf(path_wo_ua, sizeof (path_wo_ua), "%s", 1658 path_buf); 1659 strp = strrchr(path_wo_ua, '@'); 1660 *strp++ = '\0'; 1661 (void) snprintf(unitaddr, sizeof (unitaddr), "%s", 1662 strp); 1663 } 1664 /* 1665 * first look for node with unit address in devfs_path 1666 */ 1667 if (ptree_find_node(nodeh, PICL_PROP_DEVFS_PATH, 1668 PICL_PTYPE_CHARSTRING, path_w_ua, strlen(path_w_ua) + 1, 1669 &nh) == PICL_SUCCESS) { 1670 /* 1671 * node already there - there's nothing we need to do 1672 */ 1673 if (picldevtree_debug > 1) 1674 syslog(LOG_INFO, 1675 "update_subtree: path:%s node exists\n", 1676 path_buf); 1677 di_devfs_path_free(path_buf); 1678 continue; 1679 } 1680 /* 1681 * now look for node without unit address in devfs_path. 1682 * This might be just one out of several 1683 * nodes - need to check all siblings 1684 */ 1685 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, 1686 &chdh, sizeof (chdh)); 1687 if ((err != PICL_SUCCESS) && (err != PICL_PROPNOTFOUND)) 1688 return (err); 1689 gotit = 0; 1690 while (err == PICL_SUCCESS) { 1691 err = ptree_get_propval_by_name(chdh, 1692 PICL_PROP_DEVFS_PATH, buf, sizeof (buf)); 1693 if (err != PICL_SUCCESS) 1694 return (err); 1695 if (strcmp(buf, path_wo_ua) == 0) { 1696 err = ptree_get_propval_by_name(chdh, 1697 PICL_PROP_UNIT_ADDRESS, buf, sizeof (buf)); 1698 if (err != PICL_SUCCESS) 1699 return (err); 1700 if (strcmp(buf, unitaddr) == 0) { 1701 gotit = 1; 1702 break; 1703 } 1704 } 1705 err = ptree_get_propval_by_name(chdh, 1706 PICL_PROP_PEER, &chdh, sizeof (chdh)); 1707 if (err != PICL_SUCCESS) 1708 break; 1709 } 1710 if (gotit) { 1711 /* 1712 * node already there - there's nothing we need to do 1713 */ 1714 if (picldevtree_debug > 1) 1715 syslog(LOG_INFO, 1716 "update_subtree: path:%s node exists\n", 1717 path_buf); 1718 di_devfs_path_free(path_buf); 1719 continue; 1720 } 1721 1722 #define IS_MC(x) (strcmp(x, PICL_CLASS_MEMORY_CONTROLLER) == 0 ? 1 : 0) 1723 1724 if (construct_devtype_node(nodeh, nodename, nodeclass, cnode, 1725 &chdh) == PICL_SUCCESS) { 1726 if (picldevtree_debug) 1727 syslog(LOG_INFO, 1728 "picldevtree: added node:%s path:%s\n", 1729 nodename, path_buf); 1730 if (IS_MC(nodeclass)) { 1731 if (post_mc_event(PICLEVENT_MC_ADDED, chdh) != 1732 PICL_SUCCESS) 1733 syslog(LOG_WARNING, PICL_EVENT_DROPPED, 1734 PICLEVENT_MC_ADDED); 1735 } 1736 1737 di_devfs_path_free(path_buf); 1738 (void) update_subtree(chdh, cnode); 1739 } 1740 } 1741 1742 return (PICL_SUCCESS); 1743 1744 } 1745 1746 /* 1747 * Check for a stale OBP node. EINVAL is returned from the openprom(7D) driver 1748 * if the nodeid stored in the snapshot is not valid. 1749 */ 1750 static int 1751 check_stale_node(di_node_t node, void *arg) 1752 { 1753 di_prom_prop_t promp; 1754 1755 errno = 0; 1756 promp = di_prom_prop_next(ph, node, DI_PROM_PROP_NIL); 1757 if (promp == DI_PROM_PROP_NIL && errno == EINVAL) { 1758 snapshot_stale = 1; 1759 return (DI_WALK_TERMINATE); 1760 } 1761 return (DI_WALK_CONTINUE); 1762 } 1763 1764 /* 1765 * Walk the snapshot and check the OBP properties of each node. 1766 */ 1767 static int 1768 is_snapshot_stale(di_node_t root) 1769 { 1770 snapshot_stale = 0; 1771 di_walk_node(root, DI_WALK_CLDFIRST, NULL, check_stale_node); 1772 return (snapshot_stale); 1773 } 1774 1775 /* 1776 * This function processes the data from libdevinfo and creates nodes 1777 * in the PICL tree. 1778 */ 1779 static int 1780 libdevinfo_init(picl_nodehdl_t rooth) 1781 { 1782 di_node_t di_root; 1783 picl_nodehdl_t plafh; 1784 picl_nodehdl_t obph; 1785 int err; 1786 1787 /* 1788 * Use DINFOCACHE so that we obtain all attributes for all 1789 * device instances (without necessarily doing a load/attach 1790 * of all drivers). Once the (on-disk) cache file is built, it 1791 * exists over a reboot and can be read into memory at a very 1792 * low cost. 1793 */ 1794 if ((di_root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) 1795 return (PICL_FAILURE); 1796 1797 if ((ph = di_prom_init()) == NULL) 1798 return (PICL_FAILURE); 1799 1800 /* 1801 * Check if the snapshot cache contains stale OBP nodeid references. 1802 * If it does release the snapshot and obtain a live snapshot from the 1803 * kernel. 1804 */ 1805 if (is_snapshot_stale(di_root)) { 1806 syslog(LOG_INFO, "picld detected stale snapshot cache"); 1807 di_fini(di_root); 1808 if ((di_root = di_init("/", DINFOCPYALL | DINFOFORCE)) == 1809 DI_NODE_NIL) { 1810 return (PICL_FAILURE); 1811 } 1812 } 1813 1814 /* 1815 * create platform PICL node using di_root node 1816 */ 1817 err = construct_picl_platform(rooth, di_root, &plafh); 1818 if (err != PICL_SUCCESS) { 1819 di_fini(di_root); 1820 return (PICL_FAILURE); 1821 } 1822 1823 err = construct_picl_openprom(rooth, &obph); 1824 if (err != PICL_SUCCESS) { 1825 di_fini(di_root); 1826 return (PICL_FAILURE); 1827 } 1828 1829 (void) construct_devinfo_tree(plafh, obph, di_root, NULL); 1830 if (ph) { 1831 di_prom_fini(ph); 1832 ph = NULL; 1833 } 1834 di_fini(di_root); 1835 return (err); 1836 } 1837 1838 /* 1839 * This function returns the integer property value 1840 */ 1841 static int 1842 get_int_propval_by_name(picl_nodehdl_t nodeh, char *pname, int *ival) 1843 { 1844 int err; 1845 1846 err = ptree_get_propval_by_name(nodeh, pname, ival, 1847 sizeof (int)); 1848 1849 return (err); 1850 } 1851 1852 /* 1853 * This function returns the port ID (or CPU ID in the case of CMP cores) 1854 * of the specific CPU node handle. If upa_portid exists, return its value. 1855 * Otherwise, return portid/cpuid. 1856 */ 1857 static int 1858 get_cpu_portid(picl_nodehdl_t modh, int *id) 1859 { 1860 int err; 1861 1862 if (strcmp(mach_name, "sun4u") == 0 || 1863 strcmp(mach_name, "sun4v") == 0) { 1864 err = get_int_propval_by_name(modh, OBP_PROP_UPA_PORTID, id); 1865 if (err == PICL_SUCCESS) 1866 return (err); 1867 err = get_int_propval_by_name(modh, OBP_PROP_PORTID, id); 1868 if (err == PICL_SUCCESS) 1869 return (err); 1870 return (get_int_propval_by_name(modh, OBP_PROP_CPUID, id)); 1871 } 1872 if (strcmp(mach_name, "i86pc") == 0) 1873 return (get_int_propval_by_name(modh, OBP_REG, id)); 1874 1875 return (PICL_FAILURE); 1876 } 1877 1878 /* 1879 * This function is the volatile read access function of CPU state 1880 * property 1881 */ 1882 static int 1883 get_pi_state(ptree_rarg_t *rarg, void *vbuf) 1884 { 1885 int id; 1886 int err; 1887 1888 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1889 if (err != PICL_SUCCESS) 1890 return (err); 1891 1892 switch (p_online(id, P_STATUS)) { 1893 case P_ONLINE: 1894 (void) strlcpy(vbuf, PS_ONLINE, MAX_STATE_SIZE); 1895 break; 1896 case P_OFFLINE: 1897 (void) strlcpy(vbuf, PS_OFFLINE, MAX_STATE_SIZE); 1898 break; 1899 case P_NOINTR: 1900 (void) strlcpy(vbuf, PS_NOINTR, MAX_STATE_SIZE); 1901 break; 1902 case P_SPARE: 1903 (void) strlcpy(vbuf, PS_SPARE, MAX_STATE_SIZE); 1904 break; 1905 case P_FAULTED: 1906 (void) strlcpy(vbuf, PS_FAULTED, MAX_STATE_SIZE); 1907 break; 1908 case P_POWEROFF: 1909 (void) strlcpy(vbuf, PS_POWEROFF, MAX_STATE_SIZE); 1910 break; 1911 default: 1912 (void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE); 1913 break; 1914 } 1915 return (PICL_SUCCESS); 1916 } 1917 1918 /* 1919 * This function is the volatile read access function of CPU processor_type 1920 * property 1921 */ 1922 static int 1923 get_processor_type(ptree_rarg_t *rarg, void *vbuf) 1924 { 1925 processor_info_t cpu_info; 1926 int id; 1927 int err; 1928 1929 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1930 if (err != PICL_SUCCESS) 1931 return (err); 1932 1933 if (processor_info(id, &cpu_info) >= 0) { 1934 (void) strlcpy(vbuf, cpu_info.pi_processor_type, PI_TYPELEN); 1935 } 1936 return (PICL_SUCCESS); 1937 } 1938 1939 /* 1940 * This function is the volatile read access function of CPU fputypes 1941 * property 1942 */ 1943 static int 1944 get_fputypes(ptree_rarg_t *rarg, void *vbuf) 1945 { 1946 processor_info_t cpu_info; 1947 int id; 1948 int err; 1949 1950 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id); 1951 if (err != PICL_SUCCESS) 1952 return (err); 1953 1954 if (processor_info(id, &cpu_info) >= 0) { 1955 (void) strlcpy(vbuf, cpu_info.pi_fputypes, PI_FPUTYPE); 1956 } 1957 return (PICL_SUCCESS); 1958 } 1959 1960 /* 1961 * This function is the volatile read access function of CPU StateBegin 1962 * property. To minimize overhead, use kstat_chain_update() to refresh 1963 * the kstat header info as opposed to invoking kstat_open() every time. 1964 */ 1965 static int 1966 get_pi_state_begin(ptree_rarg_t *rarg, void *vbuf) 1967 { 1968 int err; 1969 int cpu_id; 1970 static kstat_ctl_t *kc = NULL; 1971 static pthread_mutex_t kc_mutex = PTHREAD_MUTEX_INITIALIZER; 1972 kstat_t *kp; 1973 kstat_named_t *kn; 1974 1975 err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &cpu_id); 1976 if (err != PICL_SUCCESS) 1977 return (err); 1978 1979 (void) pthread_mutex_lock(&kc_mutex); 1980 if (kc == NULL) 1981 kc = kstat_open(); 1982 else if (kstat_chain_update(kc) == -1) { 1983 (void) kstat_close(kc); 1984 kc = kstat_open(); 1985 } 1986 1987 if (kc == NULL) { 1988 (void) pthread_mutex_unlock(&kc_mutex); 1989 return (PICL_FAILURE); 1990 } 1991 1992 /* Get the state_begin from kstat */ 1993 if ((kp = kstat_lookup(kc, KSTAT_CPU_INFO, cpu_id, NULL)) == NULL || 1994 kp->ks_type != KSTAT_TYPE_NAMED || kstat_read(kc, kp, 0) < 0) { 1995 (void) pthread_mutex_unlock(&kc_mutex); 1996 return (PICL_FAILURE); 1997 } 1998 1999 kn = kstat_data_lookup(kp, KSTAT_STATE_BEGIN); 2000 if (kn) { 2001 *(uint64_t *)vbuf = (uint64_t)kn->value.l; 2002 err = PICL_SUCCESS; 2003 } else 2004 err = PICL_FAILURE; 2005 2006 (void) pthread_mutex_unlock(&kc_mutex); 2007 return (err); 2008 } 2009 2010 /* 2011 * This function adds CPU information to the CPU nodes 2012 */ 2013 /* ARGSUSED */ 2014 static int 2015 add_processor_info(picl_nodehdl_t cpuh, void *args) 2016 { 2017 int err; 2018 int cpu_id; 2019 ptree_propinfo_t propinfo; 2020 ptree_propinfo_t pinfo; 2021 2022 err = get_cpu_portid(cpuh, &cpu_id); 2023 if (err != PICL_SUCCESS) 2024 return (PICL_WALK_CONTINUE); 2025 2026 /* 2027 * Check to make sure that the CPU is still present, i.e. that it 2028 * has not been DR'ed out of the system. 2029 */ 2030 if (p_online(cpu_id, P_STATUS) == -1) { 2031 if (picldevtree_debug) 2032 syslog(LOG_INFO, 2033 "picldevtree: cpu %d (%llx) does not exist - " 2034 "deleting node\n", cpu_id, cpuh); 2035 2036 if (ptree_delete_node(cpuh) == PICL_SUCCESS) 2037 (void) ptree_destroy_node(cpuh); 2038 2039 return (PICL_WALK_CONTINUE); 2040 } 2041 2042 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2043 PICL_PTYPE_INT, PICL_READ, sizeof (int), PICL_PROP_ID, NULL, NULL); 2044 err = ptree_create_and_add_prop(cpuh, &propinfo, &cpu_id, NULL); 2045 if (err != PICL_SUCCESS) 2046 return (PICL_WALK_CONTINUE); 2047 2048 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2049 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), MAX_STATE_SIZE, 2050 PICL_PROP_STATE, get_pi_state, NULL); 2051 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2052 2053 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2054 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_TYPELEN, 2055 PICL_PROP_PROCESSOR_TYPE, get_processor_type, NULL); 2056 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2057 2058 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2059 PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_FPUTYPE, 2060 PICL_PROP_FPUTYPE, get_fputypes, NULL); 2061 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2062 2063 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 2064 PICL_PTYPE_TIMESTAMP, PICL_READ|PICL_VOLATILE, sizeof (uint64_t), 2065 PICL_PROP_STATE_BEGIN, get_pi_state_begin, NULL); 2066 (void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL); 2067 2068 return (PICL_WALK_CONTINUE); 2069 } 2070 2071 /* 2072 * This function sets up the "ID" property in every CPU nodes 2073 * and adds processor info 2074 */ 2075 static int 2076 setup_cpus(picl_nodehdl_t plafh) 2077 { 2078 int err; 2079 2080 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_CPU, NULL, 2081 add_processor_info); 2082 2083 return (err); 2084 } 2085 2086 /* 2087 * This function format's the manufacture's information for FFB display 2088 * devices 2089 */ 2090 static void 2091 fmt_manf_id(manuf_t manufid, int bufsz, char *outbuf) 2092 { 2093 /* 2094 * Format the manufacturer's info. Note a small inconsistency we 2095 * have to work around - Brooktree has it's part number in decimal, 2096 * while Mitsubishi has it's part number in hex. 2097 */ 2098 switch (manufid.fld.manf) { 2099 case MANF_BROOKTREE: 2100 (void) snprintf(outbuf, bufsz, "%s %d, version %d", 2101 "Brooktree", manufid.fld.partno, manufid.fld.version); 2102 break; 2103 2104 case MANF_MITSUBISHI: 2105 (void) snprintf(outbuf, bufsz, "%s %x, version %d", 2106 "Mitsubishi", manufid.fld.partno, manufid.fld.version); 2107 break; 2108 2109 default: 2110 (void) snprintf(outbuf, bufsz, 2111 "JED code %d, Part num 0x%x, version %d", 2112 manufid.fld.manf, manufid.fld.partno, manufid.fld.version); 2113 } 2114 } 2115 2116 /* 2117 * If it's an ffb device, open ffb devices and return PICL_SUCCESS 2118 */ 2119 static int 2120 open_ffb_device(picl_nodehdl_t ffbh, int *fd) 2121 { 2122 DIR *dirp; 2123 char devfs_path[PATH_MAX]; 2124 char dev_path[PATH_MAX]; 2125 char *devp; 2126 struct dirent *direntp; 2127 int err; 2128 int tmpfd; 2129 2130 /* Get the devfs_path of the ffb devices */ 2131 err = ptree_get_propval_by_name(ffbh, PICL_PROP_DEVFS_PATH, devfs_path, 2132 sizeof (devfs_path)); 2133 if (err != PICL_SUCCESS) 2134 return (err); 2135 2136 /* Get the device node name */ 2137 devp = strrchr(devfs_path, '/'); 2138 if (devp == NULL) 2139 return (PICL_FAILURE); 2140 *devp = '\0'; 2141 ++devp; 2142 2143 /* 2144 * Check if device node name has the ffb string 2145 * If not, assume it's not a ffb device. 2146 */ 2147 if (strstr(devp, FFB_NAME) == NULL) 2148 return (PICL_FAILURE); 2149 2150 /* 2151 * Get the parent path of the ffb device node. 2152 */ 2153 (void) snprintf(dev_path, sizeof (dev_path), "%s/%s", "/devices", 2154 devfs_path); 2155 2156 /* 2157 * Since we don't know ffb's minor nodename, 2158 * we need to search all the devices under its 2159 * parent dir by comparing the node name 2160 */ 2161 if ((dirp = opendir(dev_path)) == NULL) 2162 return (PICL_FAILURE); 2163 2164 while ((direntp = readdir(dirp)) != NULL) { 2165 if (strstr(direntp->d_name, devp) != NULL) { 2166 (void) strcat(dev_path, "/"); 2167 (void) strcat(dev_path, direntp->d_name); 2168 tmpfd = open(dev_path, O_RDWR); 2169 if (tmpfd < 0) 2170 continue; 2171 *fd = tmpfd; 2172 (void) closedir(dirp); 2173 return (PICL_SUCCESS); 2174 } 2175 } 2176 2177 (void) closedir(dirp); 2178 return (PICL_FAILURE); 2179 } 2180 2181 /* 2182 * This function recursively searches the tree for ffb display devices 2183 * and add ffb config information 2184 */ 2185 static int 2186 add_ffb_config_info(picl_nodehdl_t rooth) 2187 { 2188 picl_nodehdl_t nodeh; 2189 int err; 2190 char piclclass[PICL_CLASSNAMELEN_MAX]; 2191 char manfidbuf[FFB_MANUF_BUFSIZE]; 2192 int fd; 2193 int board_rev; 2194 ffb_sys_info_t fsi; 2195 ptree_propinfo_t pinfo; 2196 2197 for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh, 2198 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2199 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, 2200 &nodeh, sizeof (picl_nodehdl_t))) { 2201 2202 if (err != PICL_SUCCESS) 2203 return (err); 2204 2205 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 2206 piclclass, PICL_CLASSNAMELEN_MAX); 2207 2208 if ((err == PICL_SUCCESS) && 2209 (strcmp(piclclass, PICL_CLASS_DISPLAY) == 0)) { 2210 2211 err = open_ffb_device(nodeh, &fd); 2212 if ((err == PICL_SUCCESS) && 2213 (ioctl(fd, FFB_SYS_INFO, &fsi) >= 0)) { 2214 (void) ptree_init_propinfo(&pinfo, 2215 PTREE_PROPINFO_VERSION, 2216 PICL_PTYPE_UNSIGNED_INT, PICL_READ, 2217 sizeof (int), PICL_PROP_FFB_BOARD_REV, 2218 NULL, NULL); 2219 board_rev = fsi.ffb_strap_bits.fld.board_rev; 2220 (void) ptree_create_and_add_prop(nodeh, &pinfo, 2221 &board_rev, NULL); 2222 2223 fmt_manf_id(fsi.dac_version, 2224 sizeof (manfidbuf), manfidbuf); 2225 (void) ptree_init_propinfo(&pinfo, 2226 PTREE_PROPINFO_VERSION, 2227 PICL_PTYPE_CHARSTRING, PICL_READ, 2228 strlen(manfidbuf) + 1, 2229 PICL_PROP_FFB_DAC_VER, NULL, NULL); 2230 (void) ptree_create_and_add_prop(nodeh, &pinfo, 2231 manfidbuf, NULL); 2232 2233 fmt_manf_id(fsi.fbram_version, 2234 sizeof (manfidbuf), manfidbuf); 2235 (void) ptree_init_propinfo(&pinfo, 2236 PTREE_PROPINFO_VERSION, 2237 PICL_PTYPE_CHARSTRING, PICL_READ, 2238 strlen(manfidbuf) + 1, 2239 PICL_PROP_FFB_FBRAM_VER, NULL, 2240 NULL); 2241 (void) ptree_create_and_add_prop(nodeh, &pinfo, 2242 manfidbuf, NULL); 2243 (void) close(fd); 2244 } 2245 } else if (add_ffb_config_info(nodeh) != PICL_SUCCESS) 2246 return (PICL_FAILURE); 2247 } 2248 return (PICL_SUCCESS); 2249 } 2250 2251 static conf_entries_t * 2252 free_conf_entries(conf_entries_t *list) 2253 { 2254 conf_entries_t *el; 2255 conf_entries_t *del; 2256 2257 if (list == NULL) 2258 return (NULL); 2259 el = list; 2260 while (el != NULL) { 2261 del = el; 2262 el = el->next; 2263 free(del->name); 2264 free(del->piclclass); 2265 free(del); 2266 } 2267 return (el); 2268 } 2269 2270 /* 2271 * Reading config order: platform, common 2272 */ 2273 static conf_entries_t * 2274 read_conf_file(char *fname, conf_entries_t *list) 2275 { 2276 FILE *fp; 2277 char lbuf[CONFFILE_LINELEN_MAX]; 2278 char *nametok; 2279 char *classtok; 2280 conf_entries_t *el; 2281 conf_entries_t *ptr; 2282 2283 if (fname == NULL) 2284 return (list); 2285 2286 fp = fopen(fname, "r"); 2287 2288 if (fp == NULL) 2289 return (list); 2290 2291 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 2292 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 2293 continue; 2294 2295 nametok = strtok(lbuf, " \t\n"); 2296 if (nametok == NULL) 2297 continue; 2298 2299 classtok = strtok(NULL, " \t\n"); 2300 if (classtok == NULL) 2301 continue; 2302 2303 el = malloc(sizeof (conf_entries_t)); 2304 if (el == NULL) 2305 break; 2306 el->name = strdup(nametok); 2307 el->piclclass = strdup(classtok); 2308 if ((el->name == NULL) || (el->piclclass == NULL)) { 2309 free(el); 2310 return (list); 2311 } 2312 el->next = NULL; 2313 2314 /* 2315 * Add it to the end of list 2316 */ 2317 if (list == NULL) 2318 list = el; 2319 else { 2320 ptr = list; 2321 while (ptr->next != NULL) 2322 ptr = ptr->next; 2323 ptr->next = el; 2324 } 2325 2326 } 2327 (void) fclose(fp); 2328 return (list); 2329 } 2330 2331 /* 2332 * Process the devtree conf file and set up the conf_name_class_map list 2333 */ 2334 static void 2335 process_devtree_conf_file(void) 2336 { 2337 char nmbuf[SYS_NMLN]; 2338 char pname[PATH_MAX]; 2339 2340 conf_name_class_map = NULL; 2341 2342 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2343 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2344 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2345 conf_name_class_map = read_conf_file(pname, 2346 conf_name_class_map); 2347 } 2348 2349 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2350 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2351 (void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX); 2352 conf_name_class_map = read_conf_file(pname, 2353 conf_name_class_map); 2354 } 2355 2356 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2357 DEVTREE_CONFFILE_NAME); 2358 conf_name_class_map = read_conf_file(pname, conf_name_class_map); 2359 } 2360 2361 static asr_conf_entries_t *conf_name_asr_map = NULL; 2362 2363 static void 2364 free_asr_conf_entries(asr_conf_entries_t *list) { 2365 asr_conf_entries_t *el; 2366 asr_conf_entries_t *del; 2367 2368 el = list; 2369 while (el != NULL) { 2370 del = el; 2371 el = el->next; 2372 if (del->name) 2373 free(del->name); 2374 if (del->address) 2375 free(del->address); 2376 if (del->status) 2377 free(del->status); 2378 if (del->piclclass) 2379 free(del->piclclass); 2380 if (del->props) 2381 free(del->props); 2382 free(del); 2383 } 2384 } 2385 2386 /* 2387 * Reading config order: platform, common 2388 */ 2389 static asr_conf_entries_t * 2390 read_asr_conf_file(char *fname, asr_conf_entries_t *list) 2391 { 2392 FILE *fp; 2393 char lbuf[CONFFILE_LINELEN_MAX]; 2394 char *nametok; 2395 char *classtok; 2396 char *statustok; 2397 char *addresstok; 2398 char *propstok; 2399 asr_conf_entries_t *el; 2400 asr_conf_entries_t *ptr; 2401 2402 if (fname == NULL) 2403 return (list); 2404 2405 fp = fopen(fname, "r"); 2406 if (fp == NULL) 2407 return (list); 2408 2409 while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) { 2410 if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n')) 2411 continue; 2412 2413 nametok = strtok(lbuf, " \t\n"); 2414 if (nametok == NULL) 2415 continue; 2416 2417 classtok = strtok(NULL, " \t\n"); 2418 if (classtok == NULL) 2419 continue; 2420 2421 statustok = strtok(NULL, " \t\n"); 2422 if (statustok == NULL) 2423 continue; 2424 2425 addresstok = strtok(NULL, " \t\n"); 2426 if (addresstok == NULL) 2427 continue; 2428 2429 /* 2430 * props are optional 2431 */ 2432 propstok = strtok(NULL, " \t\n"); 2433 2434 el = malloc(sizeof (asr_conf_entries_t)); 2435 if (el == NULL) 2436 break; 2437 el->name = strdup(nametok); 2438 el->piclclass = strdup(classtok); 2439 el->status = strdup(statustok); 2440 el->address = strdup(addresstok); 2441 if (propstok != NULL) 2442 el->props = strdup(propstok); 2443 else 2444 el->props = NULL; 2445 if ((el->name == NULL) || (el->piclclass == NULL) || 2446 (el->address == NULL) || (el->status == NULL)) { 2447 if (el->name) 2448 free(el->name); 2449 if (el->address) 2450 free(el->address); 2451 if (el->status) 2452 free(el->status); 2453 if (el->piclclass) 2454 free(el->piclclass); 2455 if (el->props) 2456 free(el->props); 2457 free(el); 2458 break; 2459 } 2460 el->next = NULL; 2461 2462 /* 2463 * Add it to the end of list 2464 */ 2465 if (list == NULL) 2466 list = el; 2467 else { 2468 ptr = list; 2469 while (ptr->next != NULL) 2470 ptr = ptr->next; 2471 ptr->next = el; 2472 } 2473 2474 } 2475 (void) fclose(fp); 2476 return (list); 2477 } 2478 2479 /* 2480 * Process the asr conf file 2481 */ 2482 static void 2483 process_asrtree_conf_file(void) 2484 { 2485 char nmbuf[SYS_NMLN]; 2486 char pname[PATH_MAX]; 2487 2488 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 2489 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2490 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2491 conf_name_asr_map = read_asr_conf_file(pname, 2492 conf_name_asr_map); 2493 } 2494 2495 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 2496 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 2497 (void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX); 2498 conf_name_asr_map = read_asr_conf_file(pname, 2499 conf_name_asr_map); 2500 } 2501 2502 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 2503 ASRTREE_CONFFILE_NAME); 2504 conf_name_asr_map = read_asr_conf_file(pname, conf_name_asr_map); 2505 } 2506 2507 /* 2508 * This function reads the export file list from ASR 2509 */ 2510 static int 2511 get_asr_export_list(char **exportlist, int *exportlistlen) 2512 { 2513 struct openpromio oppbuf; 2514 struct openpromio *opp = &oppbuf; 2515 int d; 2516 int listsize; 2517 2518 d = open("/dev/openprom", O_RDWR); 2519 if (d < 0) 2520 return (0); 2521 2522 if (ioctl(d, OPROMEXPORTLEN, opp) == -1) { 2523 (void) close(d); 2524 return (0); 2525 } 2526 listsize = opp->oprom_size; 2527 opp = (struct openpromio *)malloc(sizeof (struct openpromio) + 2528 listsize); 2529 if (opp == NULL) { 2530 (void) close(d); 2531 return (0); 2532 } 2533 (void) memset(opp, '\0', sizeof (struct openpromio) + listsize); 2534 opp->oprom_size = listsize; 2535 if (ioctl(d, OPROMEXPORT, opp) == -1) { 2536 free(opp); 2537 (void) close(d); 2538 return (0); 2539 } 2540 *exportlist = malloc(listsize); 2541 if (*exportlist == NULL) { 2542 free(opp); 2543 (void) close(d); 2544 return (0); 2545 } 2546 (void) memcpy(*exportlist, opp->oprom_array, opp->oprom_size); 2547 free(opp); 2548 *exportlistlen = opp->oprom_size; 2549 (void) close(d); 2550 return (1); 2551 } 2552 2553 /* 2554 * Parses properties string, fills in triplet structure with first 2555 * type, name, val triplet and returns pointer to next property. 2556 * Returns NULL if no valid triplet found 2557 * CAUTION: drops \0 characters over separator characters: if you 2558 * want to parse the string twice, you'll have to take a copy. 2559 */ 2560 static char * 2561 parse_props_string(char *props, asr_prop_triplet_t *triplet) 2562 { 2563 char *prop_name; 2564 char *prop_val; 2565 char *prop_next; 2566 2567 prop_name = strchr(props, '?'); 2568 if (prop_name == NULL) 2569 return (NULL); 2570 *prop_name++ = '\0'; 2571 prop_val = strchr(prop_name, '='); 2572 if (prop_val == NULL) 2573 return (NULL); 2574 *prop_val++ = '\0'; 2575 triplet->proptype = props; 2576 triplet->propname = prop_name; 2577 triplet->propval = prop_val; 2578 prop_next = strchr(prop_val, ':'); 2579 if (prop_next == NULL) 2580 return (prop_val - 1); 2581 *prop_next++ = '\0'; 2582 return (prop_next); 2583 } 2584 2585 static int 2586 add_status_prop(picl_nodehdl_t chdh, char *status) 2587 { 2588 ptree_propinfo_t propinfo; 2589 picl_prophdl_t proph; 2590 int err; 2591 2592 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2593 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(status) + 1, 2594 PICL_PROP_STATUS, NULL, NULL); 2595 if (err != PICL_SUCCESS) 2596 return (err); 2597 err = ptree_create_and_add_prop(chdh, &propinfo, status, &proph); 2598 return (err); 2599 } 2600 2601 static void 2602 create_asr_node(char *parent, char *child, char *unitaddr, char *class, 2603 char *status, char *props) 2604 { 2605 char ptreepath[PATH_MAX]; 2606 char nodename[PICL_PROPNAMELEN_MAX]; 2607 char ua[MAX_UNIT_ADDRESS_LEN]; 2608 char *props_copy = NULL; 2609 char *next; 2610 char *prop_string; 2611 boolean_t found = B_FALSE; 2612 picl_nodehdl_t nodeh; 2613 picl_nodehdl_t chdh; 2614 asr_prop_triplet_t triple; 2615 ptree_propinfo_t propinfo; 2616 picl_prophdl_t proph; 2617 int val; 2618 int err; 2619 2620 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX); 2621 (void) strlcat(ptreepath, parent, PATH_MAX); 2622 2623 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS) 2624 return; 2625 /* 2626 * see if the required child node already exists 2627 */ 2628 for (err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 2629 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2630 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 2631 sizeof (picl_nodehdl_t))) { 2632 if (err != PICL_SUCCESS) 2633 break; 2634 err = ptree_get_propval_by_name(chdh, PICL_PROP_NAME, 2635 (void *)nodename, PICL_PROPNAMELEN_MAX); 2636 if (err != PICL_SUCCESS) 2637 break; 2638 if (strcmp(nodename, child) != 0) 2639 continue; 2640 /* 2641 * found a candidate child node 2642 */ 2643 if (unitaddr) { 2644 /* 2645 * does it match the required unit address? 2646 */ 2647 err = ptree_get_propval_by_name(chdh, 2648 PICL_PROP_UNIT_ADDRESS, ua, sizeof (ua)); 2649 if (err == PICL_PROPNOTFOUND) 2650 continue; 2651 if (err != PICL_SUCCESS) 2652 break; 2653 if (strcmp(unitaddr, ua) != 0) 2654 continue; 2655 } 2656 if (props == NULL) { 2657 next = ""; 2658 } else if (props_copy == NULL) { 2659 props_copy = strdup(props); 2660 if (props_copy == NULL) 2661 return; 2662 next = props_copy; 2663 } 2664 while ((next = parse_props_string(next, &triple)) != NULL) { 2665 err = ptree_get_prop_by_name(chdh, triple.propname, 2666 &proph); 2667 if (err != PICL_SUCCESS) 2668 break; 2669 err = ptree_get_propinfo(proph, &propinfo); 2670 if (err != PICL_SUCCESS) 2671 break; 2672 err = PICL_FAILURE; 2673 switch (propinfo.piclinfo.type) { 2674 case PICL_PTYPE_INT: 2675 case PICL_PTYPE_UNSIGNED_INT: 2676 if (strcmp(triple.proptype, "I") != 0) 2677 break; 2678 err = ptree_get_propval(proph, (void *)&val, 2679 sizeof (val)); 2680 if (err != PICL_SUCCESS) 2681 break; 2682 if (val != atoi(triple.propval)) 2683 err = PICL_FAILURE; 2684 break; 2685 case PICL_PTYPE_CHARSTRING: 2686 if (strcmp(triple.proptype, "S") != 0) 2687 break; 2688 prop_string = malloc(propinfo.piclinfo.size); 2689 if (prop_string == NULL) 2690 break; 2691 err = ptree_get_propval(proph, 2692 (void *)prop_string, 2693 propinfo.piclinfo.size); 2694 if (err != PICL_SUCCESS) { 2695 free(prop_string); 2696 break; 2697 } 2698 if (strcmp(prop_string, triple.propval) != 0) 2699 err = PICL_FAILURE; 2700 free(prop_string); 2701 break; 2702 default: 2703 break; 2704 } 2705 if (err != PICL_SUCCESS) { 2706 break; 2707 } 2708 } 2709 if (next == NULL) { 2710 found = B_TRUE; 2711 break; 2712 } 2713 } 2714 if (props_copy) 2715 free(props_copy); 2716 if (found) { 2717 /* 2718 * does the pre-existing node have a status property? 2719 */ 2720 err = ptree_get_propval_by_name(chdh, PICL_PROP_STATUS, 2721 ua, sizeof (ua)); 2722 if (err == PICL_PROPNOTFOUND) 2723 (void) add_status_prop(chdh, status); 2724 if (err != PICL_SUCCESS) 2725 return; 2726 if ((strcmp(ua, ASR_DISABLED) == 0) || 2727 (strcmp(ua, ASR_FAILED) == 0) || 2728 ((strcmp(status, ASR_DISABLED) != 0) && 2729 (strcmp(status, ASR_FAILED) != 0))) { 2730 return; 2731 } 2732 /* 2733 * more urgent status now, so replace existing value 2734 */ 2735 err = ptree_get_prop_by_name(chdh, PICL_PROP_STATUS, &proph); 2736 if (err != PICL_SUCCESS) 2737 return; 2738 (void) ptree_delete_prop(proph); 2739 (void) ptree_destroy_prop(proph); 2740 err = add_status_prop(chdh, status); 2741 if (err != PICL_SUCCESS) 2742 return; 2743 return; 2744 } 2745 2746 /* 2747 * typical case, node needs adding together with a set of properties 2748 */ 2749 if (ptree_create_and_add_node(nodeh, child, class, &chdh) == 2750 PICL_SUCCESS) { 2751 (void) add_status_prop(chdh, status); 2752 if (unitaddr) { 2753 (void) ptree_init_propinfo(&propinfo, 2754 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2755 PICL_READ, strlen(unitaddr) + 1, 2756 PICL_PROP_UNIT_ADDRESS, NULL, NULL); 2757 (void) ptree_create_and_add_prop(chdh, &propinfo, 2758 unitaddr, &proph); 2759 (void) strlcpy(ptreepath, parent, PATH_MAX); 2760 (void) strlcat(ptreepath, "/", PATH_MAX); 2761 (void) strlcat(ptreepath, child, PATH_MAX); 2762 (void) strlcat(ptreepath, "@", PATH_MAX); 2763 (void) strlcat(ptreepath, unitaddr, PATH_MAX); 2764 (void) ptree_init_propinfo(&propinfo, 2765 PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING, 2766 PICL_READ, strlen(ptreepath) + 1, 2767 PICL_PROP_DEVFS_PATH, NULL, NULL); 2768 (void) ptree_create_and_add_prop(chdh, &propinfo, 2769 ptreepath, &proph); 2770 } 2771 next = props; 2772 while ((next = parse_props_string(next, &triple)) != NULL) { 2773 /* 2774 * only handle int and string properties for 2775 * simplicity 2776 */ 2777 if (strcmp(triple.proptype, "I") == 0) { 2778 (void) ptree_init_propinfo(&propinfo, 2779 PTREE_PROPINFO_VERSION, 2780 PICL_PTYPE_INT, PICL_READ, 2781 sizeof (int), triple.propname, NULL, NULL); 2782 val = atoi(triple.propval); 2783 (void) ptree_create_and_add_prop(chdh, 2784 &propinfo, &val, &proph); 2785 } else { 2786 (void) ptree_init_propinfo(&propinfo, 2787 PTREE_PROPINFO_VERSION, 2788 PICL_PTYPE_CHARSTRING, PICL_READ, 2789 strlen(triple.propval) + 1, 2790 triple.propname, NULL, NULL); 2791 (void) ptree_create_and_add_prop(chdh, 2792 &propinfo, triple.propval, &proph); 2793 } 2794 } 2795 } 2796 } 2797 2798 static void 2799 add_asr_nodes() 2800 { 2801 char *asrexport; 2802 int asrexportlen; 2803 asr_conf_entries_t *c = NULL; 2804 int i; 2805 char *key; 2806 char *child; 2807 char *unitaddr; 2808 uint16_t count; 2809 int disabled; 2810 2811 if (get_asr_export_list(&asrexport, &asrexportlen) == 0) 2812 return; 2813 process_asrtree_conf_file(); 2814 if (conf_name_asr_map == NULL) 2815 return; 2816 i = 0; 2817 while (i < asrexportlen) { 2818 key = &asrexport[i]; 2819 i += strlen(key) + 1; 2820 if (i >= asrexportlen) 2821 break; 2822 2823 /* 2824 * next byte tells us whether failed by diags or manually 2825 * disabled 2826 */ 2827 disabled = asrexport[i]; 2828 i++; 2829 if (i >= asrexportlen) 2830 break; 2831 2832 /* 2833 * only type 1 supported 2834 */ 2835 if (asrexport[i] != 1) 2836 break; 2837 i++; 2838 if (i >= asrexportlen) 2839 break; 2840 2841 /* 2842 * next two bytes give size of reason string 2843 */ 2844 count = (asrexport[i] << 8) | asrexport[i + 1]; 2845 i += count + 2; 2846 if (i > asrexportlen) 2847 break; 2848 2849 /* 2850 * now look for key in conf file info 2851 */ 2852 c = conf_name_asr_map; 2853 while (c != NULL) { 2854 if (strcmp(key, c->name) == 0) { 2855 child = strrchr(c->address, '/'); 2856 *child++ = '\0'; 2857 unitaddr = strchr(child, '@'); 2858 if (unitaddr) 2859 *unitaddr++ = '\0'; 2860 if (strcmp(c->status, ASR_DISABLED) == 0) { 2861 create_asr_node(c->address, child, 2862 unitaddr, c->piclclass, disabled ? 2863 ASR_DISABLED : ASR_FAILED, 2864 c->props); 2865 } else { 2866 create_asr_node(c->address, child, 2867 unitaddr, c->piclclass, c->status, 2868 c->props); 2869 } 2870 } 2871 c = c->next; 2872 } 2873 } 2874 2875 free_asr_conf_entries(conf_name_asr_map); 2876 free(asrexport); 2877 } 2878 2879 /* 2880 * This function adds information to the /platform node 2881 */ 2882 static int 2883 add_platform_info(picl_nodehdl_t plafh) 2884 { 2885 struct utsname uts_info; 2886 int err; 2887 ptree_propinfo_t propinfo; 2888 picl_prophdl_t proph; 2889 2890 if (uname(&uts_info) < 0) 2891 return (PICL_FAILURE); 2892 2893 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2894 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.sysname) + 1, 2895 PICL_PROP_SYSNAME, NULL, NULL); 2896 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.sysname, 2897 &proph); 2898 if (err != PICL_SUCCESS) 2899 return (err); 2900 2901 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2902 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.nodename) + 1, 2903 PICL_PROP_NODENAME, NULL, NULL); 2904 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.nodename, 2905 &proph); 2906 if (err != PICL_SUCCESS) 2907 return (err); 2908 2909 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2910 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.release) + 1, 2911 PICL_PROP_RELEASE, NULL, NULL); 2912 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.release, 2913 &proph); 2914 if (err != PICL_SUCCESS) 2915 return (err); 2916 2917 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2918 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.version) + 1, 2919 PICL_PROP_VERSION, NULL, NULL); 2920 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.version, 2921 &proph); 2922 if (err != PICL_SUCCESS) 2923 return (err); 2924 2925 (void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2926 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.machine) + 1, 2927 PICL_PROP_MACHINE, NULL, NULL); 2928 err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.machine, 2929 &proph); 2930 return (err); 2931 } 2932 2933 /* 2934 * Get first 32-bit value from the reg property 2935 */ 2936 static int 2937 get_first_reg_word(picl_nodehdl_t nodeh, uint32_t *regval) 2938 { 2939 int err; 2940 uint32_t *regbuf; 2941 picl_prophdl_t regh; 2942 ptree_propinfo_t pinfo; 2943 2944 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 2945 if (err != PICL_SUCCESS) /* no reg property */ 2946 return (err); 2947 err = ptree_get_propinfo(regh, &pinfo); 2948 if (err != PICL_SUCCESS) 2949 return (err); 2950 if (pinfo.piclinfo.size < sizeof (uint32_t)) /* too small */ 2951 return (PICL_FAILURE); 2952 regbuf = alloca(pinfo.piclinfo.size); 2953 if (regbuf == NULL) 2954 return (PICL_FAILURE); 2955 err = ptree_get_propval(regh, regbuf, pinfo.piclinfo.size); 2956 if (err != PICL_SUCCESS) 2957 return (err); 2958 *regval = *regbuf; /* get first 32-bit value */ 2959 return (PICL_SUCCESS); 2960 } 2961 2962 /* 2963 * Get device ID from the reg property 2964 */ 2965 static int 2966 get_device_id(picl_nodehdl_t nodeh, uint32_t *dev_id) 2967 { 2968 int err; 2969 uint32_t regval; 2970 2971 err = get_first_reg_word(nodeh, ®val); 2972 if (err != PICL_SUCCESS) 2973 return (err); 2974 2975 *dev_id = PCI_DEVICE_ID(regval); 2976 return (PICL_SUCCESS); 2977 } 2978 2979 /* 2980 * add Slot property for children of SBUS node 2981 */ 2982 /* ARGSUSED */ 2983 static int 2984 add_sbus_slots(picl_nodehdl_t pcih, void *args) 2985 { 2986 picl_nodehdl_t nodeh; 2987 uint32_t slot; 2988 int err; 2989 ptree_propinfo_t pinfo; 2990 2991 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 2992 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 2993 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 2994 sizeof (picl_nodehdl_t))) { 2995 if (err != PICL_SUCCESS) 2996 return (err); 2997 2998 if (get_first_reg_word(nodeh, &slot) != 0) 2999 continue; 3000 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3001 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 3002 PICL_PROP_SLOT, NULL, NULL); 3003 (void) ptree_create_and_add_prop(nodeh, &pinfo, &slot, NULL); 3004 } 3005 3006 return (PICL_WALK_CONTINUE); 3007 } 3008 3009 /* 3010 * This function creates a Slot property for SBUS child nodes 3011 * which can be correlated with the slot they are plugged into 3012 * on the motherboard. 3013 */ 3014 static int 3015 set_sbus_slot(picl_nodehdl_t plafh) 3016 { 3017 int err; 3018 3019 err = ptree_walk_tree_by_class(plafh, PICL_CLASS_SBUS, NULL, 3020 add_sbus_slots); 3021 3022 return (err); 3023 } 3024 3025 /* 3026 * add DeviceID property for children of PCI/PCIEX node 3027 */ 3028 /* ARGSUSED */ 3029 static int 3030 add_pci_deviceids(picl_nodehdl_t pcih, void *args) 3031 { 3032 picl_nodehdl_t nodeh; 3033 uint32_t dev_id; 3034 int err; 3035 ptree_propinfo_t pinfo; 3036 3037 for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh, 3038 sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND; 3039 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh, 3040 sizeof (picl_nodehdl_t))) { 3041 if (err != PICL_SUCCESS) 3042 return (err); 3043 3044 if (get_device_id(nodeh, &dev_id) != 0) 3045 continue; 3046 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3047 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t), 3048 PICL_PROP_DEVICE_ID, NULL, NULL); 3049 (void) ptree_create_and_add_prop(nodeh, &pinfo, &dev_id, NULL); 3050 } 3051 3052 return (PICL_WALK_CONTINUE); 3053 } 3054 3055 /* 3056 * This function creates a DeviceID property for PCI/PCIEX child nodes 3057 * which can be correlated with the slot they are plugged into 3058 * on the motherboard. 3059 */ 3060 static void 3061 set_pci_pciex_deviceid(picl_nodehdl_t plafh) 3062 { 3063 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCI, NULL, 3064 add_pci_deviceids); 3065 3066 (void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCIEX, NULL, 3067 add_pci_deviceids); 3068 } 3069 3070 /* 3071 * Default UnitAddress encode function 3072 */ 3073 static int 3074 encode_default_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3075 { 3076 int i, len; 3077 3078 /* 3079 * Encode UnitAddress as %a,%b,%c,...,%n 3080 */ 3081 if (addrcells < 1) 3082 return (-1); 3083 3084 len = snprintf(buf, sz, "%x", *regprop); 3085 for (i = 1; i < addrcells && len < sz; i++) 3086 len += snprintf(&buf[len], sz-len, ",%x", regprop[i]); 3087 3088 return ((len >= sz) ? -1 : 0); 3089 } 3090 3091 /* 3092 * UnitAddress encode function where the last component is not printed 3093 * unless non-zero. 3094 */ 3095 static int 3096 encode_optional_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3097 { 3098 int retval; 3099 3100 /* 3101 * Encode UnitAddress as %a,%b,%c,...,%n where the last component 3102 * is printed only if non-zero. 3103 */ 3104 if (addrcells > 1 && regprop[addrcells-1] == 0) 3105 retval = encode_default_unitaddr(buf, sz, regprop, addrcells-1); 3106 else 3107 retval = encode_default_unitaddr(buf, sz, regprop, addrcells); 3108 3109 return (retval); 3110 } 3111 3112 3113 /* 3114 * UnitAddress encode function for SCSI class of devices 3115 */ 3116 static int 3117 encode_scsi_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3118 { 3119 int len, retval; 3120 3121 /* 3122 * #address-cells Format 3123 * 2 second component printed only if non-zero 3124 * 3125 * 4 regprop: phys_hi phys_lo lun_hi lun_lo 3126 * UnitAddr: w<phys_hi><phys_lo>,<lun_lo> 3127 */ 3128 3129 if (addrcells == 2) { 3130 retval = encode_optional_unitaddr(buf, sz, regprop, addrcells); 3131 } else if (addrcells == 4) { 3132 len = snprintf(buf, sz, "w%08x%08x,%x", regprop[0], regprop[1], 3133 regprop[3]); 3134 retval = (len >= sz) ? -1 : 0; 3135 } else 3136 retval = -1; 3137 3138 return (retval); 3139 } 3140 3141 /* 3142 * UnitAddress encode function for UPA devices 3143 */ 3144 static int 3145 encode_upa_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3146 { 3147 int len; 3148 3149 if (addrcells != 2) 3150 return (-1); 3151 3152 len = snprintf(buf, sz, "%x,%x", (regprop[0]/2)&0x1f, regprop[1]); 3153 return ((len >= sz) ? -1 : 0); 3154 } 3155 3156 /* 3157 * UnitAddress encode function for GPTWO, JBUS devices 3158 */ 3159 static int 3160 encode_gptwo_jbus_unitaddr(char *buf, int sz, uint32_t *regprop, 3161 uint_t addrcells) 3162 { 3163 uint32_t hi, lo; 3164 int len, id, off; 3165 3166 if (addrcells != 2) 3167 return (-1); 3168 3169 hi = regprop[0]; 3170 lo = regprop[1]; 3171 3172 if (hi & 0x400) { 3173 id = ((hi & 0x1) << 9) | (lo >> 23); /* agent id */ 3174 off = lo & 0x7fffff; /* config offset */ 3175 len = snprintf(buf, sz, "%x,%x", id, off); 3176 } else { 3177 len = snprintf(buf, sz, "m%x,%x", hi, lo); 3178 } 3179 return ((len >= sz) ? -1 : 0); 3180 } 3181 3182 /* 3183 * UnitAddress encode function for PCI devices 3184 */ 3185 static int 3186 encode_pci_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells) 3187 { 3188 typedef struct { 3189 uint32_t n:1, /* relocatable */ 3190 p:1, /* prefetchable */ 3191 t:1, /* address region aliases */ 3192 zero:3, /* must be zero */ 3193 ss:2, /* address space type */ 3194 bus:8, /* bus number */ 3195 dev:5, /* device number */ 3196 fn:3, /* function number */ 3197 reg:8; /* register number */ 3198 uint32_t phys_hi; /* high physical address */ 3199 uint32_t phys_lo; /* low physical address */ 3200 } pci_addrcell_t; 3201 3202 pci_addrcell_t *p; 3203 int len; 3204 3205 if (addrcells != 3) 3206 return (-1); 3207 3208 p = (pci_addrcell_t *)regprop; 3209 switch (p->ss) { 3210 case 0: /* Config */ 3211 if (p->fn) 3212 len = snprintf(buf, sz, "%x,%x", p->dev, p->fn); 3213 else 3214 len = snprintf(buf, sz, "%x", p->dev); 3215 break; 3216 case 1: /* IO */ 3217 len = snprintf(buf, sz, "i%x,%x,%x,%x", p->dev, p->fn, p->reg, 3218 p->phys_lo); 3219 break; 3220 case 2: /* Mem32 */ 3221 len = snprintf(buf, sz, "m%x,%x,%x,%x", p->dev, p->fn, p->reg, 3222 p->phys_lo); 3223 break; 3224 case 3: /* Mem64 */ 3225 len = snprintf(buf, sz, "x%x,%x,%x,%x%08x", p->dev, p->fn, 3226 p->reg, p->phys_hi, p->phys_lo); 3227 break; 3228 } 3229 return ((len >= sz) ? -1 : 0); 3230 } 3231 3232 /* 3233 * Get #address-cells property value 3234 */ 3235 static uint_t 3236 get_addrcells_prop(picl_nodehdl_t nodeh) 3237 { 3238 int len, err; 3239 uint32_t addrcells; 3240 ptree_propinfo_t pinfo; 3241 picl_prophdl_t proph; 3242 3243 /* 3244 * Get #address-cells property. If not present, use default value. 3245 */ 3246 err = ptree_get_prop_by_name(nodeh, OBP_PROP_ADDRESS_CELLS, &proph); 3247 if (err == PICL_SUCCESS) 3248 err = ptree_get_propinfo(proph, &pinfo); 3249 3250 len = pinfo.piclinfo.size; 3251 if (err == PICL_SUCCESS && len >= sizeof (uint8_t) && 3252 len <= sizeof (addrcells)) { 3253 err = ptree_get_propval(proph, &addrcells, len); 3254 if (err == PICL_SUCCESS) { 3255 if (len == sizeof (uint8_t)) 3256 addrcells = *(uint8_t *)&addrcells; 3257 else if (len == sizeof (uint16_t)) 3258 addrcells = *(uint16_t *)&addrcells; 3259 } else 3260 addrcells = DEFAULT_ADDRESS_CELLS; 3261 } else 3262 addrcells = DEFAULT_ADDRESS_CELLS; 3263 3264 return (addrcells); 3265 } 3266 3267 /* 3268 * Get UnitAddress mapping entry for a node 3269 */ 3270 static unitaddr_map_t * 3271 get_unitaddr_mapping(picl_nodehdl_t nodeh) 3272 { 3273 int err; 3274 unitaddr_map_t *uamap; 3275 char clname[PICL_CLASSNAMELEN_MAX]; 3276 3277 /* 3278 * Get my classname and locate a function to translate "reg" prop 3279 * into "UnitAddress" prop for my children. 3280 */ 3281 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, clname, 3282 sizeof (clname)); 3283 if (err != PICL_SUCCESS) 3284 (void) strcpy(clname, ""); /* NULL class name */ 3285 3286 for (uamap = &unitaddr_map_table[0]; uamap->class != NULL; uamap++) 3287 if (strcmp(clname, uamap->class) == 0) 3288 break; 3289 3290 return (uamap); 3291 } 3292 3293 /* 3294 * Add UnitAddress property to the specified node 3295 */ 3296 static int 3297 add_unitaddr_prop(picl_nodehdl_t nodeh, unitaddr_map_t *uamap, uint_t addrcells) 3298 { 3299 int regproplen, err; 3300 uint32_t *regbuf; 3301 picl_prophdl_t regh; 3302 ptree_propinfo_t pinfo; 3303 char unitaddr[MAX_UNIT_ADDRESS_LEN]; 3304 3305 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 3306 if (err != PICL_SUCCESS) 3307 return (err); 3308 3309 err = ptree_get_propinfo(regh, &pinfo); 3310 if (err != PICL_SUCCESS) 3311 return (PICL_FAILURE); 3312 3313 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t))) 3314 return (PICL_FAILURE); 3315 3316 regproplen = pinfo.piclinfo.size; 3317 regbuf = alloca(regproplen); 3318 if (regbuf == NULL) 3319 return (PICL_FAILURE); 3320 3321 err = ptree_get_propval(regh, regbuf, regproplen); 3322 if (err != PICL_SUCCESS || uamap->func == NULL || 3323 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) || 3324 (uamap->func)(unitaddr, sizeof (unitaddr), regbuf, 3325 addrcells) != 0) { 3326 return (PICL_FAILURE); 3327 } 3328 3329 err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3330 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(unitaddr)+1, 3331 PICL_PROP_UNIT_ADDRESS, NULL, NULL); 3332 if (err == PICL_SUCCESS) 3333 err = ptree_create_and_add_prop(nodeh, &pinfo, unitaddr, NULL); 3334 3335 return (err); 3336 } 3337 3338 /* 3339 * work out UnitAddress property of the specified node 3340 */ 3341 static int 3342 get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, char *unitaddr, 3343 size_t ualen) 3344 { 3345 int regproplen, err; 3346 uint32_t *regbuf; 3347 picl_prophdl_t regh; 3348 ptree_propinfo_t pinfo; 3349 unitaddr_map_t *uamap; 3350 uint32_t addrcells; 3351 3352 addrcells = get_addrcells_prop(parh); 3353 uamap = get_unitaddr_mapping(parh); 3354 3355 err = ptree_get_prop_by_name(nodeh, OBP_REG, ®h); 3356 if (err != PICL_SUCCESS) 3357 return (err); 3358 3359 err = ptree_get_propinfo(regh, &pinfo); 3360 if (err != PICL_SUCCESS) 3361 return (err); 3362 3363 if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t))) 3364 return (PICL_FAILURE); 3365 3366 regproplen = pinfo.piclinfo.size; 3367 regbuf = alloca(regproplen); 3368 if (regbuf == NULL) 3369 return (PICL_FAILURE); 3370 3371 err = ptree_get_propval(regh, regbuf, regproplen); 3372 if (err != PICL_SUCCESS || uamap->func == NULL || 3373 (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) || 3374 (uamap->func)(unitaddr, ualen, regbuf, addrcells) != 0) { 3375 return (PICL_FAILURE); 3376 } 3377 return (PICL_SUCCESS); 3378 } 3379 3380 /* 3381 * Add UnitAddress property to all children of the specified node 3382 */ 3383 static int 3384 add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh) 3385 { 3386 int err; 3387 picl_nodehdl_t chdh; 3388 unitaddr_map_t *uamap; 3389 uint32_t addrcells; 3390 3391 /* 3392 * Get #address-cells and unit address mapping entry for my 3393 * node's class 3394 */ 3395 addrcells = get_addrcells_prop(nodeh); 3396 uamap = get_unitaddr_mapping(nodeh); 3397 3398 /* 3399 * Add UnitAddress property to my children and their subtree 3400 */ 3401 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 3402 sizeof (picl_nodehdl_t)); 3403 3404 while (err == PICL_SUCCESS) { 3405 (void) add_unitaddr_prop(chdh, uamap, addrcells); 3406 (void) add_unitaddr_prop_to_subtree(chdh); 3407 3408 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 3409 sizeof (picl_nodehdl_t)); 3410 } 3411 3412 return (PICL_SUCCESS); 3413 } 3414 3415 static int 3416 update_memory_size_prop(picl_nodehdl_t plafh) 3417 { 3418 picl_nodehdl_t memh; 3419 picl_prophdl_t proph; 3420 ptree_propinfo_t pinfo; 3421 int err, nspecs, snum, pval; 3422 char *regbuf; 3423 memspecs_t *mspecs; 3424 uint64_t memsize; 3425 3426 /* 3427 * check if the #size-cells of the platform node is 2 3428 */ 3429 err = ptree_get_propval_by_name(plafh, OBP_PROP_SIZE_CELLS, &pval, 3430 sizeof (pval)); 3431 3432 if (err == PICL_PROPNOTFOUND) 3433 pval = SUPPORTED_NUM_CELL_SIZE; 3434 else if (err != PICL_SUCCESS) 3435 return (err); 3436 3437 /* 3438 * don't know how to handle other vals 3439 */ 3440 if (pval != SUPPORTED_NUM_CELL_SIZE) 3441 return (PICL_FAILURE); 3442 3443 err = ptree_get_node_by_path(MEMORY_PATH, &memh); 3444 if (err != PICL_SUCCESS) 3445 return (err); 3446 3447 /* 3448 * Get the REG property to calculate the size of memory 3449 */ 3450 err = ptree_get_prop_by_name(memh, OBP_REG, &proph); 3451 if (err != PICL_SUCCESS) 3452 return (err); 3453 3454 err = ptree_get_propinfo(proph, &pinfo); 3455 if (err != PICL_SUCCESS) 3456 return (err); 3457 3458 regbuf = alloca(pinfo.piclinfo.size); 3459 if (regbuf == NULL) 3460 return (PICL_FAILURE); 3461 3462 err = ptree_get_propval(proph, regbuf, pinfo.piclinfo.size); 3463 if (err != PICL_SUCCESS) 3464 return (err); 3465 3466 mspecs = (memspecs_t *)regbuf; 3467 nspecs = pinfo.piclinfo.size / sizeof (memspecs_t); 3468 3469 memsize = 0; 3470 for (snum = 0; snum < nspecs; ++snum) 3471 memsize += mspecs[snum].size; 3472 3473 err = ptree_get_prop_by_name(memh, PICL_PROP_SIZE, &proph); 3474 if (err == PICL_SUCCESS) { 3475 err = ptree_update_propval(proph, &memsize, sizeof (memsize)); 3476 return (err); 3477 } 3478 3479 /* 3480 * Add the size property 3481 */ 3482 (void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION, 3483 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (memsize), 3484 PICL_PROP_SIZE, NULL, NULL); 3485 err = ptree_create_and_add_prop(memh, &pinfo, &memsize, NULL); 3486 return (err); 3487 } 3488 3489 /* 3490 * This function is executed as part of .init when the plugin is 3491 * dlopen()ed 3492 */ 3493 static void 3494 picldevtree_register(void) 3495 { 3496 if (getenv(SUNW_PICLDEVTREE_PLUGIN_DEBUG)) 3497 picldevtree_debug = 1; 3498 (void) picld_plugin_register(&my_reg_info); 3499 } 3500 3501 /* 3502 * This function is the init entry point of the plugin. 3503 * It initializes the /platform tree based on libdevinfo 3504 */ 3505 static void 3506 picldevtree_init(void) 3507 { 3508 picl_nodehdl_t rhdl; 3509 int err; 3510 struct utsname utsname; 3511 picl_nodehdl_t plafh; 3512 3513 if (uname(&utsname) < 0) 3514 return; 3515 3516 (void) strcpy(mach_name, utsname.machine); 3517 3518 if (strcmp(mach_name, "sun4u") == 0) { 3519 builtin_map_ptr = sun4u_map; 3520 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t); 3521 } else if (strcmp(mach_name, "sun4v") == 0) { 3522 builtin_map_ptr = sun4u_map; 3523 builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t); 3524 } else if (strcmp(mach_name, "i86pc") == 0) { 3525 builtin_map_ptr = i86pc_map; 3526 builtin_map_size = sizeof (i86pc_map) / sizeof (builtin_map_t); 3527 } else { 3528 builtin_map_ptr = NULL; 3529 builtin_map_size = 0; 3530 } 3531 3532 err = ptree_get_root(&rhdl); 3533 if (err != PICL_SUCCESS) { 3534 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED); 3535 return; 3536 } 3537 3538 process_devtree_conf_file(); 3539 3540 if (libdevinfo_init(rhdl) != PICL_SUCCESS) { 3541 syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED); 3542 return; 3543 } 3544 3545 err = ptree_get_node_by_path(PLATFORM_PATH, &plafh); 3546 if (err != PICL_SUCCESS) 3547 return; 3548 3549 (void) add_unitaddr_prop_to_subtree(plafh); 3550 3551 add_asr_nodes(); 3552 3553 (void) update_memory_size_prop(plafh); 3554 3555 (void) setup_cpus(plafh); 3556 3557 (void) add_ffb_config_info(plafh); 3558 3559 (void) add_platform_info(plafh); 3560 3561 set_pci_pciex_deviceid(plafh); 3562 3563 (void) set_sbus_slot(plafh); 3564 3565 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 3566 picldevtree_evhandler, NULL); 3567 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 3568 picldevtree_evhandler, NULL); 3569 (void) ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE, 3570 picldevtree_evhandler, NULL); 3571 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE, 3572 picldevtree_evhandler, NULL); 3573 } 3574 3575 /* 3576 * This function is the fini entry point of the plugin 3577 */ 3578 static void 3579 picldevtree_fini(void) 3580 { 3581 /* First unregister the event handlers */ 3582 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 3583 picldevtree_evhandler, NULL); 3584 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED, 3585 picldevtree_evhandler, NULL); 3586 (void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE, 3587 picldevtree_evhandler, NULL); 3588 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE, 3589 picldevtree_evhandler, NULL); 3590 3591 conf_name_class_map = free_conf_entries(conf_name_class_map); 3592 } 3593 3594 /* 3595 * This function is the event handler of this plug-in. 3596 * 3597 * It processes the following events: 3598 * 3599 * PICLEVENT_SYSEVENT_DEVICE_ADDED 3600 * PICLEVENT_SYSEVENT_DEVICE_REMOVED 3601 * PICLEVENT_CPU_STATE_CHANGE 3602 * PICLEVENT_DR_AP_STATE_CHANGE 3603 */ 3604 /* ARGSUSED */ 3605 static void 3606 picldevtree_evhandler(const char *ename, const void *earg, size_t size, 3607 void *cookie) 3608 { 3609 char *devfs_path; 3610 char ptreepath[PATH_MAX]; 3611 char dipath[PATH_MAX]; 3612 picl_nodehdl_t plafh; 3613 picl_nodehdl_t nodeh; 3614 nvlist_t *nvlp; 3615 3616 if ((earg == NULL) || 3617 (ptree_get_node_by_path(PLATFORM_PATH, &plafh) != PICL_SUCCESS)) 3618 return; 3619 3620 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) == 0) { 3621 (void) setup_cpus(plafh); 3622 if (picldevtree_debug > 1) 3623 syslog(LOG_INFO, "picldevtree: event handler done\n"); 3624 return; 3625 } 3626 3627 nvlp = NULL; 3628 if (nvlist_unpack((char *)earg, size, &nvlp, NULL) || 3629 nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &devfs_path) || 3630 strlen(devfs_path) > (PATH_MAX - sizeof (PLATFORM_PATH))) { 3631 syslog(LOG_INFO, PICL_EVENT_DROPPED, ename); 3632 if (nvlp) 3633 nvlist_free(nvlp); 3634 return; 3635 } 3636 3637 (void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX); 3638 (void) strlcat(ptreepath, devfs_path, PATH_MAX); 3639 (void) strlcpy(dipath, devfs_path, PATH_MAX); 3640 nvlist_free(nvlp); 3641 3642 if (picldevtree_debug) 3643 syslog(LOG_INFO, "picldevtree: event handler invoked ename:%s " 3644 "ptreepath:%s\n", ename, ptreepath); 3645 3646 if (strcmp(ename, PICLEVENT_CPU_STATE_CHANGE) == 0) { 3647 goto done; 3648 } 3649 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) { 3650 di_node_t devnode; 3651 char *strp; 3652 picl_nodehdl_t parh; 3653 char nodeclass[PICL_CLASSNAMELEN_MAX]; 3654 char *nodename; 3655 int err; 3656 3657 /* If the node already exist, then nothing else to do here */ 3658 if (ptree_get_node_by_path(ptreepath, &nodeh) == PICL_SUCCESS) 3659 return; 3660 3661 /* Skip if unable to find parent PICL node handle */ 3662 parh = plafh; 3663 if (((strp = strrchr(ptreepath, '/')) != NULL) && 3664 (strp != strchr(ptreepath, '/'))) { 3665 *strp = '\0'; 3666 if (ptree_get_node_by_path(ptreepath, &parh) != 3667 PICL_SUCCESS) 3668 return; 3669 } 3670 3671 /* 3672 * If parent is the root node 3673 */ 3674 if (parh == plafh) { 3675 ph = di_prom_init(); 3676 devnode = di_init(dipath, DINFOCPYALL); 3677 if (devnode == DI_NODE_NIL) { 3678 if (ph != NULL) { 3679 di_prom_fini(ph); 3680 ph = NULL; 3681 } 3682 return; 3683 } 3684 nodename = di_node_name(devnode); 3685 if (nodename == NULL) { 3686 di_fini(devnode); 3687 if (ph != NULL) { 3688 di_prom_fini(ph); 3689 ph = NULL; 3690 } 3691 return; 3692 } 3693 3694 err = get_node_class(nodeclass, devnode, nodename); 3695 if (err < 0) { 3696 di_fini(devnode); 3697 if (ph != NULL) { 3698 di_prom_fini(ph); 3699 ph = NULL; 3700 } 3701 return; 3702 } 3703 err = construct_devtype_node(plafh, nodename, 3704 nodeclass, devnode, &nodeh); 3705 if (err != PICL_SUCCESS) { 3706 di_fini(devnode); 3707 if (ph != NULL) { 3708 di_prom_fini(ph); 3709 ph = NULL; 3710 } 3711 return; 3712 } 3713 (void) update_subtree(nodeh, devnode); 3714 (void) add_unitaddr_prop_to_subtree(nodeh); 3715 if (ph != NULL) { 3716 di_prom_fini(ph); 3717 ph = NULL; 3718 } 3719 di_fini(devnode); 3720 goto done; 3721 } 3722 3723 /* kludge ... try without bus-addr first */ 3724 if ((strp = strrchr(dipath, '@')) != NULL) { 3725 char *p; 3726 3727 p = strrchr(dipath, '/'); 3728 if (p != NULL && strp > p) { 3729 *strp = '\0'; 3730 devnode = di_init(dipath, DINFOCPYALL); 3731 if (devnode != DI_NODE_NIL) 3732 di_fini(devnode); 3733 *strp = '@'; 3734 } 3735 } 3736 /* Get parent devnode */ 3737 if ((strp = strrchr(dipath, '/')) != NULL) 3738 *++strp = '\0'; 3739 devnode = di_init(dipath, DINFOCPYALL); 3740 if (devnode == DI_NODE_NIL) 3741 return; 3742 ph = di_prom_init(); 3743 (void) update_subtree(parh, devnode); 3744 (void) add_unitaddr_prop_to_subtree(parh); 3745 if (ph) { 3746 di_prom_fini(ph); 3747 ph = NULL; 3748 } 3749 di_fini(devnode); 3750 } else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) { 3751 char delclass[PICL_CLASSNAMELEN_MAX]; 3752 char *strp; 3753 3754 /* 3755 * if final element of path doesn't have a unit address 3756 * then it is not uniquely identifiable - cannot remove 3757 */ 3758 if (((strp = strrchr(ptreepath, '/')) != NULL) && 3759 strchr(strp, '@') == NULL) 3760 return; 3761 3762 /* skip if can't find the node */ 3763 if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS) 3764 return; 3765 3766 if (ptree_delete_node(nodeh) != PICL_SUCCESS) 3767 return; 3768 3769 if (picldevtree_debug) 3770 syslog(LOG_INFO, 3771 "picldevtree: deleted node nodeh:%llx\n", nodeh); 3772 if ((ptree_get_propval_by_name(nodeh, 3773 PICL_PROP_CLASSNAME, delclass, PICL_CLASSNAMELEN_MAX) == 3774 PICL_SUCCESS) && IS_MC(delclass)) { 3775 if (post_mc_event(PICLEVENT_MC_REMOVED, nodeh) != 3776 PICL_SUCCESS) 3777 syslog(LOG_WARNING, PICL_EVENT_DROPPED, 3778 PICLEVENT_MC_REMOVED); 3779 } else 3780 (void) ptree_destroy_node(nodeh); 3781 } 3782 done: 3783 (void) setup_cpus(plafh); 3784 (void) add_ffb_config_info(plafh); 3785 set_pci_pciex_deviceid(plafh); 3786 (void) set_sbus_slot(plafh); 3787 if (picldevtree_debug > 1) 3788 syslog(LOG_INFO, "picldevtree: event handler done\n"); 3789 } 3790