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