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