1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright 2019 Joyent, Inc.
28  */
29 
30 /*
31  * PICL plug-in that creates device tree nodes for all platforms
32  */
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <assert.h>
40 #include <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, 0) == 0) {
289 		mch = 0;
290 		(void) nvlist_lookup_uint64(unpack_nvl,
291 		    PICLEVENTARG_NODEHANDLE, &mch);
292 		if (mch != 0) {
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, 0)) {
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, 0)) {
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 	case P_DISABLED:
1918 		(void) strlcpy(vbuf, PS_DISABLED, MAX_STATE_SIZE);
1919 		break;
1920 	default:
1921 		(void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE);
1922 		break;
1923 	}
1924 	return (PICL_SUCCESS);
1925 }
1926 
1927 /*
1928  * This function is the volatile read access function of CPU processor_type
1929  * property
1930  */
1931 static int
1932 get_processor_type(ptree_rarg_t *rarg, void *vbuf)
1933 {
1934 	processor_info_t	cpu_info;
1935 	int	id;
1936 	int	err;
1937 
1938 	err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1939 	if (err != PICL_SUCCESS)
1940 		return (err);
1941 
1942 	if (processor_info(id, &cpu_info) >= 0) {
1943 		(void) strlcpy(vbuf, cpu_info.pi_processor_type, PI_TYPELEN);
1944 	}
1945 	return (PICL_SUCCESS);
1946 }
1947 
1948 /*
1949  * This function is the volatile read access function of CPU fputypes
1950  * property
1951  */
1952 static int
1953 get_fputypes(ptree_rarg_t *rarg, void *vbuf)
1954 {
1955 	processor_info_t	cpu_info;
1956 	int	id;
1957 	int	err;
1958 
1959 	err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &id);
1960 	if (err != PICL_SUCCESS)
1961 		return (err);
1962 
1963 	if (processor_info(id, &cpu_info) >= 0) {
1964 		(void) strlcpy(vbuf, cpu_info.pi_fputypes, PI_FPUTYPE);
1965 	}
1966 	return (PICL_SUCCESS);
1967 }
1968 
1969 /*
1970  * This function is the volatile read access function of CPU StateBegin
1971  * property. To minimize overhead, use kstat_chain_update() to refresh
1972  * the kstat header info as opposed to invoking kstat_open() every time.
1973  */
1974 static int
1975 get_pi_state_begin(ptree_rarg_t *rarg, void *vbuf)
1976 {
1977 	int			err;
1978 	int			cpu_id;
1979 	static kstat_ctl_t	*kc = NULL;
1980 	static pthread_mutex_t	kc_mutex = PTHREAD_MUTEX_INITIALIZER;
1981 	kstat_t			*kp;
1982 	kstat_named_t		*kn;
1983 
1984 	err = get_int_propval_by_name(rarg->nodeh, PICL_PROP_ID, &cpu_id);
1985 	if (err != PICL_SUCCESS)
1986 		return (err);
1987 
1988 	(void) pthread_mutex_lock(&kc_mutex);
1989 	if (kc == NULL)
1990 		kc = kstat_open();
1991 	else if (kstat_chain_update(kc) == -1) {
1992 		(void) kstat_close(kc);
1993 		kc = kstat_open();
1994 	}
1995 
1996 	if (kc == NULL) {
1997 		(void) pthread_mutex_unlock(&kc_mutex);
1998 		return (PICL_FAILURE);
1999 	}
2000 
2001 	/* Get the state_begin from kstat */
2002 	if ((kp = kstat_lookup(kc, KSTAT_CPU_INFO, cpu_id, NULL)) == NULL ||
2003 	    kp->ks_type != KSTAT_TYPE_NAMED || kstat_read(kc, kp, 0) < 0) {
2004 		(void) pthread_mutex_unlock(&kc_mutex);
2005 		return (PICL_FAILURE);
2006 	}
2007 
2008 	kn = kstat_data_lookup(kp, KSTAT_STATE_BEGIN);
2009 	if (kn) {
2010 		*(uint64_t *)vbuf = (uint64_t)kn->value.l;
2011 		err = PICL_SUCCESS;
2012 	} else
2013 		err = PICL_FAILURE;
2014 
2015 	(void) pthread_mutex_unlock(&kc_mutex);
2016 	return (err);
2017 }
2018 
2019 /*
2020  * This function adds CPU information to the CPU nodes
2021  */
2022 /* ARGSUSED */
2023 static int
2024 add_processor_info(picl_nodehdl_t cpuh, void *args)
2025 {
2026 	int			err;
2027 	int			cpu_id;
2028 	ptree_propinfo_t	propinfo;
2029 	ptree_propinfo_t	pinfo;
2030 
2031 	err = get_cpu_portid(cpuh, &cpu_id);
2032 	if (err != PICL_SUCCESS)
2033 		return (PICL_WALK_CONTINUE);
2034 
2035 	/*
2036 	 * Check to make sure that the CPU is still present, i.e. that it
2037 	 * has not been DR'ed out of the system.
2038 	 */
2039 	if (p_online(cpu_id, P_STATUS) == -1) {
2040 		if (picldevtree_debug)
2041 			syslog(LOG_INFO,
2042 			    "picldevtree: cpu %d (%llx) does not exist - "
2043 			    "deleting node\n", cpu_id, cpuh);
2044 
2045 		if (ptree_delete_node(cpuh) == PICL_SUCCESS)
2046 			(void) ptree_destroy_node(cpuh);
2047 
2048 		return (PICL_WALK_CONTINUE);
2049 	}
2050 
2051 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2052 	    PICL_PTYPE_INT, PICL_READ, sizeof (int), PICL_PROP_ID, NULL, NULL);
2053 	err = ptree_create_and_add_prop(cpuh, &propinfo, &cpu_id, NULL);
2054 	if (err != PICL_SUCCESS)
2055 		return (PICL_WALK_CONTINUE);
2056 
2057 	(void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2058 	    PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), MAX_STATE_SIZE,
2059 	    PICL_PROP_STATE, get_pi_state, NULL);
2060 	(void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2061 
2062 	(void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2063 	    PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_TYPELEN,
2064 	    PICL_PROP_PROCESSOR_TYPE, get_processor_type, NULL);
2065 	(void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2066 
2067 	(void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2068 	    PICL_PTYPE_CHARSTRING, (PICL_READ|PICL_VOLATILE), PI_FPUTYPE,
2069 	    PICL_PROP_FPUTYPE, get_fputypes, NULL);
2070 	(void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2071 
2072 	(void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
2073 	    PICL_PTYPE_TIMESTAMP, PICL_READ|PICL_VOLATILE, sizeof (uint64_t),
2074 	    PICL_PROP_STATE_BEGIN, get_pi_state_begin, NULL);
2075 	(void) ptree_create_and_add_prop(cpuh, &pinfo, NULL, NULL);
2076 
2077 	return (PICL_WALK_CONTINUE);
2078 }
2079 
2080 /*
2081  * This function sets up the "ID" property in every CPU nodes
2082  * and adds processor info
2083  */
2084 static int
2085 setup_cpus(picl_nodehdl_t plafh)
2086 {
2087 	int			err;
2088 
2089 	err = ptree_walk_tree_by_class(plafh, PICL_CLASS_CPU, NULL,
2090 	    add_processor_info);
2091 
2092 	return (err);
2093 }
2094 
2095 /*
2096  * This function format's the manufacture's information for FFB display
2097  * devices
2098  */
2099 static void
2100 fmt_manf_id(manuf_t manufid, int bufsz, char *outbuf)
2101 {
2102 	/*
2103 	 * Format the manufacturer's info.  Note a small inconsistency we
2104 	 * have to work around - Brooktree has it's part number in decimal,
2105 	 * while Mitsubishi has it's part number in hex.
2106 	 */
2107 	switch (manufid.fld.manf) {
2108 	case MANF_BROOKTREE:
2109 		(void) snprintf(outbuf, bufsz, "%s %d, version %d",
2110 		    "Brooktree", manufid.fld.partno, manufid.fld.version);
2111 		break;
2112 
2113 	case MANF_MITSUBISHI:
2114 		(void) snprintf(outbuf, bufsz, "%s %x, version %d",
2115 		    "Mitsubishi", manufid.fld.partno, manufid.fld.version);
2116 		break;
2117 
2118 	default:
2119 		(void) snprintf(outbuf, bufsz,
2120 		    "JED code %d, Part num 0x%x, version %d",
2121 		    manufid.fld.manf, manufid.fld.partno, manufid.fld.version);
2122 	}
2123 }
2124 
2125 /*
2126  * If it's an ffb device, open ffb devices and return PICL_SUCCESS
2127  */
2128 static int
2129 open_ffb_device(picl_nodehdl_t ffbh, int *fd)
2130 {
2131 	DIR			*dirp;
2132 	char			devfs_path[PATH_MAX];
2133 	char			dev_path[PATH_MAX];
2134 	char			*devp;
2135 	struct dirent		*direntp;
2136 	int			err;
2137 	int			tmpfd;
2138 
2139 	/* Get the devfs_path of the ffb devices */
2140 	err = ptree_get_propval_by_name(ffbh, PICL_PROP_DEVFS_PATH, devfs_path,
2141 	    sizeof (devfs_path));
2142 	if (err != PICL_SUCCESS)
2143 		return (err);
2144 
2145 	/* Get the device node name */
2146 	devp = strrchr(devfs_path, '/');
2147 	if (devp == NULL)
2148 		return (PICL_FAILURE);
2149 	*devp = '\0';
2150 	++devp;
2151 
2152 	/*
2153 	 * Check if device node name has the ffb string
2154 	 * If not, assume it's not a ffb device.
2155 	 */
2156 	if (strstr(devp, FFB_NAME) == NULL)
2157 		return (PICL_FAILURE);
2158 
2159 	/*
2160 	 * Get the parent path of the ffb device node.
2161 	 */
2162 	(void) snprintf(dev_path, sizeof (dev_path), "%s/%s", "/devices",
2163 	    devfs_path);
2164 
2165 	/*
2166 	 * Since we don't know ffb's minor nodename,
2167 	 * we need to search all the devices under its
2168 	 * parent dir by comparing the node name
2169 	 */
2170 	if ((dirp = opendir(dev_path)) == NULL)
2171 		return (PICL_FAILURE);
2172 
2173 	while ((direntp = readdir(dirp)) != NULL) {
2174 		if (strstr(direntp->d_name, devp) != NULL) {
2175 			(void) strcat(dev_path, "/");
2176 			(void) strcat(dev_path, direntp->d_name);
2177 			tmpfd = open(dev_path, O_RDWR);
2178 			if (tmpfd < 0)
2179 				continue;
2180 			*fd = tmpfd;
2181 			(void) closedir(dirp);
2182 			return (PICL_SUCCESS);
2183 		}
2184 	}
2185 
2186 	(void) closedir(dirp);
2187 	return (PICL_FAILURE);
2188 }
2189 
2190 /*
2191  * This function recursively searches the tree for ffb display devices
2192  * and add ffb config information
2193  */
2194 static int
2195 add_ffb_config_info(picl_nodehdl_t rooth)
2196 {
2197 	picl_nodehdl_t		nodeh;
2198 	int			err;
2199 	char			piclclass[PICL_CLASSNAMELEN_MAX];
2200 	char			manfidbuf[FFB_MANUF_BUFSIZE];
2201 	int			fd;
2202 	int			board_rev;
2203 	ffb_sys_info_t		fsi;
2204 	ptree_propinfo_t	pinfo;
2205 
2206 	for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &nodeh,
2207 	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2208 	    err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
2209 	    &nodeh, sizeof (picl_nodehdl_t))) {
2210 
2211 		if (err != PICL_SUCCESS)
2212 			return (err);
2213 
2214 		err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
2215 		    piclclass, PICL_CLASSNAMELEN_MAX);
2216 
2217 		if ((err == PICL_SUCCESS) &&
2218 		    (strcmp(piclclass, PICL_CLASS_DISPLAY) == 0)) {
2219 
2220 			err = open_ffb_device(nodeh, &fd);
2221 			if ((err == PICL_SUCCESS) &&
2222 			    (ioctl(fd, FFB_SYS_INFO, &fsi) >= 0)) {
2223 				(void) ptree_init_propinfo(&pinfo,
2224 				    PTREE_PROPINFO_VERSION,
2225 				    PICL_PTYPE_UNSIGNED_INT, PICL_READ,
2226 				    sizeof (int), PICL_PROP_FFB_BOARD_REV,
2227 				    NULL, NULL);
2228 				board_rev = fsi.ffb_strap_bits.fld.board_rev;
2229 				(void) ptree_create_and_add_prop(nodeh, &pinfo,
2230 				    &board_rev, NULL);
2231 
2232 				fmt_manf_id(fsi.dac_version,
2233 				    sizeof (manfidbuf), manfidbuf);
2234 				(void) ptree_init_propinfo(&pinfo,
2235 				    PTREE_PROPINFO_VERSION,
2236 				    PICL_PTYPE_CHARSTRING, PICL_READ,
2237 				    strlen(manfidbuf) + 1,
2238 				    PICL_PROP_FFB_DAC_VER, NULL, NULL);
2239 				(void) ptree_create_and_add_prop(nodeh, &pinfo,
2240 				    manfidbuf, NULL);
2241 
2242 				fmt_manf_id(fsi.fbram_version,
2243 				    sizeof (manfidbuf), manfidbuf);
2244 				(void) ptree_init_propinfo(&pinfo,
2245 				    PTREE_PROPINFO_VERSION,
2246 				    PICL_PTYPE_CHARSTRING, PICL_READ,
2247 				    strlen(manfidbuf) + 1,
2248 				    PICL_PROP_FFB_FBRAM_VER, NULL,
2249 				    NULL);
2250 				(void) ptree_create_and_add_prop(nodeh, &pinfo,
2251 				    manfidbuf, NULL);
2252 				(void) close(fd);
2253 			}
2254 		} else if (add_ffb_config_info(nodeh) != PICL_SUCCESS)
2255 			return (PICL_FAILURE);
2256 	}
2257 	return (PICL_SUCCESS);
2258 }
2259 
2260 static conf_entries_t *
2261 free_conf_entries(conf_entries_t *list)
2262 {
2263 	conf_entries_t	*el;
2264 	conf_entries_t	*del;
2265 
2266 	if (list == NULL)
2267 		return (NULL);
2268 	el = list;
2269 	while (el != NULL) {
2270 		del = el;
2271 		el = el->next;
2272 		free(del->name);
2273 		free(del->piclclass);
2274 		free(del);
2275 	}
2276 	return (el);
2277 }
2278 
2279 /*
2280  * Reading config order: platform, common
2281  */
2282 static conf_entries_t *
2283 read_conf_file(char *fname, conf_entries_t *list)
2284 {
2285 	FILE		*fp;
2286 	char		lbuf[CONFFILE_LINELEN_MAX];
2287 	char		*nametok;
2288 	char		*classtok;
2289 	conf_entries_t	*el;
2290 	conf_entries_t	*ptr;
2291 
2292 	if (fname == NULL)
2293 		return (list);
2294 
2295 	fp = fopen(fname, "r");
2296 
2297 	if (fp == NULL)
2298 		return (list);
2299 
2300 	while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) {
2301 		if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n'))
2302 			continue;
2303 
2304 		nametok = strtok(lbuf, " \t\n");
2305 		if (nametok == NULL)
2306 			continue;
2307 
2308 		classtok = strtok(NULL, " \t\n");
2309 		if (classtok == NULL)
2310 			continue;
2311 
2312 		el = malloc(sizeof (conf_entries_t));
2313 		if (el == NULL)
2314 			break;
2315 		el->name = strdup(nametok);
2316 		el->piclclass = strdup(classtok);
2317 		if ((el->name == NULL) || (el->piclclass == NULL)) {
2318 			free(el);
2319 			return (list);
2320 		}
2321 		el->next = NULL;
2322 
2323 		/*
2324 		 * Add it to the end of list
2325 		 */
2326 		if (list == NULL)
2327 			list = el;
2328 		else {
2329 			ptr = list;
2330 			while (ptr->next != NULL)
2331 				ptr = ptr->next;
2332 			ptr->next = el;
2333 		}
2334 
2335 	}
2336 	(void) fclose(fp);
2337 	return (list);
2338 }
2339 
2340 /*
2341  * Process the devtree conf file and set up the conf_name_class_map list
2342  */
2343 static void
2344 process_devtree_conf_file(void)
2345 {
2346 	char	nmbuf[SYS_NMLN];
2347 	char	pname[PATH_MAX];
2348 
2349 	conf_name_class_map = NULL;
2350 
2351 	if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
2352 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2353 		(void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX);
2354 		conf_name_class_map = read_conf_file(pname,
2355 		    conf_name_class_map);
2356 	}
2357 
2358 	if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
2359 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2360 		(void) strlcat(pname, DEVTREE_CONFFILE_NAME, PATH_MAX);
2361 		conf_name_class_map = read_conf_file(pname,
2362 		    conf_name_class_map);
2363 	}
2364 
2365 	(void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
2366 	    DEVTREE_CONFFILE_NAME);
2367 	conf_name_class_map = read_conf_file(pname, conf_name_class_map);
2368 }
2369 
2370 static	asr_conf_entries_t	*conf_name_asr_map = NULL;
2371 
2372 static void
2373 free_asr_conf_entries(asr_conf_entries_t *list)
2374 {
2375 	asr_conf_entries_t  *el;
2376 	asr_conf_entries_t  *del;
2377 
2378 	el = list;
2379 	while (el != NULL) {
2380 		del = el;
2381 		el = el->next;
2382 		if (del->name)
2383 			free(del->name);
2384 		if (del->address)
2385 			free(del->address);
2386 		if (del->status)
2387 			free(del->status);
2388 		if (del->piclclass)
2389 			free(del->piclclass);
2390 		if (del->props)
2391 			free(del->props);
2392 		free(del);
2393 	}
2394 }
2395 
2396 /*
2397  * Reading config order: platform, common
2398  */
2399 static asr_conf_entries_t *
2400 read_asr_conf_file(char *fname, asr_conf_entries_t *list)
2401 {
2402 	FILE		*fp;
2403 	char		lbuf[CONFFILE_LINELEN_MAX];
2404 	char		*nametok;
2405 	char		*classtok;
2406 	char		*statustok;
2407 	char		*addresstok;
2408 	char		*propstok;
2409 	asr_conf_entries_t	*el;
2410 	asr_conf_entries_t	*ptr;
2411 
2412 	if (fname == NULL)
2413 		return (list);
2414 
2415 	fp = fopen(fname, "r");
2416 	if (fp == NULL)
2417 		return (list);
2418 
2419 	while (fgets(lbuf, CONFFILE_LINELEN_MAX, fp) != NULL) {
2420 		if ((lbuf[0] == CONFFILE_COMMENT_CHAR) || (lbuf[0] == '\n'))
2421 			continue;
2422 
2423 		nametok = strtok(lbuf, " \t\n");
2424 		if (nametok == NULL)
2425 			continue;
2426 
2427 		classtok = strtok(NULL, " \t\n");
2428 		if (classtok == NULL)
2429 			continue;
2430 
2431 		statustok = strtok(NULL, " \t\n");
2432 		if (statustok == NULL)
2433 			continue;
2434 
2435 		addresstok = strtok(NULL, " \t\n");
2436 		if (addresstok == NULL)
2437 			continue;
2438 
2439 		/*
2440 		 * props are optional
2441 		 */
2442 		propstok = strtok(NULL, " \t\n");
2443 
2444 		el = malloc(sizeof (asr_conf_entries_t));
2445 		if (el == NULL)
2446 			break;
2447 		el->name = strdup(nametok);
2448 		el->piclclass = strdup(classtok);
2449 		el->status = strdup(statustok);
2450 		el->address = strdup(addresstok);
2451 		if (propstok != NULL)
2452 			el->props = strdup(propstok);
2453 		else
2454 			el->props = NULL;
2455 		if ((el->name == NULL) || (el->piclclass == NULL) ||
2456 		    (el->address == NULL) || (el->status == NULL)) {
2457 			if (el->name)
2458 				free(el->name);
2459 			if (el->address)
2460 				free(el->address);
2461 			if (el->status)
2462 				free(el->status);
2463 			if (el->piclclass)
2464 				free(el->piclclass);
2465 			if (el->props)
2466 				free(el->props);
2467 			free(el);
2468 			break;
2469 		}
2470 		el->next = NULL;
2471 
2472 		/*
2473 		 * Add it to the end of list
2474 		 */
2475 		if (list == NULL)
2476 			list = el;
2477 		else {
2478 			ptr = list;
2479 			while (ptr->next != NULL)
2480 				ptr = ptr->next;
2481 			ptr->next = el;
2482 		}
2483 
2484 	}
2485 	(void) fclose(fp);
2486 	return (list);
2487 }
2488 
2489 /*
2490  * Process the asr conf file
2491  */
2492 static void
2493 process_asrtree_conf_file(void)
2494 {
2495 	char	nmbuf[SYS_NMLN];
2496 	char	pname[PATH_MAX];
2497 
2498 	if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) {
2499 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2500 		(void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX);
2501 		conf_name_asr_map = read_asr_conf_file(pname,
2502 		    conf_name_asr_map);
2503 	}
2504 
2505 	if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) {
2506 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
2507 		(void) strlcat(pname, ASRTREE_CONFFILE_NAME, PATH_MAX);
2508 		conf_name_asr_map = read_asr_conf_file(pname,
2509 		    conf_name_asr_map);
2510 	}
2511 
2512 	(void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR,
2513 	    ASRTREE_CONFFILE_NAME);
2514 	conf_name_asr_map = read_asr_conf_file(pname, conf_name_asr_map);
2515 }
2516 
2517 /*
2518  * This function reads the export file list from ASR
2519  */
2520 static int
2521 get_asr_export_list(char **exportlist, int *exportlistlen)
2522 {
2523 	struct openpromio oppbuf;
2524 	struct openpromio *opp = &oppbuf;
2525 	int d;
2526 	int listsize;
2527 
2528 	d = open("/dev/openprom", O_RDWR);
2529 	if (d < 0)
2530 		return (0);
2531 
2532 	if (ioctl(d, OPROMEXPORTLEN, opp) == -1) {
2533 		(void) close(d);
2534 		return (0);
2535 	}
2536 	listsize = opp->oprom_size;
2537 	opp = (struct openpromio *)malloc(sizeof (struct openpromio) +
2538 	    listsize);
2539 	if (opp == NULL) {
2540 		(void) close(d);
2541 		return (0);
2542 	}
2543 	(void) memset(opp, '\0', sizeof (struct openpromio) + listsize);
2544 	opp->oprom_size = listsize;
2545 	if (ioctl(d, OPROMEXPORT, opp) == -1) {
2546 		free(opp);
2547 		(void) close(d);
2548 		return (0);
2549 	}
2550 	*exportlist = malloc(listsize);
2551 	if (*exportlist == NULL) {
2552 		free(opp);
2553 		(void) close(d);
2554 		return (0);
2555 	}
2556 	(void) memcpy(*exportlist, opp->oprom_array, opp->oprom_size);
2557 	*exportlistlen = opp->oprom_size;
2558 	free(opp);
2559 	(void) close(d);
2560 	return (1);
2561 }
2562 
2563 /*
2564  * Parses properties string, fills in triplet structure with first
2565  * type, name, val triplet and returns pointer to next property.
2566  * Returns NULL if no valid triplet found
2567  * CAUTION: drops \0 characters over separator characters: if you
2568  * want to parse the string twice, you'll have to take a copy.
2569  */
2570 static char *
2571 parse_props_string(char *props, asr_prop_triplet_t *triplet)
2572 {
2573 	char	*prop_name;
2574 	char	*prop_val;
2575 	char	*prop_next;
2576 
2577 	prop_name = strchr(props, '?');
2578 	if (prop_name == NULL)
2579 		return (NULL);
2580 	*prop_name++ = '\0';
2581 	prop_val = strchr(prop_name, '=');
2582 	if (prop_val == NULL)
2583 		return (NULL);
2584 	*prop_val++ = '\0';
2585 	triplet->proptype = props;
2586 	triplet->propname = prop_name;
2587 	triplet->propval = prop_val;
2588 	prop_next = strchr(prop_val, ':');
2589 	if (prop_next == NULL)
2590 		return (prop_val - 1);
2591 	*prop_next++ = '\0';
2592 	return (prop_next);
2593 }
2594 
2595 static int
2596 add_status_prop(picl_nodehdl_t chdh, char *status)
2597 {
2598 	ptree_propinfo_t	propinfo;
2599 	picl_prophdl_t		proph;
2600 	int			err;
2601 
2602 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2603 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(status) + 1,
2604 	    PICL_PROP_STATUS, NULL, NULL);
2605 	if (err != PICL_SUCCESS)
2606 		return (err);
2607 	err = ptree_create_and_add_prop(chdh, &propinfo, status, &proph);
2608 	return (err);
2609 }
2610 
2611 static void
2612 create_asr_node(char *parent, char *child, char *unitaddr, char *class,
2613     char *status, char *props)
2614 {
2615 	char			ptreepath[PATH_MAX];
2616 	char			nodename[PICL_PROPNAMELEN_MAX];
2617 	char			ua[MAX_UNIT_ADDRESS_LEN];
2618 	char			*props_copy = NULL;
2619 	char			*next;
2620 	char			*prop_string;
2621 	boolean_t		found = B_FALSE;
2622 	picl_nodehdl_t		nodeh;
2623 	picl_nodehdl_t		chdh;
2624 	asr_prop_triplet_t	triple;
2625 	ptree_propinfo_t	propinfo;
2626 	picl_prophdl_t		proph;
2627 	int			val;
2628 	int			err;
2629 
2630 	(void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX);
2631 	(void) strlcat(ptreepath, parent, PATH_MAX);
2632 
2633 	if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS)
2634 		return;
2635 	/*
2636 	 * see if the required child node already exists
2637 	 */
2638 	for (err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
2639 	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
2640 	    err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
2641 	    sizeof (picl_nodehdl_t))) {
2642 		if (err != PICL_SUCCESS)
2643 			break;
2644 		err = ptree_get_propval_by_name(chdh, PICL_PROP_NAME,
2645 		    (void *)nodename, PICL_PROPNAMELEN_MAX);
2646 		if (err != PICL_SUCCESS)
2647 			break;
2648 		if (strcmp(nodename, child) != 0)
2649 			continue;
2650 		/*
2651 		 * found a candidate child node
2652 		 */
2653 		if (unitaddr) {
2654 			/*
2655 			 * does it match the required unit address?
2656 			 */
2657 			err = ptree_get_propval_by_name(chdh,
2658 			    PICL_PROP_UNIT_ADDRESS, ua, sizeof (ua));
2659 			if (err == PICL_PROPNOTFOUND)
2660 				continue;
2661 			if (err != PICL_SUCCESS)
2662 				break;
2663 			if (strcmp(unitaddr, ua) != 0)
2664 				continue;
2665 		}
2666 		if (props == NULL) {
2667 			next = "";
2668 		} else if (props_copy == NULL) {
2669 			props_copy = strdup(props);
2670 			if (props_copy == NULL)
2671 				return;
2672 			next = props_copy;
2673 		}
2674 		while ((next = parse_props_string(next, &triple)) != NULL) {
2675 			err = ptree_get_prop_by_name(chdh, triple.propname,
2676 			    &proph);
2677 			if (err != PICL_SUCCESS)
2678 				break;
2679 			err = ptree_get_propinfo(proph, &propinfo);
2680 			if (err != PICL_SUCCESS)
2681 				break;
2682 			err = PICL_FAILURE;
2683 			switch (propinfo.piclinfo.type) {
2684 			case PICL_PTYPE_INT:
2685 			case PICL_PTYPE_UNSIGNED_INT:
2686 				if (strcmp(triple.proptype, "I") != 0)
2687 					break;
2688 				err = ptree_get_propval(proph, (void  *)&val,
2689 				    sizeof (val));
2690 				if (err != PICL_SUCCESS)
2691 					break;
2692 				if (val != atoi(triple.propval))
2693 					err = PICL_FAILURE;
2694 				break;
2695 			case PICL_PTYPE_CHARSTRING:
2696 				if (strcmp(triple.proptype, "S") != 0)
2697 					break;
2698 				prop_string = malloc(propinfo.piclinfo.size);
2699 				if (prop_string == NULL)
2700 					break;
2701 				err = ptree_get_propval(proph,
2702 				    (void *)prop_string,
2703 				    propinfo.piclinfo.size);
2704 				if (err != PICL_SUCCESS) {
2705 					free(prop_string);
2706 					break;
2707 				}
2708 				if (strcmp(prop_string, triple.propval) != 0)
2709 					err = PICL_FAILURE;
2710 				free(prop_string);
2711 				break;
2712 			default:
2713 				break;
2714 			}
2715 			if (err != PICL_SUCCESS) {
2716 				break;
2717 			}
2718 		}
2719 		if (next == NULL) {
2720 			found = B_TRUE;
2721 			break;
2722 		}
2723 	}
2724 	if (props_copy)
2725 		free(props_copy);
2726 	if (found) {
2727 		/*
2728 		 * does the pre-existing node have a status property?
2729 		 */
2730 		err = ptree_get_propval_by_name(chdh, PICL_PROP_STATUS,
2731 		    ua, sizeof (ua));
2732 		if (err == PICL_PROPNOTFOUND)
2733 			(void) add_status_prop(chdh, status);
2734 		if (err != PICL_SUCCESS)
2735 			return;
2736 		if ((strcmp(ua, ASR_DISABLED) == 0) ||
2737 		    (strcmp(ua, ASR_FAILED) == 0) ||
2738 		    ((strcmp(status, ASR_DISABLED) != 0) &&
2739 		    (strcmp(status, ASR_FAILED) != 0))) {
2740 			return;
2741 		}
2742 		/*
2743 		 * more urgent status now, so replace existing value
2744 		 */
2745 		err = ptree_get_prop_by_name(chdh, PICL_PROP_STATUS, &proph);
2746 		if (err != PICL_SUCCESS)
2747 			return;
2748 		(void) ptree_delete_prop(proph);
2749 		(void) ptree_destroy_prop(proph);
2750 		err = add_status_prop(chdh, status);
2751 		if (err != PICL_SUCCESS)
2752 			return;
2753 		return;
2754 	}
2755 
2756 	/*
2757 	 * typical case, node needs adding together with a set of properties
2758 	 */
2759 	if (ptree_create_and_add_node(nodeh, child, class, &chdh) ==
2760 	    PICL_SUCCESS) {
2761 		(void) add_status_prop(chdh, status);
2762 		if (unitaddr) {
2763 			(void) ptree_init_propinfo(&propinfo,
2764 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
2765 			    PICL_READ, strlen(unitaddr) + 1,
2766 			    PICL_PROP_UNIT_ADDRESS, NULL, NULL);
2767 			(void) ptree_create_and_add_prop(chdh, &propinfo,
2768 			    unitaddr, &proph);
2769 			(void) strlcpy(ptreepath, parent, PATH_MAX);
2770 			(void) strlcat(ptreepath, "/", PATH_MAX);
2771 			(void) strlcat(ptreepath, child, PATH_MAX);
2772 			(void) strlcat(ptreepath, "@", PATH_MAX);
2773 			(void) strlcat(ptreepath, unitaddr, PATH_MAX);
2774 			(void) ptree_init_propinfo(&propinfo,
2775 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
2776 			    PICL_READ, strlen(ptreepath) + 1,
2777 			    PICL_PROP_DEVFS_PATH, NULL, NULL);
2778 			(void) ptree_create_and_add_prop(chdh, &propinfo,
2779 			    ptreepath, &proph);
2780 		}
2781 		next = props;
2782 		while ((next = parse_props_string(next, &triple)) != NULL) {
2783 			/*
2784 			 * only handle int and string properties for
2785 			 * simplicity
2786 			 */
2787 			if (strcmp(triple.proptype, "I") == 0) {
2788 				(void) ptree_init_propinfo(&propinfo,
2789 				    PTREE_PROPINFO_VERSION,
2790 				    PICL_PTYPE_INT, PICL_READ,
2791 				    sizeof (int), triple.propname, NULL, NULL);
2792 				val = atoi(triple.propval);
2793 				(void) ptree_create_and_add_prop(chdh,
2794 				    &propinfo, &val, &proph);
2795 			} else {
2796 				(void) ptree_init_propinfo(&propinfo,
2797 				    PTREE_PROPINFO_VERSION,
2798 				    PICL_PTYPE_CHARSTRING, PICL_READ,
2799 				    strlen(triple.propval) + 1,
2800 				    triple.propname, NULL, NULL);
2801 				(void) ptree_create_and_add_prop(chdh,
2802 				    &propinfo, triple.propval, &proph);
2803 			}
2804 		}
2805 	}
2806 }
2807 
2808 static void
2809 add_asr_nodes()
2810 {
2811 	char			*asrexport;
2812 	int			asrexportlen;
2813 	asr_conf_entries_t	*c = NULL;
2814 	int			i;
2815 	char			*key;
2816 	char			*child;
2817 	char			*unitaddr;
2818 	uint16_t		count;
2819 	int			disabled;
2820 
2821 	if (get_asr_export_list(&asrexport, &asrexportlen) == 0)
2822 		return;
2823 	process_asrtree_conf_file();
2824 	if (conf_name_asr_map == NULL)
2825 		return;
2826 	i = 0;
2827 	while (i < asrexportlen) {
2828 		key = &asrexport[i];
2829 		i += strlen(key) + 1;
2830 		if (i >= asrexportlen)
2831 			break;
2832 
2833 		/*
2834 		 * next byte tells us whether failed by diags or manually
2835 		 * disabled
2836 		 */
2837 		disabled = asrexport[i];
2838 		i++;
2839 		if (i >= asrexportlen)
2840 			break;
2841 
2842 		/*
2843 		 * only type 1 supported
2844 		 */
2845 		if (asrexport[i] != 1)
2846 			break;
2847 		i++;
2848 		if (i >= asrexportlen)
2849 			break;
2850 
2851 		/*
2852 		 * next two bytes give size of reason string
2853 		 */
2854 		count = (asrexport[i] << 8) | asrexport[i + 1];
2855 		i += count + 2;
2856 		if (i > asrexportlen)
2857 			break;
2858 
2859 		/*
2860 		 * now look for key in conf file info
2861 		 */
2862 		c = conf_name_asr_map;
2863 		while (c != NULL) {
2864 			if (strcmp(key, c->name) == 0) {
2865 				child = strrchr(c->address, '/');
2866 				*child++ = '\0';
2867 				unitaddr = strchr(child, '@');
2868 				if (unitaddr)
2869 					*unitaddr++ = '\0';
2870 				if (strcmp(c->status, ASR_DISABLED) == 0) {
2871 					create_asr_node(c->address, child,
2872 					    unitaddr, c->piclclass, disabled ?
2873 					    ASR_DISABLED : ASR_FAILED,
2874 					    c->props);
2875 				} else {
2876 					create_asr_node(c->address, child,
2877 					    unitaddr, c->piclclass, c->status,
2878 					    c->props);
2879 				}
2880 			}
2881 			c = c->next;
2882 		}
2883 	}
2884 
2885 	free_asr_conf_entries(conf_name_asr_map);
2886 	free(asrexport);
2887 }
2888 
2889 /*
2890  * This function adds information to the /platform node
2891  */
2892 static int
2893 add_platform_info(picl_nodehdl_t plafh)
2894 {
2895 	struct utsname		uts_info;
2896 	int			err;
2897 	ptree_propinfo_t	propinfo;
2898 	picl_prophdl_t		proph;
2899 
2900 	if (uname(&uts_info) < 0)
2901 		return (PICL_FAILURE);
2902 
2903 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2904 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.sysname) + 1,
2905 	    PICL_PROP_SYSNAME, NULL, NULL);
2906 	err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.sysname,
2907 	    &proph);
2908 	if (err != PICL_SUCCESS)
2909 		return (err);
2910 
2911 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2912 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.nodename) + 1,
2913 	    PICL_PROP_NODENAME, NULL, NULL);
2914 	err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.nodename,
2915 	    &proph);
2916 	if (err != PICL_SUCCESS)
2917 		return (err);
2918 
2919 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2920 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.release) + 1,
2921 	    PICL_PROP_RELEASE, NULL, NULL);
2922 	err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.release,
2923 	    &proph);
2924 	if (err != PICL_SUCCESS)
2925 		return (err);
2926 
2927 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2928 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.version) + 1,
2929 	    PICL_PROP_VERSION, NULL, NULL);
2930 	err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.version,
2931 	    &proph);
2932 	if (err != PICL_SUCCESS)
2933 		return (err);
2934 
2935 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
2936 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(uts_info.machine) + 1,
2937 	    PICL_PROP_MACHINE, NULL, NULL);
2938 	err = ptree_create_and_add_prop(plafh, &propinfo, uts_info.machine,
2939 	    &proph);
2940 	return (err);
2941 }
2942 
2943 /*
2944  * Get first 32-bit value from the reg property
2945  */
2946 static int
2947 get_first_reg_word(picl_nodehdl_t nodeh, uint32_t *regval)
2948 {
2949 	int			err;
2950 	uint32_t		*regbuf;
2951 	picl_prophdl_t		regh;
2952 	ptree_propinfo_t	pinfo;
2953 
2954 	err = ptree_get_prop_by_name(nodeh, OBP_REG, &regh);
2955 	if (err != PICL_SUCCESS)	/* no reg property */
2956 		return (err);
2957 	err = ptree_get_propinfo(regh, &pinfo);
2958 	if (err != PICL_SUCCESS)
2959 		return (err);
2960 	if (pinfo.piclinfo.size < sizeof (uint32_t)) /* too small */
2961 		return (PICL_FAILURE);
2962 	regbuf = alloca(pinfo.piclinfo.size);
2963 	if (regbuf == NULL)
2964 		return (PICL_FAILURE);
2965 	err = ptree_get_propval(regh, regbuf, pinfo.piclinfo.size);
2966 	if (err != PICL_SUCCESS)
2967 		return (err);
2968 	*regval = *regbuf;	/* get first 32-bit value */
2969 	return (PICL_SUCCESS);
2970 }
2971 
2972 /*
2973  * Get device ID from the reg property
2974  */
2975 static int
2976 get_device_id(picl_nodehdl_t nodeh, uint32_t *dev_id)
2977 {
2978 	int			err;
2979 	uint32_t		regval;
2980 
2981 	err = get_first_reg_word(nodeh, &regval);
2982 	if (err != PICL_SUCCESS)
2983 		return (err);
2984 
2985 	*dev_id = PCI_DEVICE_ID(regval);
2986 	return (PICL_SUCCESS);
2987 }
2988 
2989 /*
2990  * add Slot property for children of SBUS node
2991  */
2992 /* ARGSUSED */
2993 static int
2994 add_sbus_slots(picl_nodehdl_t pcih, void *args)
2995 {
2996 	picl_nodehdl_t		nodeh;
2997 	uint32_t		slot;
2998 	int			err;
2999 	ptree_propinfo_t	pinfo;
3000 
3001 	for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
3002 	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
3003 	    err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
3004 	    sizeof (picl_nodehdl_t))) {
3005 		if (err != PICL_SUCCESS)
3006 			return (err);
3007 
3008 		if (get_first_reg_word(nodeh, &slot) != 0)
3009 			continue;
3010 		(void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3011 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t),
3012 		    PICL_PROP_SLOT, NULL, NULL);
3013 		(void) ptree_create_and_add_prop(nodeh, &pinfo, &slot, NULL);
3014 	}
3015 
3016 	return (PICL_WALK_CONTINUE);
3017 }
3018 
3019 /*
3020  * This function creates a Slot property for SBUS child nodes
3021  * which can be correlated with the slot they are plugged into
3022  * on the motherboard.
3023  */
3024 static int
3025 set_sbus_slot(picl_nodehdl_t plafh)
3026 {
3027 	int		err;
3028 
3029 	err = ptree_walk_tree_by_class(plafh, PICL_CLASS_SBUS, NULL,
3030 	    add_sbus_slots);
3031 
3032 	return (err);
3033 }
3034 
3035 /*
3036  * add DeviceID property for children of PCI/PCIEX node
3037  */
3038 /* ARGSUSED */
3039 static int
3040 add_pci_deviceids(picl_nodehdl_t pcih, void *args)
3041 {
3042 	picl_nodehdl_t		nodeh;
3043 	uint32_t		dev_id;
3044 	int			err;
3045 	ptree_propinfo_t	pinfo;
3046 
3047 	for (err = ptree_get_propval_by_name(pcih, PICL_PROP_CHILD, &nodeh,
3048 	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
3049 	    err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, &nodeh,
3050 	    sizeof (picl_nodehdl_t))) {
3051 		if (err != PICL_SUCCESS)
3052 			return (err);
3053 
3054 		if (get_device_id(nodeh, &dev_id) != 0)
3055 			continue;
3056 		(void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3057 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (uint32_t),
3058 		    PICL_PROP_DEVICE_ID, NULL, NULL);
3059 		(void) ptree_create_and_add_prop(nodeh, &pinfo, &dev_id, NULL);
3060 	}
3061 
3062 	return (PICL_WALK_CONTINUE);
3063 }
3064 
3065 /*
3066  * This function creates a DeviceID property for PCI/PCIEX child nodes
3067  * which can be correlated with the slot they are plugged into
3068  * on the motherboard.
3069  */
3070 static void
3071 set_pci_pciex_deviceid(picl_nodehdl_t plafh)
3072 {
3073 	(void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCI, NULL,
3074 	    add_pci_deviceids);
3075 
3076 	(void) ptree_walk_tree_by_class(plafh, PICL_CLASS_PCIEX, NULL,
3077 	    add_pci_deviceids);
3078 }
3079 
3080 /*
3081  * Default UnitAddress encode function
3082  */
3083 static int
3084 encode_default_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3085 {
3086 	int	i, len;
3087 
3088 	/*
3089 	 * Encode UnitAddress as %a,%b,%c,...,%n
3090 	 */
3091 	if (addrcells < 1)
3092 		return (-1);
3093 
3094 	len = snprintf(buf, sz, "%x", *regprop);
3095 	for (i = 1; i < addrcells && len < sz; i++)
3096 		len += snprintf(&buf[len], sz-len, ",%x", regprop[i]);
3097 
3098 	return ((len >= sz) ? -1 : 0);
3099 }
3100 
3101 /*
3102  * UnitAddress encode function where the last component is not printed
3103  * unless non-zero.
3104  */
3105 static int
3106 encode_optional_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3107 {
3108 	int	retval;
3109 
3110 	/*
3111 	 * Encode UnitAddress as %a,%b,%c,...,%n where the last component
3112 	 * is printed only if non-zero.
3113 	 */
3114 	if (addrcells > 1 && regprop[addrcells-1] == 0)
3115 		retval = encode_default_unitaddr(buf, sz, regprop, addrcells-1);
3116 	else
3117 		retval = encode_default_unitaddr(buf, sz, regprop, addrcells);
3118 
3119 	return (retval);
3120 }
3121 
3122 
3123 /*
3124  * UnitAddress encode function for SCSI class of devices
3125  */
3126 static int
3127 encode_scsi_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3128 {
3129 	int	len, retval;
3130 
3131 	/*
3132 	 * #address-cells	Format
3133 	 *	2		second component printed only if non-zero
3134 	 *
3135 	 *	4		regprop:   phys_hi phys_lo lun_hi lun_lo
3136 	 *			UnitAddr:  w<phys_hi><phys_lo>,<lun_lo>
3137 	 */
3138 
3139 	if (addrcells == 2) {
3140 		retval = encode_optional_unitaddr(buf, sz, regprop, addrcells);
3141 	} else if (addrcells == 4) {
3142 		len = snprintf(buf, sz, "w%08x%08x,%x", regprop[0], regprop[1],
3143 		    regprop[3]);
3144 		retval = (len >= sz) ? -1 : 0;
3145 	} else
3146 		retval = -1;
3147 
3148 	return (retval);
3149 }
3150 
3151 /*
3152  * UnitAddress encode function for UPA devices
3153  */
3154 static int
3155 encode_upa_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3156 {
3157 	int	len;
3158 
3159 	if (addrcells != 2)
3160 		return (-1);
3161 
3162 	len = snprintf(buf, sz, "%x,%x", (regprop[0]/2)&0x1f, regprop[1]);
3163 	return ((len >= sz) ? -1 : 0);
3164 }
3165 
3166 /*
3167  * UnitAddress encode function for GPTWO, JBUS devices
3168  */
3169 static int
3170 encode_gptwo_jbus_unitaddr(char *buf, int sz, uint32_t *regprop,
3171     uint_t addrcells)
3172 {
3173 	uint32_t	hi, lo;
3174 	int		len, id, off;
3175 
3176 	if (addrcells != 2)
3177 		return (-1);
3178 
3179 	hi = regprop[0];
3180 	lo = regprop[1];
3181 
3182 	if (hi & 0x400) {
3183 		id = ((hi & 0x1) << 9) | (lo >> 23);	/* agent id */
3184 		off = lo & 0x7fffff;			/* config offset */
3185 		len = snprintf(buf, sz, "%x,%x", id, off);
3186 	} else {
3187 		len = snprintf(buf, sz, "m%x,%x", hi, lo);
3188 	}
3189 	return ((len >= sz) ? -1 : 0);
3190 }
3191 
3192 /*
3193  * UnitAddress encode function for PCI devices
3194  */
3195 static int
3196 encode_pci_unitaddr(char *buf, int sz, uint32_t *regprop, uint_t addrcells)
3197 {
3198 	typedef struct {
3199 		uint32_t	n:1,		/* relocatable */
3200 				p:1,		/* prefetchable */
3201 				t:1,		/* address region aliases */
3202 				zero:3,		/* must be zero */
3203 				ss:2,		/* address space type */
3204 				bus:8,		/* bus number */
3205 				dev:5,		/* device number */
3206 				fn:3,		/* function number */
3207 				reg:8;		/* register number */
3208 		uint32_t	phys_hi;	/* high physical address */
3209 		uint32_t	phys_lo;	/* low physical address */
3210 	} pci_addrcell_t;
3211 
3212 	pci_addrcell_t	*p;
3213 	int		len;
3214 
3215 	if (addrcells != 3)
3216 		return (-1);
3217 
3218 	p = (pci_addrcell_t *)regprop;
3219 	switch (p->ss) {
3220 	case 0:		/* Config */
3221 		if (p->fn)
3222 			len = snprintf(buf, sz, "%x,%x", p->dev, p->fn);
3223 		else
3224 			len = snprintf(buf, sz, "%x", p->dev);
3225 		break;
3226 	case 1:		/* IO */
3227 		len = snprintf(buf, sz, "i%x,%x,%x,%x", p->dev, p->fn, p->reg,
3228 		    p->phys_lo);
3229 		break;
3230 	case 2:		/* Mem32 */
3231 		len = snprintf(buf, sz, "m%x,%x,%x,%x", p->dev, p->fn, p->reg,
3232 		    p->phys_lo);
3233 		break;
3234 	case 3:		/* Mem64 */
3235 		len = snprintf(buf, sz, "x%x,%x,%x,%x%08x", p->dev, p->fn,
3236 		    p->reg, p->phys_hi, p->phys_lo);
3237 		break;
3238 	}
3239 	return ((len >= sz) ? -1 : 0);
3240 }
3241 
3242 /*
3243  * Get #address-cells property value
3244  */
3245 static uint_t
3246 get_addrcells_prop(picl_nodehdl_t nodeh)
3247 {
3248 	int			len, err;
3249 	uint32_t		addrcells;
3250 	ptree_propinfo_t	pinfo;
3251 	picl_prophdl_t		proph;
3252 
3253 	/*
3254 	 * Get #address-cells property.  If not present, use default value.
3255 	 */
3256 	err = ptree_get_prop_by_name(nodeh, OBP_PROP_ADDRESS_CELLS, &proph);
3257 	if (err == PICL_SUCCESS)
3258 		err = ptree_get_propinfo(proph, &pinfo);
3259 
3260 	len = pinfo.piclinfo.size;
3261 	if (err == PICL_SUCCESS && len >= sizeof (uint8_t) &&
3262 	    len <= sizeof (addrcells)) {
3263 		err = ptree_get_propval(proph, &addrcells, len);
3264 		if (err == PICL_SUCCESS) {
3265 			if (len == sizeof (uint8_t))
3266 				addrcells = *(uint8_t *)&addrcells;
3267 			else if (len == sizeof (uint16_t))
3268 				addrcells = *(uint16_t *)&addrcells;
3269 		} else
3270 			addrcells = DEFAULT_ADDRESS_CELLS;
3271 	} else
3272 		addrcells = DEFAULT_ADDRESS_CELLS;
3273 
3274 	return (addrcells);
3275 }
3276 
3277 /*
3278  * Get UnitAddress mapping entry for a node
3279  */
3280 static unitaddr_map_t *
3281 get_unitaddr_mapping(picl_nodehdl_t nodeh)
3282 {
3283 	int		err;
3284 	unitaddr_map_t	*uamap;
3285 	char		clname[PICL_CLASSNAMELEN_MAX];
3286 
3287 	/*
3288 	 * Get my classname and locate a function to translate "reg" prop
3289 	 * into "UnitAddress" prop for my children.
3290 	 */
3291 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, clname,
3292 	    sizeof (clname));
3293 	if (err != PICL_SUCCESS)
3294 		(void) strcpy(clname, "");	/* NULL class name */
3295 
3296 	for (uamap = &unitaddr_map_table[0]; uamap->class != NULL; uamap++)
3297 		if (strcmp(clname, uamap->class) == 0)
3298 			break;
3299 
3300 	return (uamap);
3301 }
3302 
3303 /*
3304  * Add UnitAddress property to the specified node
3305  */
3306 static int
3307 add_unitaddr_prop(picl_nodehdl_t nodeh, unitaddr_map_t *uamap, uint_t addrcells)
3308 {
3309 	int			regproplen, err;
3310 	uint32_t		*regbuf;
3311 	picl_prophdl_t		regh;
3312 	ptree_propinfo_t	pinfo;
3313 	char			unitaddr[MAX_UNIT_ADDRESS_LEN];
3314 
3315 	err = ptree_get_prop_by_name(nodeh, OBP_REG, &regh);
3316 	if (err != PICL_SUCCESS)
3317 		return (err);
3318 
3319 	err = ptree_get_propinfo(regh, &pinfo);
3320 	if (err != PICL_SUCCESS)
3321 		return (PICL_FAILURE);
3322 
3323 	if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t)))
3324 		return (PICL_FAILURE);
3325 
3326 	regproplen = pinfo.piclinfo.size;
3327 	regbuf = alloca(regproplen);
3328 	if (regbuf == NULL)
3329 		return (PICL_FAILURE);
3330 
3331 	err = ptree_get_propval(regh, regbuf, regproplen);
3332 	if (err != PICL_SUCCESS || uamap->func == NULL ||
3333 	    (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) ||
3334 	    (uamap->func)(unitaddr, sizeof (unitaddr), regbuf,
3335 	    addrcells) != 0) {
3336 		return (PICL_FAILURE);
3337 	}
3338 
3339 	err = ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3340 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(unitaddr)+1,
3341 	    PICL_PROP_UNIT_ADDRESS, NULL, NULL);
3342 	if (err == PICL_SUCCESS)
3343 		err = ptree_create_and_add_prop(nodeh, &pinfo, unitaddr, NULL);
3344 
3345 	return (err);
3346 }
3347 
3348 /*
3349  * work out UnitAddress property of the specified node
3350  */
3351 static int
3352 get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh, char *unitaddr,
3353     size_t ualen)
3354 {
3355 	int			regproplen, err;
3356 	uint32_t		*regbuf;
3357 	picl_prophdl_t		regh;
3358 	ptree_propinfo_t	pinfo;
3359 	unitaddr_map_t		*uamap;
3360 	uint32_t		addrcells;
3361 
3362 	addrcells = get_addrcells_prop(parh);
3363 	uamap = get_unitaddr_mapping(parh);
3364 
3365 	err = ptree_get_prop_by_name(nodeh, OBP_REG, &regh);
3366 	if (err != PICL_SUCCESS)
3367 		return (err);
3368 
3369 	err = ptree_get_propinfo(regh, &pinfo);
3370 	if (err != PICL_SUCCESS)
3371 		return (err);
3372 
3373 	if (pinfo.piclinfo.size < (addrcells * sizeof (uint32_t)))
3374 		return (PICL_FAILURE);
3375 
3376 	regproplen = pinfo.piclinfo.size;
3377 	regbuf = alloca(regproplen);
3378 	if (regbuf == NULL)
3379 		return (PICL_FAILURE);
3380 
3381 	err = ptree_get_propval(regh, regbuf, regproplen);
3382 	if (err != PICL_SUCCESS || uamap->func == NULL ||
3383 	    (uamap->addrcellcnt && uamap->addrcellcnt != addrcells) ||
3384 	    (uamap->func)(unitaddr, ualen, regbuf, addrcells) != 0) {
3385 		return (PICL_FAILURE);
3386 	}
3387 	return (PICL_SUCCESS);
3388 }
3389 
3390 /*
3391  * Add UnitAddress property to all children of the specified node
3392  */
3393 static int
3394 add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh)
3395 {
3396 	int			err;
3397 	picl_nodehdl_t		chdh;
3398 	unitaddr_map_t		*uamap;
3399 	uint32_t		addrcells;
3400 
3401 	/*
3402 	 * Get #address-cells and unit address mapping entry for my
3403 	 * node's class
3404 	 */
3405 	addrcells = get_addrcells_prop(nodeh);
3406 	uamap = get_unitaddr_mapping(nodeh);
3407 
3408 	/*
3409 	 * Add UnitAddress property to my children and their subtree
3410 	 */
3411 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh,
3412 	    sizeof (picl_nodehdl_t));
3413 
3414 	while (err == PICL_SUCCESS) {
3415 		(void) add_unitaddr_prop(chdh, uamap, addrcells);
3416 		(void) add_unitaddr_prop_to_subtree(chdh);
3417 
3418 		err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh,
3419 		    sizeof (picl_nodehdl_t));
3420 	}
3421 
3422 	return (PICL_SUCCESS);
3423 }
3424 
3425 static int
3426 update_memory_size_prop(picl_nodehdl_t plafh)
3427 {
3428 	picl_nodehdl_t		memh;
3429 	picl_prophdl_t		proph;
3430 	ptree_propinfo_t	pinfo;
3431 	int			err, nspecs, snum, pval;
3432 	char			*regbuf;
3433 	memspecs_t		*mspecs;
3434 	uint64_t		memsize;
3435 
3436 	/*
3437 	 * check if the #size-cells of the platform node is 2
3438 	 */
3439 	err = ptree_get_propval_by_name(plafh, OBP_PROP_SIZE_CELLS, &pval,
3440 	    sizeof (pval));
3441 
3442 	if (err == PICL_PROPNOTFOUND)
3443 		pval = SUPPORTED_NUM_CELL_SIZE;
3444 	else if (err != PICL_SUCCESS)
3445 		return (err);
3446 
3447 	/*
3448 	 * don't know how to handle other vals
3449 	 */
3450 	if (pval != SUPPORTED_NUM_CELL_SIZE)
3451 		return (PICL_FAILURE);
3452 
3453 	err = ptree_get_node_by_path(MEMORY_PATH, &memh);
3454 	if (err != PICL_SUCCESS)
3455 		return (err);
3456 
3457 	/*
3458 	 * Get the REG property to calculate the size of memory
3459 	 */
3460 	err = ptree_get_prop_by_name(memh, OBP_REG, &proph);
3461 	if (err != PICL_SUCCESS)
3462 		return (err);
3463 
3464 	err = ptree_get_propinfo(proph, &pinfo);
3465 	if (err != PICL_SUCCESS)
3466 		return (err);
3467 
3468 	regbuf = alloca(pinfo.piclinfo.size);
3469 	if (regbuf == NULL)
3470 		return (PICL_FAILURE);
3471 
3472 	err = ptree_get_propval(proph, regbuf, pinfo.piclinfo.size);
3473 	if (err != PICL_SUCCESS)
3474 		return (err);
3475 
3476 	mspecs = (memspecs_t *)regbuf;
3477 	nspecs = pinfo.piclinfo.size / sizeof (memspecs_t);
3478 
3479 	memsize = 0;
3480 	for (snum = 0; snum < nspecs; ++snum)
3481 		memsize += mspecs[snum].size;
3482 
3483 	err = ptree_get_prop_by_name(memh, PICL_PROP_SIZE, &proph);
3484 	if (err == PICL_SUCCESS) {
3485 		err = ptree_update_propval(proph, &memsize, sizeof (memsize));
3486 		return (err);
3487 	}
3488 
3489 	/*
3490 	 * Add the size property
3491 	 */
3492 	(void) ptree_init_propinfo(&pinfo, PTREE_PROPINFO_VERSION,
3493 	    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (memsize),
3494 	    PICL_PROP_SIZE, NULL, NULL);
3495 	err = ptree_create_and_add_prop(memh, &pinfo, &memsize, NULL);
3496 	return (err);
3497 }
3498 
3499 /*
3500  * This function is executed as part of .init when the plugin is
3501  * dlopen()ed
3502  */
3503 static void
3504 picldevtree_register(void)
3505 {
3506 	if (getenv(SUNW_PICLDEVTREE_PLUGIN_DEBUG))
3507 		picldevtree_debug = 1;
3508 	(void) picld_plugin_register(&my_reg_info);
3509 }
3510 
3511 /*
3512  * This function is the init entry point of the plugin.
3513  * It initializes the /platform tree based on libdevinfo
3514  */
3515 static void
3516 picldevtree_init(void)
3517 {
3518 	picl_nodehdl_t	rhdl;
3519 	int		err;
3520 	struct utsname	utsname;
3521 	picl_nodehdl_t	plafh;
3522 
3523 	if (uname(&utsname) < 0)
3524 		return;
3525 
3526 	(void) strcpy(mach_name, utsname.machine);
3527 
3528 	if (strcmp(mach_name, "sun4u") == 0) {
3529 		builtin_map_ptr = sun4u_map;
3530 		builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
3531 	} else if (strcmp(mach_name, "sun4v") == 0) {
3532 		builtin_map_ptr = sun4u_map;
3533 		builtin_map_size = sizeof (sun4u_map) / sizeof (builtin_map_t);
3534 	} else if (strcmp(mach_name, "i86pc") == 0) {
3535 		builtin_map_ptr = i86pc_map;
3536 		builtin_map_size = sizeof (i86pc_map) / sizeof (builtin_map_t);
3537 	} else {
3538 		builtin_map_ptr = NULL;
3539 		builtin_map_size = 0;
3540 	}
3541 
3542 	err = ptree_get_root(&rhdl);
3543 	if (err != PICL_SUCCESS) {
3544 		syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED);
3545 		return;
3546 	}
3547 
3548 	process_devtree_conf_file();
3549 
3550 	if (libdevinfo_init(rhdl) != PICL_SUCCESS) {
3551 		syslog(LOG_ERR, DEVINFO_PLUGIN_INIT_FAILED);
3552 		return;
3553 	}
3554 
3555 	err = ptree_get_node_by_path(PLATFORM_PATH, &plafh);
3556 	if (err != PICL_SUCCESS)
3557 		return;
3558 
3559 	(void) add_unitaddr_prop_to_subtree(plafh);
3560 
3561 	add_asr_nodes();
3562 
3563 	(void) update_memory_size_prop(plafh);
3564 
3565 	(void) setup_cpus(plafh);
3566 
3567 	(void) add_ffb_config_info(plafh);
3568 
3569 	(void) add_platform_info(plafh);
3570 
3571 	set_pci_pciex_deviceid(plafh);
3572 
3573 	(void) set_sbus_slot(plafh);
3574 
3575 	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
3576 	    picldevtree_evhandler, NULL);
3577 	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
3578 	    picldevtree_evhandler, NULL);
3579 	(void) ptree_register_handler(PICLEVENT_CPU_STATE_CHANGE,
3580 	    picldevtree_evhandler, NULL);
3581 	(void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
3582 	    picldevtree_evhandler, NULL);
3583 }
3584 
3585 /*
3586  * This function is the fini entry point of the plugin
3587  */
3588 static void
3589 picldevtree_fini(void)
3590 {
3591 	/* First unregister the event handlers */
3592 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
3593 	    picldevtree_evhandler, NULL);
3594 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
3595 	    picldevtree_evhandler, NULL);
3596 	(void) ptree_unregister_handler(PICLEVENT_CPU_STATE_CHANGE,
3597 	    picldevtree_evhandler, NULL);
3598 	(void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
3599 	    picldevtree_evhandler, NULL);
3600 
3601 	conf_name_class_map = free_conf_entries(conf_name_class_map);
3602 }
3603 
3604 /*
3605  * This function is the event handler of this plug-in.
3606  *
3607  * It processes the following events:
3608  *
3609  *	PICLEVENT_SYSEVENT_DEVICE_ADDED
3610  *	PICLEVENT_SYSEVENT_DEVICE_REMOVED
3611  *	PICLEVENT_CPU_STATE_CHANGE
3612  *	PICLEVENT_DR_AP_STATE_CHANGE
3613  */
3614 /* ARGSUSED */
3615 static void
3616 picldevtree_evhandler(const char *ename, const void *earg, size_t size,
3617     void *cookie)
3618 {
3619 	char			*devfs_path;
3620 	char			ptreepath[PATH_MAX];
3621 	char			dipath[PATH_MAX];
3622 	picl_nodehdl_t		plafh;
3623 	picl_nodehdl_t		nodeh;
3624 	nvlist_t		*nvlp;
3625 
3626 	if ((earg == NULL) ||
3627 	    (ptree_get_node_by_path(PLATFORM_PATH, &plafh) != PICL_SUCCESS))
3628 		return;
3629 
3630 	if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) == 0) {
3631 		(void) setup_cpus(plafh);
3632 		if (picldevtree_debug > 1)
3633 			syslog(LOG_INFO, "picldevtree: event handler done\n");
3634 		return;
3635 	}
3636 
3637 	nvlp = NULL;
3638 	if (nvlist_unpack((char *)earg, size, &nvlp, 0) ||
3639 	    nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &devfs_path) ||
3640 	    strlen(devfs_path) > (PATH_MAX - sizeof (PLATFORM_PATH))) {
3641 		syslog(LOG_INFO, PICL_EVENT_DROPPED, ename);
3642 		nvlist_free(nvlp);
3643 		return;
3644 	}
3645 
3646 	(void) strlcpy(ptreepath, PLATFORM_PATH, PATH_MAX);
3647 	(void) strlcat(ptreepath, devfs_path, PATH_MAX);
3648 	(void) strlcpy(dipath, devfs_path, PATH_MAX);
3649 	nvlist_free(nvlp);
3650 
3651 	if (picldevtree_debug)
3652 		syslog(LOG_INFO, "picldevtree: event handler invoked ename:%s "
3653 		    "ptreepath:%s\n", ename, ptreepath);
3654 
3655 	if (strcmp(ename, PICLEVENT_CPU_STATE_CHANGE) == 0) {
3656 		goto done;
3657 	}
3658 	if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) {
3659 		di_node_t		devnode;
3660 		char		*strp;
3661 		picl_nodehdl_t	parh;
3662 		char		nodeclass[PICL_CLASSNAMELEN_MAX];
3663 		char		*nodename;
3664 		int		err;
3665 
3666 		/* If the node already exist, then nothing else to do here */
3667 		if (ptree_get_node_by_path(ptreepath, &nodeh) == PICL_SUCCESS)
3668 			return;
3669 
3670 		/* Skip if unable to find parent PICL node handle */
3671 		parh = plafh;
3672 		if (((strp = strrchr(ptreepath, '/')) != NULL) &&
3673 		    (strp != strchr(ptreepath, '/'))) {
3674 			*strp = '\0';
3675 			if (ptree_get_node_by_path(ptreepath, &parh) !=
3676 			    PICL_SUCCESS)
3677 				return;
3678 		}
3679 
3680 		/*
3681 		 * If parent is the root node
3682 		 */
3683 		if (parh == plafh) {
3684 			ph = di_prom_init();
3685 			devnode = di_init(dipath, DINFOCPYALL);
3686 			if (devnode == DI_NODE_NIL) {
3687 				if (ph != NULL) {
3688 					di_prom_fini(ph);
3689 					ph = NULL;
3690 				}
3691 				return;
3692 			}
3693 			nodename = di_node_name(devnode);
3694 			if (nodename == NULL) {
3695 				di_fini(devnode);
3696 				if (ph != NULL) {
3697 					di_prom_fini(ph);
3698 					ph = NULL;
3699 				}
3700 				return;
3701 			}
3702 
3703 			err = get_node_class(nodeclass, devnode, nodename);
3704 			if (err < 0) {
3705 				di_fini(devnode);
3706 				if (ph != NULL) {
3707 					di_prom_fini(ph);
3708 					ph = NULL;
3709 				}
3710 				return;
3711 			}
3712 			err = construct_devtype_node(plafh, nodename,
3713 			    nodeclass, devnode, &nodeh);
3714 			if (err != PICL_SUCCESS) {
3715 				di_fini(devnode);
3716 				if (ph != NULL) {
3717 					di_prom_fini(ph);
3718 					ph = NULL;
3719 				}
3720 				return;
3721 			}
3722 			(void) update_subtree(nodeh, devnode);
3723 			(void) add_unitaddr_prop_to_subtree(nodeh);
3724 			if (ph != NULL) {
3725 				di_prom_fini(ph);
3726 				ph = NULL;
3727 			}
3728 			di_fini(devnode);
3729 			goto done;
3730 		}
3731 
3732 		/* kludge ... try without bus-addr first */
3733 		if ((strp = strrchr(dipath, '@')) != NULL) {
3734 			char *p;
3735 
3736 			p = strrchr(dipath, '/');
3737 			if (p != NULL && strp > p) {
3738 				*strp = '\0';
3739 				devnode = di_init(dipath, DINFOCPYALL);
3740 				if (devnode != DI_NODE_NIL)
3741 					di_fini(devnode);
3742 				*strp = '@';
3743 			}
3744 		}
3745 		/* Get parent devnode */
3746 		if ((strp = strrchr(dipath, '/')) != NULL)
3747 			*++strp = '\0';
3748 		devnode = di_init(dipath, DINFOCPYALL);
3749 		if (devnode == DI_NODE_NIL)
3750 			return;
3751 		ph = di_prom_init();
3752 		(void) update_subtree(parh, devnode);
3753 		(void) add_unitaddr_prop_to_subtree(parh);
3754 		if (ph) {
3755 			di_prom_fini(ph);
3756 			ph = NULL;
3757 		}
3758 		di_fini(devnode);
3759 	} else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) {
3760 		char			delclass[PICL_CLASSNAMELEN_MAX];
3761 		char		*strp;
3762 
3763 		/*
3764 		 * if final element of path doesn't have a unit address
3765 		 * then it is not uniquely identifiable - cannot remove
3766 		 */
3767 		if (((strp = strrchr(ptreepath, '/')) != NULL) &&
3768 		    strchr(strp, '@') == NULL)
3769 			return;
3770 
3771 		/* skip if can't find the node */
3772 		if (ptree_get_node_by_path(ptreepath, &nodeh) != PICL_SUCCESS)
3773 			return;
3774 
3775 		if (ptree_delete_node(nodeh) != PICL_SUCCESS)
3776 			return;
3777 
3778 		if (picldevtree_debug)
3779 			syslog(LOG_INFO,
3780 			    "picldevtree: deleted node nodeh:%llx\n", nodeh);
3781 		if ((ptree_get_propval_by_name(nodeh,
3782 		    PICL_PROP_CLASSNAME, delclass, PICL_CLASSNAMELEN_MAX) ==
3783 		    PICL_SUCCESS) && IS_MC(delclass)) {
3784 			if (post_mc_event(PICLEVENT_MC_REMOVED, nodeh) !=
3785 			    PICL_SUCCESS)
3786 				syslog(LOG_WARNING, PICL_EVENT_DROPPED,
3787 				    PICLEVENT_MC_REMOVED);
3788 		} else
3789 			(void) ptree_destroy_node(nodeh);
3790 	}
3791 done:
3792 	(void) setup_cpus(plafh);
3793 	(void) add_ffb_config_info(plafh);
3794 	set_pci_pciex_deviceid(plafh);
3795 	(void) set_sbus_slot(plafh);
3796 	if (picldevtree_debug > 1)
3797 		syslog(LOG_INFO, "picldevtree: event handler done\n");
3798 }
3799