1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * This plugin checks the status of FC-AL disks periodically and
29*7c478bd9Sstevel@tonic-gate  * in response to PICL events. It adjusts the state of the FC-AL LEDs
30*7c478bd9Sstevel@tonic-gate  * to match the disk status.
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <limits.h>
36*7c478bd9Sstevel@tonic-gate #include <unistd.h>
37*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
38*7c478bd9Sstevel@tonic-gate #include <alloca.h>
39*7c478bd9Sstevel@tonic-gate #include <syslog.h>
40*7c478bd9Sstevel@tonic-gate #include <string.h>
41*7c478bd9Sstevel@tonic-gate #include <libintl.h>
42*7c478bd9Sstevel@tonic-gate #include <pthread.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
46*7c478bd9Sstevel@tonic-gate #include <poll.h>
47*7c478bd9Sstevel@tonic-gate #include <errno.h>
48*7c478bd9Sstevel@tonic-gate #include <libnvpair.h>
49*7c478bd9Sstevel@tonic-gate #include "fcal_leds.h"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate static void fcal_leds_register(void);
52*7c478bd9Sstevel@tonic-gate static void fcal_leds_init(void);
53*7c478bd9Sstevel@tonic-gate static void fcal_leds_fini(void);
54*7c478bd9Sstevel@tonic-gate static void *fcal_poll_thread(void *args);
55*7c478bd9Sstevel@tonic-gate static FILE *open_config(void);
56*7c478bd9Sstevel@tonic-gate static int read_led_state(ptree_rarg_t *parg, void *buf);
57*7c478bd9Sstevel@tonic-gate static void add_led_refs(led_dtls_t *dtls);
58*7c478bd9Sstevel@tonic-gate static void delete_led_refs(led_dtls_t *dtls);
59*7c478bd9Sstevel@tonic-gate static void piclfcal_evhandler(const char *ename, const void *earg,
60*7c478bd9Sstevel@tonic-gate     size_t size, void *cookie);
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate /*
63*7c478bd9Sstevel@tonic-gate  * Global thread data
64*7c478bd9Sstevel@tonic-gate  */
65*7c478bd9Sstevel@tonic-gate led_dtls_t		*g_led_dtls = NULL;
66*7c478bd9Sstevel@tonic-gate pthread_cond_t		g_cv;
67*7c478bd9Sstevel@tonic-gate pthread_cond_t		g_cv_ack;
68*7c478bd9Sstevel@tonic-gate pthread_mutex_t		g_mutex;
69*7c478bd9Sstevel@tonic-gate volatile int		g_event_flag;
70*7c478bd9Sstevel@tonic-gate volatile boolean_t	g_finish_now = B_FALSE;
71*7c478bd9Sstevel@tonic-gate volatile boolean_t	g_leds_thread_ack = B_FALSE;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate static picld_plugin_reg_t  my_reg_info = {
74*7c478bd9Sstevel@tonic-gate 	PICLD_PLUGIN_VERSION_1,
75*7c478bd9Sstevel@tonic-gate 	PICLD_PLUGIN_NON_CRITICAL,
76*7c478bd9Sstevel@tonic-gate 	"SUNW_fcal_leds",
77*7c478bd9Sstevel@tonic-gate 	fcal_leds_init,
78*7c478bd9Sstevel@tonic-gate 	fcal_leds_fini
79*7c478bd9Sstevel@tonic-gate };
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static boolean_t	cvAndMutexInit = B_FALSE;
82*7c478bd9Sstevel@tonic-gate static pthread_t	ledsthr_tid;
83*7c478bd9Sstevel@tonic-gate static pthread_attr_t	ledsthr_attr;
84*7c478bd9Sstevel@tonic-gate static boolean_t	ledsthr_created = B_FALSE;
85*7c478bd9Sstevel@tonic-gate static pthread_t	pollthr_tid;
86*7c478bd9Sstevel@tonic-gate static pthread_attr_t	pollthr_attr;
87*7c478bd9Sstevel@tonic-gate static boolean_t	pollthr_created = B_FALSE;
88*7c478bd9Sstevel@tonic-gate static volatile boolean_t poll_thread_ack = B_FALSE;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate /*
91*7c478bd9Sstevel@tonic-gate  * look up table for LED state
92*7c478bd9Sstevel@tonic-gate  */
93*7c478bd9Sstevel@tonic-gate static struct {
94*7c478bd9Sstevel@tonic-gate 	const led_state_t	led_state;
95*7c478bd9Sstevel@tonic-gate 	const char		*state_str;
96*7c478bd9Sstevel@tonic-gate } state_lookup[] = {
97*7c478bd9Sstevel@tonic-gate 	{ LED_STATE_OFF,	FCAL_PICL_LED_OFF	},
98*7c478bd9Sstevel@tonic-gate 	{ LED_STATE_ON,		FCAL_PICL_LED_ON	},
99*7c478bd9Sstevel@tonic-gate 	{ LED_STATE_TEST,	FCAL_PICL_LED_TEST	}
100*7c478bd9Sstevel@tonic-gate };
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #define	state_lkup_len	(sizeof (state_lookup) / sizeof (state_lookup[0]))
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate /*
105*7c478bd9Sstevel@tonic-gate  * executed as part of .init when the plugin is dlopen()ed
106*7c478bd9Sstevel@tonic-gate  */
107*7c478bd9Sstevel@tonic-gate #pragma	init(fcal_leds_register)
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static void
fcal_leds_register(void)110*7c478bd9Sstevel@tonic-gate fcal_leds_register(void)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate 	(void) picld_plugin_register(&my_reg_info);
113*7c478bd9Sstevel@tonic-gate }
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
116*7c478bd9Sstevel@tonic-gate static void
piclfcal_evhandler(const char * ename,const void * earg,size_t size,void * cookie)117*7c478bd9Sstevel@tonic-gate piclfcal_evhandler(const char *ename, const void *earg, size_t size,
118*7c478bd9Sstevel@tonic-gate     void *cookie)
119*7c478bd9Sstevel@tonic-gate {
120*7c478bd9Sstevel@tonic-gate 	int r;
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	if (earg == NULL)
123*7c478bd9Sstevel@tonic-gate 		return;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	r = pthread_mutex_lock(&g_mutex);
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	if (r != 0) {
128*7c478bd9Sstevel@tonic-gate 		SYSLOG(LOG_ERR, EM_MUTEX_FAIL, mystrerror(r));
129*7c478bd9Sstevel@tonic-gate 		return;
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 	g_event_flag |= FCAL_EV_CONFIG;
132*7c478bd9Sstevel@tonic-gate 	(void) pthread_cond_signal(&g_cv);
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&g_mutex);
135*7c478bd9Sstevel@tonic-gate }
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate /*
138*7c478bd9Sstevel@tonic-gate  * Locate and open relevant config file
139*7c478bd9Sstevel@tonic-gate  */
140*7c478bd9Sstevel@tonic-gate static FILE *
open_config(void)141*7c478bd9Sstevel@tonic-gate open_config(void)
142*7c478bd9Sstevel@tonic-gate {
143*7c478bd9Sstevel@tonic-gate 	FILE	*fp = NULL;
144*7c478bd9Sstevel@tonic-gate 	char	nmbuf[SYS_NMLN];
145*7c478bd9Sstevel@tonic-gate 	char	fname[PATH_MAX];
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) == -1)
148*7c478bd9Sstevel@tonic-gate 		return (NULL);
149*7c478bd9Sstevel@tonic-gate 	(void) snprintf(fname, sizeof (fname), PICLD_PLAT_PLUGIN_DIRF, nmbuf);
150*7c478bd9Sstevel@tonic-gate 	(void) strlcat(fname, FCAL_LEDS_CONF_FILE, sizeof (fname));
151*7c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "r");
152*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
153*7c478bd9Sstevel@tonic-gate 		SYSLOG(LOG_ERR, EM_CANT_OPEN, fname);
154*7c478bd9Sstevel@tonic-gate 	}
155*7c478bd9Sstevel@tonic-gate 	return (fp);
156*7c478bd9Sstevel@tonic-gate }
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate /*
159*7c478bd9Sstevel@tonic-gate  * read volatile property function for led State
160*7c478bd9Sstevel@tonic-gate  */
161*7c478bd9Sstevel@tonic-gate static int
read_led_state(ptree_rarg_t * parg,void * buf)162*7c478bd9Sstevel@tonic-gate read_led_state(ptree_rarg_t *parg, void *buf)
163*7c478bd9Sstevel@tonic-gate {
164*7c478bd9Sstevel@tonic-gate 	led_dtls_t *dtls = g_led_dtls;
165*7c478bd9Sstevel@tonic-gate 	picl_nodehdl_t nodeh = parg->nodeh;
166*7c478bd9Sstevel@tonic-gate 	/*
167*7c478bd9Sstevel@tonic-gate 	 * valbuf has space for a unit address at the end
168*7c478bd9Sstevel@tonic-gate 	 */
169*7c478bd9Sstevel@tonic-gate 	char valbuf[MAX_LEN_UNIT_ADDRESS];
170*7c478bd9Sstevel@tonic-gate 	char *ptr;
171*7c478bd9Sstevel@tonic-gate 	uint_t addr;
172*7c478bd9Sstevel@tonic-gate 	int disk, led;
173*7c478bd9Sstevel@tonic-gate 	led_state_t stat;
174*7c478bd9Sstevel@tonic-gate 	/*
175*7c478bd9Sstevel@tonic-gate 	 * each led-unit node has a UnitAddress property set to the bit
176*7c478bd9Sstevel@tonic-gate 	 * value associated with the led. Read that property
177*7c478bd9Sstevel@tonic-gate 	 */
178*7c478bd9Sstevel@tonic-gate 	int r = ptree_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS,
179*7c478bd9Sstevel@tonic-gate 	    valbuf, sizeof (valbuf));
180*7c478bd9Sstevel@tonic-gate 	if (r != PICL_SUCCESS)
181*7c478bd9Sstevel@tonic-gate 		return (r);
182*7c478bd9Sstevel@tonic-gate 	valbuf[sizeof (valbuf) - 1] = '\0';	/* ensure null terminated */
183*7c478bd9Sstevel@tonic-gate 	/* UnitAddress is a string of hex digits, convert to an int */
184*7c478bd9Sstevel@tonic-gate 	addr = strtoul(valbuf, &ptr, 16);
185*7c478bd9Sstevel@tonic-gate 	if (dtls == NULL)
186*7c478bd9Sstevel@tonic-gate 		return (PICL_PROPVALUNAVAILABLE);
187*7c478bd9Sstevel@tonic-gate 	/*
188*7c478bd9Sstevel@tonic-gate 	 * search the leds of each disk for a match with this UnitAddress
189*7c478bd9Sstevel@tonic-gate 	 */
190*7c478bd9Sstevel@tonic-gate 	for (disk = 0; disk < dtls->n_disks; disk++) {
191*7c478bd9Sstevel@tonic-gate 		for (led = 0; led < FCAL_LED_CNT; led++) {
192*7c478bd9Sstevel@tonic-gate 			if (addr == dtls->led_addr[led][disk])
193*7c478bd9Sstevel@tonic-gate 				break;
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 		if (led < FCAL_LED_CNT)
196*7c478bd9Sstevel@tonic-gate 			break;
197*7c478bd9Sstevel@tonic-gate 	}
198*7c478bd9Sstevel@tonic-gate 	if (disk == dtls->n_disks)
199*7c478bd9Sstevel@tonic-gate 		return (PICL_PROPVALUNAVAILABLE);
200*7c478bd9Sstevel@tonic-gate 	stat = dtls->led_state[led][disk];
201*7c478bd9Sstevel@tonic-gate 	/*
202*7c478bd9Sstevel@tonic-gate 	 * state_lookup is a table relating led-state enums to equivalent
203*7c478bd9Sstevel@tonic-gate 	 * text strings. Locate the string for the current state.
204*7c478bd9Sstevel@tonic-gate 	 */
205*7c478bd9Sstevel@tonic-gate 	for (r = 0; r < state_lkup_len; r++) {
206*7c478bd9Sstevel@tonic-gate 		if (state_lookup[r].led_state == stat) {
207*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(buf, state_lookup[r].state_str,
208*7c478bd9Sstevel@tonic-gate 			    MAX_LEN_LED_STATE);
209*7c478bd9Sstevel@tonic-gate 			return (PICL_SUCCESS);
210*7c478bd9Sstevel@tonic-gate 		}
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate 	return (PICL_PROPVALUNAVAILABLE);
213*7c478bd9Sstevel@tonic-gate }
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate int
find_disk_slot(led_dtls_t * dtls,int disk,picl_nodehdl_t * nodeh)216*7c478bd9Sstevel@tonic-gate find_disk_slot(led_dtls_t *dtls, int disk, picl_nodehdl_t *nodeh)
217*7c478bd9Sstevel@tonic-gate {
218*7c478bd9Sstevel@tonic-gate 	int		r;
219*7c478bd9Sstevel@tonic-gate 	int		unitlen;
220*7c478bd9Sstevel@tonic-gate 	char		unitstr[MAXPATHLEN];
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 	if (dtls->disk_unit_parent == NULL) {
223*7c478bd9Sstevel@tonic-gate 		return (PICL_NODENOTFOUND);
224*7c478bd9Sstevel@tonic-gate 	}
225*7c478bd9Sstevel@tonic-gate 	unitlen = strlen(dtls->disk_unit_parent);
226*7c478bd9Sstevel@tonic-gate 	/*
227*7c478bd9Sstevel@tonic-gate 	 * get search string buffer, allow space for address
228*7c478bd9Sstevel@tonic-gate 	 */
229*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(unitstr, dtls->disk_unit_parent, MAXPATHLEN);
230*7c478bd9Sstevel@tonic-gate 	(void) snprintf(unitstr + unitlen, MAXPATHLEN - unitlen, "%x", disk);
231*7c478bd9Sstevel@tonic-gate 	r = ptree_get_node_by_path(unitstr, nodeh);
232*7c478bd9Sstevel@tonic-gate 	return (r);
233*7c478bd9Sstevel@tonic-gate }
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate int
create_Device_table(picl_prophdl_t * tbl_h,picl_prophdl_t * tableh)236*7c478bd9Sstevel@tonic-gate create_Device_table(picl_prophdl_t *tbl_h, picl_prophdl_t *tableh)
237*7c478bd9Sstevel@tonic-gate {
238*7c478bd9Sstevel@tonic-gate 	int			r;
239*7c478bd9Sstevel@tonic-gate 	ptree_propinfo_t	propinfo;
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	r = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
242*7c478bd9Sstevel@tonic-gate 	    PICL_PTYPE_TABLE, PICL_READ, sizeof (picl_prophdl_t),
243*7c478bd9Sstevel@tonic-gate 	    PICL_PROP_DEVICES, NULL, NULL);
244*7c478bd9Sstevel@tonic-gate 	if (r != PICL_SUCCESS) {
245*7c478bd9Sstevel@tonic-gate 		return (r);
246*7c478bd9Sstevel@tonic-gate 	}
247*7c478bd9Sstevel@tonic-gate 	r = ptree_create_table(tbl_h);
248*7c478bd9Sstevel@tonic-gate 	if (r != PICL_SUCCESS) {
249*7c478bd9Sstevel@tonic-gate 		return (r);
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 	r = ptree_create_prop(&propinfo, tbl_h, tableh);
252*7c478bd9Sstevel@tonic-gate 	return (r);
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate /*
256*7c478bd9Sstevel@tonic-gate  * Locate disk-slot nodes and add DeviceTable of LED references
257*7c478bd9Sstevel@tonic-gate  * Also add a volatile State property to each LED node
258*7c478bd9Sstevel@tonic-gate  */
259*7c478bd9Sstevel@tonic-gate static void
add_led_refs(led_dtls_t * dtls)260*7c478bd9Sstevel@tonic-gate add_led_refs(led_dtls_t *dtls)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	int		d, i, r;
263*7c478bd9Sstevel@tonic-gate 	int		ledlen;
264*7c478bd9Sstevel@tonic-gate 	char		ledstr[MAXPATHLEN];
265*7c478bd9Sstevel@tonic-gate 	picl_nodehdl_t  slot_node;
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 	if (dtls->disk_led_nodes == NULL) {
268*7c478bd9Sstevel@tonic-gate 		return;
269*7c478bd9Sstevel@tonic-gate 	}
270*7c478bd9Sstevel@tonic-gate 	ledlen = strlen(dtls->disk_led_nodes);
271*7c478bd9Sstevel@tonic-gate 	/* set up search string in buffer with space to append address */
272*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(ledstr, dtls->disk_led_nodes, MAXPATHLEN);
273*7c478bd9Sstevel@tonic-gate 	for (d = 0; d < dtls->n_disks; d++) {
274*7c478bd9Sstevel@tonic-gate 		picl_prophdl_t tbl_hdl;
275*7c478bd9Sstevel@tonic-gate 		picl_prophdl_t tbl_prop_hdl;
276*7c478bd9Sstevel@tonic-gate 		picl_nodehdl_t led_node_hdl;
277*7c478bd9Sstevel@tonic-gate 		picl_prophdl_t tbl_prop[FCAL_DEVTABLE_NCOLS];
278*7c478bd9Sstevel@tonic-gate 		ptree_propinfo_t propinfo;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 		r = create_Device_table(&tbl_hdl, &tbl_prop_hdl);
281*7c478bd9Sstevel@tonic-gate 		if (r != PICL_SUCCESS)
282*7c478bd9Sstevel@tonic-gate 			break;
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 		/*
285*7c478bd9Sstevel@tonic-gate 		 * locate disk-slot node in frutree
286*7c478bd9Sstevel@tonic-gate 		 */
287*7c478bd9Sstevel@tonic-gate 		if (find_disk_slot(dtls, d, &slot_node) != PICL_SUCCESS)
288*7c478bd9Sstevel@tonic-gate 			break;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < FCAL_LED_CNT; i++) {
291*7c478bd9Sstevel@tonic-gate 			/*
292*7c478bd9Sstevel@tonic-gate 			 * For each disk-slot in frutree, add a device
293*7c478bd9Sstevel@tonic-gate 			 * table of references to relevant LEDs.
294*7c478bd9Sstevel@tonic-gate 			 * En passant, add a volatile State property to
295*7c478bd9Sstevel@tonic-gate 			 * each LED node found.
296*7c478bd9Sstevel@tonic-gate 			 */
297*7c478bd9Sstevel@tonic-gate 			/*
298*7c478bd9Sstevel@tonic-gate 			 * append led address to search string
299*7c478bd9Sstevel@tonic-gate 			 */
300*7c478bd9Sstevel@tonic-gate 			(void) snprintf(ledstr + ledlen, MAXPATHLEN - ledlen,
301*7c478bd9Sstevel@tonic-gate 			    "%x", dtls->led_addr[i][d]);
302*7c478bd9Sstevel@tonic-gate 			r = ptree_get_node_by_path(ledstr, &led_node_hdl);
303*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
304*7c478bd9Sstevel@tonic-gate 				break;
305*7c478bd9Sstevel@tonic-gate 			}
306*7c478bd9Sstevel@tonic-gate 			r = ptree_init_propinfo(&propinfo,
307*7c478bd9Sstevel@tonic-gate 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
308*7c478bd9Sstevel@tonic-gate 			    PICL_READ | PICL_VOLATILE, MAX_LEN_LED_STATE,
309*7c478bd9Sstevel@tonic-gate 			    PICL_PROP_STATE, read_led_state, NULL);
310*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
311*7c478bd9Sstevel@tonic-gate 				break;
312*7c478bd9Sstevel@tonic-gate 			}
313*7c478bd9Sstevel@tonic-gate 			r = ptree_create_and_add_prop(led_node_hdl,
314*7c478bd9Sstevel@tonic-gate 			    &propinfo, NULL, NULL);
315*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
316*7c478bd9Sstevel@tonic-gate 				break;
317*7c478bd9Sstevel@tonic-gate 			}
318*7c478bd9Sstevel@tonic-gate 			r = ptree_init_propinfo(&propinfo,
319*7c478bd9Sstevel@tonic-gate 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_CHARSTRING,
320*7c478bd9Sstevel@tonic-gate 			    PICL_READ, sizeof (PICL_CLASS_LED),
321*7c478bd9Sstevel@tonic-gate 			    PICL_PROP_CLASS, NULL, NULL);
322*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
323*7c478bd9Sstevel@tonic-gate 				break;
324*7c478bd9Sstevel@tonic-gate 			}
325*7c478bd9Sstevel@tonic-gate 			r = ptree_create_prop(&propinfo, PICL_CLASS_LED,
326*7c478bd9Sstevel@tonic-gate 			    &tbl_prop[0]);
327*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
328*7c478bd9Sstevel@tonic-gate 				break;
329*7c478bd9Sstevel@tonic-gate 			}
330*7c478bd9Sstevel@tonic-gate 			r = ptree_init_propinfo(&propinfo,
331*7c478bd9Sstevel@tonic-gate 			    PTREE_PROPINFO_VERSION, PICL_PTYPE_REFERENCE,
332*7c478bd9Sstevel@tonic-gate 			    PICL_READ, sizeof (picl_prophdl_t),
333*7c478bd9Sstevel@tonic-gate 			    FCAL_PICL_LED_REF, NULL, NULL);
334*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
335*7c478bd9Sstevel@tonic-gate 				break;
336*7c478bd9Sstevel@tonic-gate 			}
337*7c478bd9Sstevel@tonic-gate 			r = ptree_create_prop(&propinfo, &led_node_hdl,
338*7c478bd9Sstevel@tonic-gate 			    &tbl_prop[1]);
339*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
340*7c478bd9Sstevel@tonic-gate 				break;
341*7c478bd9Sstevel@tonic-gate 			}
342*7c478bd9Sstevel@tonic-gate 			r = ptree_add_row_to_table(tbl_hdl,
343*7c478bd9Sstevel@tonic-gate 			    FCAL_DEVTABLE_NCOLS, tbl_prop);
344*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS) {
345*7c478bd9Sstevel@tonic-gate 				break;
346*7c478bd9Sstevel@tonic-gate 			}
347*7c478bd9Sstevel@tonic-gate 		}
348*7c478bd9Sstevel@tonic-gate 		if (r != PICL_SUCCESS)
349*7c478bd9Sstevel@tonic-gate 			break;
350*7c478bd9Sstevel@tonic-gate 		(void) ptree_add_prop(slot_node, tbl_prop_hdl);
351*7c478bd9Sstevel@tonic-gate 	}
352*7c478bd9Sstevel@tonic-gate }
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate /*
355*7c478bd9Sstevel@tonic-gate  * This is an undo function to match add_led_refs()
356*7c478bd9Sstevel@tonic-gate  * Locate disk-slot nodes and remove Devices table of LED references
357*7c478bd9Sstevel@tonic-gate  * Also remove volatile State property to each LED node
358*7c478bd9Sstevel@tonic-gate  */
359*7c478bd9Sstevel@tonic-gate static void
delete_led_refs(led_dtls_t * dtls)360*7c478bd9Sstevel@tonic-gate delete_led_refs(led_dtls_t *dtls)
361*7c478bd9Sstevel@tonic-gate {
362*7c478bd9Sstevel@tonic-gate 	int		d;
363*7c478bd9Sstevel@tonic-gate 	int		i;
364*7c478bd9Sstevel@tonic-gate 	int		r;
365*7c478bd9Sstevel@tonic-gate 	int		ledlen;
366*7c478bd9Sstevel@tonic-gate 	picl_nodehdl_t  node_hdl;
367*7c478bd9Sstevel@tonic-gate 	picl_prophdl_t	prop_hdl;
368*7c478bd9Sstevel@tonic-gate 	char		ledstr[MAXPATHLEN];
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	if (dtls->disk_led_nodes == NULL)
371*7c478bd9Sstevel@tonic-gate 		return;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 	for (d = 0; d < dtls->n_disks; d++) {
374*7c478bd9Sstevel@tonic-gate 		if (find_disk_slot(dtls, d, &node_hdl) != PICL_SUCCESS)
375*7c478bd9Sstevel@tonic-gate 			continue;
376*7c478bd9Sstevel@tonic-gate 		if (ptree_get_prop_by_name(node_hdl, PICL_PROP_DEVICES,
377*7c478bd9Sstevel@tonic-gate 		    &prop_hdl) != PICL_SUCCESS)
378*7c478bd9Sstevel@tonic-gate 			continue;
379*7c478bd9Sstevel@tonic-gate 		if (ptree_delete_prop(prop_hdl) != PICL_SUCCESS)
380*7c478bd9Sstevel@tonic-gate 			continue;
381*7c478bd9Sstevel@tonic-gate 		(void) ptree_destroy_prop(prop_hdl);
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	ledlen = strlen(dtls->disk_led_nodes);
385*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(ledstr, dtls->disk_led_nodes, MAXPATHLEN);
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	for (d = 0; d < dtls->n_disks; d++) {
388*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < FCAL_LED_CNT; i++) {
389*7c478bd9Sstevel@tonic-gate 			/*
390*7c478bd9Sstevel@tonic-gate 			 * find each led node
391*7c478bd9Sstevel@tonic-gate 			 */
392*7c478bd9Sstevel@tonic-gate 			(void) snprintf(ledstr + ledlen, MAXPATHLEN - ledlen,
393*7c478bd9Sstevel@tonic-gate 			    "%x", dtls->led_addr[i][d]);
394*7c478bd9Sstevel@tonic-gate 			r = ptree_get_node_by_path(ledstr, &node_hdl);
395*7c478bd9Sstevel@tonic-gate 			if (r != PICL_SUCCESS)
396*7c478bd9Sstevel@tonic-gate 				continue;
397*7c478bd9Sstevel@tonic-gate 			/*
398*7c478bd9Sstevel@tonic-gate 			 * locate and delete the volatile State property
399*7c478bd9Sstevel@tonic-gate 			 */
400*7c478bd9Sstevel@tonic-gate 			if (ptree_get_prop_by_name(node_hdl,
401*7c478bd9Sstevel@tonic-gate 			    PICL_PROP_STATE, &prop_hdl) != PICL_SUCCESS)
402*7c478bd9Sstevel@tonic-gate 				continue;
403*7c478bd9Sstevel@tonic-gate 			if (ptree_delete_prop(prop_hdl) != PICL_SUCCESS)
404*7c478bd9Sstevel@tonic-gate 				continue;
405*7c478bd9Sstevel@tonic-gate 			(void) ptree_destroy_prop(prop_hdl);
406*7c478bd9Sstevel@tonic-gate 		}
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate }
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate /*
411*7c478bd9Sstevel@tonic-gate  * Poll thread.
412*7c478bd9Sstevel@tonic-gate  * This thread sits on a poll() call for the fast poll interval.
413*7c478bd9Sstevel@tonic-gate  * At each wake up it determines if a time event should be passed on.
414*7c478bd9Sstevel@tonic-gate  * Poll seems to be reliable when the realtime clock is wound backwards,
415*7c478bd9Sstevel@tonic-gate  * whereas pthread_cond_timedwait() is not.
416*7c478bd9Sstevel@tonic-gate  */
417*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
418*7c478bd9Sstevel@tonic-gate static void *
fcal_poll_thread(void * args)419*7c478bd9Sstevel@tonic-gate fcal_poll_thread(void *args)
420*7c478bd9Sstevel@tonic-gate {
421*7c478bd9Sstevel@tonic-gate 	led_dtls_t	*dtls = NULL;
422*7c478bd9Sstevel@tonic-gate 	int		c;
423*7c478bd9Sstevel@tonic-gate 	int		slow_poll_count;
424*7c478bd9Sstevel@tonic-gate 	boolean_t	do_event;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	for (;;) {
427*7c478bd9Sstevel@tonic-gate 		if (g_finish_now) {
428*7c478bd9Sstevel@tonic-gate 			c = pthread_mutex_lock(&g_mutex);
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 			if (c != 0) {
431*7c478bd9Sstevel@tonic-gate 				SYSLOG(LOG_ERR, EM_MUTEX_FAIL, mystrerror(c));
432*7c478bd9Sstevel@tonic-gate 				break;
433*7c478bd9Sstevel@tonic-gate 			}
434*7c478bd9Sstevel@tonic-gate 			poll_thread_ack = B_TRUE;
435*7c478bd9Sstevel@tonic-gate 			(void) pthread_cond_signal(&g_cv_ack);
436*7c478bd9Sstevel@tonic-gate 			(void) pthread_cond_wait(&g_cv, &g_mutex);
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&g_mutex);
439*7c478bd9Sstevel@tonic-gate 			continue;
440*7c478bd9Sstevel@tonic-gate 		}
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 		/*
443*7c478bd9Sstevel@tonic-gate 		 * If picld has been recycled, or if this is the initial
444*7c478bd9Sstevel@tonic-gate 		 * entry, dtls will not match g_led_dtls.
445*7c478bd9Sstevel@tonic-gate 		 * In this case, do some resetting.
446*7c478bd9Sstevel@tonic-gate 		 */
447*7c478bd9Sstevel@tonic-gate 		if (dtls != g_led_dtls) {
448*7c478bd9Sstevel@tonic-gate 			dtls = g_led_dtls;
449*7c478bd9Sstevel@tonic-gate 			slow_poll_count = dtls->slow_poll_ticks;
450*7c478bd9Sstevel@tonic-gate 			dtls->polling = B_TRUE;
451*7c478bd9Sstevel@tonic-gate 		}
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 		c = poll(NULL, 0, dtls->fast_poll * 1000);
454*7c478bd9Sstevel@tonic-gate 		if (c == -1) {
455*7c478bd9Sstevel@tonic-gate 			SYSLOG(LOG_ERR, EM_POLL_FAIL, mystrerror(errno));
456*7c478bd9Sstevel@tonic-gate 			break;
457*7c478bd9Sstevel@tonic-gate 		}
458*7c478bd9Sstevel@tonic-gate 		/*
459*7c478bd9Sstevel@tonic-gate 		 * dtls->fast_poll_end is the number of fast poll times left
460*7c478bd9Sstevel@tonic-gate 		 * before we revert to slow polling. If it is non-zero, the
461*7c478bd9Sstevel@tonic-gate 		 * fcal_leds thread is do fast polling and we pass on every
462*7c478bd9Sstevel@tonic-gate 		 * poll wakeup.
463*7c478bd9Sstevel@tonic-gate 		 */
464*7c478bd9Sstevel@tonic-gate 		do_event = (dtls->fast_poll_end != 0);
465*7c478bd9Sstevel@tonic-gate 		/*
466*7c478bd9Sstevel@tonic-gate 		 * If a LED test is underway, fast polling would normally be
467*7c478bd9Sstevel@tonic-gate 		 * set also. Just in case the timers are configured unusually,
468*7c478bd9Sstevel@tonic-gate 		 * pass on all poll wakeups while a LED test is current.
469*7c478bd9Sstevel@tonic-gate 		 */
470*7c478bd9Sstevel@tonic-gate 		if ((!do_event) && is_led_test(dtls))
471*7c478bd9Sstevel@tonic-gate 			do_event = B_TRUE;
472*7c478bd9Sstevel@tonic-gate 		if (!do_event) {
473*7c478bd9Sstevel@tonic-gate 			/*
474*7c478bd9Sstevel@tonic-gate 			 * If we get here, the fcal_leds thread is only doing
475*7c478bd9Sstevel@tonic-gate 			 * slow polls. Count down the slow_poll_count and set
476*7c478bd9Sstevel@tonic-gate 			 * an event if it expires.
477*7c478bd9Sstevel@tonic-gate 			 */
478*7c478bd9Sstevel@tonic-gate 			if (--slow_poll_count == 0) {
479*7c478bd9Sstevel@tonic-gate 				slow_poll_count = dtls->slow_poll_ticks;
480*7c478bd9Sstevel@tonic-gate 				do_event = B_TRUE;
481*7c478bd9Sstevel@tonic-gate 			}
482*7c478bd9Sstevel@tonic-gate 		}
483*7c478bd9Sstevel@tonic-gate 		if (do_event) {
484*7c478bd9Sstevel@tonic-gate 			c = pthread_mutex_lock(&g_mutex);
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 			if (c != 0) {
487*7c478bd9Sstevel@tonic-gate 				SYSLOG(LOG_ERR, EM_MUTEX_FAIL, mystrerror(c));
488*7c478bd9Sstevel@tonic-gate 				break;
489*7c478bd9Sstevel@tonic-gate 			}
490*7c478bd9Sstevel@tonic-gate 			/*
491*7c478bd9Sstevel@tonic-gate 			 * indicate in the event flag that this is a time event
492*7c478bd9Sstevel@tonic-gate 			 */
493*7c478bd9Sstevel@tonic-gate 			g_event_flag |= FCAL_EV_POLL;
494*7c478bd9Sstevel@tonic-gate 			(void) pthread_cond_signal(&g_cv);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&g_mutex);
497*7c478bd9Sstevel@tonic-gate 		}
498*7c478bd9Sstevel@tonic-gate 	}
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	dtls->polling = B_FALSE;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	/*
503*7c478bd9Sstevel@tonic-gate 	 * if picld restarted, allow this thread to be recreated
504*7c478bd9Sstevel@tonic-gate 	 */
505*7c478bd9Sstevel@tonic-gate 	pollthr_created = B_FALSE;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	return ((void *)errno);
508*7c478bd9Sstevel@tonic-gate }
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate /*
511*7c478bd9Sstevel@tonic-gate  * Init entry point of the plugin
512*7c478bd9Sstevel@tonic-gate  * Opens and parses config file.
513*7c478bd9Sstevel@tonic-gate  * Establishes an interrupt routine to catch DEVICE ADDED/REMOVED events
514*7c478bd9Sstevel@tonic-gate  * and starts a new thread for polling FC-AL disk status information.
515*7c478bd9Sstevel@tonic-gate  */
516*7c478bd9Sstevel@tonic-gate static void
fcal_leds_init(void)517*7c478bd9Sstevel@tonic-gate fcal_leds_init(void)
518*7c478bd9Sstevel@tonic-gate {
519*7c478bd9Sstevel@tonic-gate 	FILE *fp;
520*7c478bd9Sstevel@tonic-gate 	int err = 0;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if ((fp = open_config()) == NULL)
523*7c478bd9Sstevel@tonic-gate 		return;
524*7c478bd9Sstevel@tonic-gate 	if (fc_led_parse(fp, &g_led_dtls) != 0) {
525*7c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
526*7c478bd9Sstevel@tonic-gate 		return;
527*7c478bd9Sstevel@tonic-gate 	}
528*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
529*7c478bd9Sstevel@tonic-gate 	g_finish_now = B_FALSE;
530*7c478bd9Sstevel@tonic-gate 	g_event_flag = 0;
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	if (!cvAndMutexInit) {
533*7c478bd9Sstevel@tonic-gate 		if ((pthread_cond_init(&g_cv, NULL) == 0) &&
534*7c478bd9Sstevel@tonic-gate 		    (pthread_cond_init(&g_cv_ack, NULL) == 0) &&
535*7c478bd9Sstevel@tonic-gate 		    (pthread_mutex_init(&g_mutex, NULL) == 0)) {
536*7c478bd9Sstevel@tonic-gate 			cvAndMutexInit = B_TRUE;
537*7c478bd9Sstevel@tonic-gate 		} else {
538*7c478bd9Sstevel@tonic-gate 			return;
539*7c478bd9Sstevel@tonic-gate 		}
540*7c478bd9Sstevel@tonic-gate 	}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	add_led_refs(g_led_dtls);
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
545*7c478bd9Sstevel@tonic-gate 	    piclfcal_evhandler, NULL);
546*7c478bd9Sstevel@tonic-gate 	(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
547*7c478bd9Sstevel@tonic-gate 	    piclfcal_evhandler, NULL);
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	if (ledsthr_created || pollthr_created) {
550*7c478bd9Sstevel@tonic-gate 		/*
551*7c478bd9Sstevel@tonic-gate 		 * so this is a restart, wake up sleeping threads
552*7c478bd9Sstevel@tonic-gate 		 */
553*7c478bd9Sstevel@tonic-gate 		err = pthread_mutex_lock(&g_mutex);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 		if (err != 0) {
556*7c478bd9Sstevel@tonic-gate 			SYSLOG(LOG_ERR, EM_MUTEX_FAIL, mystrerror(err));
557*7c478bd9Sstevel@tonic-gate 			return;
558*7c478bd9Sstevel@tonic-gate 		}
559*7c478bd9Sstevel@tonic-gate 		g_leds_thread_ack = B_FALSE;
560*7c478bd9Sstevel@tonic-gate 		poll_thread_ack = B_FALSE;
561*7c478bd9Sstevel@tonic-gate 		(void) pthread_cond_broadcast(&g_cv);
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&g_mutex);
564*7c478bd9Sstevel@tonic-gate 	}
565*7c478bd9Sstevel@tonic-gate 	if (!ledsthr_created) {
566*7c478bd9Sstevel@tonic-gate 		if ((pthread_attr_init(&ledsthr_attr) != 0) ||
567*7c478bd9Sstevel@tonic-gate 		    (pthread_attr_setscope(&ledsthr_attr,
568*7c478bd9Sstevel@tonic-gate 		    PTHREAD_SCOPE_SYSTEM) != 0))
569*7c478bd9Sstevel@tonic-gate 			return;
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 		if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr,
572*7c478bd9Sstevel@tonic-gate 		    fcal_leds_thread, g_led_dtls)) != 0) {
573*7c478bd9Sstevel@tonic-gate 			SYSLOG(LOG_ERR, EM_THREAD_CREATE_FAILED,
574*7c478bd9Sstevel@tonic-gate 			    mystrerror(err));
575*7c478bd9Sstevel@tonic-gate 			return;
576*7c478bd9Sstevel@tonic-gate 		}
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 		ledsthr_created = B_TRUE;
579*7c478bd9Sstevel@tonic-gate 	}
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	if (pollthr_created == B_FALSE) {
582*7c478bd9Sstevel@tonic-gate 		if ((pthread_attr_init(&pollthr_attr) != 0) ||
583*7c478bd9Sstevel@tonic-gate 		    (pthread_attr_setscope(&pollthr_attr,
584*7c478bd9Sstevel@tonic-gate 		    PTHREAD_SCOPE_SYSTEM) != 0))
585*7c478bd9Sstevel@tonic-gate 			return;
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 		if ((err = pthread_create(&pollthr_tid, &pollthr_attr,
588*7c478bd9Sstevel@tonic-gate 		    fcal_poll_thread, g_led_dtls)) != 0) {
589*7c478bd9Sstevel@tonic-gate 			g_led_dtls->polling = B_FALSE;
590*7c478bd9Sstevel@tonic-gate 			SYSLOG(LOG_ERR, EM_THREAD_CREATE_FAILED,
591*7c478bd9Sstevel@tonic-gate 			    mystrerror(err));
592*7c478bd9Sstevel@tonic-gate 			return;
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 		pollthr_created = B_TRUE;
596*7c478bd9Sstevel@tonic-gate 	}
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate /*
600*7c478bd9Sstevel@tonic-gate  * fini entry point of the plugin
601*7c478bd9Sstevel@tonic-gate  */
602*7c478bd9Sstevel@tonic-gate static void
fcal_leds_fini(void)603*7c478bd9Sstevel@tonic-gate fcal_leds_fini(void)
604*7c478bd9Sstevel@tonic-gate {
605*7c478bd9Sstevel@tonic-gate 	int	c;
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	/* unregister event handlers */
608*7c478bd9Sstevel@tonic-gate 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
609*7c478bd9Sstevel@tonic-gate 	    piclfcal_evhandler, NULL);
610*7c478bd9Sstevel@tonic-gate 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
611*7c478bd9Sstevel@tonic-gate 	    piclfcal_evhandler, NULL);
612*7c478bd9Sstevel@tonic-gate 	/*
613*7c478bd9Sstevel@tonic-gate 	 * it's very confusing to leave uncontrolled leds on, so clear them.
614*7c478bd9Sstevel@tonic-gate 	 */
615*7c478bd9Sstevel@tonic-gate 	if (g_led_dtls != NULL) {
616*7c478bd9Sstevel@tonic-gate 		int ledNo;
617*7c478bd9Sstevel@tonic-gate 		int diskNo;
618*7c478bd9Sstevel@tonic-gate 		for (ledNo = 0; ledNo < FCAL_LED_CNT; ledNo++) {
619*7c478bd9Sstevel@tonic-gate 			if ((g_led_dtls->led_addr[ledNo] == NULL) ||
620*7c478bd9Sstevel@tonic-gate 			    (g_led_dtls->led_state[ledNo] == NULL)) {
621*7c478bd9Sstevel@tonic-gate 				break;	/* incomplete setup */
622*7c478bd9Sstevel@tonic-gate 			}
623*7c478bd9Sstevel@tonic-gate 			for (diskNo = 0; diskNo < g_led_dtls->n_disks;
624*7c478bd9Sstevel@tonic-gate 			    diskNo++) {
625*7c478bd9Sstevel@tonic-gate 				clr_led(diskNo, LED_PROPS_START + 1 + ledNo,
626*7c478bd9Sstevel@tonic-gate 				    g_led_dtls);
627*7c478bd9Sstevel@tonic-gate 			}
628*7c478bd9Sstevel@tonic-gate 		}
629*7c478bd9Sstevel@tonic-gate 	}
630*7c478bd9Sstevel@tonic-gate 	/*
631*7c478bd9Sstevel@tonic-gate 	 * tell other threads to stop
632*7c478bd9Sstevel@tonic-gate 	 */
633*7c478bd9Sstevel@tonic-gate 	if (cvAndMutexInit && (ledsthr_created || pollthr_created)) {
634*7c478bd9Sstevel@tonic-gate 		g_finish_now = B_TRUE;
635*7c478bd9Sstevel@tonic-gate 		c = pthread_mutex_lock(&g_mutex);
636*7c478bd9Sstevel@tonic-gate 		if (c != 0) {
637*7c478bd9Sstevel@tonic-gate 			SYSLOG(LOG_ERR, EM_MUTEX_FAIL, mystrerror(c));
638*7c478bd9Sstevel@tonic-gate 		} else {
639*7c478bd9Sstevel@tonic-gate 			(void) pthread_cond_broadcast(&g_cv);
640*7c478bd9Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&g_mutex);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 			/*
643*7c478bd9Sstevel@tonic-gate 			 * and wait for them to acknowledge
644*7c478bd9Sstevel@tonic-gate 			 */
645*7c478bd9Sstevel@tonic-gate 			while ((ledsthr_created && !g_leds_thread_ack) ||
646*7c478bd9Sstevel@tonic-gate 			    (pollthr_created && !poll_thread_ack)) {
647*7c478bd9Sstevel@tonic-gate 				c = pthread_mutex_lock(&g_mutex);
648*7c478bd9Sstevel@tonic-gate 				if (c != 0) {
649*7c478bd9Sstevel@tonic-gate 					SYSLOG(LOG_ERR, EM_MUTEX_FAIL,
650*7c478bd9Sstevel@tonic-gate 					    mystrerror(c));
651*7c478bd9Sstevel@tonic-gate 					break;
652*7c478bd9Sstevel@tonic-gate 				}
653*7c478bd9Sstevel@tonic-gate 				(void) pthread_cond_wait(&g_cv_ack, &g_mutex);
654*7c478bd9Sstevel@tonic-gate 				(void) pthread_mutex_unlock(&g_mutex);
655*7c478bd9Sstevel@tonic-gate 			}
656*7c478bd9Sstevel@tonic-gate 		}
657*7c478bd9Sstevel@tonic-gate 	}
658*7c478bd9Sstevel@tonic-gate 	/*
659*7c478bd9Sstevel@tonic-gate 	 * remove picl nodes created by this plugin
660*7c478bd9Sstevel@tonic-gate 	 */
661*7c478bd9Sstevel@tonic-gate 	if (g_led_dtls != NULL) {
662*7c478bd9Sstevel@tonic-gate 		for (c = 0; c < g_led_dtls->n_disks; c++) {
663*7c478bd9Sstevel@tonic-gate 			/*
664*7c478bd9Sstevel@tonic-gate 			 * remove all disk unit nodes from frutree
665*7c478bd9Sstevel@tonic-gate 			 */
666*7c478bd9Sstevel@tonic-gate 			delete_disk_unit(g_led_dtls, c);
667*7c478bd9Sstevel@tonic-gate 		}
668*7c478bd9Sstevel@tonic-gate 		/*
669*7c478bd9Sstevel@tonic-gate 		 * remove Devices tables of references to leds
670*7c478bd9Sstevel@tonic-gate 		 * and led State properties
671*7c478bd9Sstevel@tonic-gate 		 */
672*7c478bd9Sstevel@tonic-gate 		delete_led_refs(g_led_dtls);
673*7c478bd9Sstevel@tonic-gate 		/*
674*7c478bd9Sstevel@tonic-gate 		 * finally free the led details
675*7c478bd9Sstevel@tonic-gate 		 */
676*7c478bd9Sstevel@tonic-gate 		free_led_dtls(g_led_dtls);
677*7c478bd9Sstevel@tonic-gate 		g_led_dtls = NULL;
678*7c478bd9Sstevel@tonic-gate 	}
679*7c478bd9Sstevel@tonic-gate }
680