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