xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4u/mpxu/frudr/piclfrudr.c (revision 12601:3fd4339427c7)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51103Sjbeloro  * Common Development and Distribution License (the "License").
61103Sjbeloro  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211103Sjbeloro 
220Sstevel@tonic-gate /*
23*12601SJustin.Frank@Sun.COM  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <stddef.h>
280Sstevel@tonic-gate #include <syslog.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <ctype.h>
340Sstevel@tonic-gate #include <picl.h>
350Sstevel@tonic-gate #include <picltree.h>
360Sstevel@tonic-gate #include <picld_pluginutil.h>
370Sstevel@tonic-gate #include <sys/types.h>
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <fcntl.h>
400Sstevel@tonic-gate #include <dirent.h>
410Sstevel@tonic-gate #include <sys/sysevent/dr.h>
420Sstevel@tonic-gate #include <pthread.h>
430Sstevel@tonic-gate #include <libdevinfo.h>
440Sstevel@tonic-gate #include <limits.h>
450Sstevel@tonic-gate #include <sys/systeminfo.h>
460Sstevel@tonic-gate #include <sys/envmon.h>
470Sstevel@tonic-gate #include <i2c_gpio.h>
480Sstevel@tonic-gate #include "libdevice.h"
490Sstevel@tonic-gate #include "picldefs.h"
500Sstevel@tonic-gate #include <sys/raidioctl.h>
510Sstevel@tonic-gate #include <sys/param.h>
521103Sjbeloro #include <sys/epic.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*
550Sstevel@tonic-gate  * Plugin registration entry points
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate static void	piclfrudr_register(void);
580Sstevel@tonic-gate static void	piclfrudr_init(void);
590Sstevel@tonic-gate static void	piclfrudr_fini(void);
601103Sjbeloro static void	rmc_state_event(void);
611103Sjbeloro static void	seattle_setleds(void);
621103Sjbeloro static void	boston_set_frontleds(const char *, int);
631103Sjbeloro static void	boston_set_rearleds(const char *, int);
641103Sjbeloro 
650Sstevel@tonic-gate #pragma	init(piclfrudr_register)
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static picld_plugin_reg_t  my_reg_info = {
680Sstevel@tonic-gate 	PICLD_PLUGIN_VERSION_1,
690Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
700Sstevel@tonic-gate 	"SUNW_MPXU_frudr",
710Sstevel@tonic-gate 	piclfrudr_init,
720Sstevel@tonic-gate 	piclfrudr_fini,
730Sstevel@tonic-gate };
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /*
760Sstevel@tonic-gate  * Log message texts
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate #define	EM_THREAD_CREATE_FAILED gettext("piclfrudr: pthread_create failed: %s")
790Sstevel@tonic-gate #define	DELETE_PROP_FAIL gettext("ptree_delete_prop failed: %d")
800Sstevel@tonic-gate #define	EM_DI_INIT_FAIL	gettext("piclfrudr: di_init failed: %s")
810Sstevel@tonic-gate #define	PROPINFO_FAIL gettext("ptree_init_propinfo %s failed: %d")
820Sstevel@tonic-gate #define	ADD_NODE_FAIL gettext("ptree_create_and_add_node %s failed: %d")
830Sstevel@tonic-gate #define	ADD_TBL_ENTRY_FAIL gettext("piclfrudr: cannot add entry to table")
840Sstevel@tonic-gate #define	EM_POLL_FAIL gettext("piclfrudr: poll() failed: %s")
850Sstevel@tonic-gate #define	ADD_PROP_FAIL gettext("ptree_create_and_add_prop %s failed: %d")
860Sstevel@tonic-gate #define	EM_MUTEX_FAIL gettext("piclfrudr: pthread_mutex_lock returned: %s")
870Sstevel@tonic-gate #define	EM_UNK_FRU gettext("piclfrudr: Fru removed event for unknown node")
880Sstevel@tonic-gate #define	PARSE_CONF_FAIL gettext("parse config file %s failed")
890Sstevel@tonic-gate #define	EM_NO_SC_DEV gettext("piclfrudr: failed to locate SC device node")
900Sstevel@tonic-gate #define	EM_NO_SYSINFO gettext("piclfrudr: failed to get SC sysinfo: %s")
910Sstevel@tonic-gate 
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate  * PICL property values
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate #define	PICL_PROPVAL_ON		"ON"
960Sstevel@tonic-gate #define	PICL_PROPVAL_OFF	"OFF"
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /*
990Sstevel@tonic-gate  * Local defines
1000Sstevel@tonic-gate  */
1010Sstevel@tonic-gate #define	SEEPROM_DRIVER_NAME	"seeprom"
1020Sstevel@tonic-gate #define	FRUTREE_PATH		"/frutree"
1030Sstevel@tonic-gate #define	CHASSIS_LOC_PATH	"/frutree/chassis/%s"
1040Sstevel@tonic-gate #define	SYS_BOARD_PATH		"/frutree/chassis/MB/system-board/%s"
1051103Sjbeloro #define	SEATTLE1U_HDDBP_PATH	\
1061103Sjbeloro 	"/frutree/chassis/MB/system-board/HDDBP/disk-backplane-1/%s"
1071103Sjbeloro #define	SEATTLE2U_HDDBP_PATH	\
1081103Sjbeloro 	"/frutree/chassis/MB/system-board/HDDBP/disk-backplane-3/%s"
1091103Sjbeloro #define	BOSTON_HDDBP_PATH	\
1101103Sjbeloro 	"/frutree/chassis/MB/system-board/HDDCNTRL/disk-controller/HDDBP" \
1111103Sjbeloro 	"/disk-backplane-8/%s"
1121103Sjbeloro 
1130Sstevel@tonic-gate #define	CONFFILE_PREFIX		"fru_"
1140Sstevel@tonic-gate #define	CONFFILE_SUFFIX		".conf"
1150Sstevel@tonic-gate #define	CONFFILE_FRUTREE	"piclfrutree.conf"
1160Sstevel@tonic-gate #define	PS_NAME			"PS"
1170Sstevel@tonic-gate #define	PS_NAME_LEN		2
1180Sstevel@tonic-gate #define	PS_FRU_NAME		"power-supply"
1190Sstevel@tonic-gate #define	PS_PLATFORM_NAME	"power-supply-fru-prom"
1200Sstevel@tonic-gate #define	DISK_NAME		"HDD"
1210Sstevel@tonic-gate #define	DISK_NAME_LEN		3
1220Sstevel@tonic-gate #define	DISK_FRU_NAME		"disk"
1230Sstevel@tonic-gate #define	SCC_NAME		"SCC"
1240Sstevel@tonic-gate #define	SCC_NAME_LEN		3
1250Sstevel@tonic-gate #define	SCC_FRU_NAME		"scc"
1260Sstevel@tonic-gate #define	RMC_NAME		"SC"
1270Sstevel@tonic-gate #define	RMC_NAME_LEN		2
1280Sstevel@tonic-gate #define	RMC_FRU_NAME		"sc"
1292606Svenki #define	FT_NAME			"FT"
1302606Svenki #define	FT_NAME_LEN		2
131*12601SJustin.Frank@Sun.COM #define	F0_NAME			"F0"
132*12601SJustin.Frank@Sun.COM #define	F0_NAME_LEN		2
133*12601SJustin.Frank@Sun.COM #define	F1_NAME			"F1"
134*12601SJustin.Frank@Sun.COM #define	F1_NAME_LEN		2
1352606Svenki #define	FT_FRU_NAME		"fan-tray"
136*12601SJustin.Frank@Sun.COM #define	FT_FRU_NAME_LEN	8
1372606Svenki #define	FT_ID_BUFSZ		(FT_NAME_LEN + 2)
1380Sstevel@tonic-gate #define	DEV_PREFIX		"/devices"
1390Sstevel@tonic-gate #define	ENXS_FRONT_SRVC_LED	0x20
1400Sstevel@tonic-gate #define	ENXS_FRONT_ACT_LED	0x10
1410Sstevel@tonic-gate #define	ENXS_REAR_SRVC_LED	0x20
1420Sstevel@tonic-gate #define	ENXS_REAR_ACT_LED	0x10
1430Sstevel@tonic-gate #define	ENTS_SRVC_LED		0x20
1440Sstevel@tonic-gate #define	ENTS_ACT_LED		0x10
1450Sstevel@tonic-gate #define	V440_SRVC_LED		0x2
1460Sstevel@tonic-gate #define	V440_ACT_LED		0x1
1471103Sjbeloro #define	BOSTON_FRONT_SRVC_LED	0x2
1481103Sjbeloro #define	BOSTON_FRONT_ACT_LED	0x4
1491103Sjbeloro #define	BOSTON_FRONT_CLEAR_DIR	0x0
1501103Sjbeloro #define	BOSTON_FRONT_CLEAR_POL	0x0
1511103Sjbeloro #define	BOSTON_FRONT_LED_MASK	0xffffffff
1521467Sfw157321 #define	BOSTON_REAR_SRVC_LED	0x8000
1531467Sfw157321 #define	BOSTON_REAR_ACT_LED	0x2000
1541103Sjbeloro #define	BOSTON_REAR_CLEAR_POL	0x0000
1551103Sjbeloro #define	BOSTON_REAR_LED_MASK	0xe000
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * PSU defines
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate #define	PSU_I2C_BUS_DEV "/devices/pci@1e,600000/isa@7/i2c@0,320:devctl"
1610Sstevel@tonic-gate #define	PSU_DEV	\
1620Sstevel@tonic-gate 	"/devices/pci@1e,600000/isa@7/i2c@0,320/power-supply-fru-prom@0,%x"
1630Sstevel@tonic-gate #define	PSU_PLATFORM	"/platform/pci@1e,600000/isa@7/i2c@0,320"
1640Sstevel@tonic-gate #define	PS0_ADDR ((sys_platform == PLAT_CHALUPA19) ? 0xc0 : 0xb0)
1650Sstevel@tonic-gate #define	PS1_ADDR ((sys_platform == PLAT_CHALUPA19) ? 0xc2 : 0xa4)
1660Sstevel@tonic-gate #define	PS2_ADDR 0x70
1670Sstevel@tonic-gate #define	PS3_ADDR 0x72
1680Sstevel@tonic-gate #define	PS0_UNITADDR	((sys_platform == PLAT_CHALUPA19) ? "0,c0" : "0,b0")
1690Sstevel@tonic-gate #define	PS1_UNITADDR	((sys_platform == PLAT_CHALUPA19) ? "0,c2" : "0,a4")
1700Sstevel@tonic-gate #define	PS2_UNITADDR	"0,70"
1710Sstevel@tonic-gate #define	PS3_UNITADDR	"0,72"
1720Sstevel@tonic-gate #define	PS0_NAME "PS0"
1730Sstevel@tonic-gate #define	PS1_NAME "PS1"
1740Sstevel@tonic-gate #define	PS2_NAME "PS2"
1750Sstevel@tonic-gate #define	PS3_NAME "PS3"
1760Sstevel@tonic-gate #define	PSU0_NAME "PSU0"
1770Sstevel@tonic-gate #define	PSU1_NAME "PSU1"
1780Sstevel@tonic-gate #define	PSU2_NAME "PSU2"
1790Sstevel@tonic-gate #define	PSU3_NAME "PSU3"
1800Sstevel@tonic-gate #define	PS_DEVICE_NAME "power-supply-fru-prom"
1812392Svenki #define	PSU_COMPATIBLE	"i2c-at24c64"
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate /*
1841103Sjbeloro  * Seattle/Boston PSU defines
1851103Sjbeloro  */
1861103Sjbeloro #define	SEATTLE_PSU_I2C_BUS_DEV "/devices/i2c@1f,530000:devctl"
1871103Sjbeloro #define	SEATTLE_PSU_DEV	\
1881103Sjbeloro 	"/devices/i2c@1f,530000/power-supply-fru-prom@0,%x"
1891103Sjbeloro #define	SEATTLE_PSU_PLATFORM	"/platform/i2c@1f,530000"
1901103Sjbeloro #define	SEATTLE_PS0_ADDR	0x6c
1911103Sjbeloro #define	SEATTLE_PS1_ADDR	0x6e
1921103Sjbeloro #define	SEATTLE_PS0_UNITADDR	"0,6c"
1931103Sjbeloro #define	SEATTLE_PS1_UNITADDR	"0,6e"
1942392Svenki #define	SEATTLE_PSU_COMPATIBLE	"i2c-at34c02"
1951103Sjbeloro #define	BOSTON_PSU_I2C_BUS_DEV	"/devices/i2c@1f,520000:devctl"
1961103Sjbeloro #define	BOSTON_PSU_DEV	\
1971103Sjbeloro 	"/devices/i2c@1f,520000/power-supply-fru-prom@0,%x"
1981103Sjbeloro #define	BOSTON_PSU_PLATFORM	"/platform/i2c@1f,520000"
1991103Sjbeloro #define	BOSTON_PS0_ADDR		0x24
2001103Sjbeloro #define	BOSTON_PS1_ADDR		0x32
2011103Sjbeloro #define	BOSTON_PS2_ADDR		0x52
2021103Sjbeloro #define	BOSTON_PS3_ADDR		0x72
2031103Sjbeloro #define	BOSTON_PS0_UNITADDR	"0,24"
2041103Sjbeloro #define	BOSTON_PS1_UNITADDR	"0,32"
2051103Sjbeloro #define	BOSTON_PS2_UNITADDR	"0,52"
2061103Sjbeloro #define	BOSTON_PS3_UNITADDR	"0,72"
2072392Svenki #define	BOSTON_PSU_COMPATIBLE	"i2c-at34c02"
2081103Sjbeloro 
2091103Sjbeloro /*
2102606Svenki  * Seattle fan-tray paths
2112606Svenki  */
2122606Svenki #define	SEATTLE_FCB0_1U \
2132606Svenki 	"/frutree/chassis/MB/system-board/FIOB/front-io-board-1" \
2142606Svenki 	"/FCB0/fan-connector-board/%s"
2152606Svenki #define	SEATTLE_FCB1_1U \
2162606Svenki 	"/frutree/chassis/MB/system-board/FIOB/front-io-board-1" \
2172606Svenki 	"/FCB1/fan-connector-board/%s"
2182606Svenki #define	SEATTLE_PDB_1U \
2192606Svenki 	"/frutree/chassis/PDB/power-distribution-board/%s"
2202606Svenki #define	SEATTLE_FCB0_2U	\
2212606Svenki 	"/frutree/chassis/MB/system-board/FIOB/front-io-board-2" \
2222606Svenki 	"/FCB0/fan-connector-board/%s"
2232606Svenki #define	SEATTLE_FCB1_2U \
2242606Svenki 	"/frutree/chassis/MB/system-board/FIOB/front-io-board-2" \
2252606Svenki 	"/FCB1/fan-connector-board/%s"
2262606Svenki #define	SEATTLE_PDB_2U \
2272606Svenki 	"/frutree/chassis/PDB/power-distribution-board" \
2282606Svenki 	"/HDDFB/fan-connector-board/%s"
2292606Svenki 
2302606Svenki /*
2310Sstevel@tonic-gate  * disk defines
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate #define	REMOK_LED "OK2RM"
2340Sstevel@tonic-gate #define	FAULT_LED "SERVICE"
2350Sstevel@tonic-gate #define	PLATFORMLEN 9
2360Sstevel@tonic-gate #define	N_DISKS 8
2370Sstevel@tonic-gate #define	N_CHALUPA_DISKS 4
2380Sstevel@tonic-gate #define	N_ENTS_DISKS 8
2390Sstevel@tonic-gate #define	N_MPXU_DISKS 4
2400Sstevel@tonic-gate #define	N_EN19_DISKS 2
2410Sstevel@tonic-gate #define	DISK_POLL_TIME	5000
2420Sstevel@tonic-gate /* For V440 RAID policy */
2430Sstevel@tonic-gate #define	V440_DISK_DEVCTL "/devices/pci@1f,700000/scsi@2:devctl"
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate /*
2461103Sjbeloro  * Seattle/Boston disk defines
2471103Sjbeloro  */
2481103Sjbeloro #define	N_SEATTLE1U_DISKS	2
2491103Sjbeloro #define	N_SEATTLE2U_DISKS	4
2501103Sjbeloro #define	N_BOSTON_DISKS		8
2511103Sjbeloro #define	SEATTLE_DISK_DEVCTL \
2521103Sjbeloro 	"/devices/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1:devctl"
2531296Sfw157321 #define	BOSTON_DISK_DEVCTL_1068X \
2541103Sjbeloro 	"/devices/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1:devctl"
2551296Sfw157321 #define	BOSTON_DISK_DEVCTL_1068E \
2561296Sfw157321 	"/devices/pci@1e,600000/pci@0/pci@2/scsi@0:devctl"
2571103Sjbeloro 
2581103Sjbeloro /*
2590Sstevel@tonic-gate  * led defines
2600Sstevel@tonic-gate  */
2610Sstevel@tonic-gate #define	ENXS_LED_DIR	"/devices/pci@1e,600000/isa@7/i2c@0,320/"
2620Sstevel@tonic-gate #define	ENXS_FRONT_LEDS	"gpio@0,70:"
2630Sstevel@tonic-gate #define	ENXS_REAR_LEDS	ENXS_LED_DIR "gpio@0,44:port_1"
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate #define	ENTS_LED_DIR	"/devices/pci@1e,600000/isa@7/i2c@0,320/"
2660Sstevel@tonic-gate #define	ENTS_LEDS	"gpio@0,70:"
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate #define	V440_LED_DIR	"/devices/pci@1e,600000/isa@7/i2c@0,320/"
2690Sstevel@tonic-gate #define	V440_LED_PATH	V440_LED_DIR "gpio@0,48:port_0"
2700Sstevel@tonic-gate 
2711103Sjbeloro /*
2721103Sjbeloro  * Seattle/Boston led defines
2731103Sjbeloro  */
2741103Sjbeloro #define	SEATTLE_LED_DEV	"/devices/ebus@1f,464000/env-monitor@3,0:env-monitor0"
2751103Sjbeloro #define	BOSTON_LED_DIR	"/devices/i2c@1f,520000/"
2761103Sjbeloro #define	BOSTON_FRONT_LED_PATH	BOSTON_LED_DIR "gpio@0,3a:port_0"
2771103Sjbeloro #define	BOSTON_REAR_LED_PATH	BOSTON_LED_DIR "hardware-monitor@0,5c:adm1026"
2781103Sjbeloro 
2791103Sjbeloro /*
2801103Sjbeloro  * Seattle/Boston USB defines
2811103Sjbeloro  */
2821103Sjbeloro #define	MAX_USB_PORTS		4
2831103Sjbeloro #define	USB_CONF_FILE_NAME	"usb-a-"
2841103Sjbeloro 
2850Sstevel@tonic-gate typedef struct id_props {
2860Sstevel@tonic-gate 	envmon_handle_t	envhandle;
2870Sstevel@tonic-gate 	picl_prophdl_t	volprop;
2880Sstevel@tonic-gate } id_props_t;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate typedef struct idp_lkup {
2910Sstevel@tonic-gate 	int		maxnum;		/* entries in array */
2920Sstevel@tonic-gate 	int		num;		/* entries in use */
2930Sstevel@tonic-gate 	id_props_t	idp[1];
2940Sstevel@tonic-gate } idp_lkup_t;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * table for mapping RMC handles to volatile property handles
2980Sstevel@tonic-gate  */
2990Sstevel@tonic-gate static idp_lkup_t	*idprop = NULL;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate /*
3020Sstevel@tonic-gate  * path names to system-controller device and fault led gpio
3030Sstevel@tonic-gate  */
3040Sstevel@tonic-gate static char		*sc_device_name = NULL;
3050Sstevel@tonic-gate static char		*bezel_leds = NULL;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate /*
3080Sstevel@tonic-gate  * disk data
3090Sstevel@tonic-gate  */
3100Sstevel@tonic-gate static int disk_ready[N_DISKS];
3110Sstevel@tonic-gate static char *disk_name[N_DISKS] = { "HDD0", "HDD1", "HDD2", "HDD3",
3120Sstevel@tonic-gate 					"HDD4", "HDD5", "HDD6", "HDD7" };
3130Sstevel@tonic-gate static volatile boolean_t	disk_leds_thread_ack = B_FALSE;
3140Sstevel@tonic-gate static volatile	boolean_t	disk_leds_thread_running = B_FALSE;
3150Sstevel@tonic-gate static pthread_t		ledsthr_tid;
3160Sstevel@tonic-gate static pthread_attr_t		ledsthr_attr;
3170Sstevel@tonic-gate static boolean_t		ledsthr_created = B_FALSE;
3180Sstevel@tonic-gate static boolean_t		g_mutex_init = B_FALSE;
3190Sstevel@tonic-gate static pthread_cond_t		g_cv;
3200Sstevel@tonic-gate static pthread_cond_t		g_cv_ack;
3210Sstevel@tonic-gate static pthread_mutex_t		g_mutex;
3220Sstevel@tonic-gate static volatile boolean_t	g_finish_now = B_FALSE;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*
3251296Sfw157321  * Boston platform-specific flag which tells us if we are using
3261296Sfw157321  * a LSI 1068X disk controller (0) or a LSI 1068E (1).
3271296Sfw157321  */
3281296Sfw157321 static int boston_1068e_flag = 0;
3291296Sfw157321 
3301296Sfw157321 /*
3310Sstevel@tonic-gate  * static strings
3320Sstevel@tonic-gate  */
3330Sstevel@tonic-gate static const char		str_devfs_path[] = "devfs-path";
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate /*
3360Sstevel@tonic-gate  * OperationalStatus property values
3370Sstevel@tonic-gate  */
3380Sstevel@tonic-gate static const char		str_opst_present[] = "present";
3390Sstevel@tonic-gate static const char		str_opst_ok[] = "okay";
3400Sstevel@tonic-gate static const char		str_opst_faulty[] = "faulty";
3410Sstevel@tonic-gate static const char		str_opst_download[] = "download";
3420Sstevel@tonic-gate static const char		str_opst_unknown[] = "unknown";
3430Sstevel@tonic-gate static size_t			max_opst_len = sizeof (str_opst_download);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate /*
3460Sstevel@tonic-gate  * forward reference
3470Sstevel@tonic-gate  */
3480Sstevel@tonic-gate static void opst_init(void);
3490Sstevel@tonic-gate static void add_op_status_by_name(const char *name, const char *child_name,
3500Sstevel@tonic-gate     picl_prophdl_t *prophdl_p);
3510Sstevel@tonic-gate static void add_op_status_to_node(picl_nodehdl_t nodeh,
3520Sstevel@tonic-gate     picl_prophdl_t *prophdl_p);
3530Sstevel@tonic-gate static int read_vol_data(ptree_rarg_t *r_arg, void *buf);
3540Sstevel@tonic-gate static int find_picl_handle(picl_prophdl_t proph);
3550Sstevel@tonic-gate static void disk_leds_init(void);
3560Sstevel@tonic-gate static void disk_leds_fini(void);
3570Sstevel@tonic-gate static void *disk_leds_thread(void *args);
3580Sstevel@tonic-gate static picl_nodehdl_t find_child_by_name(picl_nodehdl_t parh, char *name);
3590Sstevel@tonic-gate static void post_frudr_event(char *ename, picl_nodehdl_t parenth,
3600Sstevel@tonic-gate     picl_nodehdl_t fruh);
3610Sstevel@tonic-gate static int add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name);
3620Sstevel@tonic-gate static void remove_fru_parents(picl_nodehdl_t fruh);
3630Sstevel@tonic-gate static int get_node_by_class(picl_nodehdl_t nodeh, const char *classname,
3640Sstevel@tonic-gate     picl_nodehdl_t *foundnodeh);
3650Sstevel@tonic-gate static int get_sys_controller_node(picl_nodehdl_t *nodeh);
3660Sstevel@tonic-gate static char *create_sys_controller_pathname(picl_nodehdl_t sysconh);
3670Sstevel@tonic-gate static char *create_bezel_leds_pathname(const char *dirpath,
3680Sstevel@tonic-gate     const char *devname);
3690Sstevel@tonic-gate static void frudr_evhandler(const char *ename, const void *earg,
3700Sstevel@tonic-gate     size_t size, void *cookie);
3710Sstevel@tonic-gate static void fru_add_handler(const char *ename, const void *earg,
3720Sstevel@tonic-gate     size_t size, void *cookie);
3730Sstevel@tonic-gate static void frutree_evhandler(const char *ename, const void *earg,
3740Sstevel@tonic-gate 	size_t size, void *cookie);
3750Sstevel@tonic-gate static int create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp,
3760Sstevel@tonic-gate     char *tbl_name);
3770Sstevel@tonic-gate static int create_table_entry(picl_prophdl_t tblhdl,
3780Sstevel@tonic-gate     picl_nodehdl_t refhdl, char *class);
3790Sstevel@tonic-gate static int create_i2c_node(char *ap_id);
3800Sstevel@tonic-gate static void delete_i2c_node(char *ap_id);
3810Sstevel@tonic-gate static int set_led(char *name, char *ptr, char *value);
3820Sstevel@tonic-gate static int ps_name_to_addr(char *name);
3830Sstevel@tonic-gate static char *ps_name_to_unitaddr(char *name);
3840Sstevel@tonic-gate static char *ps_apid_to_nodename(char *apid);
3850Sstevel@tonic-gate static void add_op_status(envmon_hpu_t *hpu, int *index);
3862606Svenki static void get_fantray_path(char *ap_id, char *path, int bufsz);
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate #define	sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2)
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate /*
3910Sstevel@tonic-gate  * Because this plugin is shared across different platforms, we need to
3920Sstevel@tonic-gate  * distinguish for certain functionality
3930Sstevel@tonic-gate  */
3940Sstevel@tonic-gate #define	PLAT_UNKNOWN	(-1)
3950Sstevel@tonic-gate #define	PLAT_ENXS	0
3960Sstevel@tonic-gate #define	PLAT_ENTS	1
3970Sstevel@tonic-gate #define	PLAT_CHALUPA	2
3980Sstevel@tonic-gate #define	PLAT_EN19	3
3990Sstevel@tonic-gate #define	PLAT_CHALUPA19	4
4000Sstevel@tonic-gate #define	PLAT_SALSA19	5
4011103Sjbeloro #define	PLAT_SEATTLE1U	6
4021103Sjbeloro #define	PLAT_SEATTLE2U	7
4031103Sjbeloro #define	PLAT_BOSTON	8
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate static int sys_platform;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate static void
get_platform()4080Sstevel@tonic-gate get_platform()
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate 	char	platform[64];
4110Sstevel@tonic-gate 	(void) sysinfo(SI_PLATFORM, platform, sizeof (platform));
4120Sstevel@tonic-gate 	if (strcmp(platform, "SUNW,Sun-Fire-V250") == 0)
4130Sstevel@tonic-gate 		sys_platform = PLAT_ENTS;
4140Sstevel@tonic-gate 	else if (strcmp(platform, "SUNW,Sun-Fire-V440") == 0)
4150Sstevel@tonic-gate 		sys_platform = PLAT_CHALUPA;
4160Sstevel@tonic-gate 	else if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0)
4170Sstevel@tonic-gate 		sys_platform = PLAT_ENXS;
4180Sstevel@tonic-gate 	else if (strcmp(platform, "SUNW,Sun-Fire-V240") == 0)
4190Sstevel@tonic-gate 		sys_platform = PLAT_ENXS;
4200Sstevel@tonic-gate 	else if (strcmp(platform, "SUNW,Netra-240") == 0)
4210Sstevel@tonic-gate 		sys_platform = PLAT_EN19;
4220Sstevel@tonic-gate 	else if (strcmp(platform, "SUNW,Netra-210") == 0)
4230Sstevel@tonic-gate 		sys_platform = PLAT_SALSA19;
4240Sstevel@tonic-gate 	else if (strcmp(platform, "SUNW,Netra-440") == 0)
4250Sstevel@tonic-gate 		sys_platform = PLAT_CHALUPA19;
4261103Sjbeloro 	else if (strcmp(platform, "SUNW,Sun-Fire-V215") == 0)
4271103Sjbeloro 		sys_platform = PLAT_SEATTLE1U;
4281103Sjbeloro 	else if (strcmp(platform, "SUNW,Sun-Fire-V245") == 0)
4291103Sjbeloro 		sys_platform = PLAT_SEATTLE2U;
4301103Sjbeloro 	else if (strcmp(platform, "SUNW,Sun-Fire-V445") == 0)
4311103Sjbeloro 		sys_platform = PLAT_BOSTON;
4320Sstevel@tonic-gate 	else
4330Sstevel@tonic-gate 		sys_platform = PLAT_UNKNOWN;
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate /*
4370Sstevel@tonic-gate  * This function is executed as part of .init when the plugin is
4380Sstevel@tonic-gate  * dlopen()ed
4390Sstevel@tonic-gate  */
4400Sstevel@tonic-gate static void
piclfrudr_register(void)4410Sstevel@tonic-gate piclfrudr_register(void)
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate 	(void) picld_plugin_register(&my_reg_info);
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate  * This function is the init entry point of the plugin.
4480Sstevel@tonic-gate  * It initializes the /frutree tree
4490Sstevel@tonic-gate  */
4500Sstevel@tonic-gate static void
piclfrudr_init(void)4510Sstevel@tonic-gate piclfrudr_init(void)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	picl_nodehdl_t	sc_nodeh;
4540Sstevel@tonic-gate 	picl_nodehdl_t	locationh;
4550Sstevel@tonic-gate 	picl_nodehdl_t	childh;
4560Sstevel@tonic-gate 	char namebuf[PATH_MAX];
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	get_platform();
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (sc_device_name != NULL) {
4610Sstevel@tonic-gate 		free(sc_device_name);	/* must have reen restarted */
4620Sstevel@tonic-gate 		sc_device_name = NULL;
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	if ((get_sys_controller_node(&sc_nodeh) != PICL_SUCCESS) ||
4660Sstevel@tonic-gate 	    ((sc_device_name = create_sys_controller_pathname(sc_nodeh)) ==
4670Sstevel@tonic-gate 	    NULL))
4680Sstevel@tonic-gate 		syslog(LOG_ERR, EM_NO_SC_DEV);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	opst_init();
4710Sstevel@tonic-gate 	disk_leds_init();
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	(void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
4740Sstevel@tonic-gate 	    frudr_evhandler, NULL);
4750Sstevel@tonic-gate 	(void) ptree_register_handler(PICL_FRU_ADDED, fru_add_handler, NULL);
4760Sstevel@tonic-gate 	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
4770Sstevel@tonic-gate 	    frutree_evhandler, NULL);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	/*
4800Sstevel@tonic-gate 	 * There is a window of opportunity for the RMC to deliver an event
4810Sstevel@tonic-gate 	 * indicating a newly operable state just before we are listening for
4820Sstevel@tonic-gate 	 * it. In this case, envmon will have missed setting up /platform
4830Sstevel@tonic-gate 	 * and won't get a signal from frudr. So send it a PICL_FRU_ADDED just
4840Sstevel@tonic-gate 	 * in case.
4850Sstevel@tonic-gate 	 */
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	if ((sys_platform == PLAT_CHALUPA) ||
488*12601SJustin.Frank@Sun.COM 	    (sys_platform == PLAT_CHALUPA19)) {
4890Sstevel@tonic-gate 		sprintf_buf2(namebuf, CHASSIS_LOC_PATH, RMC_NAME);
4900Sstevel@tonic-gate 	} else {
4910Sstevel@tonic-gate 		sprintf_buf2(namebuf, SYS_BOARD_PATH, RMC_NAME);
4920Sstevel@tonic-gate 	}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	if (ptree_get_node_by_path(namebuf, &locationh) != PICL_SUCCESS)
4950Sstevel@tonic-gate 		return;
4960Sstevel@tonic-gate 	if (ptree_get_propval_by_name(locationh, PICL_PROP_CHILD,
4970Sstevel@tonic-gate 	    &childh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
4980Sstevel@tonic-gate 		return;
4990Sstevel@tonic-gate 	post_frudr_event(PICL_FRU_ADDED, locationh, childh);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate static void
add_op_status_by_name(const char * name,const char * child_name,picl_prophdl_t * prophdl_p)5030Sstevel@tonic-gate add_op_status_by_name(const char *name, const char *child_name,
5040Sstevel@tonic-gate     picl_prophdl_t *prophdl_p)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate 	picl_nodehdl_t		nodeh;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	if (ptree_get_node_by_path(name, &nodeh) != PICL_SUCCESS) {
5090Sstevel@tonic-gate 		return;
5100Sstevel@tonic-gate 	}
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	if (ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD,
5130Sstevel@tonic-gate 	    &nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) {
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 		if (child_name == NULL)
5160Sstevel@tonic-gate 			return;
5170Sstevel@tonic-gate 		/*
5180Sstevel@tonic-gate 		 * create fru node of supplied name
5190Sstevel@tonic-gate 		 */
5200Sstevel@tonic-gate 		if (ptree_create_and_add_node(nodeh, child_name,
5210Sstevel@tonic-gate 		    PICL_CLASS_FRU, &nodeh) != PICL_SUCCESS)
5220Sstevel@tonic-gate 			return;
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	add_op_status_to_node(nodeh, prophdl_p);
5260Sstevel@tonic-gate }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate /*
5290Sstevel@tonic-gate  * function to add a volatile property to a specified node
5300Sstevel@tonic-gate  */
5310Sstevel@tonic-gate static void
add_op_status_to_node(picl_nodehdl_t nodeh,picl_prophdl_t * prophdl_p)5320Sstevel@tonic-gate add_op_status_to_node(picl_nodehdl_t nodeh, picl_prophdl_t *prophdl_p)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate 	int			err;
5350Sstevel@tonic-gate 	ptree_propinfo_t	info;
5360Sstevel@tonic-gate 	picl_prophdl_t		proph;
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	err = ptree_init_propinfo(&info, PTREE_PROPINFO_VERSION,
5390Sstevel@tonic-gate 	    PICL_PTYPE_CHARSTRING, PICL_VOLATILE | PICL_READ, max_opst_len,
5400Sstevel@tonic-gate 	    PICL_PROP_OPERATIONAL_STATUS, read_vol_data, NULL);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	if (err == PICL_SUCCESS) {
5430Sstevel@tonic-gate 		if (ptree_get_prop_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
5440Sstevel@tonic-gate 		    &proph) == PICL_SUCCESS) {
5450Sstevel@tonic-gate 			if (ptree_delete_prop(proph) == PICL_SUCCESS)
5460Sstevel@tonic-gate 				err = ptree_destroy_prop(proph);
5470Sstevel@tonic-gate 		}
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	if ((err != PICL_SUCCESS) || ((err = ptree_create_and_add_prop(nodeh,
5510Sstevel@tonic-gate 	    &info, NULL, prophdl_p)) != PICL_SUCCESS)) {
5520Sstevel@tonic-gate 		syslog(LOG_ERR, ADD_PROP_FAIL, PICL_PROP_OPERATIONAL_STATUS,
5530Sstevel@tonic-gate 		    err);
5540Sstevel@tonic-gate 		return;
5550Sstevel@tonic-gate 	}
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate /*
5590Sstevel@tonic-gate  * Deliver volatile property value.
5600Sstevel@tonic-gate  * prtpicl gets very upset if we fail this command, so if the property
5610Sstevel@tonic-gate  * cannot be retrieved, return a status of unknown.
5620Sstevel@tonic-gate  */
5630Sstevel@tonic-gate static int
read_vol_data(ptree_rarg_t * r_arg,void * buf)5640Sstevel@tonic-gate read_vol_data(ptree_rarg_t *r_arg, void *buf)
5650Sstevel@tonic-gate {
5660Sstevel@tonic-gate 	picl_prophdl_t	proph;
5670Sstevel@tonic-gate 	int		index;
5680Sstevel@tonic-gate 	int		envmon_fd;
5690Sstevel@tonic-gate 	int		err;
5700Sstevel@tonic-gate 	envmon_hpu_t	data;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	proph = r_arg->proph;
5730Sstevel@tonic-gate 	index = find_picl_handle(proph);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (index < 0) {
5760Sstevel@tonic-gate 		/*
5770Sstevel@tonic-gate 		 * We drop memory of PSU op status handles in opst_init()
5780Sstevel@tonic-gate 		 * when we get an RMC faulty event. We cannot access the
5790Sstevel@tonic-gate 		 * status info in this circumstance, so returning "unknown"
5800Sstevel@tonic-gate 		 * is appropriate.
5810Sstevel@tonic-gate 		 */
5820Sstevel@tonic-gate 		(void) strlcpy(buf, str_opst_unknown, max_opst_len);
5830Sstevel@tonic-gate 		return (PICL_SUCCESS);
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	envmon_fd = open(sc_device_name, O_RDONLY);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	if (envmon_fd < 0) {
5890Sstevel@tonic-gate 		/*
5900Sstevel@tonic-gate 		 * To get this far we must have succeeded with an earlier
5910Sstevel@tonic-gate 		 * open, so this is an unlikely failure. It would be more
5920Sstevel@tonic-gate 		 * helpful to indicate the nature of the failure, but we
5930Sstevel@tonic-gate 		 * don't have the space to say much. Just return "unknown".
5940Sstevel@tonic-gate 		 */
5950Sstevel@tonic-gate 		(void) strlcpy(buf, str_opst_unknown, max_opst_len);
5960Sstevel@tonic-gate 		return (PICL_SUCCESS);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	data.id = idprop->idp[index].envhandle;
6000Sstevel@tonic-gate 	err = ioctl(envmon_fd, ENVMONIOCHPU, &data);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if (err < 0) {
6030Sstevel@tonic-gate 		/*
6040Sstevel@tonic-gate 		 * If we can't read the stats, "unknown" is a reasonable
6050Sstevel@tonic-gate 		 * status to return. This one really shouldn't happen.
6060Sstevel@tonic-gate 		 */
6070Sstevel@tonic-gate 		(void) strlcpy(buf, str_opst_unknown, max_opst_len);
6080Sstevel@tonic-gate 		(void) close(envmon_fd);
6090Sstevel@tonic-gate 		return (PICL_SUCCESS);
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	(void) close(envmon_fd);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	if (strncmp(data.id.name, DISK_NAME, DISK_NAME_LEN) == 0 &&
6150Sstevel@tonic-gate 	    data.fru_status == ENVMON_FRU_PRESENT) {
6160Sstevel@tonic-gate 		(void) strlcpy(buf, str_opst_present, max_opst_len);
6170Sstevel@tonic-gate 		return (PICL_SUCCESS);
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (data.sensor_status != ENVMON_SENSOR_OK) {
6210Sstevel@tonic-gate 		(void) strlcpy(buf, str_opst_unknown, max_opst_len);
6220Sstevel@tonic-gate 		return (PICL_SUCCESS);
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	(void) strlcpy(buf,
6260Sstevel@tonic-gate 	    data.fru_status == ENVMON_FRU_PRESENT ? str_opst_ok :
6270Sstevel@tonic-gate 	    data.fru_status == ENVMON_FRU_DOWNLOAD ? str_opst_download :
6280Sstevel@tonic-gate 	    data.fru_status == ENVMON_FRU_FAULT ? str_opst_faulty :
6290Sstevel@tonic-gate 	    str_opst_unknown, max_opst_len);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	return (PICL_SUCCESS);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate /*
6350Sstevel@tonic-gate  * Function for explicitly turning on system leds
6360Sstevel@tonic-gate  * for a failed/degraded RMC (SC).
6370Sstevel@tonic-gate  */
6380Sstevel@tonic-gate static void
solaris_setleds(const char * led_path,int leds)6390Sstevel@tonic-gate solaris_setleds(const char *led_path, int leds)
6400Sstevel@tonic-gate {
6410Sstevel@tonic-gate 	i2c_gpio_t	gpio;
6420Sstevel@tonic-gate 	int		fd = open(led_path, O_RDWR);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (fd < 0)
6450Sstevel@tonic-gate 		return;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	gpio.reg_val = (leds ^ 0xff);
6480Sstevel@tonic-gate 	gpio.reg_mask = 0xffffffff;
6490Sstevel@tonic-gate 	if (ioctl(fd, GPIO_SET_CONFIG, &gpio) == 0) {
6500Sstevel@tonic-gate 		gpio.reg_val = (leds ^ 0xff);
6510Sstevel@tonic-gate 		gpio.reg_mask = 0xffffffff;
6520Sstevel@tonic-gate 		(void) ioctl(fd, GPIO_SET_OUTPUT, &gpio);
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 	(void) close(fd);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate 
6571103Sjbeloro /*
6581103Sjbeloro  * Function for explicitly turning on system leds
6591103Sjbeloro  * for a failed/degraded RMC (SC) on Seattle
6601103Sjbeloro  */
6611103Sjbeloro static void
seattle_setleds(void)6621103Sjbeloro seattle_setleds(void)
6631103Sjbeloro {
6641103Sjbeloro 	int fd;
6651103Sjbeloro 
6661103Sjbeloro 	fd = open(SEATTLE_LED_DEV, O_RDWR);
6671103Sjbeloro 
6681103Sjbeloro 	if (fd < 0)
6691103Sjbeloro 		return;
6701103Sjbeloro 
6711103Sjbeloro 	ioctl(fd, EPIC_SET_POWER_LED, (char *)0);
6721103Sjbeloro 	ioctl(fd, EPIC_SET_ALERT_LED, (char *)0);
6731103Sjbeloro 	(void) close(fd);
6741103Sjbeloro }
6751103Sjbeloro 
6761103Sjbeloro /*
6771103Sjbeloro  * Function for explicitly turning on the front system leds
6781103Sjbeloro  * for a failed/degraded RMC (SC) on Boston
6791103Sjbeloro  */
6801103Sjbeloro static void
boston_set_frontleds(const char * led_path,int leds)6811103Sjbeloro boston_set_frontleds(const char *led_path, int leds)
6821103Sjbeloro {
6831103Sjbeloro 	i2c_gpio_t	gpio;
6841103Sjbeloro 	int		fd = open(led_path, O_RDWR);
6851103Sjbeloro 
6861103Sjbeloro 	if (fd < 0) {
6871103Sjbeloro 		return;
6881103Sjbeloro 	}
6891103Sjbeloro 
6901103Sjbeloro 	/* first clear the polarity */
6911103Sjbeloro 	gpio.reg_val  = BOSTON_FRONT_CLEAR_POL;
6921103Sjbeloro 	gpio.reg_mask = BOSTON_FRONT_LED_MASK;
6931103Sjbeloro 	if (ioctl(fd, GPIO_SET_POLARITY, &gpio) < 0)	{
6941103Sjbeloro 		(void) close(fd);
6951103Sjbeloro 		return;
6961103Sjbeloro 	}
6971103Sjbeloro 
6981103Sjbeloro 	/* now clear the direction */
6991103Sjbeloro 	gpio.reg_val  = BOSTON_FRONT_CLEAR_DIR;
7001103Sjbeloro 	gpio.reg_mask = BOSTON_FRONT_LED_MASK;
7011103Sjbeloro 	if (ioctl(fd, GPIO_SET_CONFIG, &gpio) < 0)	{
7021103Sjbeloro 		(void) close(fd);
7031103Sjbeloro 		return;
7041103Sjbeloro 	}
7051103Sjbeloro 
7061103Sjbeloro 	/* and light the leds */
7071103Sjbeloro 	gpio.reg_val = leds;
7081103Sjbeloro 	gpio.reg_mask = BOSTON_FRONT_LED_MASK;
7091103Sjbeloro 	ioctl(fd, GPIO_SET_OUTPUT, &gpio);
7101103Sjbeloro 	(void) close(fd);
7111103Sjbeloro }
7121103Sjbeloro 
7131103Sjbeloro /*
7141103Sjbeloro  * Function for explicitly turning on the rear system leds
7151103Sjbeloro  * for a failed/degraded RMC (SC) on Boston
7161103Sjbeloro  */
7171103Sjbeloro static void
boston_set_rearleds(const char * led_path,int leds)7181103Sjbeloro boston_set_rearleds(const char *led_path, int leds)
7191103Sjbeloro {
7201103Sjbeloro 	i2c_gpio_t	gpio;
7211103Sjbeloro 	int		fd = open(led_path, O_RDWR);
7221103Sjbeloro 
7231103Sjbeloro 	if (fd < 0) {
7241103Sjbeloro 		return;
7251103Sjbeloro 	}
7261103Sjbeloro 
7271103Sjbeloro 	/* first clear the polarity */
7281103Sjbeloro 	gpio.reg_val  = BOSTON_REAR_CLEAR_POL;
7291103Sjbeloro 	gpio.reg_mask = BOSTON_REAR_LED_MASK;
7301103Sjbeloro 	if (ioctl(fd, GPIO_SET_POLARITY, &gpio) < 0)	{
7311103Sjbeloro 		(void) close(fd);
7321103Sjbeloro 		return;
7331103Sjbeloro 	}
7341103Sjbeloro 
7351103Sjbeloro 	/* now set the direction */
7361103Sjbeloro 	gpio.reg_val  = BOSTON_REAR_LED_MASK;
7371103Sjbeloro 	gpio.reg_mask = BOSTON_REAR_LED_MASK;
7381103Sjbeloro 	if (ioctl(fd, GPIO_SET_CONFIG, &gpio) < 0)	{
7391103Sjbeloro 		(void) close(fd);
7401103Sjbeloro 		return;
7411103Sjbeloro 	}
7421103Sjbeloro 
7431103Sjbeloro 	/* and light the leds */
7441103Sjbeloro 	gpio.reg_val = leds;
7451103Sjbeloro 	gpio.reg_mask = BOSTON_REAR_LED_MASK;
7461103Sjbeloro 	ioctl(fd, GPIO_SET_OUTPUT, &gpio);
7471103Sjbeloro 	(void) close(fd);
7481103Sjbeloro }
7491103Sjbeloro 
7500Sstevel@tonic-gate static void
rmc_state_event(void)7510Sstevel@tonic-gate rmc_state_event(void)
7520Sstevel@tonic-gate {
7530Sstevel@tonic-gate 	envmon_hpu_t	hpu;
7540Sstevel@tonic-gate 	int		res;
7550Sstevel@tonic-gate 	int		fd = open(sc_device_name, O_RDONLY);
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	if (fd < 0)
7580Sstevel@tonic-gate 		return;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	(void) strlcpy(hpu.id.name, RMC_NAME, sizeof (hpu.id.name));
7610Sstevel@tonic-gate 	res = ioctl(fd, ENVMONIOCHPU, &hpu);
7620Sstevel@tonic-gate 	(void) close(fd);
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	if ((res == 0) && (hpu.sensor_status == ENVMON_SENSOR_OK) &&
7650Sstevel@tonic-gate 	    ((hpu.fru_status & ENVMON_FRU_FAULT) != 0)) {
7660Sstevel@tonic-gate 		/*
7670Sstevel@tonic-gate 		 * SC failed event - light the service led
7680Sstevel@tonic-gate 		 * note that as Solaris is still running,
7690Sstevel@tonic-gate 		 * the Solaris active led should be lit too.
7700Sstevel@tonic-gate 		 */
7710Sstevel@tonic-gate 		switch (sys_platform) {
7720Sstevel@tonic-gate 		case PLAT_ENXS:
7730Sstevel@tonic-gate 		case PLAT_SALSA19:
7740Sstevel@tonic-gate 		case PLAT_EN19:
7750Sstevel@tonic-gate 			solaris_setleds(ENXS_REAR_LEDS,
7760Sstevel@tonic-gate 			    ENXS_REAR_SRVC_LED | ENXS_REAR_ACT_LED);
7770Sstevel@tonic-gate 			/*
7780Sstevel@tonic-gate 			 * the device name for the bezel leds GPIO device
7790Sstevel@tonic-gate 			 * tends to vary from Unix to Unix. Search for it.
7800Sstevel@tonic-gate 			 */
7810Sstevel@tonic-gate 			if (bezel_leds  == NULL) {
7820Sstevel@tonic-gate 				bezel_leds =
7830Sstevel@tonic-gate 				    create_bezel_leds_pathname(ENXS_LED_DIR,
7840Sstevel@tonic-gate 				    ENXS_FRONT_LEDS);
7850Sstevel@tonic-gate 			}
7860Sstevel@tonic-gate 			if (bezel_leds == NULL)
7870Sstevel@tonic-gate 				return;
7880Sstevel@tonic-gate 			solaris_setleds(bezel_leds,
7890Sstevel@tonic-gate 			    ENXS_FRONT_SRVC_LED | ENXS_FRONT_ACT_LED);
7900Sstevel@tonic-gate 			break;
7910Sstevel@tonic-gate 		case PLAT_ENTS:
7920Sstevel@tonic-gate 			/*
7930Sstevel@tonic-gate 			 * the device name for the system leds gpio can vary
7940Sstevel@tonic-gate 			 * as there are several similar gpio devices. Search
7950Sstevel@tonic-gate 			 * for one with the desired address.
7960Sstevel@tonic-gate 			 */
7970Sstevel@tonic-gate 			if (bezel_leds  == NULL) {
7980Sstevel@tonic-gate 				bezel_leds =
7990Sstevel@tonic-gate 				    create_bezel_leds_pathname(ENTS_LED_DIR,
8000Sstevel@tonic-gate 				    ENTS_LEDS);
8010Sstevel@tonic-gate 			}
8020Sstevel@tonic-gate 			if (bezel_leds == NULL)
8030Sstevel@tonic-gate 				return;
8040Sstevel@tonic-gate 			solaris_setleds(bezel_leds,
8050Sstevel@tonic-gate 			    ENTS_SRVC_LED | ENTS_ACT_LED);
8060Sstevel@tonic-gate 			break;
8070Sstevel@tonic-gate 		case PLAT_CHALUPA:
8080Sstevel@tonic-gate 		case PLAT_CHALUPA19:
8090Sstevel@tonic-gate 			solaris_setleds(V440_LED_PATH,
8100Sstevel@tonic-gate 			    V440_SRVC_LED | V440_ACT_LED);
8110Sstevel@tonic-gate 			break;
8121103Sjbeloro 		case PLAT_BOSTON:
8131103Sjbeloro 			/* set front leds */
8141103Sjbeloro 			boston_set_frontleds(BOSTON_FRONT_LED_PATH,
8151103Sjbeloro 			    BOSTON_FRONT_SRVC_LED | BOSTON_FRONT_ACT_LED);
8161103Sjbeloro 			/* and then the rear leds */
8171103Sjbeloro 			boston_set_rearleds(BOSTON_REAR_LED_PATH,
8181103Sjbeloro 			    BOSTON_REAR_SRVC_LED | BOSTON_REAR_ACT_LED);
8191103Sjbeloro 			break;
8201103Sjbeloro 		case PLAT_SEATTLE1U:
8211103Sjbeloro 		case PLAT_SEATTLE2U:
8221103Sjbeloro 			seattle_setleds();
8231103Sjbeloro 			break;
8240Sstevel@tonic-gate 		default:
8250Sstevel@tonic-gate 			break;
8260Sstevel@tonic-gate 		}
8270Sstevel@tonic-gate 	}
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate static int
find_picl_handle(picl_prophdl_t proph)8310Sstevel@tonic-gate find_picl_handle(picl_prophdl_t proph)
8320Sstevel@tonic-gate {
8330Sstevel@tonic-gate 	int index;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	if (idprop == NULL)
8360Sstevel@tonic-gate 		return (-1);
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	for (index = 0; index < idprop->num; index++) {
8390Sstevel@tonic-gate 		if (idprop->idp[index].volprop == proph)
8400Sstevel@tonic-gate 			return (index);
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	return (-1);
8440Sstevel@tonic-gate }
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate static int
find_vol_prop_by_name(const char * name)8470Sstevel@tonic-gate find_vol_prop_by_name(const char *name)
8480Sstevel@tonic-gate {
8490Sstevel@tonic-gate 	int index;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	if (idprop == NULL)
8520Sstevel@tonic-gate 		return (-1);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	for (index = 0; index < idprop->num; index++) {
8550Sstevel@tonic-gate 		if (strcmp(idprop->idp[index].envhandle.name, name) == 0)
8560Sstevel@tonic-gate 			return (index);
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	return (-1);
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate  * This function is the fini entry point of the plugin.
8640Sstevel@tonic-gate  */
8650Sstevel@tonic-gate static void
piclfrudr_fini(void)8660Sstevel@tonic-gate piclfrudr_fini(void)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate 	(void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
8690Sstevel@tonic-gate 	    frudr_evhandler, NULL);
8700Sstevel@tonic-gate 	(void) ptree_unregister_handler(PICL_FRU_ADDED, fru_add_handler,
8710Sstevel@tonic-gate 	    NULL);
8720Sstevel@tonic-gate 	disk_leds_fini();
8730Sstevel@tonic-gate 	if (idprop != NULL) {
8740Sstevel@tonic-gate 		free(idprop);
8750Sstevel@tonic-gate 		idprop = NULL;
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 	if (sc_device_name != NULL) {
8780Sstevel@tonic-gate 		free(sc_device_name);
8790Sstevel@tonic-gate 		sc_device_name = NULL;
8800Sstevel@tonic-gate 	}
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate /*
8840Sstevel@tonic-gate  * subroutine for various functions. Finds immediate child of parh with
8850Sstevel@tonic-gate  * requested name if present. Otherwise returns NULL.
8860Sstevel@tonic-gate  */
8870Sstevel@tonic-gate static picl_nodehdl_t
find_child_by_name(picl_nodehdl_t parh,char * name)8880Sstevel@tonic-gate find_child_by_name(picl_nodehdl_t parh, char *name)
8890Sstevel@tonic-gate {
8900Sstevel@tonic-gate 	picl_nodehdl_t nodeh;
8910Sstevel@tonic-gate 	int err;
8920Sstevel@tonic-gate 	char	nodename[PICL_PROPNAMELEN_MAX];
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	err = ptree_get_propval_by_name(parh, PICL_PROP_CHILD,
8950Sstevel@tonic-gate 	    &nodeh, sizeof (picl_nodehdl_t));
8960Sstevel@tonic-gate 	if (err != PICL_SUCCESS)
8970Sstevel@tonic-gate 		return (NULL);
8980Sstevel@tonic-gate 	for (;;) {
8990Sstevel@tonic-gate 		err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename,
9000Sstevel@tonic-gate 		    sizeof (nodename));
9010Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
9020Sstevel@tonic-gate 			return (NULL);
9030Sstevel@tonic-gate 		if (strcmp(name, nodename) == 0) {
9040Sstevel@tonic-gate 			return (nodeh);
9050Sstevel@tonic-gate 		}
9060Sstevel@tonic-gate 		err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
9070Sstevel@tonic-gate 		    &nodeh, sizeof (picl_nodehdl_t));
9080Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
9090Sstevel@tonic-gate 			return (NULL);
9100Sstevel@tonic-gate 	}
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate /* Creates a reference property for a given PICL node */
9140Sstevel@tonic-gate static int
add_prop_ref(picl_nodehdl_t nodeh,picl_nodehdl_t value,char * name)9150Sstevel@tonic-gate add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	picl_prophdl_t proph;
9180Sstevel@tonic-gate 	ptree_propinfo_t propinfo;
9190Sstevel@tonic-gate 	int err;
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
9220Sstevel@tonic-gate 	    PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), name,
9230Sstevel@tonic-gate 	    NULL, NULL);
9240Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
9250Sstevel@tonic-gate 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
9260Sstevel@tonic-gate 		return (err);
9270Sstevel@tonic-gate 	}
9280Sstevel@tonic-gate 	err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
9290Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
9300Sstevel@tonic-gate 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
9310Sstevel@tonic-gate 		return (err);
9320Sstevel@tonic-gate 	}
9330Sstevel@tonic-gate 	return (PICL_SUCCESS);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate /* create an entry in the specified table */
9370Sstevel@tonic-gate static int
create_table_entry(picl_prophdl_t tblhdl,picl_nodehdl_t refhdl,char * class)9380Sstevel@tonic-gate create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
9390Sstevel@tonic-gate {
9400Sstevel@tonic-gate 	int			err;
9410Sstevel@tonic-gate 	ptree_propinfo_t	prop;
9420Sstevel@tonic-gate 	picl_prophdl_t		prophdl[2];
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 	/* first column is class */
9450Sstevel@tonic-gate 	prop.version = PTREE_PROPINFO_VERSION;
9460Sstevel@tonic-gate 	prop.piclinfo.type =  PICL_PTYPE_CHARSTRING;
9470Sstevel@tonic-gate 	prop.piclinfo.accessmode = PICL_READ;
9480Sstevel@tonic-gate 	prop.piclinfo.size = PICL_CLASSNAMELEN_MAX;
9490Sstevel@tonic-gate 	prop.read = NULL;
9500Sstevel@tonic-gate 	prop.write = NULL;
9510Sstevel@tonic-gate 	(void) strlcpy(prop.piclinfo.name, PICL_PROP_CLASS,
9520Sstevel@tonic-gate 	    sizeof (prop.piclinfo.name));
9530Sstevel@tonic-gate 	err = ptree_create_prop(&prop, class, &prophdl[0]);
9540Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
9550Sstevel@tonic-gate 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
9560Sstevel@tonic-gate 		return (err);
9570Sstevel@tonic-gate 	}
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/* second column is reference property */
9600Sstevel@tonic-gate 	prop.version = PTREE_PROPINFO_VERSION;
9610Sstevel@tonic-gate 	prop.piclinfo.type =  PICL_PTYPE_REFERENCE;
9620Sstevel@tonic-gate 	prop.piclinfo.accessmode = PICL_READ;
9630Sstevel@tonic-gate 	prop.piclinfo.size = sizeof (picl_nodehdl_t);
9640Sstevel@tonic-gate 	prop.read = NULL;
9650Sstevel@tonic-gate 	prop.write = NULL;
9660Sstevel@tonic-gate 	sprintf_buf2(prop.piclinfo.name, "_%s_", class);
9670Sstevel@tonic-gate 	err = ptree_create_prop(&prop, &refhdl, &prophdl[1]);
9680Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
9690Sstevel@tonic-gate 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
9700Sstevel@tonic-gate 		return (err);
9710Sstevel@tonic-gate 	}
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	/* add row to table */
9740Sstevel@tonic-gate 	err = ptree_add_row_to_table(tblhdl, 2, prophdl);
9750Sstevel@tonic-gate 	if (err != PICL_SUCCESS)
9760Sstevel@tonic-gate 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
9770Sstevel@tonic-gate 	return (err);
9780Sstevel@tonic-gate }
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate /* create an empty table property */
9810Sstevel@tonic-gate static int
create_table(picl_nodehdl_t fruhdl,picl_prophdl_t * tblhdlp,char * tbl_name)9820Sstevel@tonic-gate create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name)
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate 	int			err;
9850Sstevel@tonic-gate 	ptree_propinfo_t	prop;
9860Sstevel@tonic-gate 	picl_prophdl_t		tblprophdl;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	err = ptree_create_table(tblhdlp);
9890Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
9900Sstevel@tonic-gate 		syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
9910Sstevel@tonic-gate 		return (err);
9920Sstevel@tonic-gate 	}
9930Sstevel@tonic-gate 	prop.version = PTREE_PROPINFO_VERSION;
9940Sstevel@tonic-gate 	prop.piclinfo.type =  PICL_PTYPE_TABLE;
9950Sstevel@tonic-gate 	prop.piclinfo.accessmode = PICL_READ;
9960Sstevel@tonic-gate 	prop.piclinfo.size = sizeof (picl_prophdl_t);
9970Sstevel@tonic-gate 	prop.read = NULL;
9980Sstevel@tonic-gate 	prop.write = NULL;
9990Sstevel@tonic-gate 	(void) strlcpy(prop.piclinfo.name, tbl_name,
10000Sstevel@tonic-gate 	    sizeof (prop.piclinfo.name));
10010Sstevel@tonic-gate 	err = ptree_create_and_add_prop(fruhdl, &prop, tblhdlp, &tblprophdl);
10020Sstevel@tonic-gate 	if (err != PICL_SUCCESS)
10030Sstevel@tonic-gate 		syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
10040Sstevel@tonic-gate 	return (err);
10050Sstevel@tonic-gate }
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate /*
10080Sstevel@tonic-gate  * The size of outfilename must be PATH_MAX
10090Sstevel@tonic-gate  */
10100Sstevel@tonic-gate static int
get_config_file(char * outfilename,char * fru)10110Sstevel@tonic-gate get_config_file(char *outfilename, char *fru)
10120Sstevel@tonic-gate {
10130Sstevel@tonic-gate 	char		nmbuf[SYS_NMLN];
10140Sstevel@tonic-gate 	char		pname[PATH_MAX];
10150Sstevel@tonic-gate 	int		dir;
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	for (dir = 0; dir < 2; dir++) {
10180Sstevel@tonic-gate 		if (sysinfo(dir == 0 ? SI_PLATFORM : SI_MACHINE,
10190Sstevel@tonic-gate 		    nmbuf, sizeof (nmbuf)) == -1) {
10200Sstevel@tonic-gate 			continue;
10210Sstevel@tonic-gate 		}
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 		(void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf);
10240Sstevel@tonic-gate 		(void) strlcat(pname, CONFFILE_PREFIX, PATH_MAX);
10250Sstevel@tonic-gate 		(void) strlcat(pname, fru, PATH_MAX);
10260Sstevel@tonic-gate 		(void) strlcat(pname, CONFFILE_SUFFIX, PATH_MAX);
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 		if (access(pname, R_OK) == 0) {
10290Sstevel@tonic-gate 			(void) strlcpy(outfilename, pname, PATH_MAX);
10300Sstevel@tonic-gate 			return (0);
10310Sstevel@tonic-gate 		}
10320Sstevel@tonic-gate 	}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	(void) snprintf(pname, PATH_MAX, "%s/%s%s%s",
10350Sstevel@tonic-gate 	    PICLD_COMMON_PLUGIN_DIR, CONFFILE_PREFIX, fru,
10360Sstevel@tonic-gate 	    CONFFILE_SUFFIX);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	if (access(pname, R_OK) == 0) {
10390Sstevel@tonic-gate 		(void) strlcpy(outfilename, pname, PATH_MAX);
10400Sstevel@tonic-gate 		return (0);
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	return (-1);
10440Sstevel@tonic-gate }
10450Sstevel@tonic-gate 
1046*12601SJustin.Frank@Sun.COM /*
1047*12601SJustin.Frank@Sun.COM  * This helper function for Netra-440 fan tray removal removes
1048*12601SJustin.Frank@Sun.COM  * the rmclomv-rooted nodes and their properties.
1049*12601SJustin.Frank@Sun.COM  */
1050*12601SJustin.Frank@Sun.COM static void
delete_node_and_props(picl_nodehdl_t hdl)1051*12601SJustin.Frank@Sun.COM delete_node_and_props(picl_nodehdl_t hdl)
1052*12601SJustin.Frank@Sun.COM {
1053*12601SJustin.Frank@Sun.COM 	picl_prophdl_t prop;
1054*12601SJustin.Frank@Sun.COM 	int err;
1055*12601SJustin.Frank@Sun.COM 
1056*12601SJustin.Frank@Sun.COM 	do {
1057*12601SJustin.Frank@Sun.COM 		err = ptree_get_first_prop(hdl, &prop);
1058*12601SJustin.Frank@Sun.COM 		if (err == PICL_SUCCESS) {
1059*12601SJustin.Frank@Sun.COM 			if (ptree_delete_prop(prop) == PICL_SUCCESS)
1060*12601SJustin.Frank@Sun.COM 				(void) ptree_destroy_prop(prop);
1061*12601SJustin.Frank@Sun.COM 		}
1062*12601SJustin.Frank@Sun.COM 	} while (err == PICL_SUCCESS);
1063*12601SJustin.Frank@Sun.COM 	if (ptree_delete_node(hdl) == PICL_SUCCESS)
1064*12601SJustin.Frank@Sun.COM 		(void) ptree_destroy_node(hdl);
1065*12601SJustin.Frank@Sun.COM }
1066*12601SJustin.Frank@Sun.COM 
10670Sstevel@tonic-gate static void
remove_fru_parents(picl_nodehdl_t fruh)10680Sstevel@tonic-gate remove_fru_parents(picl_nodehdl_t fruh)
10690Sstevel@tonic-gate {
10700Sstevel@tonic-gate 	char			name[MAXPATHLEN];
10710Sstevel@tonic-gate 	int			retval;
10720Sstevel@tonic-gate 	picl_nodehdl_t		nodeh;
10730Sstevel@tonic-gate 	picl_prophdl_t		tableh;
10740Sstevel@tonic-gate 	picl_prophdl_t		tblh;
10750Sstevel@tonic-gate 	picl_prophdl_t		fruph;
10762606Svenki 	picl_nodehdl_t		childh;
1077*12601SJustin.Frank@Sun.COM 	int			fanfru = 0;
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	retval = ptree_get_propval_by_name(fruh, PICL_PROP_NAME, name,
10800Sstevel@tonic-gate 	    sizeof (name));
10810Sstevel@tonic-gate 	if (retval != PICL_SUCCESS) {
10820Sstevel@tonic-gate 		syslog(LOG_ERR, EM_UNK_FRU);
10830Sstevel@tonic-gate 		return;
10840Sstevel@tonic-gate 	}
10852606Svenki 
10862606Svenki 	retval = ptree_get_prop_by_name(fruh, PICL_PROP_DEVICES, &tableh);
10872606Svenki 	if (retval != PICL_SUCCESS) {
10882606Svenki 		/*
1089*12601SJustin.Frank@Sun.COM 		 * No Devices table. However on Seattle, Boston and
1090*12601SJustin.Frank@Sun.COM 		 * Netra-440 (Chalupa19) (which support fan fru hotplug),
1091*12601SJustin.Frank@Sun.COM 		 * the Devices table will be found under the child node (Fn)
1092*12601SJustin.Frank@Sun.COM 		 * of the fru (fan-tray).
10932606Svenki 		 * Therefore, check the first child of the fru for the
10942606Svenki 		 * Devices table on these platforms before returning.
10952606Svenki 		 */
10962606Svenki 		switch (sys_platform) {
10972606Svenki 		case PLAT_SEATTLE1U:
10982606Svenki 		case PLAT_SEATTLE2U:
10992606Svenki 		case PLAT_BOSTON:
11002606Svenki 			if (strcmp(name, FT_FRU_NAME) != 0)
11012606Svenki 				return;
1102*12601SJustin.Frank@Sun.COM 			fanfru = 1;
1103*12601SJustin.Frank@Sun.COM 			break;
1104*12601SJustin.Frank@Sun.COM 		case PLAT_CHALUPA19:
1105*12601SJustin.Frank@Sun.COM 			if (strncmp(name, F0_NAME, F0_NAME_LEN) &&
1106*12601SJustin.Frank@Sun.COM 			    strncmp(name, F1_NAME, F1_NAME_LEN))
11072606Svenki 				return;
1108*12601SJustin.Frank@Sun.COM 			fanfru = 1;
11092606Svenki 			break;
11102606Svenki 		default:
11112606Svenki 			/* nothing to do */
11122606Svenki 			return;
11132606Svenki 		}
1114*12601SJustin.Frank@Sun.COM 		retval = ptree_get_propval_by_name(fruh,
1115*12601SJustin.Frank@Sun.COM 		    PICL_PROP_CHILD, &childh, sizeof (picl_nodehdl_t));
1116*12601SJustin.Frank@Sun.COM 		if (retval != PICL_SUCCESS)
1117*12601SJustin.Frank@Sun.COM 			return;
1118*12601SJustin.Frank@Sun.COM 		retval = ptree_get_prop_by_name(childh,
1119*12601SJustin.Frank@Sun.COM 		    PICL_PROP_DEVICES, &tableh);
1120*12601SJustin.Frank@Sun.COM 		if (retval != PICL_SUCCESS)
1121*12601SJustin.Frank@Sun.COM 			return;
11220Sstevel@tonic-gate 	}
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	/*
11250Sstevel@tonic-gate 	 * follow all reference properties in the second
11260Sstevel@tonic-gate 	 * column of the table and delete any _fru_parent node
11270Sstevel@tonic-gate 	 * at the referenced node.
11280Sstevel@tonic-gate 	 */
11290Sstevel@tonic-gate 	retval = ptree_get_propval(tableh, &tblh, sizeof (tblh));
11300Sstevel@tonic-gate 	if (retval != PICL_SUCCESS) {
11310Sstevel@tonic-gate 		/* can't get value of table property */
1132*12601SJustin.Frank@Sun.COM 		goto afterloop;
11330Sstevel@tonic-gate 	}
11342606Svenki 
11350Sstevel@tonic-gate 	/* get first col, first row */
11360Sstevel@tonic-gate 	retval = ptree_get_next_by_col(tblh, &tblh);
11370Sstevel@tonic-gate 	if (retval != PICL_SUCCESS) {
11380Sstevel@tonic-gate 		/* no rows? */
1139*12601SJustin.Frank@Sun.COM 		goto afterloop;
11400Sstevel@tonic-gate 	}
11412606Svenki 
11420Sstevel@tonic-gate 	/*
11430Sstevel@tonic-gate 	 * starting at next col, get every entry in the column
11440Sstevel@tonic-gate 	 */
11450Sstevel@tonic-gate 	for (retval = ptree_get_next_by_row(tblh, &tblh);
11460Sstevel@tonic-gate 	    retval == PICL_SUCCESS;
11470Sstevel@tonic-gate 	    retval = ptree_get_next_by_col(tblh, &tblh)) {
11480Sstevel@tonic-gate 		/*
11490Sstevel@tonic-gate 		 * should be a ref prop in our hands,
11500Sstevel@tonic-gate 		 * get the target node handle
11510Sstevel@tonic-gate 		 */
11520Sstevel@tonic-gate 		retval = ptree_get_propval(tblh, &nodeh,
11530Sstevel@tonic-gate 		    sizeof (nodeh));
11540Sstevel@tonic-gate 		if (retval != PICL_SUCCESS) {
11550Sstevel@tonic-gate 			continue;
11560Sstevel@tonic-gate 		}
11570Sstevel@tonic-gate 		/*
11580Sstevel@tonic-gate 		 * got the referenced node, has it got a
11590Sstevel@tonic-gate 		 * _fru_parent property?
11600Sstevel@tonic-gate 		 */
11610Sstevel@tonic-gate 		retval = ptree_get_prop_by_name(nodeh,
11620Sstevel@tonic-gate 		    PICL_REFPROP_FRU_PARENT, &fruph);
11630Sstevel@tonic-gate 		if (retval != PICL_SUCCESS) {
11642606Svenki 			/*
1165*12601SJustin.Frank@Sun.COM 			 * on Boston, Seattle and Netra-440 we should
1166*12601SJustin.Frank@Sun.COM 			 * actually be looking for the _location_parent
1167*12601SJustin.Frank@Sun.COM 			 * property for fan frus
11682606Svenki 			 */
1169*12601SJustin.Frank@Sun.COM 			if (fanfru) {
1170*12601SJustin.Frank@Sun.COM 				retval = ptree_get_prop_by_name(nodeh,
1171*12601SJustin.Frank@Sun.COM 				    PICL_REFPROP_LOC_PARENT, &fruph);
11722606Svenki 			}
11732606Svenki 			if (retval != PICL_SUCCESS)
11742606Svenki 				continue;
11750Sstevel@tonic-gate 		}
11760Sstevel@tonic-gate 		/*
11770Sstevel@tonic-gate 		 * got a _fru_parent node reference delete it
11780Sstevel@tonic-gate 		 */
1179*12601SJustin.Frank@Sun.COM 		if (ptree_delete_prop(fruph) == PICL_SUCCESS)
1180*12601SJustin.Frank@Sun.COM 			(void) ptree_destroy_prop(fruph);
1181*12601SJustin.Frank@Sun.COM 
1182*12601SJustin.Frank@Sun.COM 		/* On Netra-440, extra clean-up is required for fan trays */
1183*12601SJustin.Frank@Sun.COM 		if ((sys_platform == PLAT_CHALUPA19) && (fanfru)) {
1184*12601SJustin.Frank@Sun.COM 			/* remove the rmclomv node and its properties */
1185*12601SJustin.Frank@Sun.COM 			delete_node_and_props(nodeh);
11860Sstevel@tonic-gate 		}
1187*12601SJustin.Frank@Sun.COM 	}
1188*12601SJustin.Frank@Sun.COM afterloop:
1189*12601SJustin.Frank@Sun.COM 	/* More Netra-440 fan tray clean-up  */
1190*12601SJustin.Frank@Sun.COM 	if ((sys_platform == PLAT_CHALUPA19) && (fanfru)) {
1191*12601SJustin.Frank@Sun.COM 		/* remove the fru's child's table */
1192*12601SJustin.Frank@Sun.COM 		if (ptree_delete_prop(tableh) == PICL_SUCCESS)
1193*12601SJustin.Frank@Sun.COM 			(void) ptree_destroy_prop(tableh);
1194*12601SJustin.Frank@Sun.COM 		/* remove the child */
1195*12601SJustin.Frank@Sun.COM 		if (ptree_delete_node(childh) == PICL_SUCCESS)
1196*12601SJustin.Frank@Sun.COM 			(void) ptree_destroy_node(childh);
11970Sstevel@tonic-gate 	}
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate static void
remove_tables(picl_nodehdl_t rootnd)12010Sstevel@tonic-gate remove_tables(picl_nodehdl_t rootnd)
12020Sstevel@tonic-gate {
12030Sstevel@tonic-gate 	picl_nodehdl_t	tableh;
12040Sstevel@tonic-gate 	int		retval;
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	retval = ptree_get_prop_by_name(rootnd, PICL_PROP_DEVICES, &tableh);
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 	if (retval == PICL_SUCCESS) {
12090Sstevel@tonic-gate 		/*
12100Sstevel@tonic-gate 		 * found a Devices property, delete it
12110Sstevel@tonic-gate 		 */
12120Sstevel@tonic-gate 		if ((retval = ptree_delete_prop(tableh)) == PICL_SUCCESS) {
12130Sstevel@tonic-gate 			(void) ptree_destroy_prop(tableh);
12140Sstevel@tonic-gate 		}
12150Sstevel@tonic-gate 	}
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	/*
12180Sstevel@tonic-gate 	 * is there a child node?
12190Sstevel@tonic-gate 	 */
12200Sstevel@tonic-gate 	retval = ptree_get_propval_by_name(rootnd, PICL_PROP_CHILD, &rootnd,
12210Sstevel@tonic-gate 	    sizeof (rootnd));
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	while (retval == PICL_SUCCESS) {
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 		remove_tables(rootnd);
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 		/*
12280Sstevel@tonic-gate 		 * any siblings?
12290Sstevel@tonic-gate 		 */
12300Sstevel@tonic-gate 		retval = ptree_get_propval_by_name(rootnd, PICL_PROP_PEER,
12310Sstevel@tonic-gate 		    &rootnd, sizeof (rootnd));
12320Sstevel@tonic-gate 	}
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate 
12352606Svenki /*
12362606Svenki  * Event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events
12372606Svenki  */
1238*12601SJustin.Frank@Sun.COM /* ARGSUSED */
12390Sstevel@tonic-gate static void
frudr_completion_handler(char * ename,void * earg,size_t size)12400Sstevel@tonic-gate frudr_completion_handler(char *ename, void *earg, size_t size)
12410Sstevel@tonic-gate {
12420Sstevel@tonic-gate 	picl_nodehdl_t	fruh;
12432606Svenki 	picl_nodehdl_t	parh;
1244*12601SJustin.Frank@Sun.COM 	picl_nodehdl_t	peerh = NULL;
1245*12601SJustin.Frank@Sun.COM 	char	nodename[PICL_PROPNAMELEN_MAX] = { '\0' };
12460Sstevel@tonic-gate 	int err;
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
12490Sstevel@tonic-gate 		/*
12500Sstevel@tonic-gate 		 * now frudata has been notified that the node is to be
12510Sstevel@tonic-gate 		 * removed, we can actually remove it
12520Sstevel@tonic-gate 		 */
12530Sstevel@tonic-gate 		fruh = NULL;
12540Sstevel@tonic-gate 		(void) nvlist_lookup_uint64(earg,
12550Sstevel@tonic-gate 		    PICLEVENTARG_FRUHANDLE, &fruh);
12560Sstevel@tonic-gate 		if (fruh != NULL) {
1257*12601SJustin.Frank@Sun.COM 			(void) ptree_get_propval_by_name(fruh, PICL_PROP_PEER,
1258*12601SJustin.Frank@Sun.COM 			    &peerh, sizeof (peerh));
1259*12601SJustin.Frank@Sun.COM 
12600Sstevel@tonic-gate 			/*
12610Sstevel@tonic-gate 			 * first find name of the fru
12620Sstevel@tonic-gate 			 */
12630Sstevel@tonic-gate 			err = ptree_get_propval_by_name(fruh, PICL_PROP_PARENT,
12642606Svenki 			    &parh, sizeof (parh));
12650Sstevel@tonic-gate 			if (err == PICL_SUCCESS) {
12662606Svenki 				err = ptree_get_propval_by_name(parh,
12670Sstevel@tonic-gate 				    PICL_PROP_NAME, nodename,
12680Sstevel@tonic-gate 				    sizeof (nodename));
12690Sstevel@tonic-gate 			}
12700Sstevel@tonic-gate 			if (err == PICL_SUCCESS) {
12710Sstevel@tonic-gate 				/*
12720Sstevel@tonic-gate 				 * if it was a power supply, delete i2c node
12730Sstevel@tonic-gate 				 */
12740Sstevel@tonic-gate 				if (strncmp(nodename, PS_NAME,
12750Sstevel@tonic-gate 				    PS_NAME_LEN) == 0) {
12760Sstevel@tonic-gate 					(void) delete_i2c_node(nodename);
12770Sstevel@tonic-gate 				}
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 				/*
12800Sstevel@tonic-gate 				 * is disk node, make thread re-evaluate led
12810Sstevel@tonic-gate 				 * state
12820Sstevel@tonic-gate 				 */
12830Sstevel@tonic-gate 				if (strncmp(nodename, DISK_NAME,
12840Sstevel@tonic-gate 				    DISK_NAME_LEN) == 0) {
12850Sstevel@tonic-gate 					disk_ready[nodename[DISK_NAME_LEN] -
12860Sstevel@tonic-gate 					    '0'] = -1;
12870Sstevel@tonic-gate 				}
12880Sstevel@tonic-gate 			}
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 			remove_fru_parents(fruh);
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 			/*
12930Sstevel@tonic-gate 			 * now we can delete the node
12940Sstevel@tonic-gate 			 */
12950Sstevel@tonic-gate 			err = ptree_delete_node(fruh);
12960Sstevel@tonic-gate 			if (err == PICL_SUCCESS) {
12970Sstevel@tonic-gate 				(void) ptree_destroy_node(fruh);
12980Sstevel@tonic-gate 			} else {
12990Sstevel@tonic-gate 				syslog(LOG_ERR, DELETE_PROP_FAIL, err);
13000Sstevel@tonic-gate 			}
1301*12601SJustin.Frank@Sun.COM 
1302*12601SJustin.Frank@Sun.COM 			if ((sys_platform == PLAT_CHALUPA19) &&
1303*12601SJustin.Frank@Sun.COM 			    (strncmp(nodename, FT_NAME, FT_NAME_LEN) == 0) &&
1304*12601SJustin.Frank@Sun.COM 			    (peerh != NULL)) {
1305*12601SJustin.Frank@Sun.COM 				/*
1306*12601SJustin.Frank@Sun.COM 				 * On Netra-440 platforms, a fan tray
1307*12601SJustin.Frank@Sun.COM 				 * may contain 2 fans (F0 and F1) but
1308*12601SJustin.Frank@Sun.COM 				 * we only receive a single notification
1309*12601SJustin.Frank@Sun.COM 				 * for removal of F0.  If F1 is present,
1310*12601SJustin.Frank@Sun.COM 				 * peerh will be valid and we need to
1311*12601SJustin.Frank@Sun.COM 				 * process it as well.
1312*12601SJustin.Frank@Sun.COM 				 */
1313*12601SJustin.Frank@Sun.COM 				remove_fru_parents(peerh);
1314*12601SJustin.Frank@Sun.COM 				err = ptree_delete_node(peerh);
1315*12601SJustin.Frank@Sun.COM 				if (err == PICL_SUCCESS) {
1316*12601SJustin.Frank@Sun.COM 					(void) ptree_destroy_node(peerh);
1317*12601SJustin.Frank@Sun.COM 				} else {
1318*12601SJustin.Frank@Sun.COM 					syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1319*12601SJustin.Frank@Sun.COM 				}
1320*12601SJustin.Frank@Sun.COM 			}
13210Sstevel@tonic-gate 		}
13220Sstevel@tonic-gate 	}
13232606Svenki 
13242606Svenki 	free(ename);
13250Sstevel@tonic-gate 	nvlist_free(earg);
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate /*
13290Sstevel@tonic-gate  * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
13300Sstevel@tonic-gate  */
13310Sstevel@tonic-gate static void
post_frudr_event(char * ename,picl_nodehdl_t parenth,picl_nodehdl_t fruh)13320Sstevel@tonic-gate post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
13330Sstevel@tonic-gate {
13340Sstevel@tonic-gate 	nvlist_t	*nvl;
13350Sstevel@tonic-gate 	char		*ev_name;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	ev_name = strdup(ename);
13380Sstevel@tonic-gate 	if (ev_name == NULL)
13390Sstevel@tonic-gate 		return;
13400Sstevel@tonic-gate 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) {
13410Sstevel@tonic-gate 		free(ev_name);
13420Sstevel@tonic-gate 		return;
13430Sstevel@tonic-gate 	}
13440Sstevel@tonic-gate 	if (parenth != 0L &&
13450Sstevel@tonic-gate 	    nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
13460Sstevel@tonic-gate 		free(ev_name);
13470Sstevel@tonic-gate 		nvlist_free(nvl);
13480Sstevel@tonic-gate 		return;
13490Sstevel@tonic-gate 	}
13500Sstevel@tonic-gate 	if (fruh != 0L &&
13510Sstevel@tonic-gate 	    nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
13520Sstevel@tonic-gate 		free(ev_name);
13530Sstevel@tonic-gate 		nvlist_free(nvl);
13540Sstevel@tonic-gate 		return;
13550Sstevel@tonic-gate 	}
13560Sstevel@tonic-gate 	if (ptree_post_event(ev_name, nvl, sizeof (nvl),
13570Sstevel@tonic-gate 	    frudr_completion_handler) != 0) {
13580Sstevel@tonic-gate 		free(ev_name);
13590Sstevel@tonic-gate 		nvlist_free(nvl);
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate }
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate static void
add_ps_to_platform(char * unit)13640Sstevel@tonic-gate add_ps_to_platform(char *unit)
13650Sstevel@tonic-gate {
13660Sstevel@tonic-gate 	picl_nodehdl_t		parent_hdl;
13670Sstevel@tonic-gate 	picl_nodehdl_t		child_hdl;
13680Sstevel@tonic-gate 	ptree_propinfo_t	info;
13690Sstevel@tonic-gate 	int			unit_size = 1 + strlen(unit);
13700Sstevel@tonic-gate 	int			res;
13710Sstevel@tonic-gate 	char			unit_addr[PICL_UNITADDR_LEN_MAX];
13720Sstevel@tonic-gate 
13731103Sjbeloro 	switch (sys_platform) {
13741103Sjbeloro 	case PLAT_SEATTLE1U:
13751103Sjbeloro 	case PLAT_SEATTLE2U:
13761103Sjbeloro 		res = ptree_get_node_by_path(SEATTLE_PSU_PLATFORM, &parent_hdl);
13771103Sjbeloro 		break;
13781103Sjbeloro 	case PLAT_BOSTON:
13791103Sjbeloro 		res = ptree_get_node_by_path(BOSTON_PSU_PLATFORM, &parent_hdl);
13801103Sjbeloro 		break;
13811103Sjbeloro 	default:
13821103Sjbeloro 		res = ptree_get_node_by_path(PSU_PLATFORM, &parent_hdl);
13831103Sjbeloro 		break;
13841103Sjbeloro 	}
13851103Sjbeloro 
13861103Sjbeloro 	if (res != PICL_SUCCESS)
13870Sstevel@tonic-gate 		return;
13880Sstevel@tonic-gate 	/*
13890Sstevel@tonic-gate 	 * seeprom nodes sit below this node,
13900Sstevel@tonic-gate 	 * is there one with the supplied unit address?
13910Sstevel@tonic-gate 	 */
13920Sstevel@tonic-gate 	res = ptree_get_propval_by_name(parent_hdl, PICL_PROP_CHILD,
13930Sstevel@tonic-gate 	    &child_hdl, sizeof (picl_nodehdl_t));
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	while (res == PICL_SUCCESS) {
13960Sstevel@tonic-gate 		res = ptree_get_propval_by_name(child_hdl, PICL_PROP_PEER,
13970Sstevel@tonic-gate 		    &child_hdl, sizeof (picl_nodehdl_t));
13980Sstevel@tonic-gate 		if ((res == PICL_SUCCESS) &&
1399*12601SJustin.Frank@Sun.COM 		    ptree_get_propval_by_name(child_hdl,
1400*12601SJustin.Frank@Sun.COM 		    PICL_PROP_UNIT_ADDRESS, unit_addr,
1401*12601SJustin.Frank@Sun.COM 		    sizeof (unit_addr)) == PICL_SUCCESS) {
14020Sstevel@tonic-gate 			unit_addr[sizeof (unit_addr) - 1] = '\0';
14030Sstevel@tonic-gate 			if (strcmp(unit_addr, unit) == 0)
14040Sstevel@tonic-gate 				return;	/* unit address exists already */
14050Sstevel@tonic-gate 		}
14060Sstevel@tonic-gate 	}
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	/*
14090Sstevel@tonic-gate 	 * found platform location for PS seeprom node, create it
14100Sstevel@tonic-gate 	 */
14110Sstevel@tonic-gate 	if (ptree_create_and_add_node(parent_hdl, PS_PLATFORM_NAME,
14120Sstevel@tonic-gate 	    PICL_CLASS_SEEPROM, &child_hdl) != PICL_SUCCESS)
14130Sstevel@tonic-gate 		return;
14140Sstevel@tonic-gate 	if (ptree_init_propinfo(&info, PTREE_PROPINFO_VERSION,
14150Sstevel@tonic-gate 	    PICL_PTYPE_CHARSTRING, PICL_READ, unit_size,
14160Sstevel@tonic-gate 	    PICL_PROP_UNIT_ADDRESS, NULL, NULL) != PICL_SUCCESS)
14170Sstevel@tonic-gate 		return;
14180Sstevel@tonic-gate 	(void) ptree_create_and_add_prop(child_hdl, &info, unit, NULL);
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate 
14212606Svenki static void
get_fantray_path(char * ap_id,char * path,int bufsz)14222606Svenki get_fantray_path(char *ap_id, char *path, int bufsz)
14232606Svenki {
14242606Svenki 	char	ft_id[FT_ID_BUFSZ];
14252606Svenki 
14262606Svenki 	(void) strlcpy(ft_id, ap_id, FT_ID_BUFSZ);
14272606Svenki 
14282606Svenki 	switch (sys_platform) {
14292606Svenki 	case PLAT_SEATTLE1U:
14302606Svenki 		if ((strncmp(ap_id, "FT0", 3) == 0) ||
14312606Svenki 		    (strncmp(ap_id, "FT1", 3) == 0) ||
14322606Svenki 		    (strncmp(ap_id, "FT2", 3) == 0)) {
14332606Svenki 			(void) snprintf(path, bufsz, SEATTLE_FCB0_1U, ft_id);
14342606Svenki 		} else if ((strncmp(ap_id, "FT3", 3) == 0) ||
14352606Svenki 		    (strncmp(ap_id, "FT4", 3) == 0) ||
14362606Svenki 		    (strncmp(ap_id, "FT5", 3) == 0)) {
14372606Svenki 			(void) snprintf(path, bufsz, SEATTLE_FCB1_1U, ft_id);
14382606Svenki 		} else {
14392606Svenki 			(void) snprintf(path, bufsz, SEATTLE_PDB_1U, ft_id);
14402606Svenki 		}
14412606Svenki 		break;
14422606Svenki 
14432606Svenki 	case PLAT_SEATTLE2U:
14442606Svenki 		if ((strncmp(ap_id, "FT0", 3) == 0) ||
14452606Svenki 		    (strncmp(ap_id, "FT1", 3) == 0) ||
14462606Svenki 		    (strncmp(ap_id, "FT2", 3) == 0)) {
14472606Svenki 			(void) snprintf(path, bufsz, SEATTLE_FCB0_2U, ft_id);
14482606Svenki 		} else if ((strncmp(ap_id, "FT3", 3) == 0) ||
14492606Svenki 		    (strncmp(ap_id, "FT4", 3) == 0) ||
14502606Svenki 		    (strncmp(ap_id, "FT5", 3) == 0)) {
14512606Svenki 			(void) snprintf(path, bufsz, SEATTLE_FCB1_2U, ft_id);
14522606Svenki 		} else {
14532606Svenki 			(void) snprintf(path, bufsz, SEATTLE_PDB_2U, ft_id);
14542606Svenki 		}
14552606Svenki 		break;
14562606Svenki 
14572606Svenki 	case PLAT_BOSTON:
14582606Svenki 		(void) snprintf(path, bufsz, SYS_BOARD_PATH, ft_id);
14592606Svenki 		break;
14602606Svenki 
14612606Svenki 	default:
14622606Svenki 		(void) snprintf(path, bufsz, CHASSIS_LOC_PATH, ft_id);
14632606Svenki 		break;
14642606Svenki 	}
14652606Svenki }
14662606Svenki 
14670Sstevel@tonic-gate /*
14680Sstevel@tonic-gate  * handle EC_DR picl events
14690Sstevel@tonic-gate  */
14700Sstevel@tonic-gate /*ARGSUSED*/
14710Sstevel@tonic-gate static void
frudr_evhandler(const char * ename,const void * earg,size_t size,void * cookie)14720Sstevel@tonic-gate frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	nvlist_t		*nvlp;
14750Sstevel@tonic-gate 	char			*dtype;
14760Sstevel@tonic-gate 	char			*ap_id;
14770Sstevel@tonic-gate 	char			*hint;
14780Sstevel@tonic-gate 	char			path[MAXPATHLEN];
14790Sstevel@tonic-gate 	picl_nodehdl_t		fruh;
14800Sstevel@tonic-gate 	picl_nodehdl_t		locnodeh;
14810Sstevel@tonic-gate 	int			err;
14820Sstevel@tonic-gate 	int			index;
14830Sstevel@tonic-gate 	picl_nodehdl_t		childh;
14840Sstevel@tonic-gate 	char			*fru_name;
14850Sstevel@tonic-gate 	boolean_t		rmc_flag = B_FALSE;
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0) {
14880Sstevel@tonic-gate 		return;
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
14920Sstevel@tonic-gate 		return;
14930Sstevel@tonic-gate 	}
14940Sstevel@tonic-gate 
14950Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
14960Sstevel@tonic-gate 		nvlist_free(nvlp);
14970Sstevel@tonic-gate 		return;
14980Sstevel@tonic-gate 	}
14990Sstevel@tonic-gate 
15000Sstevel@tonic-gate 	if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
15010Sstevel@tonic-gate 		nvlist_free(nvlp);
15020Sstevel@tonic-gate 		return;
15030Sstevel@tonic-gate 	}
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
15060Sstevel@tonic-gate 		nvlist_free(nvlp);
15070Sstevel@tonic-gate 		return;
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	/*
15110Sstevel@tonic-gate 	 * check ap_id really is a hot-plug device
15120Sstevel@tonic-gate 	 */
15130Sstevel@tonic-gate 	if (strncmp(ap_id, PS_NAME, PS_NAME_LEN) == 0) {
15140Sstevel@tonic-gate 		fru_name = PS_FRU_NAME;
15150Sstevel@tonic-gate 	} else if (strncmp(ap_id, DISK_NAME, DISK_NAME_LEN) == 0) {
15160Sstevel@tonic-gate 		fru_name = DISK_FRU_NAME;
15170Sstevel@tonic-gate 	} else if (strncmp(ap_id, SCC_NAME, SCC_NAME_LEN) == 0) {
15180Sstevel@tonic-gate 		fru_name = SCC_FRU_NAME;
15190Sstevel@tonic-gate 	} else if (strncmp(ap_id, RMC_NAME, RMC_NAME_LEN) == 0) {
15200Sstevel@tonic-gate 		fru_name = RMC_FRU_NAME;
15210Sstevel@tonic-gate 		rmc_flag = B_TRUE;
15222606Svenki 	} else if (strncmp(ap_id, FT_NAME, FT_NAME_LEN) == 0) {
15232606Svenki 		fru_name = FT_FRU_NAME;
15240Sstevel@tonic-gate 	} else {
15250Sstevel@tonic-gate 		nvlist_free(nvlp);
15260Sstevel@tonic-gate 		return;
15270Sstevel@tonic-gate 	}
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
15300Sstevel@tonic-gate 		nvlist_free(nvlp);
15310Sstevel@tonic-gate 		return;
15320Sstevel@tonic-gate 	}
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	/*
15350Sstevel@tonic-gate 	 * OK - so this is an EC_DR event - let's handle it.
15360Sstevel@tonic-gate 	 */
15370Sstevel@tonic-gate 	if (rmc_flag && (sys_platform != PLAT_CHALUPA) &&
1538*12601SJustin.Frank@Sun.COM 	    (sys_platform != PLAT_CHALUPA19))
15390Sstevel@tonic-gate 		sprintf_buf2(path, SYS_BOARD_PATH, ap_id);
15400Sstevel@tonic-gate 	else {
15410Sstevel@tonic-gate 		if ((sys_platform == PLAT_CHALUPA19) &&
1542*12601SJustin.Frank@Sun.COM 		    (strncmp(ap_id, PS_NAME, PS_NAME_LEN) == 0)) {
15430Sstevel@tonic-gate 			sprintf_buf2(path, CHASSIS_LOC_PATH,
1544*12601SJustin.Frank@Sun.COM 			    ps_apid_to_nodename(ap_id));
15451103Sjbeloro 		} else	if (strncmp(ap_id, DISK_NAME, DISK_NAME_LEN) == 0) {
15461103Sjbeloro 			switch (sys_platform)	{
15471103Sjbeloro 			case PLAT_SEATTLE1U:
15481103Sjbeloro 				sprintf_buf2(path, SEATTLE1U_HDDBP_PATH, ap_id);
15491103Sjbeloro 				break;
15501103Sjbeloro 			case PLAT_SEATTLE2U:
15511103Sjbeloro 				sprintf_buf2(path, SEATTLE2U_HDDBP_PATH, ap_id);
15521103Sjbeloro 				break;
15531103Sjbeloro 			case PLAT_BOSTON:
15541103Sjbeloro 				sprintf_buf2(path, BOSTON_HDDBP_PATH, ap_id);
15551103Sjbeloro 				break;
15561103Sjbeloro 			default:
15571103Sjbeloro 				sprintf_buf2(path, CHASSIS_LOC_PATH, ap_id);
15581103Sjbeloro 				break;
15591103Sjbeloro 			}
15602606Svenki 		} else if (strncmp(ap_id, FT_NAME, FT_NAME_LEN) == 0) {
15612606Svenki 			get_fantray_path(ap_id, path, MAXPATHLEN);
15621103Sjbeloro 		} else	{
15631103Sjbeloro 			sprintf_buf2(path, CHASSIS_LOC_PATH, ap_id);
15640Sstevel@tonic-gate 		}
15650Sstevel@tonic-gate 	}
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
15680Sstevel@tonic-gate 		nvlist_free(nvlp);
15690Sstevel@tonic-gate 		return;
15700Sstevel@tonic-gate 	}
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	/*
15730Sstevel@tonic-gate 	 * now either add or delete the fru node as appropriate. If no
15740Sstevel@tonic-gate 	 * hint, treat as insert and update the tree if necessary.
15750Sstevel@tonic-gate 	 */
15760Sstevel@tonic-gate 	if (strcmp(hint, DR_HINT_REMOVE) == 0) {
15770Sstevel@tonic-gate 		if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD,
15780Sstevel@tonic-gate 		    &fruh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS) {
15790Sstevel@tonic-gate 			/*
15800Sstevel@tonic-gate 			 * fru was there - but has gone away
15810Sstevel@tonic-gate 			 */
15820Sstevel@tonic-gate 			post_frudr_event(PICL_FRU_REMOVED, NULL, fruh);
15830Sstevel@tonic-gate 		}
15840Sstevel@tonic-gate 	} else if (rmc_flag) {
15850Sstevel@tonic-gate 		/*
15860Sstevel@tonic-gate 		 * An event on the RMC location, just pass it on
15870Sstevel@tonic-gate 		 * it's not really a PICL_FRU_ADDED event, so offer
15880Sstevel@tonic-gate 		 * the child handle as well (if it exists).
15890Sstevel@tonic-gate 		 */
15900Sstevel@tonic-gate 		if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD,
15910Sstevel@tonic-gate 		    &fruh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) {
15920Sstevel@tonic-gate 			fruh = NULL;
15930Sstevel@tonic-gate 		}
15940Sstevel@tonic-gate 		post_frudr_event(PICL_FRU_ADDED, locnodeh, fruh);
15950Sstevel@tonic-gate 	} else {
15960Sstevel@tonic-gate 		/*
15970Sstevel@tonic-gate 		 * fru has been inserted (or may need to update)
15980Sstevel@tonic-gate 		 * if node already there, then just return
15990Sstevel@tonic-gate 		 */
16000Sstevel@tonic-gate 		childh = find_child_by_name(locnodeh, fru_name);
16010Sstevel@tonic-gate 		if (childh != NULL) {
16020Sstevel@tonic-gate 			nvlist_free(nvlp);
16030Sstevel@tonic-gate 			return;
16040Sstevel@tonic-gate 		}
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 		/*
1607*12601SJustin.Frank@Sun.COM 		 * On Netra-440, the fan-tray location nodes are
1608*12601SJustin.Frank@Sun.COM 		 * not deleted when fan-trays are physically
1609*12601SJustin.Frank@Sun.COM 		 * removed, so we do not need to create another
1610*12601SJustin.Frank@Sun.COM 		 * fru node.
16110Sstevel@tonic-gate 		 */
1612*12601SJustin.Frank@Sun.COM 		if ((sys_platform != PLAT_CHALUPA19) ||
1613*12601SJustin.Frank@Sun.COM 		    (strncmp(fru_name, FT_FRU_NAME, FT_FRU_NAME_LEN) != 0)) {
1614*12601SJustin.Frank@Sun.COM 			/*
1615*12601SJustin.Frank@Sun.COM 			 * create requested fru node
1616*12601SJustin.Frank@Sun.COM 			 */
1617*12601SJustin.Frank@Sun.COM 			err = ptree_create_and_add_node(locnodeh, fru_name,
1618*12601SJustin.Frank@Sun.COM 			    PICL_CLASS_FRU, &childh);
1619*12601SJustin.Frank@Sun.COM 			if (err != PICL_SUCCESS) {
1620*12601SJustin.Frank@Sun.COM 				syslog(LOG_ERR, ADD_NODE_FAIL, ap_id, err);
1621*12601SJustin.Frank@Sun.COM 				nvlist_free(nvlp);
1622*12601SJustin.Frank@Sun.COM 				return;
1623*12601SJustin.Frank@Sun.COM 			}
16240Sstevel@tonic-gate 		}
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 		/*
16270Sstevel@tonic-gate 		 * power supplies have operational status and fruid -
16280Sstevel@tonic-gate 		 * add OperationalStatus property and create i2c device node
16290Sstevel@tonic-gate 		 * before posting fru_added event
16300Sstevel@tonic-gate 		 */
16310Sstevel@tonic-gate 		if (strncmp(ap_id, PS_NAME, PS_NAME_LEN) == 0) {
16320Sstevel@tonic-gate 			index = find_vol_prop_by_name(
1633*12601SJustin.Frank@Sun.COM 			    ps_apid_to_nodename(ap_id));
16340Sstevel@tonic-gate 			if (index >= 0)
16350Sstevel@tonic-gate 				add_op_status_to_node(childh,
16360Sstevel@tonic-gate 				    &idprop->idp[index].volprop);
16370Sstevel@tonic-gate 			(void) create_i2c_node(ap_id);
16380Sstevel@tonic-gate 			add_ps_to_platform(ps_name_to_unitaddr(ap_id));
16390Sstevel@tonic-gate 		}
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 		/*
16420Sstevel@tonic-gate 		 * now post event
16430Sstevel@tonic-gate 		 */
16440Sstevel@tonic-gate 		post_frudr_event(PICL_FRU_ADDED, locnodeh, NULL);
16450Sstevel@tonic-gate 	}
16460Sstevel@tonic-gate 	nvlist_free(nvlp);
16470Sstevel@tonic-gate }
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate /*
16500Sstevel@tonic-gate  * Handle PICL_FRU_ADDED events.
16510Sstevel@tonic-gate  * These events are posted by the frudr_evhandler of this plugin in response to
16520Sstevel@tonic-gate  * PICLEVENT_DR_AP_STATE_CHANGE events. The sequence is as follows:
16530Sstevel@tonic-gate  *	1) frudr_evhandler catches PICLEVENT_DR_AP_STATE_CHANGE and creates a
16540Sstevel@tonic-gate  *	child node below the relevant location.
16550Sstevel@tonic-gate  *	2) frudr_evhandler posts a PICL_FRU_ADDED event.
16560Sstevel@tonic-gate  *	3) envmon catches PICL_FRU_ADDED event, gropes the RMC configuration
16570Sstevel@tonic-gate  *	and creates platform tree nodes (primarily for PSUs). (If the event
16580Sstevel@tonic-gate  *	is for the RMC itself, envmon deletes existing platform nodes and
16590Sstevel@tonic-gate  *	rebuilds from scratch.)
16600Sstevel@tonic-gate  *	4) this plugin catches PICL_FRU_ADDED event, looks for a related
16610Sstevel@tonic-gate  *	configuration file and parses it. This adds Fru data properties (etc.).
16620Sstevel@tonic-gate  *	5) frudata catches the event and updates its FRUID data cache.
16630Sstevel@tonic-gate  */
16640Sstevel@tonic-gate /*ARGSUSED*/
16650Sstevel@tonic-gate static void
fru_add_handler(const char * ename,const void * earg,size_t size,void * cookie)16660Sstevel@tonic-gate fru_add_handler(const char *ename, const void *earg, size_t size, void *cookie)
16670Sstevel@tonic-gate {
16680Sstevel@tonic-gate 	int			retval;
16690Sstevel@tonic-gate 	picl_nodehdl_t		locnodeh;
16700Sstevel@tonic-gate 	picl_nodehdl_t		rooth;
16710Sstevel@tonic-gate 	char			path[MAXPATHLEN];
16720Sstevel@tonic-gate 	char			*fru_name;
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	if (strcmp(ename, PICL_FRU_ADDED) != 0)
16750Sstevel@tonic-gate 		return;
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 	retval = nvlist_lookup_uint64((nvlist_t *)earg,
16780Sstevel@tonic-gate 	    PICLEVENTARG_PARENTHANDLE, &locnodeh);
16790Sstevel@tonic-gate 	if (retval != PICL_SUCCESS)
16800Sstevel@tonic-gate 		return;
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME,
16830Sstevel@tonic-gate 	    path, sizeof (path));
16840Sstevel@tonic-gate 	if (retval != PICL_SUCCESS)
16850Sstevel@tonic-gate 		return;
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	fru_name = strdup(path);
16880Sstevel@tonic-gate 	if (fru_name == NULL)
16890Sstevel@tonic-gate 		return;
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	/*
16920Sstevel@tonic-gate 	 * We're about to parse a fru-specific .conf file to populate
16930Sstevel@tonic-gate 	 * picl nodes relating to the dynamically added component. In the
16940Sstevel@tonic-gate 	 * case of the RMC, there is a problem: all of its /platform tree
16950Sstevel@tonic-gate 	 * nodes have just been replaced by envmon. It is now necessary to
16960Sstevel@tonic-gate 	 * repopulate Devices tables in /frutree.
16970Sstevel@tonic-gate 	 * picld_pluginutil_parse_config_file doesn't handle repopulating
16980Sstevel@tonic-gate 	 * existing tables, so as a work round, delete all tables found
16990Sstevel@tonic-gate 	 * under /frutree. This works on Enchilada Server as the tables
17000Sstevel@tonic-gate 	 * are all created from parsing a .conf file, and we're about to
17010Sstevel@tonic-gate 	 * redo that action.
17020Sstevel@tonic-gate 	 */
17030Sstevel@tonic-gate 	if (strcmp(fru_name, RMC_NAME) == 0) {
17040Sstevel@tonic-gate 		rmc_state_event();
17050Sstevel@tonic-gate 		retval = ptree_get_node_by_path(FRUTREE_PATH, &rooth);
17060Sstevel@tonic-gate 		if (retval == PICL_SUCCESS) {
17070Sstevel@tonic-gate 			remove_tables(rooth);
17080Sstevel@tonic-gate 		}
17090Sstevel@tonic-gate 	}
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	/*
17120Sstevel@tonic-gate 	 * Re-establish the HPU(FRU) volatile properties.
17130Sstevel@tonic-gate 	 * This needs to be done before the .conf file is parsed because
17140Sstevel@tonic-gate 	 * it has a side effect of re-creating any missing power-supply
17150Sstevel@tonic-gate 	 * fru node. The .conf file can then hang properties beneath.
17160Sstevel@tonic-gate 	 */
17170Sstevel@tonic-gate 	opst_init();
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 	/*
17200Sstevel@tonic-gate 	 * see if there's a .conf file for this fru
17210Sstevel@tonic-gate 	 */
17220Sstevel@tonic-gate 	if (get_config_file(path, fru_name) == 0) {
17230Sstevel@tonic-gate 		if ((ptree_get_root(&rooth) != PICL_SUCCESS) ||
17240Sstevel@tonic-gate 		    (picld_pluginutil_parse_config_file(rooth, path) !=
17250Sstevel@tonic-gate 		    PICL_SUCCESS)) {
17260Sstevel@tonic-gate 			syslog(LOG_ERR, PARSE_CONF_FAIL, path);
17270Sstevel@tonic-gate 		}
17280Sstevel@tonic-gate 	}
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	free(fru_name);
17310Sstevel@tonic-gate }
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate /*
17340Sstevel@tonic-gate  * Handle PICLEVENT_SYSEVENT_DEVICE_ADDED events.
17350Sstevel@tonic-gate  */
17360Sstevel@tonic-gate /*ARGSUSED*/
17370Sstevel@tonic-gate static void
frutree_evhandler(const char * ename,const void * earg,size_t size,void * cookie)17380Sstevel@tonic-gate frutree_evhandler(const char *ename, const void *earg, size_t size,
17390Sstevel@tonic-gate     void *cookie)
17400Sstevel@tonic-gate {
17410Sstevel@tonic-gate 	nvlist_t		*nvlp;
17420Sstevel@tonic-gate 	picl_nodehdl_t		rooth;
17430Sstevel@tonic-gate 	char			path[MAXPATHLEN];
17440Sstevel@tonic-gate 	char			*fru_name;
17450Sstevel@tonic-gate 	char			*dtype;
17460Sstevel@tonic-gate 	char			*dpath;
17470Sstevel@tonic-gate 	char			*ptr;
17480Sstevel@tonic-gate 	char			*ptr2;
17490Sstevel@tonic-gate 	int			done = B_FALSE;
17501103Sjbeloro 	int			i;
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 	if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) != 0)
17530Sstevel@tonic-gate 		return;
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
17560Sstevel@tonic-gate 		return;
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
17590Sstevel@tonic-gate 		nvlist_free(nvlp);
17600Sstevel@tonic-gate 		return;
17610Sstevel@tonic-gate 	}
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
17640Sstevel@tonic-gate 		nvlist_free(nvlp);
17650Sstevel@tonic-gate 		return;
17660Sstevel@tonic-gate 	}
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &dpath)) {
17690Sstevel@tonic-gate 		nvlist_free(nvlp);
17700Sstevel@tonic-gate 		return;
17710Sstevel@tonic-gate 	}
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	fru_name = strdup(dpath);
17740Sstevel@tonic-gate 	if (fru_name == NULL) {
17750Sstevel@tonic-gate 		nvlist_free(nvlp);
17760Sstevel@tonic-gate 		return;
17770Sstevel@tonic-gate 	}
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	nvlist_free(nvlp);
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	/*
17820Sstevel@tonic-gate 	 * fru_name is of the form
17830Sstevel@tonic-gate 	 *	"/pci@1e,600000/usb@a/mouse@2"
17840Sstevel@tonic-gate 	 * or
17850Sstevel@tonic-gate 	 *	"/pci@1e,600000/usb@a/device@2/mouse@0"
17860Sstevel@tonic-gate 	 * reduce it to "usb-a-2"
17870Sstevel@tonic-gate 	 */
17881103Sjbeloro 	if ((sys_platform == PLAT_SEATTLE1U) ||
17891103Sjbeloro 	    (sys_platform == PLAT_SEATTLE2U) ||
17901103Sjbeloro 	    (sys_platform == PLAT_BOSTON)) {
17911103Sjbeloro 		for (i = 0; i < MAX_USB_PORTS; i++) {
17921103Sjbeloro 			sprintf(fru_name, "%s%d", USB_CONF_FILE_NAME, i+1);
17931103Sjbeloro 			if (get_config_file(path, fru_name) == 0) {
17941103Sjbeloro 				if ((ptree_get_root(&rooth) != PICL_SUCCESS) ||
17951103Sjbeloro 				    (picld_pluginutil_parse_config_file(rooth,
17961103Sjbeloro 				    path) != PICL_SUCCESS)) {
17971103Sjbeloro 					syslog(LOG_ERR, PARSE_CONF_FAIL, path);
17981103Sjbeloro 				}
17991103Sjbeloro 			}
18001103Sjbeloro 		}
18011103Sjbeloro 	} else {
18021103Sjbeloro 		ptr = fru_name;
18031103Sjbeloro 		if (*ptr == '/') {
18040Sstevel@tonic-gate 			ptr++;
18051103Sjbeloro 			ptr = strchr(ptr, '/');
18060Sstevel@tonic-gate 			if (ptr != NULL) {
18070Sstevel@tonic-gate 				ptr++;
18081103Sjbeloro 				(void) memmove(fru_name, ptr, strlen(ptr) + 1);
18091103Sjbeloro 				ptr = strchr(fru_name, '@');
18100Sstevel@tonic-gate 				if (ptr != NULL) {
18110Sstevel@tonic-gate 					*ptr = '-';
18120Sstevel@tonic-gate 					ptr++;
18131103Sjbeloro 					ptr = strchr(ptr, '/');
18140Sstevel@tonic-gate 					if (ptr != NULL) {
18151103Sjbeloro 						*ptr = '-';
18160Sstevel@tonic-gate 						ptr++;
18171103Sjbeloro 						ptr2 = ptr;
18181103Sjbeloro 						ptr = strchr(ptr, '@');
18191103Sjbeloro 						if (ptr != NULL) {
18201103Sjbeloro 							ptr++;
18211103Sjbeloro 							(void) memmove(ptr2,
18221103Sjbeloro 							    ptr, strlen(ptr)+1);
18231103Sjbeloro 							ptr2 = strchr(ptr2,
18241103Sjbeloro 							    '/');
18251103Sjbeloro 							if (ptr2 != NULL) {
18261103Sjbeloro 								*ptr2 = '\0';
18271103Sjbeloro 							}
18281103Sjbeloro 							done = B_TRUE;
18290Sstevel@tonic-gate 						}
18300Sstevel@tonic-gate 					}
18310Sstevel@tonic-gate 				}
18320Sstevel@tonic-gate 			}
18330Sstevel@tonic-gate 		}
18341103Sjbeloro 		if (done == B_FALSE) {
18351103Sjbeloro 			free(fru_name);
18361103Sjbeloro 			return;
18371103Sjbeloro 		}
18380Sstevel@tonic-gate 
18391103Sjbeloro 		/*
18401103Sjbeloro 		 * see if there's a .conf file for this fru
18411103Sjbeloro 		 */
18421103Sjbeloro 
18431103Sjbeloro 		if (get_config_file(path, fru_name) == 0) {
18441103Sjbeloro 			if ((ptree_get_root(&rooth) != PICL_SUCCESS) ||
18451103Sjbeloro 			    (picld_pluginutil_parse_config_file(rooth, path) !=
18461103Sjbeloro 			    PICL_SUCCESS)) {
18471103Sjbeloro 				syslog(LOG_ERR, PARSE_CONF_FAIL, path);
18481103Sjbeloro 			}
18490Sstevel@tonic-gate 		}
18500Sstevel@tonic-gate 	}
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	free(fru_name);
18530Sstevel@tonic-gate }
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate static int
set_led(char * name,char * ptr,char * value)18560Sstevel@tonic-gate set_led(char *name, char *ptr, char *value)
18570Sstevel@tonic-gate {
18580Sstevel@tonic-gate 	char			path[MAXPATHLEN];
18590Sstevel@tonic-gate 	picl_prophdl_t		proph;
18600Sstevel@tonic-gate 	ptree_propinfo_t	propinfo;
18610Sstevel@tonic-gate 	picl_prophdl_t		tableh;
18620Sstevel@tonic-gate 	picl_nodehdl_t		locnodeh;
18630Sstevel@tonic-gate 	picl_nodehdl_t		nodeh;
18640Sstevel@tonic-gate 	picl_prophdl_t		tblh;
18650Sstevel@tonic-gate 	int			retval;
18660Sstevel@tonic-gate 	char			*value_ptr;
18670Sstevel@tonic-gate 	char			label[PICL_PROPNAMELEN_MAX];
18680Sstevel@tonic-gate 	char			class[PICL_PROPNAMELEN_MAX];
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	/* find the location node */
18711103Sjbeloro 	switch (sys_platform)	{
18721103Sjbeloro 	case PLAT_CHALUPA:
18731103Sjbeloro 	case PLAT_CHALUPA19:
18741103Sjbeloro 		sprintf_buf2(path, CHASSIS_LOC_PATH, name);
18751103Sjbeloro 		break;
18761103Sjbeloro 	case PLAT_SEATTLE1U:
18771103Sjbeloro 		sprintf_buf2(path, SEATTLE1U_HDDBP_PATH, name);
18781103Sjbeloro 		break;
18791103Sjbeloro 	case PLAT_SEATTLE2U:
18801103Sjbeloro 		sprintf_buf2(path, SEATTLE2U_HDDBP_PATH, name);
18811103Sjbeloro 		break;
18821103Sjbeloro 	case PLAT_BOSTON:
18831103Sjbeloro 		sprintf_buf2(path, BOSTON_HDDBP_PATH, name);
18841103Sjbeloro 		break;
18851103Sjbeloro 	default:
18861103Sjbeloro 		sprintf_buf2(path, CHASSIS_LOC_PATH, name);
18871103Sjbeloro 		break;
18881103Sjbeloro 	}
18891103Sjbeloro 
18901103Sjbeloro 	if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS)	{
18910Sstevel@tonic-gate 		return (PICL_FAILURE);
18921103Sjbeloro 	}
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 	/*
18950Sstevel@tonic-gate 	 * if no fru node, then turn led off
18960Sstevel@tonic-gate 	 */
18970Sstevel@tonic-gate 	if (find_child_by_name(locnodeh, DISK_FRU_NAME) != NULL)
18980Sstevel@tonic-gate 		value_ptr = value;
18990Sstevel@tonic-gate 	else
19000Sstevel@tonic-gate 		value_ptr = PICL_PROPVAL_OFF;
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	/* get its Devices table */
19030Sstevel@tonic-gate 	if (ptree_get_prop_by_name(locnodeh, PICL_PROP_DEVICES, &tableh) !=
19040Sstevel@tonic-gate 	    PICL_SUCCESS)
19050Sstevel@tonic-gate 		return (PICL_FAILURE);
19060Sstevel@tonic-gate 	if (ptree_get_propval(tableh, &tblh, sizeof (tblh)) != PICL_SUCCESS)
19070Sstevel@tonic-gate 		return (PICL_FAILURE);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	/* get first col, first row */
19100Sstevel@tonic-gate 	if (ptree_get_next_by_col(tblh, &tblh) != PICL_SUCCESS)
19110Sstevel@tonic-gate 		return (PICL_FAILURE);
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	/*
19140Sstevel@tonic-gate 	 * starting at next col, get every entry in the column
19150Sstevel@tonic-gate 	 */
19160Sstevel@tonic-gate 	for (retval = ptree_get_next_by_row(tblh, &tblh);
19170Sstevel@tonic-gate 	    retval == PICL_SUCCESS;
19180Sstevel@tonic-gate 	    retval = ptree_get_next_by_col(tblh, &tblh)) {
19190Sstevel@tonic-gate 		/*
19200Sstevel@tonic-gate 		 * get the target node handle
19210Sstevel@tonic-gate 		 */
19220Sstevel@tonic-gate 		if (ptree_get_propval(tblh, &nodeh, sizeof (nodeh))
19230Sstevel@tonic-gate 		    != PICL_SUCCESS)
19240Sstevel@tonic-gate 			continue;
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 		/*
19270Sstevel@tonic-gate 		 * check it's a led
19280Sstevel@tonic-gate 		 */
19290Sstevel@tonic-gate 		if (ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME,
19300Sstevel@tonic-gate 		    class, sizeof (class)) != PICL_SUCCESS)
19310Sstevel@tonic-gate 			continue;
19320Sstevel@tonic-gate 		if (strcmp(class, "led") != 0)
19330Sstevel@tonic-gate 			continue;
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 		/*
19360Sstevel@tonic-gate 		 * check its the right led
19370Sstevel@tonic-gate 		 */
19380Sstevel@tonic-gate 		if (ptree_get_propval_by_name(nodeh, PICL_PROP_LABEL,
19390Sstevel@tonic-gate 		    label, sizeof (label)) != PICL_SUCCESS)
19400Sstevel@tonic-gate 			continue;
19410Sstevel@tonic-gate 		if (strcmp(label, ptr) == 0) {
19420Sstevel@tonic-gate 			/*
19430Sstevel@tonic-gate 			 * set it
19440Sstevel@tonic-gate 			 */
19450Sstevel@tonic-gate 			if (ptree_get_prop_by_name(nodeh, PICL_PROP_STATE,
19460Sstevel@tonic-gate 			    &proph) != PICL_SUCCESS)
19470Sstevel@tonic-gate 				continue;
19480Sstevel@tonic-gate 			if (ptree_get_propinfo(proph, &propinfo) !=
19490Sstevel@tonic-gate 			    PICL_SUCCESS)
19500Sstevel@tonic-gate 				continue;
19510Sstevel@tonic-gate 			retval =  ptree_update_propval_by_name(nodeh,
19520Sstevel@tonic-gate 			    PICL_PROP_STATE, value_ptr, propinfo.piclinfo.size);
19530Sstevel@tonic-gate 			return (retval);
19540Sstevel@tonic-gate 		}
19550Sstevel@tonic-gate 	}
19560Sstevel@tonic-gate 	return (PICL_FAILURE);
19570Sstevel@tonic-gate }
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate /*
19600Sstevel@tonic-gate  * function to find first node of specified class beneath supplied node
19610Sstevel@tonic-gate  */
19620Sstevel@tonic-gate static int
get_node_by_class(picl_nodehdl_t nodeh,const char * classname,picl_nodehdl_t * foundnodeh)19630Sstevel@tonic-gate get_node_by_class(picl_nodehdl_t nodeh, const char *classname,
19640Sstevel@tonic-gate     picl_nodehdl_t *foundnodeh)
19650Sstevel@tonic-gate {
19660Sstevel@tonic-gate 	int		err;
19670Sstevel@tonic-gate 	char		clname[PICL_CLASSNAMELEN_MAX+1];
19680Sstevel@tonic-gate 	picl_nodehdl_t	childh;
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 	/*
19710Sstevel@tonic-gate 	 * go through the children
19720Sstevel@tonic-gate 	 */
19730Sstevel@tonic-gate 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &childh,
19740Sstevel@tonic-gate 	    sizeof (picl_nodehdl_t));
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 	while (err == PICL_SUCCESS) {
19770Sstevel@tonic-gate 		err = ptree_get_propval_by_name(childh, PICL_PROP_CLASSNAME,
19780Sstevel@tonic-gate 		    clname, sizeof (clname));
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 		if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0)) {
19810Sstevel@tonic-gate 			*foundnodeh = childh;
19820Sstevel@tonic-gate 			return (PICL_SUCCESS);
19830Sstevel@tonic-gate 		}
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate 		err = get_node_by_class(childh, classname, foundnodeh);
19860Sstevel@tonic-gate 		if (err == PICL_SUCCESS)
19870Sstevel@tonic-gate 			return (PICL_SUCCESS);
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 		err = ptree_get_propval_by_name(childh, PICL_PROP_PEER,
19900Sstevel@tonic-gate 		    &childh, sizeof (picl_nodehdl_t));
19910Sstevel@tonic-gate 	}
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate 	return (PICL_NODENOTFOUND);
19940Sstevel@tonic-gate }
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate /*
19970Sstevel@tonic-gate  * get system-controller node
19980Sstevel@tonic-gate  */
19990Sstevel@tonic-gate static int
get_sys_controller_node(picl_nodehdl_t * nodeh)20000Sstevel@tonic-gate get_sys_controller_node(picl_nodehdl_t *nodeh)
20010Sstevel@tonic-gate {
20020Sstevel@tonic-gate 	int		err;
20030Sstevel@tonic-gate 
20040Sstevel@tonic-gate 	/* get platform node */
20050Sstevel@tonic-gate 	err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, nodeh);
20060Sstevel@tonic-gate 	if (err != PICL_SUCCESS)
20070Sstevel@tonic-gate 		return (err);
20080Sstevel@tonic-gate 	err = get_node_by_class(*nodeh, PICL_CLASS_SERVICE_PROCESSOR, nodeh);
20090Sstevel@tonic-gate 	return (err);
20100Sstevel@tonic-gate }
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate /*
20130Sstevel@tonic-gate  * create pathname string for system-controller device
20140Sstevel@tonic-gate  */
20150Sstevel@tonic-gate static char *
create_sys_controller_pathname(picl_nodehdl_t sysconh)20160Sstevel@tonic-gate create_sys_controller_pathname(picl_nodehdl_t sysconh)
20170Sstevel@tonic-gate {
20180Sstevel@tonic-gate 	char		*ptr;
20190Sstevel@tonic-gate 	char		namebuf[PATH_MAX];
20200Sstevel@tonic-gate 	size_t		len;
20210Sstevel@tonic-gate 	DIR		*dirp;
20220Sstevel@tonic-gate 	struct dirent	*dp;
20230Sstevel@tonic-gate 	struct stat	statbuf;
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate 	/*
20260Sstevel@tonic-gate 	 * prefix devfs-path name with /devices
20270Sstevel@tonic-gate 	 */
20280Sstevel@tonic-gate 	(void) strlcpy(namebuf, DEV_PREFIX, PATH_MAX);
20290Sstevel@tonic-gate 
20300Sstevel@tonic-gate 	/*
20310Sstevel@tonic-gate 	 * append devfs-path property
20320Sstevel@tonic-gate 	 */
20330Sstevel@tonic-gate 	len = strlen(namebuf);
20340Sstevel@tonic-gate 	if (ptree_get_propval_by_name(sysconh, str_devfs_path, namebuf + len,
20350Sstevel@tonic-gate 	    sizeof (namebuf) - len) != PICL_SUCCESS) {
20360Sstevel@tonic-gate 		return (NULL);
20370Sstevel@tonic-gate 	}
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 	/*
20400Sstevel@tonic-gate 	 * locate final component of name
20410Sstevel@tonic-gate 	 */
20420Sstevel@tonic-gate 	ptr = strrchr(namebuf, '/');
20430Sstevel@tonic-gate 	if (ptr == NULL)
20440Sstevel@tonic-gate 		return (NULL);
20450Sstevel@tonic-gate 	*ptr = '\0';		/* terminate at end of directory path */
20460Sstevel@tonic-gate 	len = strlen(ptr + 1);	/* length of terminal name */
20470Sstevel@tonic-gate 	dirp = opendir(namebuf);
20480Sstevel@tonic-gate 	if (dirp == NULL) {
20490Sstevel@tonic-gate 		return (NULL);
20500Sstevel@tonic-gate 	}
20510Sstevel@tonic-gate 	*ptr++ = '/';		/* restore '/' and advance to final name */
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL) {
20540Sstevel@tonic-gate 		/*
20550Sstevel@tonic-gate 		 * look for a name which starts with the string at *ptr
20560Sstevel@tonic-gate 		 */
20570Sstevel@tonic-gate 		if (strlen(dp->d_name) < len)
20580Sstevel@tonic-gate 			continue;	/* skip short names */
20590Sstevel@tonic-gate 		if (strncmp(dp->d_name, ptr, len) == 0) {
20600Sstevel@tonic-gate 			/*
20610Sstevel@tonic-gate 			 * Got a match, restore full pathname and stat the
20620Sstevel@tonic-gate 			 * entry. Reject if not a char device
20630Sstevel@tonic-gate 			 */
20640Sstevel@tonic-gate 			(void) strlcpy(ptr, dp->d_name,
20650Sstevel@tonic-gate 			    sizeof (namebuf) - (ptr - namebuf));
20660Sstevel@tonic-gate 			if (stat(namebuf, &statbuf) < 0)
20670Sstevel@tonic-gate 				continue;	/* reject if can't stat it */
20680Sstevel@tonic-gate 			if (!S_ISCHR(statbuf.st_mode))
20690Sstevel@tonic-gate 				continue;	/* not a character device */
20700Sstevel@tonic-gate 			/*
20710Sstevel@tonic-gate 			 * go with this entry
20720Sstevel@tonic-gate 			 */
20730Sstevel@tonic-gate 			(void) closedir(dirp);
20740Sstevel@tonic-gate 			return (strdup(namebuf));
20750Sstevel@tonic-gate 		}
20760Sstevel@tonic-gate 	}
20770Sstevel@tonic-gate 	(void) closedir(dirp);
20780Sstevel@tonic-gate 	return (NULL);
20790Sstevel@tonic-gate }
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate /*
20820Sstevel@tonic-gate  * create pathname string for bezel leds device
20830Sstevel@tonic-gate  */
20840Sstevel@tonic-gate static char *
create_bezel_leds_pathname(const char * dirpath,const char * devname)20850Sstevel@tonic-gate create_bezel_leds_pathname(const char *dirpath, const char *devname)
20860Sstevel@tonic-gate {
20870Sstevel@tonic-gate 	char		namebuf[PATH_MAX];
20880Sstevel@tonic-gate 	size_t		lendirpath;
20890Sstevel@tonic-gate 	size_t		len;
20900Sstevel@tonic-gate 	DIR		*dirp;
20910Sstevel@tonic-gate 	struct dirent	*dp;
20920Sstevel@tonic-gate 	struct stat	statbuf;
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	/*
20950Sstevel@tonic-gate 	 * start with directory name
20960Sstevel@tonic-gate 	 */
20970Sstevel@tonic-gate 	(void) strlcpy(namebuf, dirpath, PATH_MAX);
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	/*
21000Sstevel@tonic-gate 	 * append devfs-path property
21010Sstevel@tonic-gate 	 */
21020Sstevel@tonic-gate 	lendirpath = strlen(namebuf);
21030Sstevel@tonic-gate 	dirp = opendir(namebuf);
21040Sstevel@tonic-gate 	if (dirp == NULL) {
21050Sstevel@tonic-gate 		return (NULL);
21060Sstevel@tonic-gate 	}
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 	len = strlen(devname);
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL) {
21110Sstevel@tonic-gate 		/*
21120Sstevel@tonic-gate 		 * look for a name which starts with the gpio string
21130Sstevel@tonic-gate 		 */
21140Sstevel@tonic-gate 		if (strlen(dp->d_name) < len)
21150Sstevel@tonic-gate 			continue;	/* skip short names */
21160Sstevel@tonic-gate 		if (strncmp(dp->d_name, devname, len) == 0) {
21170Sstevel@tonic-gate 			/*
21180Sstevel@tonic-gate 			 * Got a match, restore full pathname and stat the
21190Sstevel@tonic-gate 			 * entry. Reject if not a char device
21200Sstevel@tonic-gate 			 */
21210Sstevel@tonic-gate 			(void) strlcpy(namebuf + lendirpath, dp->d_name,
21220Sstevel@tonic-gate 			    sizeof (namebuf) - lendirpath);
21230Sstevel@tonic-gate 			if (stat(namebuf, &statbuf) < 0)
21240Sstevel@tonic-gate 				continue;	/* reject if can't stat it */
21250Sstevel@tonic-gate 			if (!S_ISCHR(statbuf.st_mode))
21260Sstevel@tonic-gate 				continue;	/* not a character device */
21270Sstevel@tonic-gate 			/*
21280Sstevel@tonic-gate 			 * go with this entry
21290Sstevel@tonic-gate 			 */
21300Sstevel@tonic-gate 			(void) closedir(dirp);
21310Sstevel@tonic-gate 			return (strdup(namebuf));
21320Sstevel@tonic-gate 		}
21330Sstevel@tonic-gate 	}
21340Sstevel@tonic-gate 	(void) closedir(dirp);
21350Sstevel@tonic-gate 	return (NULL);
21360Sstevel@tonic-gate }
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate /*
21390Sstevel@tonic-gate  * initialise structure associated with nodes requiring OperationalStatus
21400Sstevel@tonic-gate  */
21410Sstevel@tonic-gate static void
opst_init(void)21420Sstevel@tonic-gate opst_init(void)
21430Sstevel@tonic-gate {
21440Sstevel@tonic-gate 	int			res;
21450Sstevel@tonic-gate 	int			index = 0;
21460Sstevel@tonic-gate 	int			fd;
21470Sstevel@tonic-gate 	int			entries = 0;
21480Sstevel@tonic-gate 	int			err = 0;
21490Sstevel@tonic-gate 	boolean_t		rmc_flag;
21500Sstevel@tonic-gate 	boolean_t		ps_flag;
21510Sstevel@tonic-gate 	boolean_t		disk_flag;
21520Sstevel@tonic-gate 	size_t			len;
21530Sstevel@tonic-gate 	envmon_sysinfo_t	sysinfo;
21540Sstevel@tonic-gate 	envmon_hpu_t		hpu;
21550Sstevel@tonic-gate 
21560Sstevel@tonic-gate 	if (idprop != NULL) {
21570Sstevel@tonic-gate 		/*
21580Sstevel@tonic-gate 		 * This must be a restart, clean up earlier allocation
21590Sstevel@tonic-gate 		 */
21600Sstevel@tonic-gate 		free(idprop);
21610Sstevel@tonic-gate 		idprop = NULL;
21620Sstevel@tonic-gate 	}
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 	if (sc_device_name == NULL)
21650Sstevel@tonic-gate 		err = 1;
21660Sstevel@tonic-gate 	else {
21670Sstevel@tonic-gate 		fd = open(sc_device_name, O_RDONLY);
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 		if (fd < 0) {
21700Sstevel@tonic-gate 			syslog(LOG_ERR, EM_NO_SC_DEV);
21710Sstevel@tonic-gate 			err = 1;
21720Sstevel@tonic-gate 		}
21730Sstevel@tonic-gate 	}
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 	if (err == 0) {
21760Sstevel@tonic-gate 		res = ioctl(fd, ENVMONIOCSYSINFO, &sysinfo);
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 		if (res < 0) {
21790Sstevel@tonic-gate 			syslog(LOG_ERR, EM_NO_SYSINFO, strerror(errno));
21800Sstevel@tonic-gate 			(void) close(fd);
21810Sstevel@tonic-gate 			err = 1;
21820Sstevel@tonic-gate 		}
21830Sstevel@tonic-gate 	}
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	if (err == 0) {
21860Sstevel@tonic-gate 		entries = sysinfo.maxHPU;
21870Sstevel@tonic-gate 		len = offsetof(idp_lkup_t, idp) + entries * sizeof (id_props_t);
21880Sstevel@tonic-gate 		idprop = calloc(len, 1);
21890Sstevel@tonic-gate 		if (idprop == NULL) {
21900Sstevel@tonic-gate 			(void) close(fd);
21910Sstevel@tonic-gate 			err = 1;
21920Sstevel@tonic-gate 		}
21930Sstevel@tonic-gate 	}
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	if (err == 0) {
21960Sstevel@tonic-gate 		idprop->maxnum = entries;
21970Sstevel@tonic-gate 		hpu.id.name[0] = '\0';	/* request for first name */
21980Sstevel@tonic-gate 		res = ioctl(fd, ENVMONIOCHPU, &hpu);
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 		/*
22010Sstevel@tonic-gate 		 * The HPU node for the RMC is a special case. Its handle is
22020Sstevel@tonic-gate 		 * generated by the rmclomv driver. Rather than building
22030Sstevel@tonic-gate 		 * knowledge of its frutree hierarchic name into the driver, we
22040Sstevel@tonic-gate 		 * put that knowledge here.
22050Sstevel@tonic-gate 		 */
22060Sstevel@tonic-gate 		while ((res == 0) && (index < entries) &&
22070Sstevel@tonic-gate 		    (hpu.next_id.name[0] != '\0')) {
22080Sstevel@tonic-gate 			hpu.id = hpu.next_id;
22090Sstevel@tonic-gate 			res = ioctl(fd, ENVMONIOCHPU, &hpu);
22100Sstevel@tonic-gate 			if ((res == 0) &&
22110Sstevel@tonic-gate 			    ((hpu.sensor_status & ENVMON_NOT_PRESENT) == 0)) {
22120Sstevel@tonic-gate 				add_op_status(&hpu, &index);
22130Sstevel@tonic-gate 			}
22140Sstevel@tonic-gate 		}
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 		idprop->num = index;
22170Sstevel@tonic-gate 		(void) close(fd);
22180Sstevel@tonic-gate 	}
22190Sstevel@tonic-gate }
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate static void
disk_leds_init(void)22220Sstevel@tonic-gate disk_leds_init(void)
22230Sstevel@tonic-gate {
22240Sstevel@tonic-gate 	int err = 0, i;
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 	if (!g_mutex_init) {
22270Sstevel@tonic-gate 		if ((pthread_cond_init(&g_cv, NULL) == 0) &&
22280Sstevel@tonic-gate 		    (pthread_cond_init(&g_cv_ack, NULL) == 0) &&
22290Sstevel@tonic-gate 		    (pthread_mutex_init(&g_mutex, NULL) == 0)) {
22300Sstevel@tonic-gate 			g_mutex_init = B_TRUE;
22310Sstevel@tonic-gate 		} else {
22320Sstevel@tonic-gate 			return;
22330Sstevel@tonic-gate 		}
22340Sstevel@tonic-gate 	}
22350Sstevel@tonic-gate 
22360Sstevel@tonic-gate 	/*
22370Sstevel@tonic-gate 	 * Initialise to -1 so the led thread will set correctly.
22380Sstevel@tonic-gate 	 * Do this before creating the disk_leds thread,
22390Sstevel@tonic-gate 	 * so there's no race.
22400Sstevel@tonic-gate 	 */
22410Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++)
22420Sstevel@tonic-gate 		disk_ready[i] = -1;
22430Sstevel@tonic-gate 
22440Sstevel@tonic-gate 	if (ledsthr_created) {
22450Sstevel@tonic-gate 		/*
22460Sstevel@tonic-gate 		 * this is a restart, wake up sleeping threads
22470Sstevel@tonic-gate 		 */
22480Sstevel@tonic-gate 		err = pthread_mutex_lock(&g_mutex);
22490Sstevel@tonic-gate 		if (err != 0) {
22500Sstevel@tonic-gate 			syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(errno));
22510Sstevel@tonic-gate 			return;
22520Sstevel@tonic-gate 		}
22530Sstevel@tonic-gate 		g_finish_now = B_FALSE;
22540Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&g_cv);
22550Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&g_mutex);
22560Sstevel@tonic-gate 	} else {
22570Sstevel@tonic-gate 		if ((pthread_attr_init(&ledsthr_attr) != 0) ||
22580Sstevel@tonic-gate 		    (pthread_attr_setscope(&ledsthr_attr,
22590Sstevel@tonic-gate 		    PTHREAD_SCOPE_SYSTEM) != 0))
22600Sstevel@tonic-gate 			return;
22610Sstevel@tonic-gate 		if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr,
22620Sstevel@tonic-gate 		    disk_leds_thread, NULL)) != 0) {
22630Sstevel@tonic-gate 			syslog(LOG_ERR, EM_THREAD_CREATE_FAILED,
22640Sstevel@tonic-gate 			    strerror(errno));
22650Sstevel@tonic-gate 			return;
22660Sstevel@tonic-gate 		}
22670Sstevel@tonic-gate 		ledsthr_created = B_TRUE;
22680Sstevel@tonic-gate 	}
22690Sstevel@tonic-gate }
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate static void
disk_leds_fini(void)22720Sstevel@tonic-gate disk_leds_fini(void)
22730Sstevel@tonic-gate {
22740Sstevel@tonic-gate 	int	err, i;
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 	/*
22770Sstevel@tonic-gate 	 * turn the leds off as we'll no longer be monitoring them
22780Sstevel@tonic-gate 	 */
22790Sstevel@tonic-gate 	for (i = 0; i < N_DISKS; i++)
22800Sstevel@tonic-gate 		(void) set_led(disk_name[i], REMOK_LED, PICL_PROPVAL_OFF);
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 	/*
22830Sstevel@tonic-gate 	 * disk_leds_thread() never started or an error occured so
22840Sstevel@tonic-gate 	 * that it's not running
22850Sstevel@tonic-gate 	 */
22860Sstevel@tonic-gate 	if (!disk_leds_thread_running)
22870Sstevel@tonic-gate 		return;
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	/*
22900Sstevel@tonic-gate 	 * tell led thread to pause
22910Sstevel@tonic-gate 	 */
22920Sstevel@tonic-gate 	if (!ledsthr_created)
22930Sstevel@tonic-gate 		return;
22940Sstevel@tonic-gate 	err = pthread_mutex_lock(&g_mutex);
22950Sstevel@tonic-gate 	if (err != 0) {
22960Sstevel@tonic-gate 		syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(errno));
22970Sstevel@tonic-gate 		return;
22980Sstevel@tonic-gate 	}
22990Sstevel@tonic-gate 	g_finish_now = B_TRUE;
23000Sstevel@tonic-gate 	disk_leds_thread_ack = B_FALSE;
23010Sstevel@tonic-gate 	(void) pthread_cond_broadcast(&g_cv);
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 	/*
23040Sstevel@tonic-gate 	 * and wait for them to acknowledge
23050Sstevel@tonic-gate 	 */
23060Sstevel@tonic-gate 	while (!disk_leds_thread_ack) {
23070Sstevel@tonic-gate 		(void) pthread_cond_wait(&g_cv_ack, &g_mutex);
23080Sstevel@tonic-gate 	}
23090Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&g_mutex);
23100Sstevel@tonic-gate }
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate static void
update_disk_node(char * fruname,char * devpath)23130Sstevel@tonic-gate update_disk_node(char *fruname, char *devpath)
23140Sstevel@tonic-gate {
23150Sstevel@tonic-gate 	picl_nodehdl_t slotndh;
23160Sstevel@tonic-gate 	picl_nodehdl_t diskndh;
23170Sstevel@tonic-gate 	picl_nodehdl_t devhdl;
23180Sstevel@tonic-gate 	picl_prophdl_t tblhdl;
23190Sstevel@tonic-gate 	picl_prophdl_t tblhdl2;
23200Sstevel@tonic-gate 	picl_prophdl_t tblproph;
23210Sstevel@tonic-gate 	int err;
23220Sstevel@tonic-gate 	char path[MAXPATHLEN];
23230Sstevel@tonic-gate 
23241103Sjbeloro 	switch (sys_platform)	{
23251103Sjbeloro 	case PLAT_CHALUPA:
23261103Sjbeloro 	case PLAT_CHALUPA19:
23271103Sjbeloro 		sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
23281103Sjbeloro 		break;
23291103Sjbeloro 	case PLAT_SEATTLE1U:
23301103Sjbeloro 		sprintf_buf2(path, SEATTLE1U_HDDBP_PATH, fruname);
23311103Sjbeloro 		break;
23321103Sjbeloro 	case PLAT_SEATTLE2U:
23331103Sjbeloro 		sprintf_buf2(path, SEATTLE2U_HDDBP_PATH, fruname);
23341103Sjbeloro 		break;
23351103Sjbeloro 	case PLAT_BOSTON:
23361103Sjbeloro 		sprintf_buf2(path, BOSTON_HDDBP_PATH, fruname);
23371103Sjbeloro 		break;
23381103Sjbeloro 	default:
23391103Sjbeloro 		sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
23401103Sjbeloro 		break;
23411103Sjbeloro 	}
23421103Sjbeloro 
23430Sstevel@tonic-gate 	if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) {
23440Sstevel@tonic-gate 		return;
23450Sstevel@tonic-gate 	}
23460Sstevel@tonic-gate 	diskndh = find_child_by_name(slotndh, DISK_FRU_NAME);
23470Sstevel@tonic-gate 	if (diskndh == NULL) {
23480Sstevel@tonic-gate 		return;
23490Sstevel@tonic-gate 	}
23500Sstevel@tonic-gate 	err = ptree_get_node_by_path(devpath, &devhdl);
23510Sstevel@tonic-gate 	if (err == PICL_SUCCESS) {
23520Sstevel@tonic-gate 		err = ptree_get_propval_by_name(diskndh,
23530Sstevel@tonic-gate 		    PICL_PROP_DEVICES, &tblhdl, sizeof (tblhdl));
23540Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
23550Sstevel@tonic-gate 			return;
23560Sstevel@tonic-gate 		err = ptree_get_next_by_col(tblhdl, &tblhdl2);
23570Sstevel@tonic-gate 		if (err != PICL_SUCCESS) {
23580Sstevel@tonic-gate 			err = create_table_entry(tblhdl, devhdl,
23590Sstevel@tonic-gate 			    PICL_CLASS_BLOCK);
23600Sstevel@tonic-gate 			if (err != PICL_SUCCESS)
23610Sstevel@tonic-gate 				return;
23620Sstevel@tonic-gate 			err = add_prop_ref(devhdl, diskndh,
23630Sstevel@tonic-gate 			    PICL_REFPROP_FRU_PARENT);
23640Sstevel@tonic-gate 			if (err != PICL_SUCCESS)
23650Sstevel@tonic-gate 				return;
23660Sstevel@tonic-gate 		}
23670Sstevel@tonic-gate 	} else {
23680Sstevel@tonic-gate 		/*
23690Sstevel@tonic-gate 		 * no mechanism for deleting row - so delete
23700Sstevel@tonic-gate 		 * whole table and start again
23710Sstevel@tonic-gate 		 */
23720Sstevel@tonic-gate 		err = ptree_get_prop_by_name(diskndh, PICL_PROP_DEVICES,
23730Sstevel@tonic-gate 		    &tblproph);
23740Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
23750Sstevel@tonic-gate 			return;
23760Sstevel@tonic-gate 		err = ptree_delete_prop(tblproph);
23770Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
23780Sstevel@tonic-gate 			return;
23790Sstevel@tonic-gate 		(void) ptree_destroy_prop(tblproph);
23800Sstevel@tonic-gate 		err = create_table(diskndh, &tblhdl, PICL_PROP_DEVICES);
23810Sstevel@tonic-gate 		if (err != PICL_SUCCESS)
23820Sstevel@tonic-gate 			return;
23830Sstevel@tonic-gate 	}
23840Sstevel@tonic-gate }
23850Sstevel@tonic-gate 
23861103Sjbeloro /*
23871103Sjbeloro  * We will light the OK2REMOVE LED for disks configured
23881103Sjbeloro  * into a raid if (and only if) the driver reports
23891103Sjbeloro  * that the disk has failed.
23901103Sjbeloro  */
23910Sstevel@tonic-gate static int
raid_ok2rem_policy(raid_config_t config,int target)23921103Sjbeloro raid_ok2rem_policy(raid_config_t config, int target)
23930Sstevel@tonic-gate {
23941103Sjbeloro 	int i;
23951103Sjbeloro 
23961103Sjbeloro 	for (i = 0; i < config.ndisks; i++) {
23971103Sjbeloro 		int d = config.disk[i];
23981103Sjbeloro 		int dstatus = config.diskstatus[i];
23991103Sjbeloro 
24001103Sjbeloro 		if (d  == target)	{
24011103Sjbeloro 			switch (dstatus) {
24021103Sjbeloro 			case RAID_DISKSTATUS_MISSING:
24031103Sjbeloro 				/* If LED is on, turn it off */
24041103Sjbeloro 				if (disk_ready[d] == B_FALSE) {
24051103Sjbeloro 					if (set_led(disk_name[d], REMOK_LED,
24061103Sjbeloro 					    PICL_PROPVAL_OFF) == PICL_SUCCESS) {
24071103Sjbeloro 						disk_ready[d] = B_TRUE;
24081103Sjbeloro 					}
24091103Sjbeloro 				}
24101103Sjbeloro 			break;
24111103Sjbeloro 			case RAID_DISKSTATUS_GOOD:
24121103Sjbeloro 				if (disk_ready[d] != B_TRUE) {
24131103Sjbeloro 					if (set_led(disk_name[d], REMOK_LED,
24141103Sjbeloro 					    PICL_PROPVAL_OFF) == PICL_SUCCESS) {
24151103Sjbeloro 						disk_ready[d] = B_TRUE;
24161103Sjbeloro 					}
24171103Sjbeloro 				}
24181103Sjbeloro 			break;
24191103Sjbeloro 			case RAID_DISKSTATUS_FAILED:
24201103Sjbeloro 				if (disk_ready[d] != B_FALSE) {
24211103Sjbeloro 					if (set_led(disk_name[d], REMOK_LED,
2422*12601SJustin.Frank@Sun.COM 					    PICL_PROPVAL_ON) == PICL_SUCCESS) {
24231103Sjbeloro 						disk_ready[d] = B_FALSE;
24241103Sjbeloro 					}
24251103Sjbeloro 				}
24261103Sjbeloro 			break;
24271103Sjbeloro 			default:
24281103Sjbeloro 			break;
24291103Sjbeloro 			}
24301103Sjbeloro 			return (1);
24311103Sjbeloro 		}
24321103Sjbeloro 	}
24331103Sjbeloro 	return (0);
24341103Sjbeloro }
24351103Sjbeloro 
24361103Sjbeloro static int
check_raid(int target)24371103Sjbeloro check_raid(int target)
24381103Sjbeloro {
24391103Sjbeloro 	raid_config_t	config;
24400Sstevel@tonic-gate 	int	fd;
24411103Sjbeloro 	int	numvols;
24421103Sjbeloro 	int	i, j;
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 	switch (sys_platform) {
24450Sstevel@tonic-gate 	case PLAT_CHALUPA:
24460Sstevel@tonic-gate 	case PLAT_CHALUPA19:
24470Sstevel@tonic-gate 		fd = open(V440_DISK_DEVCTL, O_RDONLY);
24480Sstevel@tonic-gate 		break;
24491103Sjbeloro 	case PLAT_SEATTLE1U:
24501103Sjbeloro 	case PLAT_SEATTLE2U:
24511103Sjbeloro 		fd = open(SEATTLE_DISK_DEVCTL, O_RDONLY);
24521103Sjbeloro 		break;
24531103Sjbeloro 	case PLAT_BOSTON:
24541296Sfw157321 		if (boston_1068e_flag) {
2455*12601SJustin.Frank@Sun.COM 			fd = open(BOSTON_DISK_DEVCTL_1068E, O_RDONLY);
24561296Sfw157321 		} else {
2457*12601SJustin.Frank@Sun.COM 			fd = open(BOSTON_DISK_DEVCTL_1068X, O_RDONLY);
24581296Sfw157321 		}
24591103Sjbeloro 		break;
24600Sstevel@tonic-gate 	default:
24610Sstevel@tonic-gate 		fd = -1;
24620Sstevel@tonic-gate 		break;
24630Sstevel@tonic-gate 	}
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 	if (fd == -1) {
24661103Sjbeloro 		return (0);
24671103Sjbeloro 	}
24681103Sjbeloro 
24691103Sjbeloro 	if (ioctl(fd, RAID_NUMVOLUMES, &numvols)) {
24701103Sjbeloro 		(void) close(fd);
24711103Sjbeloro 		return (0);
24720Sstevel@tonic-gate 	}
24730Sstevel@tonic-gate 
24741103Sjbeloro 	for (i = 0; i < numvols; i++)	{
24751103Sjbeloro 		config.unitid = i;
24761103Sjbeloro 		if (ioctl(fd, RAID_GETCONFIG, &config)) {
24771103Sjbeloro 			(void) close(fd);
24781103Sjbeloro 			return (0);
24791103Sjbeloro 		}
24801103Sjbeloro 		if (raid_ok2rem_policy(config, target))	{
24811103Sjbeloro 			(void) close(fd);
24821103Sjbeloro 			return (1);
24831103Sjbeloro 		}
24840Sstevel@tonic-gate 	}
24850Sstevel@tonic-gate 
24860Sstevel@tonic-gate 	(void) close(fd);
24870Sstevel@tonic-gate 	return (0);
24880Sstevel@tonic-gate }
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate /*ARGSUSED*/
24910Sstevel@tonic-gate static void *
disk_leds_thread(void * args)24920Sstevel@tonic-gate disk_leds_thread(void *args)
24930Sstevel@tonic-gate {
24940Sstevel@tonic-gate 	int 	c;
24950Sstevel@tonic-gate 	int 	i;
24960Sstevel@tonic-gate 	char	**disk_dev;
24971296Sfw157321 	int fd;
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	devctl_hdl_t dhdl;
25000Sstevel@tonic-gate 
25010Sstevel@tonic-gate 	int 	n_disks = 0,
2502*12601SJustin.Frank@Sun.COM 	    do_raid = 0,
2503*12601SJustin.Frank@Sun.COM 	    err 	= 0;
25040Sstevel@tonic-gate 	uint_t	statep	= 0;
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate 	static char *mpxu_devs[] = {
25070Sstevel@tonic-gate 		"/pci@1c,600000/scsi@2/sd@0,0",
25080Sstevel@tonic-gate 		"/pci@1c,600000/scsi@2/sd@1,0",
25090Sstevel@tonic-gate 		"/pci@1c,600000/scsi@2/sd@2,0",
25100Sstevel@tonic-gate 		"/pci@1c,600000/scsi@2/sd@3,0"
25110Sstevel@tonic-gate 	};
25120Sstevel@tonic-gate 
25130Sstevel@tonic-gate 	static char *ents_devs[] = {
25140Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@0,0",
25150Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@1,0",
25160Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@2,0",
25170Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@3,0",
25180Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@8,0",
25190Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@9,0",
25200Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@a,0",
25210Sstevel@tonic-gate 		"/pci@1d,700000/scsi@4/sd@b,0"
25220Sstevel@tonic-gate 	};
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate 	static char *v440_devs[] = {
25250Sstevel@tonic-gate 		"/pci@1f,700000/scsi@2/sd@0,0",
25260Sstevel@tonic-gate 		"/pci@1f,700000/scsi@2/sd@1,0",
25270Sstevel@tonic-gate 		"/pci@1f,700000/scsi@2/sd@2,0",
25280Sstevel@tonic-gate 		"/pci@1f,700000/scsi@2/sd@3,0"
25290Sstevel@tonic-gate 	};
25300Sstevel@tonic-gate 
25310Sstevel@tonic-gate 	static char *n210_devs[] = {
25320Sstevel@tonic-gate 		"/pci@1c,600000/LSILogic,sas@1/sd@0,0",
25330Sstevel@tonic-gate 		"/pci@1c,600000/LSILogic,sas@1/sd@1,0"
25340Sstevel@tonic-gate 	};
25350Sstevel@tonic-gate 
25361103Sjbeloro 	static char *seattle_devs[] = {
25371103Sjbeloro 		"/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@0,0",
25381103Sjbeloro 		"/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@1,0",
25391103Sjbeloro 		"/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@2,0",
25401103Sjbeloro 		"/pci@1e,600000/pci@0/pci@a/pci@0/pci@8/scsi@1/sd@3,0"
25411103Sjbeloro 	};
25421103Sjbeloro 
25431296Sfw157321 	static char *boston_devs_1068e[] = {
25441296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@0,0",
25451296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@1,0",
25461296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@2,0",
25471296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@3,0",
25481296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@4,0",
25491296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@5,0",
25501296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@6,0",
25511296Sfw157321 		"/pci@1e,600000/pci@0/pci@2/scsi@0/sd@7,0"
25521296Sfw157321 	};
25531296Sfw157321 	static char *boston_devs_1068x[] = {
25541103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@0,0",
25551103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@1,0",
25561103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@2,0",
25571103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@3,0",
25581103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@4,0",
25591103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@5,0",
25601103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@6,0",
25611103Sjbeloro 		"/pci@1f,700000/pci@0/pci@2/pci@0/pci@8/LSILogic,sas@1/sd@7,0"
25621103Sjbeloro 	};
25631103Sjbeloro 
25640Sstevel@tonic-gate 	char	*ddev[N_DISKS];		/* "/devices"  */
25650Sstevel@tonic-gate 	char	*pdev[N_DISKS];		/* "/platform" */
25660Sstevel@tonic-gate 
25670Sstevel@tonic-gate 	switch (sys_platform) {
25680Sstevel@tonic-gate 
25690Sstevel@tonic-gate 	case PLAT_ENTS:
25700Sstevel@tonic-gate 		disk_dev = ents_devs;
25710Sstevel@tonic-gate 		n_disks = N_ENTS_DISKS;
25720Sstevel@tonic-gate 		break;
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 	case PLAT_CHALUPA:
25750Sstevel@tonic-gate 	case PLAT_CHALUPA19:
25760Sstevel@tonic-gate 		do_raid = 1;
25770Sstevel@tonic-gate 		disk_dev = v440_devs;
25780Sstevel@tonic-gate 		n_disks = N_CHALUPA_DISKS;
25790Sstevel@tonic-gate 		break;
25800Sstevel@tonic-gate 
25810Sstevel@tonic-gate 	case PLAT_SALSA19:
25820Sstevel@tonic-gate 		disk_dev = n210_devs;
25830Sstevel@tonic-gate 		n_disks = N_EN19_DISKS;
25840Sstevel@tonic-gate 		break;
25850Sstevel@tonic-gate 
25861103Sjbeloro 	case PLAT_SEATTLE1U:
25871103Sjbeloro 	case PLAT_SEATTLE2U:
25881103Sjbeloro 		do_raid = 1;
25891103Sjbeloro 		disk_dev = seattle_devs;
25901103Sjbeloro 		n_disks = (sys_platform == PLAT_SEATTLE1U) ?
2591*12601SJustin.Frank@Sun.COM 		    N_SEATTLE1U_DISKS : N_SEATTLE2U_DISKS;
25921103Sjbeloro 		break;
25931103Sjbeloro 
25941103Sjbeloro 	case PLAT_BOSTON:
25951296Sfw157321 		/*
25961296Sfw157321 		 * If we can open the devctl path for the built-in 1068E
25971296Sfw157321 		 * controller then assume we're a 1068E-equipped Boston
25981296Sfw157321 		 * and make all the paths appropriate for that hardware.
25991296Sfw157321 		 * Otherwise assume we are a 1068X-equipped Boston and
26001296Sfw157321 		 * make all of the paths appropriate for a 1068X PCI-X
26011296Sfw157321 		 * controller in PCI slot 4.
26021296Sfw157321 		 *
26031296Sfw157321 		 * The flag is also used in the check_raid() function.
26041296Sfw157321 		 */
26051296Sfw157321 		if ((fd = open(BOSTON_DISK_DEVCTL_1068E, O_RDONLY)) != -1) {
26061296Sfw157321 			boston_1068e_flag = 1;
26071296Sfw157321 			disk_dev = boston_devs_1068e;
26081296Sfw157321 		} else {
26091296Sfw157321 			boston_1068e_flag = 0;
26101296Sfw157321 			disk_dev = boston_devs_1068x;
26111296Sfw157321 		}
26121296Sfw157321 		(void) close(fd);
26131103Sjbeloro 		do_raid = 1;
26141103Sjbeloro 		n_disks = N_BOSTON_DISKS;
26151103Sjbeloro 		break;
26161103Sjbeloro 
26170Sstevel@tonic-gate 	default: /* PLAT_ENXS/PLAT_EN19 */
26180Sstevel@tonic-gate 		disk_dev = mpxu_devs;
26190Sstevel@tonic-gate 		n_disks = (sys_platform == PLAT_EN19) ?
2620*12601SJustin.Frank@Sun.COM 		    N_EN19_DISKS : N_MPXU_DISKS;
26210Sstevel@tonic-gate 	}
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 	/*
26240Sstevel@tonic-gate 	 * make up disk names
26250Sstevel@tonic-gate 	 */
26260Sstevel@tonic-gate 
26270Sstevel@tonic-gate 	for (i = 0; i < n_disks; i++) {
26280Sstevel@tonic-gate 		char buffer[MAXPATHLEN];
26290Sstevel@tonic-gate 		sprintf(buffer, "/devices%s", disk_dev[i]);
26300Sstevel@tonic-gate 		ddev[i] = strdup(buffer);
26310Sstevel@tonic-gate 		sprintf(buffer, "/platform%s", disk_dev[i]);
26320Sstevel@tonic-gate 		pdev[i] = strdup(buffer);
26330Sstevel@tonic-gate 	}
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 	disk_leds_thread_running = B_TRUE;
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 	for (;;) {
26380Sstevel@tonic-gate 		for (i = 0; i < n_disks; i++) {
26390Sstevel@tonic-gate 			/*
26401103Sjbeloro 			 * If it's one of the RAID disks, we have already
26410Sstevel@tonic-gate 			 * applied the ok2remove policy.
26420Sstevel@tonic-gate 			 */
26431103Sjbeloro 			if (do_raid && check_raid(i))	{
26440Sstevel@tonic-gate 				continue;
26451103Sjbeloro 			}
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate 			dhdl = devctl_device_acquire(ddev[i], 0);
26480Sstevel@tonic-gate 			devctl_device_getstate(dhdl, &statep);
26490Sstevel@tonic-gate 			devctl_release(dhdl);
26500Sstevel@tonic-gate 
26510Sstevel@tonic-gate 			if (statep & DEVICE_OFFLINE) {
26520Sstevel@tonic-gate 				if (disk_ready[i] != B_FALSE) {
26530Sstevel@tonic-gate 					update_disk_node(disk_name[i], pdev[i]);
26540Sstevel@tonic-gate 					if (set_led(disk_name[i], REMOK_LED,
26550Sstevel@tonic-gate 					    PICL_PROPVAL_ON) == PICL_SUCCESS)
26560Sstevel@tonic-gate 						disk_ready[i] = B_FALSE;
26570Sstevel@tonic-gate 				}
26580Sstevel@tonic-gate 			} else if (statep & DEVICE_ONLINE) {
26590Sstevel@tonic-gate 				if (disk_ready[i] != B_TRUE) {
26600Sstevel@tonic-gate 					update_disk_node(disk_name[i], pdev[i]);
26610Sstevel@tonic-gate 					if (set_led(disk_name[i], REMOK_LED,
26620Sstevel@tonic-gate 					    PICL_PROPVAL_OFF) == PICL_SUCCESS)
26630Sstevel@tonic-gate 						disk_ready[i] = B_TRUE;
26640Sstevel@tonic-gate 				}
26650Sstevel@tonic-gate 			}
26660Sstevel@tonic-gate 		}
26670Sstevel@tonic-gate 
26680Sstevel@tonic-gate 		/*
26690Sstevel@tonic-gate 		 * wait a bit until we check again
26700Sstevel@tonic-gate 		 */
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate 		(void) poll(NULL, 0, DISK_POLL_TIME);
26730Sstevel@tonic-gate 
26740Sstevel@tonic-gate 		/*
26750Sstevel@tonic-gate 		 * are we to stop?
26760Sstevel@tonic-gate 		 */
26770Sstevel@tonic-gate 
26780Sstevel@tonic-gate 		(void) pthread_mutex_lock(&g_mutex);
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate 		while (g_finish_now) {
26810Sstevel@tonic-gate 			/*
26820Sstevel@tonic-gate 			 * notify _fini routine that we've paused
26830Sstevel@tonic-gate 			 */
26840Sstevel@tonic-gate 			disk_leds_thread_ack = B_TRUE;
26850Sstevel@tonic-gate 			(void) pthread_cond_signal(&g_cv_ack);
26860Sstevel@tonic-gate 
26870Sstevel@tonic-gate 			/*
26880Sstevel@tonic-gate 			 * and go to sleep in case we get restarted
26890Sstevel@tonic-gate 			 */
26900Sstevel@tonic-gate 			(void) pthread_cond_wait(&g_cv, &g_mutex);
26910Sstevel@tonic-gate 		}
26920Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&g_mutex);
26930Sstevel@tonic-gate 	}
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	return ((void *)err);
26960Sstevel@tonic-gate }
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate /*
26990Sstevel@tonic-gate  * Given the powersupply name, convert to addr
27000Sstevel@tonic-gate  */
27010Sstevel@tonic-gate static int
ps_name_to_addr(char * name)27020Sstevel@tonic-gate ps_name_to_addr(char *name)
27030Sstevel@tonic-gate {
27040Sstevel@tonic-gate 	int ps_addr = 0;
27050Sstevel@tonic-gate 	if ((strcmp(name, PS0_NAME) == 0) ||
2706*12601SJustin.Frank@Sun.COM 	    (strcmp(name, PSU0_NAME) == 0))	{
27071103Sjbeloro 		switch (sys_platform) {
27081103Sjbeloro 		case PLAT_SEATTLE1U:
27091103Sjbeloro 		case PLAT_SEATTLE2U:
27101103Sjbeloro 			ps_addr = SEATTLE_PS0_ADDR;
27111103Sjbeloro 			break;
27121103Sjbeloro 		case PLAT_BOSTON:
27131103Sjbeloro 			ps_addr = BOSTON_PS0_ADDR;
27141103Sjbeloro 			break;
27151103Sjbeloro 		default:
27161103Sjbeloro 			ps_addr = PS0_ADDR;
27171103Sjbeloro 			break;
27181103Sjbeloro 		}
27191103Sjbeloro 	} else if ((strcmp(name, PS1_NAME) == 0) ||
2720*12601SJustin.Frank@Sun.COM 	    (strcmp(name, PSU1_NAME) == 0))	{
27211103Sjbeloro 		switch (sys_platform) {
27221103Sjbeloro 		case PLAT_SEATTLE1U:
27231103Sjbeloro 		case PLAT_SEATTLE2U:
27241103Sjbeloro 			ps_addr = SEATTLE_PS1_ADDR;
27251103Sjbeloro 			break;
27261103Sjbeloro 		case PLAT_BOSTON:
27271103Sjbeloro 			ps_addr = BOSTON_PS1_ADDR;
27281103Sjbeloro 			break;
27291103Sjbeloro 		default:
27301103Sjbeloro 			ps_addr = PS1_ADDR;
27311103Sjbeloro 			break;
27321103Sjbeloro 		}
27331103Sjbeloro 	} else if ((strcmp(name, PS2_NAME) == 0) ||
2734*12601SJustin.Frank@Sun.COM 	    (strcmp(name, PSU2_NAME) == 0))	{
27351103Sjbeloro 		switch (sys_platform) {
27361103Sjbeloro 		case PLAT_BOSTON:
27371103Sjbeloro 			ps_addr = BOSTON_PS2_ADDR;
27381103Sjbeloro 			break;
27391103Sjbeloro 		default:
27401103Sjbeloro 			ps_addr = PS2_ADDR;
27411103Sjbeloro 			break;
27421103Sjbeloro 		}
27431103Sjbeloro 	} else if ((strcmp(name, PS3_NAME) == 0) ||
2744*12601SJustin.Frank@Sun.COM 	    (strcmp(name, PSU3_NAME) == 0))	{
27451103Sjbeloro 		switch (sys_platform) {
27461103Sjbeloro 		case PLAT_BOSTON:
27471103Sjbeloro 			ps_addr = BOSTON_PS3_ADDR;
27481103Sjbeloro 			break;
27491103Sjbeloro 		default:
27501103Sjbeloro 			ps_addr = PS3_ADDR;
27511103Sjbeloro 			break;
27521103Sjbeloro 		}
27531103Sjbeloro 	}
27540Sstevel@tonic-gate 
27550Sstevel@tonic-gate 	return (ps_addr);
27560Sstevel@tonic-gate }
27570Sstevel@tonic-gate 
27580Sstevel@tonic-gate /*
27590Sstevel@tonic-gate  * Given powersupply name, convert to unit addr
27600Sstevel@tonic-gate  */
27610Sstevel@tonic-gate static char *
ps_name_to_unitaddr(char * name)27620Sstevel@tonic-gate ps_name_to_unitaddr(char *name)
27630Sstevel@tonic-gate {
27640Sstevel@tonic-gate 	char *unitaddr;
27650Sstevel@tonic-gate 
27661103Sjbeloro 	if (strcmp(name, PS0_NAME) == 0)	{
27671103Sjbeloro 		switch (sys_platform) {
27681103Sjbeloro 		case PLAT_SEATTLE1U:
27691103Sjbeloro 		case PLAT_SEATTLE2U:
27701103Sjbeloro 			unitaddr = SEATTLE_PS0_UNITADDR;
27711103Sjbeloro 			break;
27721103Sjbeloro 		case PLAT_BOSTON:
27731103Sjbeloro 			unitaddr = BOSTON_PS0_UNITADDR;
27741103Sjbeloro 			break;
27751103Sjbeloro 		default:
27761103Sjbeloro 			unitaddr = PS0_UNITADDR;
27771103Sjbeloro 			break;
27781103Sjbeloro 		}
27791103Sjbeloro 	} else if (strcmp(name, PS1_NAME) == 0)	{
27801103Sjbeloro 		switch (sys_platform) {
27811103Sjbeloro 		case PLAT_SEATTLE1U:
27821103Sjbeloro 		case PLAT_SEATTLE2U:
27831103Sjbeloro 			unitaddr = SEATTLE_PS1_UNITADDR;
27841103Sjbeloro 			break;
27851103Sjbeloro 		case PLAT_BOSTON:
27861103Sjbeloro 			unitaddr = BOSTON_PS1_UNITADDR;
27871103Sjbeloro 			break;
27881103Sjbeloro 		default:
27891103Sjbeloro 			unitaddr = PS1_UNITADDR;
27901103Sjbeloro 			break;
27911103Sjbeloro 		}
27921103Sjbeloro 	} else if (strcmp(name, PS2_NAME) == 0)	{
27931103Sjbeloro 		switch (sys_platform) {
27941103Sjbeloro 		case PLAT_BOSTON:
27951103Sjbeloro 			unitaddr = BOSTON_PS2_UNITADDR;
27961103Sjbeloro 			break;
27971103Sjbeloro 		default:
27981103Sjbeloro 			unitaddr = PS2_UNITADDR;
27991103Sjbeloro 			break;
28001103Sjbeloro 		}
28011103Sjbeloro 	} else if (strcmp(name, PS3_NAME) == 0)	{
28021103Sjbeloro 		switch (sys_platform) {
28031103Sjbeloro 		case PLAT_BOSTON:
28041103Sjbeloro 			unitaddr = BOSTON_PS3_UNITADDR;
28051103Sjbeloro 			break;
28061103Sjbeloro 		default:
28071103Sjbeloro 			unitaddr = PS3_UNITADDR;
28081103Sjbeloro 			break;
28091103Sjbeloro 		}
28101103Sjbeloro 	}
28110Sstevel@tonic-gate 	else
28120Sstevel@tonic-gate 		unitaddr = NULL;
28130Sstevel@tonic-gate 
28140Sstevel@tonic-gate 	return (unitaddr);
28150Sstevel@tonic-gate }
28160Sstevel@tonic-gate 
28170Sstevel@tonic-gate /*
28180Sstevel@tonic-gate  * converts apid to real FRU name in PICL tree. The
28190Sstevel@tonic-gate  * name of powersupply devices on chalupa19 are
28200Sstevel@tonic-gate  * PSU instead of PS
28210Sstevel@tonic-gate  */
28220Sstevel@tonic-gate static char *
ps_apid_to_nodename(char * apid)28230Sstevel@tonic-gate ps_apid_to_nodename(char *apid)
28240Sstevel@tonic-gate {
28250Sstevel@tonic-gate 	char *nodename;
28260Sstevel@tonic-gate 
28270Sstevel@tonic-gate 	if (sys_platform != PLAT_CHALUPA19)
28280Sstevel@tonic-gate 		return (apid);
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 	if (strcmp(apid, PS0_NAME) == 0)
28310Sstevel@tonic-gate 		nodename = PSU0_NAME;
28320Sstevel@tonic-gate 	else if (strcmp(apid, PS1_NAME) == 0)
28330Sstevel@tonic-gate 		nodename = PSU1_NAME;
28340Sstevel@tonic-gate 	else if (strcmp(apid, PS2_NAME) == 0)
28350Sstevel@tonic-gate 		nodename = PSU2_NAME;
28360Sstevel@tonic-gate 	else if (strcmp(apid, PS3_NAME) == 0)
28370Sstevel@tonic-gate 		nodename = PSU3_NAME;
28380Sstevel@tonic-gate 	else
28390Sstevel@tonic-gate 		nodename = apid;
28400Sstevel@tonic-gate 
28410Sstevel@tonic-gate 	return (nodename);
28420Sstevel@tonic-gate }
28430Sstevel@tonic-gate 
28440Sstevel@tonic-gate /*
28450Sstevel@tonic-gate  * Create SEEPROM node at insertion time.
28460Sstevel@tonic-gate  */
28470Sstevel@tonic-gate static int
create_i2c_node(char * ap_id)28480Sstevel@tonic-gate create_i2c_node(char *ap_id)
28490Sstevel@tonic-gate {
28500Sstevel@tonic-gate 	int	nd_reg[2];
28510Sstevel@tonic-gate 	devctl_ddef_t	ddef_hdl;
28520Sstevel@tonic-gate 	devctl_hdl_t	bus_hdl;
28530Sstevel@tonic-gate 	devctl_hdl_t	dev_hdl;
28540Sstevel@tonic-gate 	char		dev_path[MAXPATHLEN];
28552392Svenki 	char		*compatible;
28560Sstevel@tonic-gate 
28570Sstevel@tonic-gate 	/* create seeprom node */
28580Sstevel@tonic-gate 	nd_reg[0] = 0;
28590Sstevel@tonic-gate 	nd_reg[1] = ps_name_to_addr(ap_id);
28600Sstevel@tonic-gate 
28611103Sjbeloro 	switch (sys_platform) {
28621103Sjbeloro 	case PLAT_SEATTLE1U:
28631103Sjbeloro 	case PLAT_SEATTLE2U:
28641103Sjbeloro 		bus_hdl = devctl_bus_acquire(SEATTLE_PSU_I2C_BUS_DEV, 0);
28652392Svenki 		compatible = SEATTLE_PSU_COMPATIBLE;
28661103Sjbeloro 		break;
28671103Sjbeloro 	case PLAT_BOSTON:
28681103Sjbeloro 		bus_hdl = devctl_bus_acquire(BOSTON_PSU_I2C_BUS_DEV, 0);
28692392Svenki 		compatible = BOSTON_PSU_COMPATIBLE;
28701103Sjbeloro 		break;
28711103Sjbeloro 	default:
28721103Sjbeloro 		bus_hdl = devctl_bus_acquire(PSU_I2C_BUS_DEV, 0);
28732392Svenki 		compatible = PSU_COMPATIBLE;
28741103Sjbeloro 		break;
28751103Sjbeloro 	}
28761103Sjbeloro 
28770Sstevel@tonic-gate 	if (bus_hdl == NULL)
28780Sstevel@tonic-gate 		return (DDI_FAILURE);
28790Sstevel@tonic-gate 
28800Sstevel@tonic-gate 	/* device definition properties */
28810Sstevel@tonic-gate 	ddef_hdl = devctl_ddef_alloc(PS_DEVICE_NAME, 0);
28822392Svenki 	(void) devctl_ddef_string(ddef_hdl, "compatible", compatible);
28830Sstevel@tonic-gate 	(void) devctl_ddef_string(ddef_hdl, "device_type", "seeprom");
28840Sstevel@tonic-gate 	(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg);
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate 	/* create the device node */
28870Sstevel@tonic-gate 	if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl))
28880Sstevel@tonic-gate 		return (DDI_FAILURE);
28890Sstevel@tonic-gate 
28900Sstevel@tonic-gate 	if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL)
28910Sstevel@tonic-gate 		return (DDI_FAILURE);
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate 	devctl_release(dev_hdl);
28940Sstevel@tonic-gate 	devctl_ddef_free(ddef_hdl);
28950Sstevel@tonic-gate 	devctl_release(bus_hdl);
28960Sstevel@tonic-gate 	return (DDI_SUCCESS);
28970Sstevel@tonic-gate }
28980Sstevel@tonic-gate 
28990Sstevel@tonic-gate /*
29000Sstevel@tonic-gate  * Delete SEEPROM node at insertion time.
29010Sstevel@tonic-gate  */
29020Sstevel@tonic-gate static void
delete_i2c_node(char * ap_id)29030Sstevel@tonic-gate delete_i2c_node(char *ap_id)
29040Sstevel@tonic-gate {
29050Sstevel@tonic-gate 	devctl_hdl_t	dev_hdl;
29060Sstevel@tonic-gate 	char	buf[MAXPATHLEN];
29070Sstevel@tonic-gate 
29081103Sjbeloro 	switch (sys_platform) {
29091103Sjbeloro 	case PLAT_SEATTLE1U:
29101103Sjbeloro 	case PLAT_SEATTLE2U:
29111103Sjbeloro 		sprintf_buf2(buf, SEATTLE_PSU_DEV, ps_name_to_addr(ap_id));
29121103Sjbeloro 		break;
29131103Sjbeloro 	case PLAT_BOSTON:
29141103Sjbeloro 		sprintf_buf2(buf, BOSTON_PSU_DEV, ps_name_to_addr(ap_id));
29151103Sjbeloro 		break;
29161103Sjbeloro 	default:
29171103Sjbeloro 		sprintf_buf2(buf, PSU_DEV, ps_name_to_addr(ap_id));
29181103Sjbeloro 		break;
29191103Sjbeloro 	}
29201103Sjbeloro 
29210Sstevel@tonic-gate 	dev_hdl = devctl_device_acquire(buf, 0);
29220Sstevel@tonic-gate 	if (dev_hdl == NULL) {
29230Sstevel@tonic-gate 		return;
29240Sstevel@tonic-gate 	}
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 	/*
29270Sstevel@tonic-gate 	 * If the seeprom driver is not loaded, calls to
29280Sstevel@tonic-gate 	 * devctl_device_remove fails for seeprom devices
29290Sstevel@tonic-gate 	 */
29300Sstevel@tonic-gate 	if (devctl_device_remove(dev_hdl)) {
29310Sstevel@tonic-gate 		di_init_driver(SEEPROM_DRIVER_NAME, 0);
29320Sstevel@tonic-gate 		devctl_device_remove(dev_hdl);
29330Sstevel@tonic-gate 	}
29340Sstevel@tonic-gate 	devctl_release(dev_hdl);
29350Sstevel@tonic-gate }
29360Sstevel@tonic-gate 
29370Sstevel@tonic-gate static void
add_op_status(envmon_hpu_t * hpu,int * index)29380Sstevel@tonic-gate add_op_status(envmon_hpu_t *hpu, int *index)
29390Sstevel@tonic-gate {
29400Sstevel@tonic-gate 	boolean_t		rmc_flag;
29410Sstevel@tonic-gate 	boolean_t		ps_flag;
29420Sstevel@tonic-gate 	boolean_t		disk_flag;
29430Sstevel@tonic-gate 	char			node_name[MAXPATHLEN];
29440Sstevel@tonic-gate 	boolean_t		flag;
29450Sstevel@tonic-gate 
29460Sstevel@tonic-gate 	rmc_flag = (strcmp(hpu->id.name, RMC_NAME) == 0);
29470Sstevel@tonic-gate 	ps_flag = (strncmp(hpu->id.name, PS_NAME,
2948*12601SJustin.Frank@Sun.COM 	    PS_NAME_LEN) == 0);
29490Sstevel@tonic-gate 	disk_flag = (strncmp(hpu->id.name, DISK_NAME,
2950*12601SJustin.Frank@Sun.COM 	    DISK_NAME_LEN) == 0);
29511103Sjbeloro 	if (rmc_flag || ps_flag) {
29520Sstevel@tonic-gate 		idprop->idp[*index].envhandle = hpu->id;
29530Sstevel@tonic-gate 		flag = rmc_flag && ((sys_platform != PLAT_CHALUPA) &&
2954*12601SJustin.Frank@Sun.COM 		    (sys_platform != PLAT_CHALUPA19));
29550Sstevel@tonic-gate 		sprintf_buf2(node_name,
2956*12601SJustin.Frank@Sun.COM 		    flag ? SYS_BOARD_PATH : CHASSIS_LOC_PATH, ps_flag ?
2957*12601SJustin.Frank@Sun.COM 		    ps_apid_to_nodename(hpu->id.name) : hpu->id.name);
29580Sstevel@tonic-gate 
29591103Sjbeloro 		add_op_status_by_name(node_name, ps_flag ? PS_FRU_NAME : NULL,
2960*12601SJustin.Frank@Sun.COM 		    &idprop->idp[(*index)++].volprop);
29611103Sjbeloro 	} else if (disk_flag)	{
29621103Sjbeloro 		idprop->idp[*index].envhandle = hpu->id;
29631103Sjbeloro 		switch (sys_platform)	{
29641103Sjbeloro 		case PLAT_CHALUPA:
29651103Sjbeloro 		case PLAT_CHALUPA19:
29661103Sjbeloro 			sprintf_buf2(node_name, CHASSIS_LOC_PATH, hpu->id.name);
29671103Sjbeloro 			break;
29681103Sjbeloro 		case PLAT_SEATTLE1U:
29691103Sjbeloro 			sprintf_buf2(node_name, SEATTLE1U_HDDBP_PATH, \
2970*12601SJustin.Frank@Sun.COM 			    hpu->id.name);
29711103Sjbeloro 			break;
29721103Sjbeloro 		case PLAT_SEATTLE2U:
29731103Sjbeloro 			sprintf_buf2(node_name, SEATTLE2U_HDDBP_PATH, \
2974*12601SJustin.Frank@Sun.COM 			    hpu->id.name);
29751103Sjbeloro 			break;
29761103Sjbeloro 		case PLAT_BOSTON:
29771103Sjbeloro 			sprintf_buf2(node_name, BOSTON_HDDBP_PATH, \
2978*12601SJustin.Frank@Sun.COM 			    hpu->id.name);
29791103Sjbeloro 			break;
29801103Sjbeloro 		default:
29811103Sjbeloro 			sprintf_buf2(node_name, SYS_BOARD_PATH, hpu->id.name);
29821103Sjbeloro 			break;
29831103Sjbeloro 		}
29841103Sjbeloro 		add_op_status_by_name(node_name, DISK_FRU_NAME,
2985*12601SJustin.Frank@Sun.COM 		    &idprop->idp[(*index)++].volprop);
29860Sstevel@tonic-gate 	}
29870Sstevel@tonic-gate }
2988