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