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