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