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