17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
561db5dcaSrd  * Common Development and Distribution License (the "License").
661db5dcaSrd  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2248556476SJustin Frank  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26720c4860SJohn Levon /*
27c3377ee9SJohn Levon  * Copyright 2019 Joyent, Inc.
28720c4860SJohn Levon  */
29720c4860SJohn Levon 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * PICL plug-in that creates device tree nodes for all platforms
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <ctype.h>
377c478bd9Sstevel@tonic-gate #include <limits.h>
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
397c478bd9Sstevel@tonic-gate #include <assert.h>
407c478bd9Sstevel@tonic-gate #include <unistd.h>
417c478bd9Sstevel@tonic-gate #include <stropts.h>
427c478bd9Sstevel@tonic-gate #include <syslog.h>
437c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
447c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
457c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
467c478bd9Sstevel@tonic-gate #include <sys/time.h>
477c478bd9Sstevel@tonic-gate #include <fcntl.h>
487c478bd9Sstevel@tonic-gate #include <picl.h>
497c478bd9Sstevel@tonic-gate #include <picltree.h>
507c478bd9Sstevel@tonic-gate #include <sys/types.h>
517c478bd9Sstevel@tonic-gate #include <sys/processor.h>
527c478bd9Sstevel@tonic-gate #include <kstat.h>
537c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h>
547c478bd9Sstevel@tonic-gate #include <dirent.h>
557c478bd9Sstevel@tonic-gate #include <libintl.h>
567c478bd9Sstevel@tonic-gate #include <pthread.h>
577c478bd9Sstevel@tonic-gate #include <libnvpair.h>
587c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
597c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
607c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h>
617c478bd9Sstevel@tonic-gate #include <sys/openpromio.h>
627c478bd9Sstevel@tonic-gate #include "picldevtree.h"
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * Plugin registration entry points
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate static void	picldevtree_register(void);
687c478bd9Sstevel@tonic-gate static void	picldevtree_init(void);
697c478bd9Sstevel@tonic-gate static void	picldevtree_fini(void);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static void	picldevtree_evhandler(const char *ename, const void *earg,
727c478bd9Sstevel@tonic-gate 		    size_t size, void *cookie);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #pragma	init(picldevtree_register)
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Log message texts
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate #define	DEVINFO_PLUGIN_INIT_FAILED	gettext("SUNW_picldevtree failed!\n")
807c478bd9Sstevel@tonic-gate #define	PICL_EVENT_DROPPED	\
817c478bd9Sstevel@tonic-gate 	gettext("SUNW_picldevtree '%s' event dropped.\n")
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Macro to get PCI device id (from IEEE 1275 spec)
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate #define	PCI_DEVICE_ID(x)			(((x) >> 11) & 0x1f)
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Local variables
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate static picld_plugin_reg_t  my_reg_info = {
917c478bd9Sstevel@tonic-gate 	PICLD_PLUGIN_VERSION_1,
927c478bd9Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
937c478bd9Sstevel@tonic-gate 	"SUNW_picldevtree",
947c478bd9Sstevel@tonic-gate 	picldevtree_init,
957c478bd9Sstevel@tonic-gate 	picldevtree_fini
967c478bd9Sstevel@tonic-gate };
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Debug enabling environment variable
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate #define	SUNW_PICLDEVTREE_PLUGIN_DEBUG	"SUNW_PICLDEVTREE_PLUGIN_DEBUG"
1027c478bd9Sstevel@tonic-gate static	int		picldevtree_debug = 0;
1037c478bd9Sstevel@tonic-gate 
104e9610e3eSToomas Soome static	conf_entries_t	*conf_name_class_map = NULL;
1057c478bd9Sstevel@tonic-gate static	builtin_map_t	sun4u_map[] = {
1067c478bd9Sstevel@tonic-gate 	/* MAX_NAMEVAL_SIZE */
1077c478bd9Sstevel@tonic-gate 	{ "SUNW,bpp", PICL_CLASS_PARALLEL},
1087c478bd9Sstevel@tonic-gate 	{ "parallel", PICL_CLASS_PARALLEL},
1097c478bd9Sstevel@tonic-gate 	{ "floppy", PICL_CLASS_FLOPPY},
1107c478bd9Sstevel@tonic-gate 	{ "memory", PICL_CLASS_MEMORY},
1117c478bd9Sstevel@tonic-gate 	{ "ebus", PICL_CLASS_EBUS},
1127c478bd9Sstevel@tonic-gate 	{ "i2c", PICL_CLASS_I2C},
1137c478bd9Sstevel@tonic-gate 	{ "usb", PICL_CLASS_USB},
1147c478bd9Sstevel@tonic-gate 	{ "isa", PICL_CLASS_ISA},
1157c478bd9Sstevel@tonic-gate 	{ "dma", PICL_CLASS_DMA},
1167c478bd9Sstevel@tonic-gate 	{ "keyboard", PICL_CLASS_KEYBOARD},
1177c478bd9Sstevel@tonic-gate 	{ "mouse", PICL_CLASS_MOUSE},
1187c478bd9Sstevel@tonic-gate 	{ "fan-control", PICL_CLASS_FAN_CONTROL},
1197c478bd9Sstevel@tonic-gate 	{ "sc", PICL_CLASS_SYSTEM_CONTROLLER},
1207c478bd9Sstevel@tonic-gate 	{ "dimm", PICL_CLASS_SEEPROM},
1217c478bd9Sstevel@tonic-gate 	{ "dimm-fru", PICL_CLASS_SEEPROM},
1227c478bd9Sstevel@tonic-gate 	{ "cpu", PICL_CLASS_SEEPROM},
1237c478bd9Sstevel@tonic-gate 	{ "cpu-fru", PICL_CLASS_SEEPROM},
1247c478bd9Sstevel@tonic-gate 	{ "flashprom", PICL_CLASS_FLASHPROM},
1257c478bd9Sstevel@tonic-gate 	{ "temperature", PICL_CLASS_TEMPERATURE_DEVICE},
1267c478bd9Sstevel@tonic-gate 	{ "motherboard", PICL_CLASS_SEEPROM},
1277c478bd9Sstevel@tonic-gate 	{ "motherboard-fru", PICL_CLASS_SEEPROM},
1287c478bd9Sstevel@tonic-gate 	{ "motherboard-fru-prom", PICL_CLASS_SEEPROM},
1297c478bd9Sstevel@tonic-gate 	{ "pmu", PICL_CLASS_PMU},
1307c478bd9Sstevel@tonic-gate 	{ "sound", PICL_CLASS_SOUND},
1317c478bd9Sstevel@tonic-gate 	{ "firewire", PICL_CLASS_FIREWIRE},
1327c478bd9Sstevel@tonic-gate 	{ "i2c-at34c02", PICL_CLASS_SEEPROM},
1337c478bd9Sstevel@tonic-gate 	{ "hardware-monitor", PICL_CLASS_HARDWARE_MONITOR},
1347c478bd9Sstevel@tonic-gate 	{ "", ""}
1357c478bd9Sstevel@tonic-gate };
1367c478bd9Sstevel@tonic-gate static	builtin_map_t	i86pc_map[] = {
1377c478bd9Sstevel@tonic-gate 	/* MAX_NAMEVAL_SIZE */
1387c478bd9Sstevel@tonic-gate 	{ "cpus", PICL_CLASS_I86CPUS},
1397c478bd9Sstevel@tonic-gate 	{ "cpu", PICL_CLASS_CPU},
1407c478bd9Sstevel@tonic-gate 	{ "memory", PICL_CLASS_MEMORY},
1417c478bd9Sstevel@tonic-gate 	{ "asy", PICL_CLASS_SERIAL},
1427c478bd9Sstevel@tonic-gate 	{ "", ""}
1437c478bd9Sstevel@tonic-gate };
1447c478bd9Sstevel@tonic-gate static	pname_type_map_t	pname_type_map[] = {
1457c478bd9Sstevel@tonic-gate 	{ "reg", PICL_PTYPE_BYTEARRAY},
1467c478bd9Sstevel@tonic-gate 	{ "device_type", PICL_PTYPE_CHARSTRING},
1477c478bd9Sstevel@tonic-gate 	{ "ranges", PICL_PTYPE_BYTEARRAY},
1487c478bd9Sstevel@tonic-gate 	{ "status", PICL_PTYPE_CHARSTRING},
1497c478bd9Sstevel@tonic-gate 	{ "compatible", PICL_PTYPE_CHARSTRING},
1507c478bd9Sstevel@tonic-gate 	{ "interrupts", PICL_PTYPE_BYTEARRAY},
1517c478bd9Sstevel@tonic-gate 	{ "model", PICL_PTYPE_CHARSTRING},
1527c478bd9Sstevel@tonic-gate 	{ "address", PICL_PTYPE_BYTEARRAY},
1537c478bd9Sstevel@tonic-gate 	{ "vendor-id", PICL_PTYPE_UNSIGNED_INT},
1547c478bd9Sstevel@tonic-gate 	{ "device-id", PICL_PTYPE_UNSIGNED_INT},
1557c478bd9Sstevel@tonic-gate 	{ "revision-id", PICL_PTYPE_UNSIGNED_INT},
1567c478bd9Sstevel@tonic-gate 	{ "class-code", PICL_PTYPE_UNSIGNED_INT},
1577c478bd9Sstevel@tonic-gate 	{ "min-grant", PICL_PTYPE_UNSIGNED_INT},
1587c478bd9Sstevel@tonic-gate 	{ "max-latency", PICL_PTYPE_UNSIGNED_INT},
1597c478bd9Sstevel@tonic-gate 	{ "devsel-speed", PICL_PTYPE_UNSIGNED_INT},
1607c478bd9Sstevel@tonic-gate 	{ "subsystem-id", PICL_PTYPE_UNSIGNED_INT},
1617c478bd9Sstevel@tonic-gate 	{ "subsystem-vendor-id", PICL_PTYPE_UNSIGNED_INT},
1627c478bd9Sstevel@tonic-gate 	{ "assigned-addresses", PICL_PTYPE_BYTEARRAY},
1637c478bd9Sstevel@tonic-gate 	{ "configuration#", PICL_PTYPE_UNSIGNED_INT},
1647c478bd9Sstevel@tonic-gate 	{ "assigned-address", PICL_PTYPE_UNSIGNED_INT},
1657c478bd9Sstevel@tonic-gate 	{ "#address-cells", PICL_PTYPE_UNSIGNED_INT},
1667c478bd9Sstevel@tonic-gate 	{ "#size-cells", PICL_PTYPE_UNSIGNED_INT},
1677c478bd9Sstevel@tonic-gate 	{ "clock-frequency", PICL_PTYPE_UNSIGNED_INT},
1687c478bd9Sstevel@tonic-gate 	{ "scsi-initiator-id", PICL_PTYPE_UNSIGNED_INT},
1697c478bd9Sstevel@tonic-gate 	{ "differential", PICL_PTYPE_UNSIGNED_INT},
1707c478bd9Sstevel@tonic-gate 	{ "idprom", PICL_PTYPE_BYTEARRAY},
1717c478bd9Sstevel@tonic-gate 	{ "bus-range", PICL_PTYPE_BYTEARRAY},
1727c478bd9Sstevel@tonic-gate 	{ "alternate-reg", PICL_PTYPE_BYTEARRAY},
1737c478bd9Sstevel@tonic-gate 	{ "power-consumption", PICL_PTYPE_BYTEARRAY},
1747c478bd9Sstevel@tonic-gate 	{ "slot-names", PICL_PTYPE_BYTEARRAY},
1757c478bd9Sstevel@tonic-gate 	{ "burst-sizes", PICL_PTYPE_UNSIGNED_INT},
1767c478bd9Sstevel@tonic-gate 	{ "up-burst-sizes", PICL_PTYPE_UNSIGNED_INT},
1777c478bd9Sstevel@tonic-gate 	{ "slot-address-bits", PICL_PTYPE_UNSIGNED_INT},
1787c478bd9Sstevel@tonic-gate 	{ "eisa-slots", PICL_PTYPE_BYTEARRAY},
1797c478bd9Sstevel@tonic-gate 	{ "dma", PICL_PTYPE_BYTEARRAY},
1807c478bd9Sstevel@tonic-gate 	{ "slot-names-index", PICL_PTYPE_UNSIGNED_INT},
1817c478bd9Sstevel@tonic-gate 	{ "pnp-csn", PICL_PTYPE_UNSIGNED_INT},
1827c478bd9Sstevel@tonic-gate 	{ "pnp-data", PICL_PTYPE_BYTEARRAY},
1837c478bd9Sstevel@tonic-gate 	{ "description", PICL_PTYPE_CHARSTRING},
1847c478bd9Sstevel@tonic-gate 	{ "pnp-id", PICL_PTYPE_CHARSTRING},
1857c478bd9Sstevel@tonic-gate 	{ "max-frame-size", PICL_PTYPE_UNSIGNED_INT},
1867c478bd9Sstevel@tonic-gate 	{ "address-bits", PICL_PTYPE_UNSIGNED_INT},
1877c478bd9Sstevel@tonic-gate 	{ "local-mac-address", PICL_PTYPE_BYTEARRAY},
1887c478bd9Sstevel@tonic-gate 	{ "mac-address", PICL_PTYPE_BYTEARRAY},
1897c478bd9Sstevel@tonic-gate 	{ "character-set", PICL_PTYPE_CHARSTRING},
1907c478bd9Sstevel@tonic-gate 	{ "available", PICL_PTYPE_BYTEARRAY},
1917c478bd9Sstevel@tonic-gate 	{ "port-wwn", PICL_PTYPE_BYTEARRAY},
1927c478bd9Sstevel@tonic-gate 	{ "node-wwn", PICL_PTYPE_BYTEARRAY},
1937c478bd9Sstevel@tonic-gate 	{ "width", PICL_PTYPE_UNSIGNED_INT},
1947c478bd9Sstevel@tonic-gate 	{ "linebytes", PICL_PTYPE_UNSIGNED_INT},
1957c478bd9Sstevel@tonic-gate 	{ "height", PICL_PTYPE_UNSIGNED_INT},
1967c478bd9Sstevel@tonic-gate 	{ "banner-name", PICL_PTYPE_CHARSTRING},
1977c478bd9Sstevel@tonic-gate 	{ "reset-reason", PICL_PTYPE_CHARSTRING},
1987c478bd9Sstevel@tonic-gate 	{ "implementation#", PICL_PTYPE_UNSIGNED_INT},
1997c478bd9Sstevel@tonic-gate 	{ "version#", PICL_PTYPE_UNSIGNED_INT},
2007c478bd9Sstevel@tonic-gate 	{ "icache-size", PICL_PTYPE_UNSIGNED_INT},
2017c478bd9Sstevel@tonic-gate 	{ "icache-line-size", PICL_PTYPE_UNSIGNED_INT},
2027c478bd9Sstevel@tonic-gate 	{ "icache-associativity", PICL_PTYPE_UNSIGNED_INT},
2037c478bd9Sstevel@tonic-gate 	{ "l1-icache-size", PICL_PTYPE_UNSIGNED_INT},
2047c478bd9Sstevel@tonic-gate 	{ "l1-icache-line-size", PICL_PTYPE_UNSIGNED_INT},
2057c478bd9Sstevel@tonic-gate 	{ "l1-icache-associativity", PICL_PTYPE_UNSIGNED_INT},
2067c478bd9Sstevel@tonic-gate 	{ "#itlb-entries", PICL_PTYPE_UNSIGNED_INT},
2077c478bd9Sstevel@tonic-gate 	{ "dcache-size", PICL_PTYPE_UNSIGNED_INT},
2087c478bd9Sstevel@tonic-gate 	{ "dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
2097c478bd9Sstevel@tonic-gate 	{ "dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
2107c478bd9Sstevel@tonic-gate 	{ "l1-dcache-size", PICL_PTYPE_UNSIGNED_INT},
2117c478bd9Sstevel@tonic-gate 	{ "l1-dcache-line-size", PICL_PTYPE_UNSIGNED_INT},
2127c478bd9Sstevel@tonic-gate 	{ "l1-dcache-associativity", PICL_PTYPE_UNSIGNED_INT},
2137c478bd9Sstevel@tonic-gate 	{ "#dtlb-entries", PICL_PTYPE_UNSIGNED_INT},
2147c478bd9Sstevel@tonic-gate 	{ "ecache-size", PICL_PTYPE_UNSIGNED_INT},
2157c478bd9Sstevel@tonic-gate 	{ "ecache-line-size", PICL_PTYPE_UNSIGNED_INT},
2167c478bd9Sstevel@tonic-gate 	{ "ecache-associativity", PICL_PTYPE_UNSIGNED_INT},
2177c478bd9Sstevel@tonic-gate 	{ "l2-cache-size", PICL_PTYPE_UNSIGNED_INT},
2187c478bd9Sstevel@tonic-gate 	{ "l2-cache-line-size", PICL_PTYPE_UNSIGNED_INT},
2197c478bd9Sstevel@tonic-gate 	{ "l2-cache-associativity", PICL_PTYPE_UNSIGNED_INT},
2207c478bd9Sstevel@tonic-gate 	{ "l2-cache-sharing", PICL_PTYPE_BYTEARRAY},
2217c478bd9Sstevel@tonic-gate 	{ "mask#", PICL_PTYPE_UNSIGNED_INT},
2227c478bd9Sstevel@tonic-gate 	{ "manufacturer#", PICL_PTYPE_UNSIGNED_INT},
2237c478bd9Sstevel@tonic-gate 	{ "sparc-version", PICL_PTYPE_UNSIGNED_INT},
2247c478bd9Sstevel@tonic-gate 	{ "version", PICL_PTYPE_CHARSTRING},
2257c478bd9Sstevel@tonic-gate 	{ "cpu-model", PICL_PTYPE_UNSIGNED_INT},
2267c478bd9Sstevel@tonic-gate 	{ "memory-layout", PICL_PTYPE_BYTEARRAY},
2277c478bd9Sstevel@tonic-gate 	{ "#interrupt-cells", PICL_PTYPE_UNSIGNED_INT},
2287c478bd9Sstevel@tonic-gate 	{ "interrupt-map", PICL_PTYPE_BYTEARRAY},
2297c478bd9Sstevel@tonic-gate 	{ "interrupt-map-mask", PICL_PTYPE_BYTEARRAY}
2307c478bd9Sstevel@tonic-gate };
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate #define	PNAME_MAP_SIZE	sizeof (pname_type_map) / sizeof (pname_type_map_t)
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static	builtin_map_t	*builtin_map_ptr = NULL;
2357c478bd9Sstevel@tonic-gate static	int		builtin_map_size = 0;
2367c478bd9Sstevel@tonic-gate static	char		mach_name[SYS_NMLN];
2377c478bd9Sstevel@tonic-gate static	di_prom_handle_t	ph = DI_PROM_HANDLE_NIL;
238bdee4892SMichael Bergknoff static	int		snapshot_stale;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate  * UnitAddress mapping table
2427c478bd9Sstevel@tonic-gate  */
2437c478bd9Sstevel@tonic-gate static	unitaddr_func_t	encode_default_unitaddr;
2447c478bd9Sstevel@tonic-gate static	unitaddr_func_t	encode_optional_unitaddr;
2457c478bd9Sstevel@tonic-gate static	unitaddr_func_t	encode_scsi_unitaddr;
2467c478bd9Sstevel@tonic-gate static	unitaddr_func_t	encode_upa_unitaddr;
2477c478bd9Sstevel@tonic-gate static	unitaddr_func_t	encode_gptwo_jbus_unitaddr;
2487c478bd9Sstevel@tonic-gate static	unitaddr_func_t	encode_pci_unitaddr;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate static	unitaddr_map_t unitaddr_map_table[] = {
2517c478bd9Sstevel@tonic-gate 	{PICL_CLASS_JBUS, encode_gptwo_jbus_unitaddr, 0},
2527c478bd9Sstevel@tonic-gate 	{PICL_CLASS_GPTWO, encode_gptwo_jbus_unitaddr, 0},
2537c478bd9Sstevel@tonic-gate 	{PICL_CLASS_PCI, encode_pci_unitaddr, 0},
2547ef4fcfbSvenki 	{PICL_CLASS_PCIEX, encode_pci_unitaddr, 0},
2557c478bd9Sstevel@tonic-gate 	{PICL_CLASS_UPA, encode_upa_unitaddr, 0},
2567c478bd9Sstevel@tonic-gate 	{PICL_CLASS_SCSI, encode_scsi_unitaddr, 0},
2577c478bd9Sstevel@tonic-gate 	{PICL_CLASS_SCSI2, encode_scsi_unitaddr, 0},
2587c478bd9Sstevel@tonic-gate 	{PICL_CLASS_EBUS, encode_default_unitaddr, 2},
2597c478bd9Sstevel@tonic-gate 	{PICL_CLASS_SBUS, encode_default_unitaddr, 2},
2607c478bd9Sstevel@tonic-gate 	{PICL_CLASS_I2C, encode_default_unitaddr, 2},
2617c478bd9Sstevel@tonic-gate 	{PICL_CLASS_USB, encode_default_unitaddr, 1},
2627c478bd9Sstevel@tonic-gate 	{PICL_CLASS_PMU, encode_optional_unitaddr, 2},
2637c478bd9Sstevel@tonic-gate 	{NULL, encode_default_unitaddr, 0}
2647c478bd9Sstevel@tonic-gate };
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate static int add_unitaddr_prop_to_subtree(picl_nodehdl_t nodeh);
2677c478bd9Sstevel@tonic-gate static int get_unitaddr(picl_nodehdl_t parh, picl_nodehdl_t nodeh,
2687c478bd9Sstevel@tonic-gate 	char *unitaddr, size_t ualen);
2697ef4fcfbSvenki static void set_pci_pciex_deviceid(picl_nodehdl_t plafh);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * The mc event completion handler.
2737c478bd9Sstevel@tonic-gate  * The arguments are event name buffer and a packed nvlist buffer
2747c478bd9Sstevel@tonic-gate  * with the size specifying the size of unpacked nvlist. These
2757c478bd9Sstevel@tonic-gate  * buffers are deallcoated here.
2767c478bd9Sstevel@tonic-gate  *
2777c478bd9Sstevel@tonic-gate  * Also, if a memory controller node is being removed then destroy the
2787c478bd9Sstevel@tonic-gate  * PICL subtree associated with that memory controller.
2797c478bd9Sstevel@tonic-gate  */
2807c478bd9Sstevel@tonic-gate static void
mc_completion_handler(char * ename,void * earg,size_t size)2817c478bd9Sstevel@tonic-gate mc_completion_handler(char *ename, void *earg, size_t size)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate 	picl_nodehdl_t	mch;
2847c478bd9Sstevel@tonic-gate 	nvlist_t	*unpack_nvl;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0 &&
287e9610e3eSToomas Soome 	    nvlist_unpack(earg, size, &unpack_nvl, 0) == 0) {
288e9610e3eSToomas Soome 		mch = 0;
2897c478bd9Sstevel@tonic-gate 		(void) nvlist_lookup_uint64(unpack_nvl,
2907c478bd9Sstevel@tonic-gate 		    PICLEVENTARG_NODEHANDLE, &mch);
291e9610e3eSToomas Soome 		if (mch != 0) {
2927c478bd9Sstevel@tonic-gate 			if (picldevtree_debug)
2937c478bd9Sstevel@tonic-gate 				syslog(LOG_INFO,
2947c478bd9Sstevel@tonic-gate 				    "picldevtree: destroying_node:%llx\n",
2957c478bd9Sstevel@tonic-gate 				    mch);
2967c478bd9Sstevel@tonic-gate 			(void) ptree_destroy_node(mch);
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 		nvlist_free(unpack_nvl);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	free(ename);
3027c478bd9Sstevel@tonic-gate 	free(earg);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate  * Functions to post memory controller change event
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate static int
post_mc_event(char * ename,picl_nodehdl_t mch)3097c478bd9Sstevel@tonic-gate post_mc_event(char *ename, picl_nodehdl_t mch)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	nvlist_t	*nvl;
3127c478bd9Sstevel@tonic-gate 	size_t		nvl_size;
3137c478bd9Sstevel@tonic-gate 	char		*pack_buf;
3147c478bd9Sstevel@tonic-gate 	char		*ev_name;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	ev_name = strdup(ename);
3177c478bd9Sstevel@tonic-gate 	if (ev_name == NULL)
3187c478bd9Sstevel@tonic-gate 		return (-1);
3197c478bd9Sstevel@tonic-gate 
320e9610e3eSToomas Soome 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) {
3217c478bd9Sstevel@tonic-gate 		free(ev_name);
3227c478bd9Sstevel@tonic-gate 		return (-1);
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	pack_buf = NULL;
3267c478bd9Sstevel@tonic-gate 	if (nvlist_add_uint64(nvl, PICLEVENTARG_NODEHANDLE, mch) ||
327e9610e3eSToomas Soome 	    nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE, 0)) {
3287c478bd9Sstevel@tonic-gate 		free(ev_name);
3297c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
3307c478bd9Sstevel@tonic-gate 		return (-1);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (picldevtree_debug)
3347c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO,
3357c478bd9Sstevel@tonic-gate 		    "picldevtree: posting MC event ename:%s nodeh:%llx\n",
3367c478bd9Sstevel@tonic-gate 		    ev_name, mch);
3377c478bd9Sstevel@tonic-gate 	if (ptree_post_event(ev_name, pack_buf, nvl_size,
3387c478bd9Sstevel@tonic-gate 	    mc_completion_handler) != PICL_SUCCESS) {
3397c478bd9Sstevel@tonic-gate 		free(ev_name);
3407c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
3417c478bd9Sstevel@tonic-gate 		return (-1);
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
3447c478bd9Sstevel@tonic-gate 	return (0);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate  * Lookup a name in the name to class map tables
3497c478bd9Sstevel@tonic-gate  */
3507c478bd9Sstevel@tonic-gate static int
lookup_name_class_map(char * classbuf,const char * nm)3517c478bd9Sstevel@tonic-gate lookup_name_class_map(char *classbuf, const char *nm)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	conf_entries_t	*ptr;
3547c478bd9Sstevel@tonic-gate 	int		i;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	/*
3577c478bd9Sstevel@tonic-gate 	 * check name to class mapping in conf file
3587c478bd9Sstevel@tonic-gate 	 */
3597c478bd9Sstevel@tonic-gate 	ptr = conf_name_class_map;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	while (ptr != NULL) {
3627c478bd9Sstevel@tonic-gate 		if (strcmp(ptr->name, nm) == 0) {
3637c478bd9Sstevel@tonic-gate 			(void) strlcpy(classbuf, ptr->piclclass,
3647c478bd9Sstevel@tonic-gate 			    PICL_CLASSNAMELEN_MAX);
3657c478bd9Sstevel@tonic-gate 			return (0);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 		ptr = ptr->next;
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	/*
3717c478bd9Sstevel@tonic-gate 	 * check name to class mapping in builtin table
3727c478bd9Sstevel@tonic-gate 	 */
3737c478bd9Sstevel@tonic-gate 	if (builtin_map_ptr == NULL)
3747c478bd9Sstevel@tonic-gate 		return (-1);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	for (i = 0; i < builtin_map_size; ++i)
3777c478bd9Sstevel@tonic-gate 		if (strcmp(builtin_map_ptr[i].name, nm) == 0) {
3787c478bd9Sstevel@tonic-gate 			(void) strlcpy(classbuf, builtin_map_ptr[i].piclclass,
3797c478bd9Sstevel@tonic-gate 			    PICL_CLASSNAMELEN_MAX);
3807c478bd9Sstevel@tonic-gate 			return (0);
3817c478bd9Sstevel@tonic-gate 		}
3827c478bd9Sstevel@tonic-gate 	return (-1);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * Lookup a prop name in the pname to class map table
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate static int
lookup_pname_type_map(const char * pname,picl_prop_type_t * type)3897c478bd9Sstevel@tonic-gate lookup_pname_type_map(const char *pname, picl_prop_type_t *type)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	int		i;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	for (i = 0; i < PNAME_MAP_SIZE; ++i)
3947c478bd9Sstevel@tonic-gate 		if (strcmp(pname_type_map[i].pname, pname) == 0) {
3957c478bd9Sstevel@tonic-gate 			*type = pname_type_map[i].type;
3967c478bd9Sstevel@tonic-gate 			return (0);
3977c478bd9Sstevel@tonic-gate 		}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	return (-1);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate  * Return the number of strings in the buffer
4047c478bd9Sstevel@tonic-gate  */
4057c478bd9Sstevel@tonic-gate static int
get_string_count(char * strdat,int length)4067c478bd9Sstevel@tonic-gate get_string_count(char *strdat, int length)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate 	int	count;
4097c478bd9Sstevel@tonic-gate 	char	*lastnull;
4107c478bd9Sstevel@tonic-gate 	char	*nullptr;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	count = 1;
4137c478bd9Sstevel@tonic-gate 	for (lastnull = &strdat[length - 1], nullptr = strchr(strdat, '\0');
4147c478bd9Sstevel@tonic-gate 	    nullptr != lastnull; nullptr = strchr(nullptr+1, '\0'))
4157c478bd9Sstevel@tonic-gate 		count++;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	return (count);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * Return 1 if the node has a "reg" property
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate static int
has_reg_prop(di_node_t dn)4247c478bd9Sstevel@tonic-gate has_reg_prop(di_node_t dn)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	int			*pdata;
4277c478bd9Sstevel@tonic-gate 	int			dret;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	dret = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, OBP_REG, &pdata);
4307c478bd9Sstevel@tonic-gate 	if (dret > 0)
4317c478bd9Sstevel@tonic-gate 		return (1);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if (!ph)
4347c478bd9Sstevel@tonic-gate 		return (0);
4357c478bd9Sstevel@tonic-gate 	dret = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata);
4367c478bd9Sstevel@tonic-gate 	return (dret < 0 ? 0 : 1);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate /*
4407c478bd9Sstevel@tonic-gate  * This function copies a PROM node's device_type property value into the
4417c478bd9Sstevel@tonic-gate  * buffer given by outbuf. The buffer size is PICL_CLASSNAMELEN_MAX.
4427c478bd9Sstevel@tonic-gate  *
4437c478bd9Sstevel@tonic-gate  * We reclassify device_type 'fru-prom' to PICL class 'seeprom'
4447c478bd9Sstevel@tonic-gate  * for FRUID support.
4457c478bd9Sstevel@tonic-gate  */
4467c478bd9Sstevel@tonic-gate static int
get_device_type(char * outbuf,di_node_t dn)4477c478bd9Sstevel@tonic-gate get_device_type(char *outbuf, di_node_t dn)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate 	char			*pdata;
4507c478bd9Sstevel@tonic-gate 	char			*pdatap;
4517c478bd9Sstevel@tonic-gate 	int			dret;
4527c478bd9Sstevel@tonic-gate 	int			i;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_DEVICETYPE,
4557c478bd9Sstevel@tonic-gate 	    &pdata);
4567c478bd9Sstevel@tonic-gate 	if (dret <= 0) {
4577c478bd9Sstevel@tonic-gate 		if (!ph)
4587c478bd9Sstevel@tonic-gate 			return (-1);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		dret = di_prom_prop_lookup_strings(ph, dn, OBP_DEVICETYPE,
4617c478bd9Sstevel@tonic-gate 		    &pdata);
4627c478bd9Sstevel@tonic-gate 		if (dret <= 0) {
4637c478bd9Sstevel@tonic-gate 			return (-1);
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	if (dret != 1) {
4687c478bd9Sstevel@tonic-gate 		/*
4697c478bd9Sstevel@tonic-gate 		 * multiple strings
4707c478bd9Sstevel@tonic-gate 		 */
4717c478bd9Sstevel@tonic-gate 		pdatap = pdata;
4727c478bd9Sstevel@tonic-gate 		for (i = 0; i < (dret - 1); ++i) {
4737c478bd9Sstevel@tonic-gate 			pdatap += strlen(pdatap);
4747c478bd9Sstevel@tonic-gate 			*pdatap = '-';	/* replace '\0' with '-' */
4757c478bd9Sstevel@tonic-gate 			pdatap++;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	if (strcasecmp(pdata, "fru-prom") == 0) {
4797c478bd9Sstevel@tonic-gate 		/*
4807c478bd9Sstevel@tonic-gate 		 * Use PICL 'seeprom' class for fru-prom device types
4817c478bd9Sstevel@tonic-gate 		 */
4827c478bd9Sstevel@tonic-gate 		(void) strlcpy(outbuf, PICL_CLASS_SEEPROM,
4837c478bd9Sstevel@tonic-gate 		    PICL_CLASSNAMELEN_MAX);
4847c478bd9Sstevel@tonic-gate 	} else {
4857c478bd9Sstevel@tonic-gate 		(void) strlcpy(outbuf, pdata, PICL_CLASSNAMELEN_MAX);
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 	return (0);
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate /*
4917c478bd9Sstevel@tonic-gate  * Get the minor node name in the class buffer passed
4927c478bd9Sstevel@tonic-gate  */
4937c478bd9Sstevel@tonic-gate static int
get_minor_class(char * classbuf,di_node_t dn)4947c478bd9Sstevel@tonic-gate get_minor_class(char *classbuf, di_node_t dn)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate 	di_minor_t	mi_node;
4977c478bd9Sstevel@tonic-gate 	char		*mi_nodetype;
4987c478bd9Sstevel@tonic-gate 	char		*mi_name;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/* get minor node type */
5017c478bd9Sstevel@tonic-gate 	mi_node = di_minor_next(dn, DI_MINOR_NIL);
5027c478bd9Sstevel@tonic-gate 	if (mi_node == DI_MINOR_NIL)
5037c478bd9Sstevel@tonic-gate 		return (-1);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	mi_nodetype = di_minor_nodetype(mi_node);
5067c478bd9Sstevel@tonic-gate 	if (mi_nodetype == NULL) { /* no type info, return name */
5077c478bd9Sstevel@tonic-gate 		mi_name = di_minor_name(mi_node);
5087c478bd9Sstevel@tonic-gate 		if (mi_name == NULL)
5097c478bd9Sstevel@tonic-gate 			return (-1);
5107c478bd9Sstevel@tonic-gate 		(void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX);
5117c478bd9Sstevel@tonic-gate 		return (0);
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate #define	DDI_NODETYPE(x, y) (strncmp(x, y, (sizeof (y) - 1)) == 0)
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	/*
5177c478bd9Sstevel@tonic-gate 	 * convert the string to the picl class for non-peudo nodes
5187c478bd9Sstevel@tonic-gate 	 */
5197c478bd9Sstevel@tonic-gate 	if (DDI_NODETYPE(mi_nodetype, DDI_PSEUDO))
5207c478bd9Sstevel@tonic-gate 		return (-1);
5217c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_WWN))
5227c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_BLOCK);
5237c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_CHAN))
5247c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_BLOCK);
5257c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD))
5267c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_CDROM);
5277c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_CD_CHAN))
5287c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_CDROM);
5297c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_FD))
5307c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_FLOPPY);
5317c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_FABRIC))
5327c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_FABRIC);
533d88e498aSjiang wu - Sun Microsystems - Beijing China 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK_SAS))
534d88e498aSjiang wu - Sun Microsystems - Beijing China 		(void) strcpy(classbuf, PICL_CLASS_SAS);
5357c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_BLOCK))
5367c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_BLOCK);
5377c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_MOUSE))
5387c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_MOUSE);
5397c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_KEYBOARD))
5407c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_KEYBOARD);
5417c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ATTACHMENT_POINT))
5427c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_ATTACHMENT_POINT);
5437c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_TAPE))
5447c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_TAPE);
5457c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_SCSI_ENCLOSURE))
5467c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_SCSI);
5477c478bd9Sstevel@tonic-gate 	else if (DDI_NODETYPE(mi_nodetype, DDI_NT_ENCLOSURE)) {
5487c478bd9Sstevel@tonic-gate 		char	*colon;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		if ((colon = strchr(mi_nodetype, ':')) == NULL)
5517c478bd9Sstevel@tonic-gate 			return (-1);
5527c478bd9Sstevel@tonic-gate 		++colon;
5537c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, colon);
5547c478bd9Sstevel@tonic-gate 	} else {	/* unrecognized type, return name */
5557c478bd9Sstevel@tonic-gate 		mi_name = di_minor_name(mi_node);
5567c478bd9Sstevel@tonic-gate 		if (mi_name == NULL)
5577c478bd9Sstevel@tonic-gate 			return (-1);
5587c478bd9Sstevel@tonic-gate 		(void) strlcpy(classbuf, mi_name, PICL_CLASSNAMELEN_MAX);
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 	return (0);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate /*
5647c478bd9Sstevel@tonic-gate  * Derive PICL class using the compatible property of the node
5657c478bd9Sstevel@tonic-gate  * We use the map table to map compatible property value to
5667c478bd9Sstevel@tonic-gate  * class.
5677c478bd9Sstevel@tonic-gate  */
5687c478bd9Sstevel@tonic-gate static int
get_compatible_class(char * outbuf,di_node_t dn)5697c478bd9Sstevel@tonic-gate get_compatible_class(char *outbuf, di_node_t dn)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	char			*pdata;
5727c478bd9Sstevel@tonic-gate 	char			*pdatap;
5737c478bd9Sstevel@tonic-gate 	int			dret;
5747c478bd9Sstevel@tonic-gate 	int			i;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	dret = di_prop_lookup_strings(DDI_DEV_T_ANY, dn, OBP_COMPATIBLE,
5777c478bd9Sstevel@tonic-gate 	    &pdata);
5787c478bd9Sstevel@tonic-gate 	if (dret <= 0) {
5797c478bd9Sstevel@tonic-gate 		if (!ph)
5807c478bd9Sstevel@tonic-gate 			return (-1);
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		dret = di_prom_prop_lookup_strings(ph, dn, OBP_COMPATIBLE,
5837c478bd9Sstevel@tonic-gate 		    &pdata);
5847c478bd9Sstevel@tonic-gate 		if (dret <= 0) {
5857c478bd9Sstevel@tonic-gate 			return (-1);
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	pdatap = pdata;
5907c478bd9Sstevel@tonic-gate 	for (i = 0; i < dret; ++i) {
5917c478bd9Sstevel@tonic-gate 		if (lookup_name_class_map(outbuf, pdatap) == 0)
5927c478bd9Sstevel@tonic-gate 			return (0);
5937c478bd9Sstevel@tonic-gate 		pdatap += strlen(pdatap);
5947c478bd9Sstevel@tonic-gate 		pdatap++;
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 	return (-1);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate /*
6007c478bd9Sstevel@tonic-gate  * For a given device node find the PICL class to use. Returns NULL
6017c478bd9Sstevel@tonic-gate  * for non device node
6027c478bd9Sstevel@tonic-gate  */
6037c478bd9Sstevel@tonic-gate static int
get_node_class(char * classbuf,di_node_t dn,const char * nodename)6047c478bd9Sstevel@tonic-gate get_node_class(char *classbuf, di_node_t dn, const char *nodename)
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate 	if (get_device_type(classbuf, dn) == 0) {
6077c478bd9Sstevel@tonic-gate 		if (di_nodeid(dn) == DI_PROM_NODEID) {
6087c478bd9Sstevel@tonic-gate 			/*
6097c478bd9Sstevel@tonic-gate 			 * discard place holder nodes
6107c478bd9Sstevel@tonic-gate 			 */
6117c478bd9Sstevel@tonic-gate 			if ((strcmp(classbuf, DEVICE_TYPE_BLOCK) == 0) ||
6127c478bd9Sstevel@tonic-gate 			    (strcmp(classbuf, DEVICE_TYPE_BYTE) == 0) ||
6137c478bd9Sstevel@tonic-gate 			    (strcmp(classbuf, DEVICE_TYPE_SES) == 0) ||
6147c478bd9Sstevel@tonic-gate 			    (strcmp(classbuf, DEVICE_TYPE_FP) == 0) ||
6157c478bd9Sstevel@tonic-gate 			    (strcmp(classbuf, DEVICE_TYPE_DISK) == 0))
6167c478bd9Sstevel@tonic-gate 				return (-1);
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 			return (0);
6197c478bd9Sstevel@tonic-gate 		}
6207c478bd9Sstevel@tonic-gate 		return (0);	/* return device_type value */
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	if (get_compatible_class(classbuf, dn) == 0) {
6247c478bd9Sstevel@tonic-gate 		return (0);	/* derive class using compatible prop */
6257c478bd9Sstevel@tonic-gate 	}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if (lookup_name_class_map(classbuf, nodename) == 0)
6287c478bd9Sstevel@tonic-gate 		return (0);	/* derive class using name prop */
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	if (has_reg_prop(dn)) { /* use default obp-device */
6317c478bd9Sstevel@tonic-gate 		(void) strcpy(classbuf, PICL_CLASS_OBP_DEVICE);
6327c478bd9Sstevel@tonic-gate 		return (0);
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	return (get_minor_class(classbuf, dn));
6367c478bd9Sstevel@tonic-gate }
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate  * Add a table property containing nrows with one column
6407c478bd9Sstevel@tonic-gate  */
6417c478bd9Sstevel@tonic-gate static int
add_string_list_prop(picl_nodehdl_t nodeh,char * name,char * strlist,unsigned int nrows)6427c478bd9Sstevel@tonic-gate add_string_list_prop(picl_nodehdl_t nodeh, char *name, char *strlist,
6437c478bd9Sstevel@tonic-gate     unsigned int nrows)
6447c478bd9Sstevel@tonic-gate {
6457c478bd9Sstevel@tonic-gate 	ptree_propinfo_t	propinfo;
6467c478bd9Sstevel@tonic-gate 	picl_prophdl_t		proph;
6477c478bd9Sstevel@tonic-gate 	picl_prophdl_t		tblh;
6487c478bd9Sstevel@tonic-gate 	int			err;
6497c478bd9Sstevel@tonic-gate 	unsigned int		i;
6507c478bd9Sstevel@tonic-gate 	unsigned int		j;
6517c478bd9Sstevel@tonic-gate 	picl_prophdl_t		*proprow;
6527c478bd9Sstevel@tonic-gate 	int			len;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate #define	NCOLS_IN_STRING_TABLE	1
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
6577c478bd9Sstevel@tonic-gate 	    PICL_PTYPE_TABLE, PICL_READ, sizeof (picl_prophdl_t), name,
6587c478bd9Sstevel@tonic-gate 	    NULL, NULL);
6597c478bd9Sstevel@tonic-gate 	if (err != PICL_SUCCESS)
6607c478bd9Sstevel@tonic-gate 		return (err);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	err = ptree_create_table(&tblh);
6637c478bd9Sstevel@tonic-gate 	if (err != PICL_SUCCESS)
6647c478bd9Sstevel@tonic-gate 		return (err);
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	err = ptree_create_and_add_prop(nodeh, &propinfo, &tblh, &proph);
6677c478bd9Sstevel@tonic-gate 	if (err != PICL_SUCCESS)
6687c478bd9Sstevel@tonic-gate 		return (err);
6697c478bd9Sstevel@tonic-gate 
670ce41cfb3SToomas Soome 	proprow = calloc(nrows, sizeof (picl_prophdl_t));
6717c478bd9Sstevel@tonic-gate 	if (proprow == NULL) {
6727c478bd9Sstevel@tonic-gate 		(void) ptree_destroy_prop(proph);
6737c478bd9Sstevel@tonic-gate 		return (PICL_FAILURE);
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	for (j = 0; j < nrows; ++j) {
6777c478bd9Sstevel@tonic-gate 		len = strlen(strlist) + 1;
6787c478bd9Sstevel@tonic-gate 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
6797c478bd9Sstevel@tonic-gate 		    PICL_PTYPE_CHARSTRING, PICL_READ, len, name,
6807c478bd9Sstevel@tonic-gate 		    NULL, NULL);
6817c478bd9Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
6827c478bd9Sstevel@tonic-gate 			break;
6837c478bd9Sstevel@tonic-gate 		err = ptree_create_prop(&propinfo, strlist, &proprow[j]);
6847c478bd9Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
6857c478bd9Sstevel@tonic-gate 			break;
6867c478bd9Sstevel@tonic-gate 		strlist += len;
6877c478bd9Sstevel@tonic-gate 		err = ptree_add_row_to_table(tblh, NCOLS_IN_STRING_TABLE,
6887c478bd9Sstevel@tonic-gate 		    &proprow[j]);
6897c478bd9Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
6907c478bd9Sstevel@tonic-gate 			break;
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
6947c478bd9Sstevel@tonic-gate 		for (i = 0; i < j; ++i)
6957c478bd9Sstevel@tonic-gate 			(void) ptree_destroy_prop(proprow[i]);
6967c478bd9Sstevel@tonic-gate 		(void) ptree_delete_prop(proph);
6977c478bd9Sstevel@tonic-gate 		(void) ptree_destroy_prop(proph);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 
700ce41cfb3SToomas Soome 	free(proprow);
701ce41cfb3SToomas Soome 	return (err);
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate /*
7057c478bd9Sstevel@tonic-gate  * return 1 if this node has this property with the given value
7067c478bd9Sstevel@tonic-gate  */
7077c478bd9Sstevel@tonic-gate static int
compare_string_propval(picl_nodehdl_t nodeh,const char * pname,const char * pval)7087c478bd9Sstevel@tonic-gate compare_string_propval(picl_nodehdl_t nodeh, const char *pname,
7097c478bd9Sstevel@tonic-gate     const char *pval)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate 	char			*pvalbuf;
7127c478bd9Sstevel@tonic-gate 	int			err;
7137c478bd9Sstevel@tonic-gate 	int			len;
7147c478bd9Sstevel@tonic-gate 	ptree_propinfo_t	pinfo;
7157c478bd9Sstevel@tonic-gate 	picl_prophdl_t		proph;
716ce41cfb3SToomas Soome 	int			rv;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	err = ptree_get_prop_by_name(nodeh, pname, &proph);
7197c478bd9Sstevel@tonic-gate 	if (err != PICL_SUCCESS)	/* prop doesn't exist */
7207c478bd9Sstevel@tonic-gate 		return (0);
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	err = ptree_get_propinfo(proph, &pinfo);
7237c478bd9Sstevel@tonic-gate 	if (pinfo.piclinfo.type != PICL_PTYPE_CHARSTRING)
7247c478bd9Sstevel@tonic-gate 		return (0);	/* not string prop */
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	len = strlen(pval) + 1;
7277c478bd9Sstevel@tonic-gate 
728ce41cfb3SToomas Soome 	pvalbuf = malloc(len);
7297c478bd9Sstevel@tonic-gate 	if (pvalbuf == NULL)
7307c478bd9Sstevel@tonic-gate 		return (0);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	err = ptree_get_propval(proph, pvalbuf, len);
7337c478bd9Sstevel@tonic-gate 	if ((err == PICL_SUCCESS) && (strcmp(pvalbuf, pval) == 0))
734ce41cfb3SToomas Soome 		rv = 1;	/* prop match */
735ce41cfb3SToomas Soome 	else
736ce41cfb3SToomas Soome 		rv = 0;
7377c478bd9Sstevel@tonic-gate 
738ce41cfb3SToomas Soome 	free(pvalbuf);
739ce41cfb3SToomas Soome 	return (rv);
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate /*
7437c478bd9Sstevel@tonic-gate  * This function recursively searches the tree for a node that has
7447c478bd9Sstevel@tonic-gate  * the specified string property name and value
7457c478bd9Sstevel@tonic-gate  */
7467c478bd9Sstevel@tonic-gate static int
find_node_by_string_prop(picl_nodehdl_t rooth,const char * pname,const char * pval,picl_nodehdl_t * nodeh)7477c478bd9Sstevel@tonic-gate find_node_by_string_prop(picl_nodehdl_t rooth, const char *pname,
7487c478bd9Sstevel@tonic-gate     const char *pval, picl_nodehdl_t *nodeh)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate 	picl_nodehdl_t		childh;
7517c478bd9Sstevel@tonic-gate 	int			err;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	for (err = ptree_get_propval_by_name(rooth, PICL_PROP_CHILD, &childh,
7547c478bd9Sstevel@tonic-gate 	    sizeof (picl_nodehdl_t)); err != PICL_PROPNOTFOUND;
7555e3e415aSfw 	    err = ptree_get_propval_by_name(childh, PICL_PROP_PEER, &childh,
7565e3e415aSfw 	    sizeof (picl_nodehdl_t))) {
7577c478bd9Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
7587c478bd9Sstevel@tonic-gate 			return (err);
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		if (compare_string_propval(childh, pname, pval)) {
7617c478bd9Sstevel@tonic-gate 			*nodeh = childh;
7627c478bd9Sstevel@tonic-gate 			return (PICL_SUCCESS);
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 		if (find_node_by_string_prop(childh, pname, pval, nodeh) ==
7667c478bd9Sstevel@tonic-gate 		    PICL_SUCCESS)
7677c478bd9Sstevel@tonic-gate 			return (PICL_SUCCESS);
7687c478bd9Sstevel@tonic-gate 	}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	return (PICL_FAILURE);
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate /*
7747c478bd9Sstevel@tonic-gate  * check if this is a string prop
7757c478bd9Sstevel@tonic-gate  * If the length is less than or equal to 4, assume it's not a string list.
7767c478bd9Sstevel@tonic-gate  * If there is any non-ascii or non-print char, it's not a string prop
7777c478bd9Sstevel@tonic-gate  * If \0 is in the first char or any two consecutive \0's exist,
7787c478bd9Sstevel@tonic-gate  * it's a bytearray prop.
7797c478bd9Sstevel@tonic-gate  * Return value: 0 means it's not a string prop, 1 means it's a string prop
7807c478bd9Sstevel@tonic-gate  */
7817c478bd9Sstevel@tonic-gate static int
is_string_propval(unsigned char * pdata,int len)7827c478bd9Sstevel@tonic-gate is_string_propval(unsigned char *pdata, int len)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	int	i;
7857c478bd9Sstevel@tonic-gate 	int	lastindex;
7867c478bd9Sstevel@tonic-gate 	int	prevnull = -1;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	switch (len) {
7897c478bd9Sstevel@tonic-gate 	case 1:
7907c478bd9Sstevel@tonic-gate 		if (!isascii(pdata[0]) || !isprint(pdata[0]))
7917c478bd9Sstevel@tonic-gate 			return (0);
7927c478bd9Sstevel@tonic-gate 		return (1);
7937c478bd9Sstevel@tonic-gate 	case 2:
7947c478bd9Sstevel@tonic-gate 	case 3:
7957c478bd9Sstevel@tonic-gate 	case 4:
7967c478bd9Sstevel@tonic-gate 		lastindex = len;
7977c478bd9Sstevel@tonic-gate 		if (pdata[len-1] == '\0')
7987c478bd9Sstevel@tonic-gate 			lastindex = len - 1;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 		for (i = 0; i < lastindex; i++)
8017c478bd9Sstevel@tonic-gate 			if (!isascii(pdata[i]) || !isprint(pdata[i]))
8027c478bd9Sstevel@tonic-gate 				return (0);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 		return (1);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	default:
8077c478bd9Sstevel@tonic-gate 		if (len <= 0)
8087c478bd9Sstevel@tonic-gate 			return (0);
8097c478bd9Sstevel@tonic-gate 		for (i = 0; i < len; i++) {
8107c478bd9Sstevel@tonic-gate 			if (!isascii(pdata[i]) || !isprint(pdata[i])) {
8117c478bd9Sstevel@tonic-gate 				if (pdata[i] != '\0')
8127c478bd9Sstevel@tonic-gate 					return (0);
8137c478bd9Sstevel@tonic-gate 				/*
8147c478bd9Sstevel@tonic-gate 				 * if the null char is in the first char
8157c478bd9Sstevel@tonic-gate 				 * or two consecutive nulls' exist,
8167c478bd9Sstevel@tonic-gate 				 * it's a bytearray prop
8177c478bd9Sstevel@tonic-gate 				 */
8187c478bd9Sstevel@tonic-gate 				if ((i == 0) || ((i - prevnull) == 1))
8197c478bd9Sstevel@tonic-gate 					return (0);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 				prevnull = i;
8227c478bd9Sstevel@tonic-gate 			}
8237c478bd9Sstevel@tonic-gate 		}
8247c478bd9Sstevel@tonic-gate 		break;
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	return (1);
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate /*
8317c478bd9Sstevel@tonic-gate  * This function counts the number of strings in the value buffer pdata
8327c478bd9Sstevel@tonic-gate  * and creates a property.
8337c478bd9Sstevel@tonic-gate  * If there is only one string in the buffer, pdata, a charstring property
8347c478bd9Sstevel@tonic-gate  * type is created and added.
8357c478bd9Sstevel@tonic-gate  * If there are more than one string in the buffer, pdata, then a table
8367c478bd9Sstevel@tonic-gate  * of charstrings is added.
8377c478bd9Sstevel@tonic-gate  */
8387c478bd9Sstevel@tonic-gate static int
process_charstring_data(picl_nodehdl_t nodeh,char * pname,unsigned char * pdata,int retval)8397c478bd9Sstevel@tonic-gate process_charstring_data(picl_nodehdl_t nodeh, char *pname, unsigned char *pdata,
8407c478bd9Sstevel@tonic-gate     int retval)
8417c478bd9Sstevel@tonic-gate {
8427c478bd9Sstevel@tonic-gate 	int			err;
8437c478bd9Sstevel@tonic-gate 	int			strcount;
8447c478bd9Sstevel@tonic-gate 	char			*strdat;
8457c478bd9Sstevel@tonic-gate 	ptree_propinfo_t	propinfo;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	/*
8487c478bd9Sstevel@tonic-gate 	 * append the null char at the end of string when there is
8497c478bd9Sstevel@tonic-gate 	 * no null terminator
8507c478bd9Sstevel@tonic-gate 	 */
8517c478bd9Sstevel@tonic-gate 	if (pdata[retval - 1] != '\0') {
852ce41cfb3SToomas Soome 		strdat = malloc(retval + 1);
853ce41cfb3SToomas Soome 		if (strdat != NULL) {
854ce41cfb3SToomas Soome 			(void) memcpy(strdat, pdata, retval);
855ce41cfb3SToomas Soome 			strdat[retval] = '\0';
856ce41cfb3SToomas Soome 			retval++;
857ce41cfb3SToomas Soome 		}
8587c478bd9Sstevel@tonic-gate 	} else {
859ce41cfb3SToomas Soome 		strdat = malloc(retval);
860ce41cfb3SToomas Soome 		if (strdat != NULL)
861ce41cfb3SToomas Soome 			(void) memcpy(strdat, pdata, retval);
8627c478bd9Sstevel@tonic-gate 	}
863ce41cfb3SToomas Soome 	if (strdat == NULL)
864ce41cfb3SToomas Soome 		return (PICL_FAILURE);
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	/*
8677c478bd9Sstevel@tonic-gate 	 * If it's a string list, create a table prop
8687c478bd9Sstevel@tonic-gate 	 */
8697c478bd9Sstevel@tonic-gate 	strcount = get_string_count(strdat, retval);
8707c478bd9Sstevel@tonic-gate 	if (strcount > 1) {
8717c478bd9Sstevel@tonic-gate 		err = add_string_list_prop(nodeh, pname,
8727c478bd9Sstevel@tonic-gate 		    strdat, strcount);
873ce41cfb3SToomas Soome 		if (err != PICL_SUCCESS) {
874ce41cfb3SToomas Soome 			free(strdat);
8757c478bd9Sstevel@tonic-gate 			return (err);
876ce41cfb3SToomas Soome 		}
8777c478bd9Sstevel@tonic-gate 	} else {
8787c478bd9Sstevel@tonic-gate 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
8797c478bd9Sstevel@tonic-gate 		    PICL_PTYPE_CHARSTRING, PICL_READ,
8807c478bd9Sstevel@tonic-gate 		    strlen(strdat) + 1, pname, NULL,
8817c478bd9Sstevel@tonic-gate 		    NULL);
882ce41cfb3SToomas Soome 		if (err != PICL_SUCCESS) {
883ce41cfb3SToomas Soome 			free(strdat);
8847c478bd9Sstevel@tonic-gate 			return (err);
885ce41cfb3SToomas Soome 		}
8867c478bd9Sstevel@tonic-gate 		(void) ptree_create_and_add_prop(nodeh, &propinfo,
8877c478bd9Sstevel@tonic-gate 		    strdat, NULL);
8887c478bd9Sstevel@tonic-gate 	}
889ce41cfb3SToomas Soome 
890ce41cfb3SToomas Soome 	free(strdat);
8917c478bd9Sstevel@tonic-gate 	return (PICL_SUCCESS);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate /*
8957c478bd9Sstevel@tonic-gate  * Add the OBP properties as properties of the PICL node
8967c478bd9Sstevel@tonic-gate  */
8977c478bd9Sstevel@tonic-gate static int
add_openprom_props(picl_nodehdl_t nodeh,di_node_t di_node)8987c478bd9Sstevel@tonic-gate add_openprom_props(picl_nodehdl_t nodeh, di_node_t di_node)
8997c478bd9Sstevel@tonic-gate {
9007c478bd9Sstevel@tonic-gate 	di_prom_prop_t		promp;
9017c478bd9Sstevel@tonic-gate 	char			*pname;
9027c478bd9Sstevel@tonic-gate 	unsigned char		*pdata;
9037c478bd9Sstevel@tonic-gate 	int			retval;
9047c478bd9Sstevel@tonic-gate 	ptree_propinfo_t	propinfo;
9057c478bd9Sstevel@tonic-gate 	int			err;
9067c478bd9Sstevel@tonic-gate 	picl_prop_type_t	type;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	if (!ph)
9097c478bd9Sstevel@tonic-gate 		return (PICL_FAILURE);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	for (promp = di_prom_prop_next(ph, di_node, DI_PROM_PROP_NIL);
9127c478bd9Sstevel@tonic-gate 	    promp != DI_PROM_PROP_NIL;
9135e3e415aSfw 	    promp = di_prom_prop_next(ph, di_node, promp)) {
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 		pname = di_prom_prop_name(promp);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 		retval = di_prom_prop_data(promp, &pdata);
9187c478bd9Sstevel@tonic-gate 		if (retval < 0) {
9197c478bd9Sstevel@tonic-gate 			return (PICL_SUCCESS);
9207c478bd9Sstevel@tonic-gate 		}
9217c478bd9Sstevel@tonic-gate 		if (retval == 0) {
9227c478bd9Sstevel@tonic-gate 			err = ptree_init_propinfo(&propinfo,
9237c478bd9Sstevel@tonic-gate 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_VOID,
9247c478bd9Sstevel@tonic-gate 			    PICL_READ, (size_t)0, pname, NULL, NULL);
9257c478bd9Sstevel@tonic-gate 			if (err != PICL_SUCCESS) {
9267c478bd9Sstevel@tonic-gate 				return (err);
9277c478bd9Sstevel@tonic-gate 			}
9287c478bd9Sstevel@tonic-gate 			(void) ptree_create_and_add_prop(nodeh, &propinfo, NULL,
9297c478bd9Sstevel@tonic-gate 			    NULL);
9307c478bd9Sstevel@tonic-gate 			continue;
9317c478bd9Sstevel@tonic-gate 		}
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 		/*
9347c478bd9Sstevel@tonic-gate 		 * Get the prop type from pname map table
9357c478bd9Sstevel@tonic-gate 		 */
9367c478bd9Sstevel@tonic-gate 		if (lookup_pname_type_map(pname, &type) == 0) {
9377c478bd9Sstevel@tonic-gate 			if (type == PICL_PTYPE_CHARSTRING) {
9387c478bd9Sstevel@tonic-gate 				err = process_charstring_data(nodeh, pname,
9397c478bd9Sstevel@tonic-gate 				    pdata, retval);
9407c478bd9Sstevel@tonic-gate 				if (err != PICL_SUCCESS) {
9417c478bd9Sstevel@tonic-gate 					return (err);
9427c478bd9Sstevel@tonic-gate 				}
9437c478bd9Sstevel@tonic-gate 				continue;
9447c478bd9Sstevel@tonic-gate 			}
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 			err = ptree_init_propinfo(&propinfo,
9477c478bd9Sstevel@tonic-gate 			    PTREE_PROPINFO_VERSION, type, PICL_READ,
9487c478bd9Sstevel@tonic-gate 			    retval, pname, NULL, NULL);
9497c478bd9Sstevel@tonic-gate 			if (err != PICL_SUCCESS) {
9507c478bd9Sstevel@tonic-gate 				return (err);
9517c478bd9Sstevel@tonic-gate 			}
9527c478bd9Sstevel@tonic-gate 			(void) ptree_create_and_add_prop(nodeh, &propinfo,
9537c478bd9Sstevel@tonic-gate 			    pdata, NULL);
9547c478bd9Sstevel@tonic-gate 		} else if (!is_string_propval(pdata, retval)) {
9557c478bd9Sstevel@tonic-gate 			switch (retval) {
9567c478bd9Sstevel@tonic-gate 			case sizeof (uint8_t):
9577c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
9587c478bd9Sstevel@tonic-gate 			case sizeof (uint16_t):
9597c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
9607c478bd9Sstevel@tonic-gate 			case sizeof (uint32_t):
9617c478bd9Sstevel@tonic-gate 				type = PICL_PTYPE_UNSIGNED_INT;
9627c478bd9Sstevel@tonic-gate 				break;
9637c478bd9Sstevel@tonic-gate 			default:
9647c478bd9Sstevel@tonic-gate 				type = PICL_PTYPE_BYTEARRAY;
9657c478bd9Sstevel@tonic-gate 				break;
9667c478bd9Sstevel@tonic-gate 			}
9677c478bd9Sstevel@tonic-gate 			err = ptree_init_propinfo(&propinfo,
9687c478bd9Sstevel@tonic-gate 			    PTREE_PROPINFO_VERSION, type, PICL_READ,
9697c478bd9Sstevel@tonic-gate 			    retval, pname, NULL, NULL);
9707c478bd9Sstevel@tonic-gate 			if (err != PICL_SUCCESS) {
9717c478bd9Sstevel@tonic-gate 				return (err);
9727c478bd9Sstevel@tonic-gate 			}
9737c478bd9Sstevel@tonic-gate 			(void) ptree_create_and_add_prop(nodeh, &propinfo,
9747c478bd9Sstevel@tonic-gate 			    pdata, NULL);
9757c478bd9Sstevel@tonic-gate 		} else {
9767c478bd9Sstevel@tonic-gate 			err = process_charstring_data(nodeh, pname, pdata,
9777c478bd9Sstevel@tonic-gate 			    retval);
9787c478bd9Sstevel@tonic-gate 			if (err != PICL_SUCCESS) {
9797c478bd9Sstevel@tonic-gate 				return (err);
9807c478bd9Sstevel@tonic-gate 			}
9817c478bd9Sstevel@tonic-gate 		}
9827c478bd9Sstevel@tonic-gate 	}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	return (PICL_SUCCESS);
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
98761db5dcaSrd static void
add_boolean_prop(picl_nodehdl_t nodeh,ptree_propinfo_t propinfo,char * di_val)98861db5dcaSrd add_boolean_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val)
98961db5dcaSrd {
99061db5dcaSrd 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
99161db5dcaSrd 	    PICL_PTYPE_VOID, PICL_READ, (size_t)0, di_val, NULL, NULL);
99261db5dcaSrd 	(void) ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
99361db5dcaSrd }
99461db5dcaSrd 
99561db5dcaSrd static void
add_uints_prop(picl_nodehdl_t nodeh,ptree_propinfo_t propinfo,char * di_val,int * idata,int len)99661db5dcaSrd add_uints_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
99761db5dcaSrd     int *idata, int len)
99861db5dcaSrd {
99961db5dcaSrd 	if (len == 1)
100061db5dcaSrd 		(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
100161db5dcaSrd 		    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (int), di_val,
100261db5dcaSrd 		    NULL, NULL);
100361db5dcaSrd 	else
100461db5dcaSrd 		(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
100561db5dcaSrd 		    PICL_PTYPE_BYTEARRAY, PICL_READ, len * sizeof (int), di_val,
100661db5dcaSrd 		    NULL, NULL);
100761db5dcaSrd 
100861db5dcaSrd 	(void) ptree_create_and_add_prop(nodeh, &propinfo, idata, NULL);
100961db5dcaSrd }
101061db5dcaSrd 
101161db5dcaSrd static void
add_strings_prop(picl_nodehdl_t nodeh,ptree_propinfo_t propinfo,char * di_val,char * sdata,int len)101261db5dcaSrd add_strings_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
101361db5dcaSrd     char *sdata, int len)
101461db5dcaSrd {
101561db5dcaSrd 	if (len == 1) {
101661db5dcaSrd 		(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
101761db5dcaSrd 		    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(sdata) + 1, di_val,
101861db5dcaSrd 		    NULL, NULL);
101961db5dcaSrd 		(void) ptree_create_and_add_prop(nodeh, &propinfo, sdata, NULL);
102061db5dcaSrd 	} else {
102161db5dcaSrd 		(void) add_string_list_prop(nodeh, di_val, sdata, len);
102261db5dcaSrd 	}
102361db5dcaSrd }
102461db5dcaSrd 
102561db5dcaSrd static void
add_bytes_prop(picl_nodehdl_t nodeh,ptree_propinfo_t propinfo,char * di_val,unsigned char * bdata,int len)102661db5dcaSrd add_bytes_prop(picl_nodehdl_t nodeh, ptree_propinfo_t propinfo, char *di_val,
102761db5dcaSrd     unsigned char *bdata, int len)
102861db5dcaSrd {
102961db5dcaSrd 	(void) ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
103061db5dcaSrd 	    PICL_PTYPE_BYTEARRAY, PICL_READ, len, di_val, NULL, NULL);
103161db5dcaSrd 	(void) ptree_create_and_add_prop(nodeh, &propinfo, bdata, NULL);
103261db5dcaSrd }
103361db5dcaSrd 
103443e66171SMichael Bergknoff static const char *
path_state_name(di_path_state_t st)103543e66171SMichael Bergknoff path_state_name(di_path_state_t st)
103643e66171SMichael Bergknoff {
103743e66171SMichael Bergknoff 	switch (st) {
103843e66171SMichael Bergknoff 		case DI_PATH_STATE_ONLINE:
103943e66171SMichael Bergknoff 			return ("online");
104043e66171SMichael Bergknoff 		case DI_PATH_STATE_STANDBY:
104143e66171SMichael Bergknoff 			return ("standby");
104243e66171SMichael Bergknoff 		case DI_PATH_STATE_OFFLINE:
104343e66171SMichael Bergknoff 			return ("offline");
104443e66171SMichael Bergknoff 		case DI_PATH_STATE_FAULT:
104543e66171SMichael Bergknoff 			return ("faulted");
104643e66171SMichael Bergknoff 	}
104743e66171SMichael Bergknoff 	return ("unknown");
104843e66171SMichael Bergknoff }
104943e66171SMichael Bergknoff 
105043e66171SMichael Bergknoff /*
105143e66171SMichael Bergknoff  * This function is the volatile property handler for the multipath node
105243e66171SMichael Bergknoff  * "State" property. It must locate the associated devinfo node in order to
105343e66171SMichael Bergknoff  * determine the current state. Since the devinfo node can have multiple
105443e66171SMichael Bergknoff  * paths the devfs_path is used to locate the correct path.
105543e66171SMichael Bergknoff  */
105643e66171SMichael Bergknoff static int
get_path_state_name(ptree_rarg_t * rarg,void * vbuf)105743e66171SMichael Bergknoff get_path_state_name(ptree_rarg_t *rarg, void *vbuf)
105843e66171SMichael Bergknoff {
105943e66171SMichael Bergknoff 	int		err;
106043e66171SMichael Bergknoff 	picl_nodehdl_t	parh;
106143e66171SMichael Bergknoff 	char		devfs_path[PATH_MAX];
106243e66171SMichael Bergknoff 	di_node_t	di_node;
106343e66171SMichael Bergknoff 	di_node_t	di_root;
106443e66171SMichael Bergknoff 	di_path_t	pi = DI_PATH_NIL;
106543e66171SMichael Bergknoff 	picl_nodehdl_t	mpnode;
106643e66171SMichael Bergknoff 
106743e66171SMichael Bergknoff 	(void) strlcpy(vbuf, "unknown", MAX_STATE_SIZE);
106843e66171SMichael Bergknoff 
106943e66171SMichael Bergknoff 	mpnode = rarg->nodeh;
107043e66171SMichael Bergknoff 
107143e66171SMichael Bergknoff 	/*
107243e66171SMichael Bergknoff 	 * The parent node represents the vHCI.
107343e66171SMichael Bergknoff 	 */
107443e66171SMichael Bergknoff 	err = ptree_get_propval_by_name(mpnode, PICL_PROP_PARENT, &parh,
107543e66171SMichael Bergknoff 	    sizeof (picl_nodehdl_t));
107643e66171SMichael Bergknoff 	if (err != PICL_SUCCESS) {
107743e66171SMichael Bergknoff 		return (PICL_SUCCESS);
107843e66171SMichael Bergknoff 	}
107943e66171SMichael Bergknoff 
108043e66171SMichael Bergknoff 	/*
108143e66171SMichael Bergknoff 	 * The PICL_PROP_DEVFS_PATH property will be used to locate the
108243e66171SMichael Bergknoff 	 * devinfo node for the vHCI driver.
108343e66171SMichael Bergknoff 	 */
108443e66171SMichael Bergknoff 	err = ptree_get_propval_by_name(parh, PICL_PROP_DEVFS_PATH, devfs_path,
108543e66171SMichael Bergknoff 	    sizeof (devfs_path));
108643e66171SMichael Bergknoff 	if (err != PICL_SUCCESS) {
108743e66171SMichael Bergknoff 		return (PICL_SUCCESS);
108843e66171SMichael Bergknoff 	}
108943e66171SMichael Bergknoff 	/*
109043e66171SMichael Bergknoff 	 * Find the di_node for the vHCI driver. It will be used to scan
109143e66171SMichael Bergknoff 	 * the path information nodes.
109243e66171SMichael Bergknoff 	 */
109343e66171SMichael Bergknoff 	di_root = di_init("/", DINFOCACHE);
109443e66171SMichael Bergknoff 	if (di_root == DI_NODE_NIL) {
109543e66171SMichael Bergknoff 		return (PICL_SUCCESS);
109643e66171SMichael Bergknoff 	}
109743e66171SMichael Bergknoff 	di_node = di_lookup_node(di_root, devfs_path);
109843e66171SMichael Bergknoff 	if (di_node == DI_NODE_NIL) {
109943e66171SMichael Bergknoff 		di_fini(di_root);
110043e66171SMichael Bergknoff 		return (PICL_SUCCESS);
110143e66171SMichael Bergknoff 	}
110243e66171SMichael Bergknoff 
110343e66171SMichael Bergknoff 	/*
110443e66171SMichael Bergknoff 	 * The devfs_path will be used below to match the
110543e66171SMichael Bergknoff 	 * proper path information node.
110643e66171SMichael Bergknoff 	 */
110743e66171SMichael Bergknoff 	err = ptree_get_propval_by_name(mpnode, PICL_PROP_DEVFS_PATH,
110843e66171SMichael Bergknoff 	    devfs_path, sizeof (devfs_path));
110943e66171SMichael Bergknoff 	if (err != PICL_SUCCESS) {
111043e66171SMichael Bergknoff 		di_fini(di_root);
111143e66171SMichael Bergknoff 		return (PICL_SUCCESS);
111243e66171SMichael Bergknoff 	}
111343e66171SMichael Bergknoff 
111443e66171SMichael Bergknoff 	/*
111543e66171SMichael Bergknoff 	 * Scan the path information nodes looking for the matching devfs
111643e66171SMichael Bergknoff 	 * path. When found obtain the state information.
111743e66171SMichael Bergknoff 	 */
111843e66171SMichael Bergknoff 	while ((pi = di_path_next_phci(di_node, pi)) != DI_PATH_NIL) {
111943e66171SMichael Bergknoff 		char		*di_path;
112043e66171SMichael Bergknoff 		di_node_t	phci_node = di_path_phci_node(pi);
112143e66171SMichael Bergknoff 
112243e66171SMichael Bergknoff 		if (phci_node == DI_PATH_NIL)
112343e66171SMichael Bergknoff 			continue;
112443e66171SMichael Bergknoff 
112543e66171SMichael Bergknoff 		di_path = di_devfs_path(phci_node);
112643e66171SMichael Bergknoff 		if (di_path) {
112743e66171SMichael Bergknoff 			if (strcmp(di_path, devfs_path) != 0) {
112843e66171SMichael Bergknoff 				di_devfs_path_free(di_path);
112943e66171SMichael Bergknoff 				continue;
113043e66171SMichael Bergknoff 			}
113143e66171SMichael Bergknoff 			(void) strlcpy(vbuf, path_state_name(di_path_state(pi)),
113243e66171SMichael Bergknoff 			    MAX_STATE_SIZE);
113343e66171SMichael Bergknoff 			di_devfs_path_free(di_path);
1134