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