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