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