Home | History | Annotate | Download | only in devtree
      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 		if (nvlp)
   3635 			nvlist_free(nvlp);
   3636 		return;
   3637 	}
   3638 
   3639 	(void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX);
   3640 	(void) strlcat(ptreepath, devfs_path, PATH_MAX);
   3641 	(void) strlcpy(dipath, devfs_path, PATH_MAX);
   3642 	nvlist_free(nvlp);
   3643 
   3644 	if (picldevtree_debug)
   3645 		syslog(LOG_INFO, "picldevtree: event handler invoked ename:%s "
   3646 		    "ptreepath:%s\n", ename, ptreepath);
   3647 
   3648 	if (strcmp(ename, PICLEVENT_CPU_STATE_CHANGE) == 0) {
   3649 		goto done;
   3650 	}
   3651 	if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) {
   3652 		di_node_t		devnode;
   3653 		char		*strp;
   3654 		picl_nodehdl_t	parh;
   3655 		char		nodeclass[PICL_CLASSNAMELEN_MAX];
   3656 		char		*nodename;
   3657 		int		err;
   3658 
   3659 		/* If the node already exist, then nothing else to do here */
   3660 		if (ptree_get_node_by_path(ptreepath, &nodeh) == PICL_SUCCESS)
   3661 			return;
   3662 
   3663 		/* Skip if unable to find parent PICL node handle */
   3664 		parh = plafh;
   3665 		if (((strp = strrchr(ptreepath, '/')) != NULL) &&
   3666 		    (strp != strchr(ptreepath, '/'))) {
   3667 			*strp = '\0';
   3668 			if (ptree_get_node_by_path(ptreepath, &parh) !=
   3669 			    PICL_SUCCESS)
   3670 				return;
   3671 		}
   3672 
   3673 		/*
   3674 		 * If parent is the root node
   3675 		 */
   3676 		if (parh == plafh) {
   3677 			ph = di_prom_init();
   3678 			devnode = di_init(dipath, DINFOCPYALL);
   3679 			if (devnode == DI_NODE_NIL) {
   3680 				if (ph != NULL) {
   3681 					di_prom_fini(ph);
   3682 					ph = NULL;
   3683 				}
   3684 				return;
   3685 			}
   3686 			nodename = di_node_name(devnode);
   3687 			if (nodename == NULL) {
   3688 				di_fini(devnode);
   3689 				if (ph != NULL) {
   3690 					di_prom_fini(ph);
   3691 					ph = NULL;
   3692 				}
   3693 				return;
   3694 			}
   3695 
   3696 			err = get_node_class(nodeclass, devnode, nodename);
   3697 			if (err < 0) {
   3698 				di_fini(devnode);
   3699 				if (ph != NULL) {
   3700 					di_prom_fini(ph);
   3701 					ph = NULL;
   3702 				}
   3703 				return;
   3704 			}
   3705 			err = construct_devtype_node(plafh, nodename,
   3706 			    nodeclass, devnode, &nodeh);
   3707 			if (err != PICL_SUCCESS) {
   3708 				di_fini(devnode);
   3709 				if (ph != NULL) {
   3710 					di_prom_fini(ph);
   3711 					ph = NULL;
   3712 				}
   3713 				return;
   3714 			}
   3715 			(void) update_subtree(nodeh, devnode);
   3716 			(void) add_unitaddr_prop_to_subtree(nodeh);
   3717 			if (ph != NULL) {
   3718 				di_prom_fini(ph);
   3719 				ph = NULL;
   3720 			}
   3721 			di_fini(devnode);
   3722 			goto done;
   3723 		}
   3724 
   3725 		/* kludge ... try without bus-addr first */
   3726 		if ((strp = strrchr(dipath, '@')) != NULL) {
   3727 			char *p;
   3728 
   3729 			p = strrchr(dipath, '/');
   3730 			if (p != NULL && strp > p) {
   3731 				*strp = '\0';
   3732 				devnode = di_init(dipath, DINFOCPYALL);
   3733 				if (devnode != DI_NODE_NIL)
   3734 					di_fini(devnode);
   3735 				*strp = '@';
   3736 			}
   3737 		}
   3738 		/* Get parent devnode */
   3739 		if ((strp = strrchr(dipath, '/')) != NULL)
   3740 			*++strp = '\0';
   3741 		devnode = di_init(dipath, DINFOCPYALL);
   3742 		if (devnode == DI_NODE_NIL)
   3743 			return;
   3744 		ph = di_prom_init();
   3745 		(void) update_subtree(parh, devnode);
   3746 		(void) add_unitaddr_prop_to_subtree(parh);
   3747 		if (ph) {
   3748 			di_prom_fini(ph);
   3749 			ph = NULL;
   3750 		}
   3751 		di_fini(devnode);
   3752 	} else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) {
   3753 		char			delclass[PICL_CLASSNAMELEN_MAX];
   3754 		char		*strp;
   3755 
   3756 		/*
   3757 		 * if final element of path doesn't have a unit address
   3758 		 * then it is not uniquely identifiable - cannot remove
   3759 		 */
   3760 		if (((strp = strrchr(ptreepath, '/')) != NULL) &&
   3761 		    strchr(strp, '@') == NULL)
   3762 			return;
   3763 
   3764 		/* skip if can't find the node */
   3765 		if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS)
   3766 			return;
   3767 
   3768 		if (ptree_delete_node(nodeh) != PICL_SUCCESS)
   3769 			return;
   3770 
   3771 		if (picldevtree_debug)
   3772 			syslog(LOG_INFO,
   3773 			    "picldevtree: deleted node nodeh:%llx\n", nodeh);
   3774 		if ((ptree_get_propval_by_name(nodeh,
   3775 		    PICL_PROP_CLASSNAME, delclass, PICL_CLASSNAMELEN_MAX) ==
   3776 		    PICL_SUCCESS) && IS_MC(delclass)) {
   3777 			if (post_mc_event(PICLEVENT_MC_REMOVED, nodeh) !=
   3778 			    PICL_SUCCESS)
   3779 				syslog(LOG_WARNING, PICL_EVENT_DROPPED,
   3780 				    PICLEVENT_MC_REMOVED);
   3781 		} else
   3782 			(void) ptree_destroy_node(nodeh);
   3783 	}
   3784 done:
   3785 	(void) setup_cpus(plafh);
   3786 	(void) add_ffb_config_info(plafh);
   3787 	set_pci_pciex_deviceid(plafh);
   3788 	(void) set_sbus_slot(plafh);
   3789 	if (picldevtree_debug > 1)
   3790 		syslog(LOG_INFO, "picldevtree: event handler done\n");
   3791 }
   3792