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