1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * This module is used to monitor and control watchdog timer for
31*0Sstevel@tonic-gate  * UltraSPARC-IIi CPU in Snowbird
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <stdio.h>
35*0Sstevel@tonic-gate #include <fcntl.h>
36*0Sstevel@tonic-gate #include <unistd.h>
37*0Sstevel@tonic-gate #include <stdlib.h>
38*0Sstevel@tonic-gate #include <stdarg.h>
39*0Sstevel@tonic-gate #include <strings.h>
40*0Sstevel@tonic-gate #include <string.h>
41*0Sstevel@tonic-gate #include <ctype.h>
42*0Sstevel@tonic-gate #include <alloca.h>
43*0Sstevel@tonic-gate #include <limits.h>
44*0Sstevel@tonic-gate #include <sys/types.h>
45*0Sstevel@tonic-gate #include <sys/stat.h>
46*0Sstevel@tonic-gate #include <libintl.h>
47*0Sstevel@tonic-gate #include <syslog.h>
48*0Sstevel@tonic-gate #include <locale.h>
49*0Sstevel@tonic-gate #include <picl.h>
50*0Sstevel@tonic-gate #include <picltree.h>
51*0Sstevel@tonic-gate #include <libnvpair.h>
52*0Sstevel@tonic-gate #include <poll.h>
53*0Sstevel@tonic-gate #include <errno.h>
54*0Sstevel@tonic-gate #include <syslog.h>
55*0Sstevel@tonic-gate #include <sys/priocntl.h>
56*0Sstevel@tonic-gate #include <sys/rtpriocntl.h>
57*0Sstevel@tonic-gate #include <sys/tspriocntl.h>
58*0Sstevel@tonic-gate #include <sys/fsspriocntl.h>
59*0Sstevel@tonic-gate #include <stropts.h>
60*0Sstevel@tonic-gate #include <synch.h>
61*0Sstevel@tonic-gate #include <signal.h>
62*0Sstevel@tonic-gate #include <thread.h>
63*0Sstevel@tonic-gate #include <picldefs.h>
64*0Sstevel@tonic-gate #include <smclib.h>
65*0Sstevel@tonic-gate #include "piclwatchdog.h"
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate #pragma	init(wd_picl_register)	/* init section */
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate /* debug variables */
70*0Sstevel@tonic-gate static  int wd_debug = 0;
71*0Sstevel@tonic-gate static hrtime_t start1, end1;
72*0Sstevel@tonic-gate static int count = 0;
73*0Sstevel@tonic-gate typedef struct { /* used to keep track of time taken for last 5 pats */
74*0Sstevel@tonic-gate 	int res_seq;
75*0Sstevel@tonic-gate 	int req_seq;
76*0Sstevel@tonic-gate 	int64_t time;
77*0Sstevel@tonic-gate } wd_time_t;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate #define	NUMBER_OF_READINGS	5
80*0Sstevel@tonic-gate static wd_time_t time1[NUMBER_OF_READINGS];
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate /* global declarations */
83*0Sstevel@tonic-gate static int	wd_fd = -1;	/* fd used to send watchdog commands */
84*0Sstevel@tonic-gate static int 	polling_fd = -1; /* polling thread that snoops for events */
85*0Sstevel@tonic-gate static int 	wd_enable = 1;
86*0Sstevel@tonic-gate static int 	state_configured = 0;	/* chassis state */
87*0Sstevel@tonic-gate static int	props_created = 0;
88*0Sstevel@tonic-gate static int 	wd_pat_thr_priority = -1;
89*0Sstevel@tonic-gate static pid_t 	pid = -1;	/* PID that owns watchdog services */
90*0Sstevel@tonic-gate static cond_t	patting_cv;
91*0Sstevel@tonic-gate static mutex_t	data_lock;
92*0Sstevel@tonic-gate static mutex_t	patting_lock;
93*0Sstevel@tonic-gate static int32_t	pat_time = 0;
94*0Sstevel@tonic-gate static thread_t	polling_thr_tid;
95*0Sstevel@tonic-gate static thread_t patting_thr_tid;
96*0Sstevel@tonic-gate static wd_data_t wd_data;
97*0Sstevel@tonic-gate static char wd_conf[MAXPATHLEN];
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate #define	NULLREAD	(int (*)(ptree_rarg_t *, void *))0
100*0Sstevel@tonic-gate #define	NULLWRITE	(int (*)(ptree_warg_t *, const void *))0
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate /* ptree interface */
103*0Sstevel@tonic-gate static void wd_picl_register(void);
104*0Sstevel@tonic-gate static void wd_picl_init(void);
105*0Sstevel@tonic-gate static void wd_picl_fini(void);
106*0Sstevel@tonic-gate static void wd_state_change_evhandler(const char *,
107*0Sstevel@tonic-gate 	const void *, size_t, void *);
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate /* local functions */
110*0Sstevel@tonic-gate static int wd_write_timeout(ptree_warg_t *, const void *);
111*0Sstevel@tonic-gate static int wd_write_action(ptree_warg_t *, const void *);
112*0Sstevel@tonic-gate static int wd_read_action(ptree_rarg_t *, void *);
113*0Sstevel@tonic-gate static int wd_read_timeout(ptree_rarg_t *, void *);
114*0Sstevel@tonic-gate extern char *strtok_r(char *s1, const char *s2, char **lasts);
115*0Sstevel@tonic-gate extern int wd_get_chassis_type();
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate static picld_plugin_reg_t wd_reg_info = {
118*0Sstevel@tonic-gate 	PICLD_PLUGIN_VERSION_1,
119*0Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
120*0Sstevel@tonic-gate 	"SUNW_picl_watchdog",
121*0Sstevel@tonic-gate 	wd_picl_init,
122*0Sstevel@tonic-gate 	wd_picl_fini,
123*0Sstevel@tonic-gate };
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate /*
126*0Sstevel@tonic-gate  * This function parses wd.conf file to set the tunables
127*0Sstevel@tonic-gate  * tunables at present: patting thread priority, pat time, wd_enable
128*0Sstevel@tonic-gate  */
129*0Sstevel@tonic-gate static void
wd_parse_config_file(char * wd_conf)130*0Sstevel@tonic-gate wd_parse_config_file(char *wd_conf)
131*0Sstevel@tonic-gate {
132*0Sstevel@tonic-gate 	FILE	*fp;
133*0Sstevel@tonic-gate 	char	buf[WD_CONF_MAXSIZE];
134*0Sstevel@tonic-gate 	char	*token, *last, *value;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	if ((fp = fopen(wd_conf, "r")) == NULL) {
137*0Sstevel@tonic-gate 		return;
138*0Sstevel@tonic-gate 	}
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	while (fgets(buf, sizeof (buf), fp) != NULL) {
141*0Sstevel@tonic-gate 		if (buf[0] == '\0' || buf[0] == '#') {
142*0Sstevel@tonic-gate 			continue;
143*0Sstevel@tonic-gate 		}
144*0Sstevel@tonic-gate 		token = last = value = NULL;
145*0Sstevel@tonic-gate 		value = (char *)strtok_r((char *)buf, WD_DELIMETER, &last);
146*0Sstevel@tonic-gate 		if (last) {
147*0Sstevel@tonic-gate 			token = (char *)strtok_r(last, WD_DELIMETER, &last);
148*0Sstevel@tonic-gate 		} else {
149*0Sstevel@tonic-gate 			continue;
150*0Sstevel@tonic-gate 		}
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		if (value == NULL || token == NULL) {
153*0Sstevel@tonic-gate 			continue;
154*0Sstevel@tonic-gate 		}
155*0Sstevel@tonic-gate 		if (strcmp(token, WD_PAT_THREAD_PRIORITY) == 0) {
156*0Sstevel@tonic-gate 			wd_pat_thr_priority = strtol(value,
157*0Sstevel@tonic-gate 				(char **)NULL, 10);
158*0Sstevel@tonic-gate 		} else if (strcmp(token, WD_PATTING_TIME) == 0) {
159*0Sstevel@tonic-gate 			errno = 0;
160*0Sstevel@tonic-gate 			pat_time = strtol(value, (char **)NULL, 10);
161*0Sstevel@tonic-gate 			if (errno != 0) {
162*0Sstevel@tonic-gate 				pat_time = 0;
163*0Sstevel@tonic-gate 			}
164*0Sstevel@tonic-gate 		} else if (strcmp(token, WD_ENABLE) == 0) {
165*0Sstevel@tonic-gate 			if (strcmp(value, "false") == 0) {
166*0Sstevel@tonic-gate 				wd_enable = 0;
167*0Sstevel@tonic-gate 			}
168*0Sstevel@tonic-gate 		} else {	/* unknown token */
169*0Sstevel@tonic-gate 			continue;
170*0Sstevel@tonic-gate 		}
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 	(void) fclose(fp);
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate /*
176*0Sstevel@tonic-gate  * read the SMC watchdog registers
177*0Sstevel@tonic-gate  */
178*0Sstevel@tonic-gate static int
wd_get_reg_dump(uint8_t buffer[])179*0Sstevel@tonic-gate wd_get_reg_dump(uint8_t buffer[])
180*0Sstevel@tonic-gate {
181*0Sstevel@tonic-gate 	int rc = 0, i;
182*0Sstevel@tonic-gate 	sc_reqmsg_t	req_pkt;
183*0Sstevel@tonic-gate 	sc_rspmsg_t	rsp_pkt;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	/* initialize the request packet */
186*0Sstevel@tonic-gate 	(void) smc_init_smc_msg(&req_pkt, SMC_GET_WATCHDOG_TIMER,
187*0Sstevel@tonic-gate 		DEFAULT_SEQN, 0);
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	/* make a call to smc library to send cmd */
190*0Sstevel@tonic-gate 	if ((rc = smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
191*0Sstevel@tonic-gate 		WD_POLL_TIMEOUT)) != SMC_SUCCESS) {
192*0Sstevel@tonic-gate 		WD_DEBUG1(WD_PICL_GET_ERR, rc);
193*0Sstevel@tonic-gate 		return (PICL_FAILURE);
194*0Sstevel@tonic-gate 	}
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	/* read 8 bytes */
197*0Sstevel@tonic-gate 	bzero(buffer, WD_REGISTER_LEN);
198*0Sstevel@tonic-gate 	for (i = 0; i < WD_REGISTER_LEN; i++) {
199*0Sstevel@tonic-gate 		buffer[i] = rsp_pkt.data[i];
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate /*
205*0Sstevel@tonic-gate  * get the HEALTHY# line state
206*0Sstevel@tonic-gate  * Return -1 for Error
207*0Sstevel@tonic-gate  *         0 for HEALTHY# down
208*0Sstevel@tonic-gate  *         1 for HEALTHY# up
209*0Sstevel@tonic-gate  */
210*0Sstevel@tonic-gate static int
wd_get_healthy_status()211*0Sstevel@tonic-gate wd_get_healthy_status()
212*0Sstevel@tonic-gate {
213*0Sstevel@tonic-gate 	sc_reqmsg_t	req_pkt;
214*0Sstevel@tonic-gate 	sc_rspmsg_t	rsp_pkt;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	/* initialize the request packet */
217*0Sstevel@tonic-gate 	(void) smc_init_smc_msg(&req_pkt, SMC_GET_EXECUTION_STATE,
218*0Sstevel@tonic-gate 		DEFAULT_SEQN, 0);
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	/* make a call to smc library to send cmd */
221*0Sstevel@tonic-gate 	if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
222*0Sstevel@tonic-gate 		WD_POLL_TIMEOUT) != SMC_SUCCESS) {
223*0Sstevel@tonic-gate 		return (-1);
224*0Sstevel@tonic-gate 	}
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	return ((rsp_pkt.data[0] & IS_HEALTHY) ? WD_HEALTHY_UP :
227*0Sstevel@tonic-gate 		WD_HEALTHY_DOWN);
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*ARGSUSED*/
231*0Sstevel@tonic-gate static void
event_completion_handler(char * ename,void * earg,size_t size)232*0Sstevel@tonic-gate event_completion_handler(char *ename, void *earg, size_t size)
233*0Sstevel@tonic-gate {
234*0Sstevel@tonic-gate 	free(ename);
235*0Sstevel@tonic-gate 	free(earg);
236*0Sstevel@tonic-gate }
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate /*
239*0Sstevel@tonic-gate  * posts picl-state-change event if there is change in watchdog-timer state
240*0Sstevel@tonic-gate  */
241*0Sstevel@tonic-gate static picl_errno_t
post_wd_state_event(picl_nodehdl_t nodeh,char * state)242*0Sstevel@tonic-gate post_wd_state_event(picl_nodehdl_t nodeh, char *state)
243*0Sstevel@tonic-gate {
244*0Sstevel@tonic-gate 	nvlist_t	*nvl;
245*0Sstevel@tonic-gate 	size_t		nvl_size;
246*0Sstevel@tonic-gate 	char		*pack_buf = NULL;
247*0Sstevel@tonic-gate 	picl_errno_t	rc;
248*0Sstevel@tonic-gate 	char *ename = PICLEVENT_STATE_CHANGE, *evname = NULL;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	if (state == NULL) {
251*0Sstevel@tonic-gate 		return (PICL_FAILURE);
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	if ((evname = strdup(ename)) == NULL) {
255*0Sstevel@tonic-gate 		return (PICL_NOSPACE);
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	if ((rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) != 0) {
259*0Sstevel@tonic-gate 		free(evname);
260*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NVLIST_ERR, rc);
261*0Sstevel@tonic-gate 		return (PICL_FAILURE);
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint64(nvl, PICLEVENTARG_NODEHANDLE,
265*0Sstevel@tonic-gate 		nodeh)) != 0) {
266*0Sstevel@tonic-gate 		nvlist_free(nvl);
267*0Sstevel@tonic-gate 		free(evname);
268*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NVLIST_ERR, rc);
269*0Sstevel@tonic-gate 		return (PICL_FAILURE);
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvl, PICLEVENTARG_STATE,
273*0Sstevel@tonic-gate 		state)) != 0) {
274*0Sstevel@tonic-gate 		nvlist_free(nvl);
275*0Sstevel@tonic-gate 		free(evname);
276*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NVLIST_ERR, rc);
277*0Sstevel@tonic-gate 		return (PICL_FAILURE);
278*0Sstevel@tonic-gate 	}
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	if ((rc = nvlist_pack(nvl, &pack_buf, &nvl_size, NV_ENCODE_NATIVE,
281*0Sstevel@tonic-gate 		NULL)) != 0) {
282*0Sstevel@tonic-gate 		nvlist_free(nvl);
283*0Sstevel@tonic-gate 		free(evname);
284*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NVLIST_ERR, rc);
285*0Sstevel@tonic-gate 		return (PICL_FAILURE);
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	if ((rc = ptree_post_event(evname, pack_buf, nvl_size,
289*0Sstevel@tonic-gate 		event_completion_handler)) != PICL_SUCCESS) {
290*0Sstevel@tonic-gate 		free(pack_buf);
291*0Sstevel@tonic-gate 		free(evname);
292*0Sstevel@tonic-gate 		nvlist_free(nvl);
293*0Sstevel@tonic-gate 		return (rc);
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate 	nvlist_free(nvl);
296*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
297*0Sstevel@tonic-gate }
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate /*
300*0Sstevel@tonic-gate  * Updates the State value in picl tree and posts a state-change event
301*0Sstevel@tonic-gate  */
302*0Sstevel@tonic-gate static void
wd_picl_update_state(int level,uint8_t stat)303*0Sstevel@tonic-gate wd_picl_update_state(int level, uint8_t stat)
304*0Sstevel@tonic-gate {
305*0Sstevel@tonic-gate 	picl_errno_t rc;
306*0Sstevel@tonic-gate 	char 	state[PICL_PROPNAMELEN_MAX];
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	switch (stat) {
309*0Sstevel@tonic-gate 	case WD_ARMED:
310*0Sstevel@tonic-gate 		(void) strncpy(state, PICL_PROPVAL_WD_STATE_ARMED,
311*0Sstevel@tonic-gate 			sizeof (state));
312*0Sstevel@tonic-gate 		break;
313*0Sstevel@tonic-gate 	case WD_DISARMED:
314*0Sstevel@tonic-gate 		(void) strncpy(state, PICL_PROPVAL_WD_STATE_DISARMED,
315*0Sstevel@tonic-gate 			sizeof (state));
316*0Sstevel@tonic-gate 		break;
317*0Sstevel@tonic-gate 	case WD_EXPIRED:
318*0Sstevel@tonic-gate 		(void) strncpy(state, PICL_PROPVAL_WD_STATE_EXPIRED,
319*0Sstevel@tonic-gate 			sizeof (state));
320*0Sstevel@tonic-gate 		break;
321*0Sstevel@tonic-gate 	default:
322*0Sstevel@tonic-gate 		return;
323*0Sstevel@tonic-gate 	}
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
326*0Sstevel@tonic-gate 	switch (level) {
327*0Sstevel@tonic-gate 	case WD1:
328*0Sstevel@tonic-gate 		wd_data.wd1_run_state = stat;
329*0Sstevel@tonic-gate 		break;
330*0Sstevel@tonic-gate 	case WD2:
331*0Sstevel@tonic-gate 		wd_data.wd2_run_state = stat;
332*0Sstevel@tonic-gate 		break;
333*0Sstevel@tonic-gate 	case WD1_2:
334*0Sstevel@tonic-gate 		wd_data.wd1_run_state = stat;
335*0Sstevel@tonic-gate 		wd_data.wd2_run_state = stat;
336*0Sstevel@tonic-gate 		break;
337*0Sstevel@tonic-gate 	default:
338*0Sstevel@tonic-gate 		return;
339*0Sstevel@tonic-gate 	}
340*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	if (!state_configured) {
343*0Sstevel@tonic-gate 		return;
344*0Sstevel@tonic-gate 	}
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	switch (level) {
347*0Sstevel@tonic-gate 	case WD1:
348*0Sstevel@tonic-gate 		if ((rc = post_wd_state_event(wd_data.wd1_nodehdl,
349*0Sstevel@tonic-gate 			state)) != PICL_SUCCESS) {
350*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_POST_EVENT_ERR, rc);
351*0Sstevel@tonic-gate 		}
352*0Sstevel@tonic-gate 		break;
353*0Sstevel@tonic-gate 	case WD2:
354*0Sstevel@tonic-gate 		if ((rc = post_wd_state_event(wd_data.wd2_nodehdl,
355*0Sstevel@tonic-gate 			state)) != PICL_SUCCESS) {
356*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_POST_EVENT_ERR, rc);
357*0Sstevel@tonic-gate 		}
358*0Sstevel@tonic-gate 		break;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	case WD1_2:
361*0Sstevel@tonic-gate 		if ((rc = post_wd_state_event(wd_data.wd1_nodehdl,
362*0Sstevel@tonic-gate 			state)) != PICL_SUCCESS) {
363*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_POST_EVENT_ERR, rc);
364*0Sstevel@tonic-gate 		}
365*0Sstevel@tonic-gate 		if ((rc = post_wd_state_event(wd_data.wd2_nodehdl,
366*0Sstevel@tonic-gate 			state)) != PICL_SUCCESS) {
367*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_POST_EVENT_ERR, rc);
368*0Sstevel@tonic-gate 		}
369*0Sstevel@tonic-gate 		break;
370*0Sstevel@tonic-gate 	}
371*0Sstevel@tonic-gate }
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate /*
374*0Sstevel@tonic-gate  * Sends a command to SMC to reset the watchdog-timers
375*0Sstevel@tonic-gate  */
376*0Sstevel@tonic-gate static int
wd_pat()377*0Sstevel@tonic-gate wd_pat()
378*0Sstevel@tonic-gate {
379*0Sstevel@tonic-gate 	int rc = 0;
380*0Sstevel@tonic-gate 	static uint8_t	seq = 1;
381*0Sstevel@tonic-gate 	sc_reqmsg_t	req_pkt;
382*0Sstevel@tonic-gate 	sc_rspmsg_t	rsp_pkt;
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	if (seq < WD_MAX_SEQN) {
385*0Sstevel@tonic-gate 		req_pkt.hdr.msg_id = seq++;
386*0Sstevel@tonic-gate 	} else {
387*0Sstevel@tonic-gate 		seq = 1;
388*0Sstevel@tonic-gate 		req_pkt.hdr.msg_id = seq;
389*0Sstevel@tonic-gate 	}
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	if (wd_debug & WD_TIME_DEBUG) {
392*0Sstevel@tonic-gate 		start1 = gethrtime();
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	/* initialize the request packet */
396*0Sstevel@tonic-gate 	(void) smc_init_smc_msg(&req_pkt, SMC_RESET_WATCHDOG_TIMER,
397*0Sstevel@tonic-gate 		DEFAULT_SEQN, 0);
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	/* make a call to smc library to send cmd */
400*0Sstevel@tonic-gate 	if ((rc = smc_send_msg(wd_fd, &req_pkt, &rsp_pkt,
401*0Sstevel@tonic-gate 		WD_POLL_TIMEOUT)) != SMC_SUCCESS) {
402*0Sstevel@tonic-gate 		syslog(LOG_CRIT, WD_PICL_PAT_ERR, rc);
403*0Sstevel@tonic-gate 		return (PICL_FAILURE);
404*0Sstevel@tonic-gate 	}
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	if (wd_debug & WD_TIME_DEBUG) {
407*0Sstevel@tonic-gate 		end1 = gethrtime();
408*0Sstevel@tonic-gate 		time1[count].res_seq = SC_MSG_ID(&rsp_pkt);
409*0Sstevel@tonic-gate 		time1[count].req_seq = SC_MSG_ID(&req_pkt);
410*0Sstevel@tonic-gate 		time1[count].time = (end1 - start1);
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 		if (count < (NUMBER_OF_READINGS - 1)) {
413*0Sstevel@tonic-gate 			count++;
414*0Sstevel@tonic-gate 		} else {
415*0Sstevel@tonic-gate 			count = 0;
416*0Sstevel@tonic-gate 		}
417*0Sstevel@tonic-gate 	}
418*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
419*0Sstevel@tonic-gate }
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate /* used to set the new values for watchdog and start the watchdog */
422*0Sstevel@tonic-gate static int
wd_start(uchar_t action_1,uchar_t action_2,uchar_t timeout_2,uchar_t * timeout_1,uint8_t patting_option)423*0Sstevel@tonic-gate wd_start(uchar_t action_1, uchar_t action_2,
424*0Sstevel@tonic-gate 	uchar_t timeout_2, uchar_t *timeout_1, uint8_t patting_option)
425*0Sstevel@tonic-gate {
426*0Sstevel@tonic-gate 	int rc = 0;
427*0Sstevel@tonic-gate 	sc_reqmsg_t	req_pkt;
428*0Sstevel@tonic-gate 	sc_rspmsg_t	rsp_pkt;
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate 	if (timeout_1 == NULL) {
431*0Sstevel@tonic-gate 		return (PICL_FAILURE);
432*0Sstevel@tonic-gate 	}
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	req_pkt.data[0] = WD_USEFLAG_OS;
435*0Sstevel@tonic-gate 	req_pkt.data[1] = action_1 | action_2;	/* actions */
436*0Sstevel@tonic-gate 	req_pkt.data[2] = timeout_2;		/* wd timeout 2 */
437*0Sstevel@tonic-gate 	req_pkt.data[3] = WD_XPR_FLG_CLR_OS;	/* expiration flags */
438*0Sstevel@tonic-gate 	req_pkt.data[4] = timeout_1[1];		/* LSB for wd timeout 1 */
439*0Sstevel@tonic-gate 	req_pkt.data[5] = timeout_1[0];		/* MSB for wd timeout 1 */
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	if (patting_option == ENABLE_AUTO_PAT) {
442*0Sstevel@tonic-gate 		req_pkt.data[0] |= WD_ENABLE_AUTO_PAT;
443*0Sstevel@tonic-gate 	}
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	/* initialize the request packet */
446*0Sstevel@tonic-gate 	(void) smc_init_smc_msg(&req_pkt, SMC_SET_WATCHDOG_TIMER,
447*0Sstevel@tonic-gate 		DEFAULT_SEQN, WD_SET_CMD_DATA_LEN);
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	/* make a call to smc library to send cmd */
450*0Sstevel@tonic-gate 	if ((rc = smc_send_msg(wd_fd, &req_pkt, &rsp_pkt,
451*0Sstevel@tonic-gate 		WD_POLL_TIMEOUT)) != SMC_SUCCESS) {
452*0Sstevel@tonic-gate 		WD_DEBUG1(WD_PICL_START_ERR, rc);
453*0Sstevel@tonic-gate 		return (PICL_FAILURE);
454*0Sstevel@tonic-gate 	}
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	/* reset the watchdog timer */
457*0Sstevel@tonic-gate 	(void) smc_init_smc_msg(&req_pkt, SMC_RESET_WATCHDOG_TIMER,
458*0Sstevel@tonic-gate 		DEFAULT_SEQN, 0);
459*0Sstevel@tonic-gate 	if ((rc = smc_send_msg(wd_fd, &req_pkt, &rsp_pkt,
460*0Sstevel@tonic-gate 		WD_POLL_TIMEOUT)) != SMC_SUCCESS) {
461*0Sstevel@tonic-gate 		WD_DEBUG1(WD_PICL_START_ERR, rc);
462*0Sstevel@tonic-gate 		return (PICL_FAILURE);
463*0Sstevel@tonic-gate 	}
464*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
465*0Sstevel@tonic-gate }
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate /*
468*0Sstevel@tonic-gate  * Validates timeout and action fields and arms the watchdog-timers
469*0Sstevel@tonic-gate  */
470*0Sstevel@tonic-gate static int
wd_arm(uint8_t patting_option)471*0Sstevel@tonic-gate wd_arm(uint8_t patting_option)
472*0Sstevel@tonic-gate {
473*0Sstevel@tonic-gate 	int rc;
474*0Sstevel@tonic-gate 	uint16_t	wd_time1;
475*0Sstevel@tonic-gate 	uint8_t		wd_time2, wd1_action, wd2_action;
476*0Sstevel@tonic-gate 	uint8_t		timeout1[2];
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	if (wd_data.wd1_timeout >= 0) {
479*0Sstevel@tonic-gate 		wd_time1 = wd_data.wd1_timeout/WD_L1_RESOLUTION;
480*0Sstevel@tonic-gate 	} else {
481*0Sstevel@tonic-gate 		wd_time1 = 0;
482*0Sstevel@tonic-gate 	}
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	if (wd_data.wd2_timeout >= 0) {
485*0Sstevel@tonic-gate 		wd_time2 = wd_data.wd2_timeout/WD_L2_RESOLUTION;
486*0Sstevel@tonic-gate 	} else {
487*0Sstevel@tonic-gate 		wd_time2 = 0;
488*0Sstevel@tonic-gate 	}
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	timeout1[0] = wd_time1 >> 8;	/* MSB */
491*0Sstevel@tonic-gate 	timeout1[1] = wd_time1 & 0x00ff;	/* LSB */
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	/* check the HELATHY# status if action is alarm */
494*0Sstevel@tonic-gate 	if (wd_data.wd1_action == WD_ACTION_HEALTHY_DOWN_HOST ||
495*0Sstevel@tonic-gate 		wd_data.wd1_action == WD_ACTION_HEALTHY_DOWN_SAT) {
496*0Sstevel@tonic-gate 		rc = wd_get_healthy_status();
497*0Sstevel@tonic-gate 		if (rc == WD_HEALTHY_DOWN) {
498*0Sstevel@tonic-gate 			WD_DEBUG0(WD_HEALTHY_ERR);
499*0Sstevel@tonic-gate 			return (PICL_FAILURE);
500*0Sstevel@tonic-gate 		} else if (rc == -1) {
501*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_GET_HEALTH_ERR);
502*0Sstevel@tonic-gate 			return (PICL_FAILURE);
503*0Sstevel@tonic-gate 		}
504*0Sstevel@tonic-gate 	}
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	if (wd_data.wd1_timeout == -1) {
507*0Sstevel@tonic-gate 		wd1_action = WD_ACTION_NONE2;
508*0Sstevel@tonic-gate 	} else {
509*0Sstevel@tonic-gate 		wd1_action = wd_data.wd1_action;
510*0Sstevel@tonic-gate 	}
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 	if (wd_data.wd2_timeout == -1) {
513*0Sstevel@tonic-gate 		wd2_action = WD_ACTION_NONE2;
514*0Sstevel@tonic-gate 	} else {
515*0Sstevel@tonic-gate 		wd2_action = wd_data.wd2_action;
516*0Sstevel@tonic-gate 	}
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	rc = wd_start(wd1_action, wd2_action,
519*0Sstevel@tonic-gate 		wd_time2, timeout1, patting_option);
520*0Sstevel@tonic-gate 	return (rc);
521*0Sstevel@tonic-gate }
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate /*
524*0Sstevel@tonic-gate  * This is thread is a RealTime class thread. This thread pats the
525*0Sstevel@tonic-gate  * watchdog-timers in regular intervals before the expiry.
526*0Sstevel@tonic-gate  */
527*0Sstevel@tonic-gate /*ARGSUSED*/
528*0Sstevel@tonic-gate static void *
wd_patting_thread(void * args)529*0Sstevel@tonic-gate wd_patting_thread(void *args)
530*0Sstevel@tonic-gate {
531*0Sstevel@tonic-gate 	time_t sec;
532*0Sstevel@tonic-gate 	pcinfo_t pci;
533*0Sstevel@tonic-gate 	long nano_sec;
534*0Sstevel@tonic-gate 	timestruc_t to;
535*0Sstevel@tonic-gate 	long sleep_time;
536*0Sstevel@tonic-gate 	struct timeval tp;
537*0Sstevel@tonic-gate 	int err, state;
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	for (;;) {
540*0Sstevel@tonic-gate 		(void) mutex_lock(&patting_lock);
541*0Sstevel@tonic-gate 		while (wd_data.wd_pat_state == WD_NORESET) {
542*0Sstevel@tonic-gate 			(void) cond_wait(&patting_cv, &patting_lock);
543*0Sstevel@tonic-gate 		}
544*0Sstevel@tonic-gate 		(void) mutex_unlock(&patting_lock);
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 		/* reset pat-time to zero */
547*0Sstevel@tonic-gate 		pat_time = 0;		/* tunable */
548*0Sstevel@tonic-gate 		wd_parse_config_file(wd_conf);
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate 		if (wd_pat_thr_priority < 0 || wd_pat_thr_priority > 59) {
551*0Sstevel@tonic-gate 			wd_pat_thr_priority = WD_DEFAULT_THREAD_PRIORITY;
552*0Sstevel@tonic-gate 		}
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 		/* change the priority of thread to realtime class */
555*0Sstevel@tonic-gate 		(void) strncpy(pci.pc_clname, "RT", sizeof (pci.pc_clname));
556*0Sstevel@tonic-gate 		if (priocntl(P_LWPID, P_MYID, PC_GETCID, (caddr_t)&pci) != -1) {
557*0Sstevel@tonic-gate 			pcparms_t pcp;
558*0Sstevel@tonic-gate 			rtparms_t *rtp = (rtparms_t *)pcp.pc_clparms;
559*0Sstevel@tonic-gate 			rtp->rt_pri = wd_pat_thr_priority;
560*0Sstevel@tonic-gate 			rtp->rt_tqsecs = 0;
561*0Sstevel@tonic-gate 			rtp->rt_tqnsecs = RT_TQDEF;
562*0Sstevel@tonic-gate 			pcp.pc_cid = pci.pc_cid;
563*0Sstevel@tonic-gate 			if (priocntl(P_LWPID, P_MYID, PC_SETPARMS,
564*0Sstevel@tonic-gate 				(caddr_t)&pcp) != 0) {
565*0Sstevel@tonic-gate 				syslog(LOG_ERR, WD_PICL_RT_THRD_FAIL);
566*0Sstevel@tonic-gate 			}
567*0Sstevel@tonic-gate 		} else {
568*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_RT_THRD_NO_PERM_ERR);
569*0Sstevel@tonic-gate 		}
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 		switch (wd_data.wd1_timeout) {
572*0Sstevel@tonic-gate 		case 0:
573*0Sstevel@tonic-gate 			if (wd_arm(DISABLE_AUTO_PAT) == PICL_SUCCESS) {
574*0Sstevel@tonic-gate 				wd_picl_update_state(WD1, WD_ARMED);
575*0Sstevel@tonic-gate 				if (wd_data.wd2_timeout >= 0) {
576*0Sstevel@tonic-gate 					wd_picl_update_state(WD2, WD_ARMED);
577*0Sstevel@tonic-gate 				}
578*0Sstevel@tonic-gate 			} else {
579*0Sstevel@tonic-gate 				syslog(LOG_ERR, WD_PICL_START_ERR,
580*0Sstevel@tonic-gate 					PICL_FAILURE);
581*0Sstevel@tonic-gate 			}
582*0Sstevel@tonic-gate 			/* no need to pat */
583*0Sstevel@tonic-gate 			(void) mutex_lock(&patting_lock);
584*0Sstevel@tonic-gate 			wd_data.wd_pat_state = WD_NORESET;
585*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
586*0Sstevel@tonic-gate 			continue;
587*0Sstevel@tonic-gate 		case -1:
588*0Sstevel@tonic-gate 			if (wd_data.wd2_timeout < 0) {
589*0Sstevel@tonic-gate 				(void) mutex_lock(&patting_lock);
590*0Sstevel@tonic-gate 				wd_data.wd_pat_state = WD_NORESET;
591*0Sstevel@tonic-gate 				(void) mutex_unlock(&patting_lock);
592*0Sstevel@tonic-gate 				continue;
593*0Sstevel@tonic-gate 			}
594*0Sstevel@tonic-gate 			if (wd_arm(DISABLE_AUTO_PAT) == PICL_SUCCESS) {
595*0Sstevel@tonic-gate 				wd_picl_update_state(WD2, WD_ARMED);
596*0Sstevel@tonic-gate 			} else {
597*0Sstevel@tonic-gate 				syslog(LOG_ERR, WD_PICL_START_ERR,
598*0Sstevel@tonic-gate 					PICL_FAILURE);
599*0Sstevel@tonic-gate 			}
600*0Sstevel@tonic-gate 			/* no need to pat */
601*0Sstevel@tonic-gate 			(void) mutex_lock(&patting_lock);
602*0Sstevel@tonic-gate 			wd_data.wd_pat_state = WD_NORESET;
603*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
604*0Sstevel@tonic-gate 			continue;
605*0Sstevel@tonic-gate 		default:
606*0Sstevel@tonic-gate 			break;
607*0Sstevel@tonic-gate 		}
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 		if (pat_time == 0) {
610*0Sstevel@tonic-gate 			if (wd_data.wd1_timeout > WD_PAT_TIME) {
611*0Sstevel@tonic-gate 				pat_time = WD_PAT_TIME;
612*0Sstevel@tonic-gate 			} else {
613*0Sstevel@tonic-gate 				pat_time = wd_data.wd1_timeout - 80;
614*0Sstevel@tonic-gate 			}
615*0Sstevel@tonic-gate 		}
616*0Sstevel@tonic-gate 		if (pat_time <= 0) {
617*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_PAT_TIME_ERR);
618*0Sstevel@tonic-gate 			(void) mutex_lock(&patting_lock);
619*0Sstevel@tonic-gate 				wd_data.wd_pat_state = WD_NORESET;
620*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
621*0Sstevel@tonic-gate 			continue;
622*0Sstevel@tonic-gate 		}
623*0Sstevel@tonic-gate 		sleep_time = wd_data.wd1_timeout - pat_time;
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 		if (wd_data.wd1_timeout <= 0 || sleep_time <= 0) {
626*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_ARM_PAT_ERR);
627*0Sstevel@tonic-gate 			(void) mutex_lock(&patting_lock);
628*0Sstevel@tonic-gate 				wd_data.wd_pat_state = WD_NORESET;
629*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
630*0Sstevel@tonic-gate 			continue;
631*0Sstevel@tonic-gate 		} else {
632*0Sstevel@tonic-gate 			wd_picl_update_state(WD1, WD_ARMED);
633*0Sstevel@tonic-gate 		}
634*0Sstevel@tonic-gate 
635*0Sstevel@tonic-gate 		if (wd_data.wd2_timeout >= 0) {
636*0Sstevel@tonic-gate 			wd_picl_update_state(WD2, WD_ARMED);
637*0Sstevel@tonic-gate 		}
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 		sec = sleep_time/1000;
640*0Sstevel@tonic-gate 		nano_sec = (sleep_time - (sec * 1000)) * 1000000;
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 		if (wd_arm(ENABLE_AUTO_PAT) != PICL_SUCCESS) {
643*0Sstevel@tonic-gate 			wd_picl_update_state(WD1_2, WD_DISARMED);
644*0Sstevel@tonic-gate 			(void) mutex_lock(&patting_lock);
645*0Sstevel@tonic-gate 				wd_data.wd_pat_state = WD_NORESET;
646*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
647*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_START_ERR, PICL_FAILURE);
648*0Sstevel@tonic-gate 			continue;
649*0Sstevel@tonic-gate 		}
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 		do	/* pat the watchdog until expiry or user disarm */
652*0Sstevel@tonic-gate 		{
653*0Sstevel@tonic-gate 			(void) mutex_lock(&patting_lock);
654*0Sstevel@tonic-gate 			state = wd_data.wd_pat_state;
655*0Sstevel@tonic-gate 			if (state == WD_NORESET) {
656*0Sstevel@tonic-gate 				(void) mutex_unlock(&patting_lock);
657*0Sstevel@tonic-gate 				break;
658*0Sstevel@tonic-gate 			}
659*0Sstevel@tonic-gate 			(void) gettimeofday(&tp, NULL);
660*0Sstevel@tonic-gate 			to.tv_sec = tp.tv_sec + sec;
661*0Sstevel@tonic-gate 			if ((nano_sec + (tp.tv_usec * 1000)) >= 1000000000) {
662*0Sstevel@tonic-gate 				to.tv_sec +=  1;
663*0Sstevel@tonic-gate 				to.tv_nsec = (nano_sec +
664*0Sstevel@tonic-gate 					(tp.tv_usec * 1000)) - 1000000000;
665*0Sstevel@tonic-gate 			} else {
666*0Sstevel@tonic-gate 				to.tv_nsec = nano_sec + (tp.tv_usec * 1000);
667*0Sstevel@tonic-gate 			}
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 			err = cond_timedwait(&patting_cv, &patting_lock, &to);
670*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 			if (err == ETIME) { /* woke up from sleep */
673*0Sstevel@tonic-gate 				(void) wd_pat();
674*0Sstevel@tonic-gate 			}
675*0Sstevel@tonic-gate 		} while (state == WD_RESET);
676*0Sstevel@tonic-gate 	}
677*0Sstevel@tonic-gate 	/*NOTREACHED*/
678*0Sstevel@tonic-gate 	return (NULL);
679*0Sstevel@tonic-gate }
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate /*
682*0Sstevel@tonic-gate  * returns 0 if owner is not alive
683*0Sstevel@tonic-gate  * returns 1 if owner is alive
684*0Sstevel@tonic-gate  * returns -1 if there is no active owner
685*0Sstevel@tonic-gate  */
686*0Sstevel@tonic-gate static int
is_owner_alive()687*0Sstevel@tonic-gate is_owner_alive()
688*0Sstevel@tonic-gate {
689*0Sstevel@tonic-gate 	char strpid[50];
690*0Sstevel@tonic-gate 	struct stat buf;
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	if (pid == -1) {
693*0Sstevel@tonic-gate 		return (-1);
694*0Sstevel@tonic-gate 	}
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 	/* check if the file exists or not */
697*0Sstevel@tonic-gate 	(void) snprintf(strpid, sizeof (pid), "/proc/%ld/status", pid);
698*0Sstevel@tonic-gate 	errno = 0;
699*0Sstevel@tonic-gate 	if (stat(strpid, &buf) == 0) {
700*0Sstevel@tonic-gate 		return (1);
701*0Sstevel@tonic-gate 	}
702*0Sstevel@tonic-gate 	if (errno == ENOENT) {
703*0Sstevel@tonic-gate 		return (0);
704*0Sstevel@tonic-gate 	} else {
705*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_GET_OWN_FAILED, errno);
706*0Sstevel@tonic-gate 	}
707*0Sstevel@tonic-gate 	return (-1);
708*0Sstevel@tonic-gate }
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate /*
711*0Sstevel@tonic-gate  * Sends a cmd to SMC to stop watchdog timers
712*0Sstevel@tonic-gate  */
713*0Sstevel@tonic-gate static int
wd_stop()714*0Sstevel@tonic-gate wd_stop()
715*0Sstevel@tonic-gate {
716*0Sstevel@tonic-gate 	int rc = 0;
717*0Sstevel@tonic-gate 	sc_reqmsg_t	req_pkt;
718*0Sstevel@tonic-gate 	sc_rspmsg_t	rsp_pkt;
719*0Sstevel@tonic-gate 	uint8_t	buffer[8];
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	if (wd_get_reg_dump(buffer) != 0) {
722*0Sstevel@tonic-gate 		return (PICL_FAILURE);
723*0Sstevel@tonic-gate 	}
724*0Sstevel@tonic-gate 	/* clear the expiration flags */
725*0Sstevel@tonic-gate 	buffer[3] = 0xff;	/* expiration flags */
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 	(void) memcpy(SC_MSG_DATA(&req_pkt), buffer,
728*0Sstevel@tonic-gate 		WD_SET_CMD_DATA_LEN);
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	/* initialize the request packet */
731*0Sstevel@tonic-gate 	(void) smc_init_smc_msg(&req_pkt, SMC_SET_WATCHDOG_TIMER,
732*0Sstevel@tonic-gate 		DEFAULT_SEQN, WD_SET_CMD_DATA_LEN);
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	/* make a call to smc library to send cmd */
735*0Sstevel@tonic-gate 	if ((rc = smc_send_msg(wd_fd, &req_pkt, &rsp_pkt,
736*0Sstevel@tonic-gate 		WD_POLL_TIMEOUT)) != SMC_SUCCESS) {
737*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_STOP_ERR, rc);
738*0Sstevel@tonic-gate 		return (PICL_FAILURE);
739*0Sstevel@tonic-gate 	}
740*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
741*0Sstevel@tonic-gate }
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate /*
744*0Sstevel@tonic-gate  * Function used by volatile callback function for wd-op property
745*0Sstevel@tonic-gate  * under controller. This is used to arm, disarm the watchdog-timers
746*0Sstevel@tonic-gate  * in response to user actions
747*0Sstevel@tonic-gate  */
748*0Sstevel@tonic-gate static int
wd_worker_function(uint8_t flag,pid_t proc_id)749*0Sstevel@tonic-gate wd_worker_function(uint8_t flag, pid_t proc_id)
750*0Sstevel@tonic-gate {
751*0Sstevel@tonic-gate 	int rc = PICL_SUCCESS;
752*0Sstevel@tonic-gate 	int wd1_state, wd2_state;
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
755*0Sstevel@tonic-gate 	wd1_state = wd_data.wd1_run_state;
756*0Sstevel@tonic-gate 	wd2_state = wd_data.wd2_run_state;
757*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate 	switch (flag) {
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	case USER_ARMED_WD:
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	/* watchdog can only be armed if all the timers are disarmed */
764*0Sstevel@tonic-gate 	if (wd1_state != WD_DISARMED) {
765*0Sstevel@tonic-gate 		WD_DEBUG0(WD_PICL_WD1_RUNNING_ERR);
766*0Sstevel@tonic-gate 		rc = PICL_FAILURE;
767*0Sstevel@tonic-gate 		break;
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 	if (wd2_state != WD_DISARMED) {
770*0Sstevel@tonic-gate 		WD_DEBUG0(WD_PICL_WD2_RUNNING_ERR);
771*0Sstevel@tonic-gate 		rc = PICL_FAILURE;
772*0Sstevel@tonic-gate 		break;
773*0Sstevel@tonic-gate 	}
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	/* check the HELATHY# status if action is alarm */
776*0Sstevel@tonic-gate 	if (wd_data.wd1_timeout >= 0) {
777*0Sstevel@tonic-gate 		if (wd_data.wd1_action == WD_ACTION_HEALTHY_DOWN_HOST ||
778*0Sstevel@tonic-gate 			wd_data.wd1_action == WD_ACTION_HEALTHY_DOWN_SAT) {
779*0Sstevel@tonic-gate 			rc = wd_get_healthy_status();
780*0Sstevel@tonic-gate 			if (rc == WD_HEALTHY_DOWN) {
781*0Sstevel@tonic-gate 				WD_DEBUG0(WD_HEALTHY_ERR);
782*0Sstevel@tonic-gate 				return (PICL_FAILURE);
783*0Sstevel@tonic-gate 			} else if (rc == -1) {
784*0Sstevel@tonic-gate 				syslog(LOG_ERR, WD_GET_HEALTH_ERR);
785*0Sstevel@tonic-gate 				return (PICL_FAILURE);
786*0Sstevel@tonic-gate 			} else {
787*0Sstevel@tonic-gate 				rc = PICL_SUCCESS;
788*0Sstevel@tonic-gate 			}
789*0Sstevel@tonic-gate 		}
790*0Sstevel@tonic-gate 	}
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	/* signal the patting thread */
793*0Sstevel@tonic-gate 	(void) mutex_lock(&patting_lock);
794*0Sstevel@tonic-gate 	wd_data.wd_pat_state = WD_RESET;
795*0Sstevel@tonic-gate 	(void) cond_signal(&patting_cv);
796*0Sstevel@tonic-gate 	(void) mutex_unlock(&patting_lock);
797*0Sstevel@tonic-gate 	break;
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	case USER_DISARMED_WD:
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 	/*
802*0Sstevel@tonic-gate 	 * if the caller doesnot own watchdog services,
803*0Sstevel@tonic-gate 	 * check to see if the owner is still alive using procfs
804*0Sstevel@tonic-gate 	 */
805*0Sstevel@tonic-gate 	if (proc_id !=  pid) {
806*0Sstevel@tonic-gate 		switch (is_owner_alive()) {
807*0Sstevel@tonic-gate 		case -1:
808*0Sstevel@tonic-gate 			if ((wd1_state != WD_DISARMED) ||
809*0Sstevel@tonic-gate 			(wd2_state != WD_DISARMED)) {
810*0Sstevel@tonic-gate 				break;
811*0Sstevel@tonic-gate 			}
812*0Sstevel@tonic-gate 			/* watchdog is already disarmed */
813*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_NO_WD_ERR);
814*0Sstevel@tonic-gate 			return (PICL_FAILURE);
815*0Sstevel@tonic-gate 		case 1:
816*0Sstevel@tonic-gate 			/* owner is still alive, deny the operation */
817*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_PERM_DENIED);
818*0Sstevel@tonic-gate 			return (PICL_PERMDENIED);
819*0Sstevel@tonic-gate 		default:
820*0Sstevel@tonic-gate 			break;
821*0Sstevel@tonic-gate 		}
822*0Sstevel@tonic-gate 	}
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	/* watchdog is running */
825*0Sstevel@tonic-gate 	if ((rc = wd_stop()) == PICL_SUCCESS) {
826*0Sstevel@tonic-gate 		wd_picl_update_state(WD1_2, WD_DISARMED);
827*0Sstevel@tonic-gate 		(void) mutex_lock(&patting_lock);
828*0Sstevel@tonic-gate 		wd_data.wd_pat_state = WD_NORESET;
829*0Sstevel@tonic-gate 		(void) cond_signal(&patting_cv);
830*0Sstevel@tonic-gate 		(void) mutex_unlock(&patting_lock);
831*0Sstevel@tonic-gate 	}
832*0Sstevel@tonic-gate 	break;
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 	case USER_ARMED_PAT_WD: /* for debug purposes only */
835*0Sstevel@tonic-gate 
836*0Sstevel@tonic-gate 	/*
837*0Sstevel@tonic-gate 	 * first arm-pat operation is used for arming the watchdog
838*0Sstevel@tonic-gate 	 * subsequent arm-pat operations will be used for patting
839*0Sstevel@tonic-gate 	 * the watchdog
840*0Sstevel@tonic-gate 	 */
841*0Sstevel@tonic-gate 	/* WD is stopped */
842*0Sstevel@tonic-gate 	if (wd1_state == WD_DISARMED && wd2_state == WD_DISARMED) {
843*0Sstevel@tonic-gate 		if ((rc = wd_arm(DISABLE_AUTO_PAT)) == PICL_SUCCESS) {
844*0Sstevel@tonic-gate 			if (wd_data.wd1_timeout >= 0) {
845*0Sstevel@tonic-gate 				wd_picl_update_state(WD1, WD_ARMED);
846*0Sstevel@tonic-gate 			}
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate 			if (wd_data.wd2_timeout >= 0) {
849*0Sstevel@tonic-gate 				wd_picl_update_state(WD2, WD_ARMED);
850*0Sstevel@tonic-gate 			}
851*0Sstevel@tonic-gate 		} else {
852*0Sstevel@tonic-gate 			return (rc);
853*0Sstevel@tonic-gate 		}
854*0Sstevel@tonic-gate 	} else {	/* WD is running */
855*0Sstevel@tonic-gate 		if (wd1_state != WD_ARMED) {
856*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_NO_WD_ERR);
857*0Sstevel@tonic-gate 			return (PICL_INVALIDARG);
858*0Sstevel@tonic-gate 		}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 		/* check if OS is patting the watchdog or not */
861*0Sstevel@tonic-gate 		(void) mutex_lock(&patting_lock);
862*0Sstevel@tonic-gate 		if (wd_data.wd_pat_state == WD_RESET) {
863*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_TRY_PAT_ERR);
864*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
865*0Sstevel@tonic-gate 			return (PICL_INVALIDARG);
866*0Sstevel@tonic-gate 		}
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 		/* check if the process owns the WD services */
869*0Sstevel@tonic-gate 		if (proc_id != pid) {
870*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_PERM_DENIED);
871*0Sstevel@tonic-gate 			return (PICL_PERMDENIED);
872*0Sstevel@tonic-gate 		}
873*0Sstevel@tonic-gate 		rc = wd_pat();
874*0Sstevel@tonic-gate 	}
875*0Sstevel@tonic-gate 	break;
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 	default:
878*0Sstevel@tonic-gate 	rc = PICL_INVALIDARG;
879*0Sstevel@tonic-gate 	break;
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	} /* switch */
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	return (rc);
884*0Sstevel@tonic-gate }
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate /*ARGSUSED*/
887*0Sstevel@tonic-gate static int
wd_write_op(ptree_warg_t * parg,const void * buf)888*0Sstevel@tonic-gate wd_write_op(ptree_warg_t *parg, const void *buf)
889*0Sstevel@tonic-gate {
890*0Sstevel@tonic-gate 	int rc = PICL_INVALIDARG;
891*0Sstevel@tonic-gate 	uint8_t	flag;
892*0Sstevel@tonic-gate 
893*0Sstevel@tonic-gate 	/* only after state is configured */
894*0Sstevel@tonic-gate 	if (!state_configured) {
895*0Sstevel@tonic-gate 		if (parg->cred.dc_pid != getpid()) {
896*0Sstevel@tonic-gate 			WD_DEBUG0(WD_PICL_STATE_INVALID);
897*0Sstevel@tonic-gate 			return (PICL_PERMDENIED);
898*0Sstevel@tonic-gate 		}
899*0Sstevel@tonic-gate 	}
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 	/* only super user can write this property */
902*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != SUPER_USER) {
903*0Sstevel@tonic-gate 		WD_DEBUG0(WD_NO_ROOT_PERM);
904*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
905*0Sstevel@tonic-gate 	}
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	if (strcmp((char *)buf, PICL_PROPVAL_WD_OP_ARM) == 0) {
908*0Sstevel@tonic-gate 		flag = USER_ARMED_WD;
909*0Sstevel@tonic-gate 		rc = PICL_SUCCESS;
910*0Sstevel@tonic-gate 	}
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	if (strcmp((char *)buf, PICL_PROPVAL_WD_OP_DISARM) == 0) {
913*0Sstevel@tonic-gate 		flag = USER_DISARMED_WD;
914*0Sstevel@tonic-gate 		rc = PICL_SUCCESS;
915*0Sstevel@tonic-gate 	}
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 	/* for debug purpose only */
918*0Sstevel@tonic-gate 	if (strcmp((char *)buf, WD_ARM_PAT) == 0) {
919*0Sstevel@tonic-gate 		flag = USER_ARMED_PAT_WD;
920*0Sstevel@tonic-gate 		rc = PICL_SUCCESS;
921*0Sstevel@tonic-gate 	}
922*0Sstevel@tonic-gate 
923*0Sstevel@tonic-gate 	if (rc == PICL_SUCCESS) {
924*0Sstevel@tonic-gate 		rc = wd_worker_function(flag, parg->cred.dc_pid);
925*0Sstevel@tonic-gate 	} else {
926*0Sstevel@tonic-gate 		rc = PICL_INVALIDARG;
927*0Sstevel@tonic-gate 	}
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 	if (rc == PICL_SUCCESS) {
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 		switch (flag) {
932*0Sstevel@tonic-gate 		case USER_ARMED_PAT_WD:
933*0Sstevel@tonic-gate 		case USER_ARMED_WD:
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 			/* get the process id of client */
936*0Sstevel@tonic-gate 			if (parg->cred.dc_pid != getpid()) {
937*0Sstevel@tonic-gate 				pid = parg->cred.dc_pid;
938*0Sstevel@tonic-gate 			} else {
939*0Sstevel@tonic-gate 				pid = -1;
940*0Sstevel@tonic-gate 			}
941*0Sstevel@tonic-gate 			break;
942*0Sstevel@tonic-gate 		case USER_DISARMED_WD:
943*0Sstevel@tonic-gate 			/* reset the pid */
944*0Sstevel@tonic-gate 			pid = -1;
945*0Sstevel@tonic-gate 		default:
946*0Sstevel@tonic-gate 			break;
947*0Sstevel@tonic-gate 		}
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate 	return (rc);
950*0Sstevel@tonic-gate }
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate /* volatile call back function to read the watchdog L1 status */
953*0Sstevel@tonic-gate /*ARGSUSED*/
954*0Sstevel@tonic-gate static int
wd1_read_status(ptree_rarg_t * parg,void * buf)955*0Sstevel@tonic-gate wd1_read_status(ptree_rarg_t *parg, void *buf)
956*0Sstevel@tonic-gate {
957*0Sstevel@tonic-gate 	int rc = PICL_SUCCESS;
958*0Sstevel@tonic-gate 
959*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 	switch (wd_data.wd1_run_state) {
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate 	case WD_EXPIRED:
964*0Sstevel@tonic-gate 		(void) strncpy((char *)buf, PICL_PROPVAL_WD_STATE_EXPIRED,
965*0Sstevel@tonic-gate 			PICL_PROPNAMELEN_MAX);
966*0Sstevel@tonic-gate 		break;
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate 	case WD_DISARMED:
969*0Sstevel@tonic-gate 		(void) strncpy((char *)buf, PICL_PROPVAL_WD_STATE_DISARMED,
970*0Sstevel@tonic-gate 			PICL_PROPNAMELEN_MAX);
971*0Sstevel@tonic-gate 		break;
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	case WD_ARMED:
974*0Sstevel@tonic-gate 		(void) strncpy((char *)buf, PICL_PROPVAL_WD_STATE_ARMED,
975*0Sstevel@tonic-gate 			PICL_PROPNAMELEN_MAX);
976*0Sstevel@tonic-gate 		break;
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	default:
979*0Sstevel@tonic-gate 		rc = PICL_FAILURE;
980*0Sstevel@tonic-gate 	}
981*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
982*0Sstevel@tonic-gate 	return (rc);
983*0Sstevel@tonic-gate }
984*0Sstevel@tonic-gate 
985*0Sstevel@tonic-gate /*
986*0Sstevel@tonic-gate  * this function is used to read the state of L2 timer
987*0Sstevel@tonic-gate  */
988*0Sstevel@tonic-gate static int
wd_get_wd2_status(int * present_status)989*0Sstevel@tonic-gate wd_get_wd2_status(int *present_status)
990*0Sstevel@tonic-gate {
991*0Sstevel@tonic-gate 	int rc;
992*0Sstevel@tonic-gate 	uchar_t	buffer[WD_REGISTER_LEN];
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 	bzero(buffer, WD_REGISTER_LEN);
995*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
996*0Sstevel@tonic-gate 	*present_status = wd_data.wd2_run_state;
997*0Sstevel@tonic-gate 	if (wd_data.wd2_run_state != WD_ARMED) {
998*0Sstevel@tonic-gate 		/* we already have the latest state */
999*0Sstevel@tonic-gate 		(void) mutex_unlock(&data_lock);
1000*0Sstevel@tonic-gate 		return (PICL_SUCCESS);
1001*0Sstevel@tonic-gate 	}
1002*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate 	/* read watchdog registers */
1005*0Sstevel@tonic-gate 	if ((rc = wd_get_reg_dump(buffer)) != 0) {
1006*0Sstevel@tonic-gate 		return (rc);
1007*0Sstevel@tonic-gate 	}
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate 	if (buffer[0] & WD_WD_RUNNING) {
1010*0Sstevel@tonic-gate 		*present_status = WD_ARMED;
1011*0Sstevel@tonic-gate 		return (PICL_SUCCESS);
1012*0Sstevel@tonic-gate 	}
1013*0Sstevel@tonic-gate 
1014*0Sstevel@tonic-gate 	if (buffer[3] != 0) {
1015*0Sstevel@tonic-gate 		(void) mutex_lock(&data_lock);
1016*0Sstevel@tonic-gate 		*present_status = wd_data.wd2_run_state = WD_EXPIRED;
1017*0Sstevel@tonic-gate 		(void) mutex_unlock(&data_lock);
1018*0Sstevel@tonic-gate 	}
1019*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
1020*0Sstevel@tonic-gate }
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate /* volatile call back function to read the watchdog L2 status */
1023*0Sstevel@tonic-gate /*ARGSUSED*/
1024*0Sstevel@tonic-gate static int
wd2_read_status(ptree_rarg_t * parg,void * buf)1025*0Sstevel@tonic-gate wd2_read_status(ptree_rarg_t *parg, void *buf)
1026*0Sstevel@tonic-gate {
1027*0Sstevel@tonic-gate 	int present_status, rc;
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 	if ((rc = wd_get_wd2_status(&present_status)) !=
1030*0Sstevel@tonic-gate 		PICL_SUCCESS) {
1031*0Sstevel@tonic-gate 		return (rc);
1032*0Sstevel@tonic-gate 	}
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 	/* copy the present state in user buffer */
1035*0Sstevel@tonic-gate 	switch (present_status) {
1036*0Sstevel@tonic-gate 	case WD_ARMED:
1037*0Sstevel@tonic-gate 		(void) strncpy((char *)buf, PICL_PROPVAL_WD_STATE_ARMED,
1038*0Sstevel@tonic-gate 			PICL_PROPNAMELEN_MAX);
1039*0Sstevel@tonic-gate 		break;
1040*0Sstevel@tonic-gate 	case WD_EXPIRED:
1041*0Sstevel@tonic-gate 		(void) strncpy((char *)buf, PICL_PROPVAL_WD_STATE_EXPIRED,
1042*0Sstevel@tonic-gate 			PICL_PROPNAMELEN_MAX);
1043*0Sstevel@tonic-gate 		break;
1044*0Sstevel@tonic-gate 	case WD_DISARMED:
1045*0Sstevel@tonic-gate 		(void) strncpy((char *)buf, PICL_PROPVAL_WD_STATE_DISARMED,
1046*0Sstevel@tonic-gate 			PICL_PROPNAMELEN_MAX);
1047*0Sstevel@tonic-gate 		break;
1048*0Sstevel@tonic-gate 	}
1049*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
1050*0Sstevel@tonic-gate }
1051*0Sstevel@tonic-gate 
1052*0Sstevel@tonic-gate /* this thread listens for watchdog expiry events */
1053*0Sstevel@tonic-gate /*ARGSUSED*/
1054*0Sstevel@tonic-gate static void *
wd_polling(void * args)1055*0Sstevel@tonic-gate wd_polling(void *args)
1056*0Sstevel@tonic-gate {
1057*0Sstevel@tonic-gate 	uint8_t	stat;
1058*0Sstevel@tonic-gate 	int poll_retval;
1059*0Sstevel@tonic-gate 	struct pollfd fds;
1060*0Sstevel@tonic-gate 	sc_rspmsg_t rsp_pkt;
1061*0Sstevel@tonic-gate 	int i;
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate 	fds.fd = polling_fd;
1064*0Sstevel@tonic-gate 	fds.events = POLLIN | POLLPRI;
1065*0Sstevel@tonic-gate 	fds.revents = 0;
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	for (;;) {
1068*0Sstevel@tonic-gate 		poll_retval = poll(&fds, 1, -1);
1069*0Sstevel@tonic-gate 		if (props_created == 0)
1070*0Sstevel@tonic-gate 			continue;
1071*0Sstevel@tonic-gate 		switch (poll_retval) {
1072*0Sstevel@tonic-gate 		case 0:
1073*0Sstevel@tonic-gate 		break;
1074*0Sstevel@tonic-gate 
1075*0Sstevel@tonic-gate 		case -1:
1076*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_POLL_ERR);
1077*0Sstevel@tonic-gate 		break;
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 		default:
1080*0Sstevel@tonic-gate 		/* something happened */
1081*0Sstevel@tonic-gate 		if ((read(polling_fd, &rsp_pkt,
1082*0Sstevel@tonic-gate 			sizeof (sc_rspmsg_t))) < 0) {
1083*0Sstevel@tonic-gate 			syslog(LOG_ERR, WD_PICL_SMC_READ_ERR);
1084*0Sstevel@tonic-gate 			break;
1085*0Sstevel@tonic-gate 		}
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 		if (rsp_pkt.hdr.cmd == SMC_EXPIRED_WATCHDOG_NOTIF) {
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate 			(void) mutex_lock(&data_lock);
1090*0Sstevel@tonic-gate 			stat = wd_data.wd1_run_state;
1091*0Sstevel@tonic-gate 			(void) mutex_unlock(&data_lock);
1092*0Sstevel@tonic-gate 
1093*0Sstevel@tonic-gate 			if (stat != WD_ARMED) {
1094*0Sstevel@tonic-gate 				continue;
1095*0Sstevel@tonic-gate 			}
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 			wd_picl_update_state(WD1, WD_EXPIRED);
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 			(void) mutex_lock(&patting_lock);
1100*0Sstevel@tonic-gate 			wd_data.wd_pat_state = WD_NORESET;
1101*0Sstevel@tonic-gate 			(void) cond_signal(&patting_cv);
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate 			(void) mutex_unlock(&patting_lock);
1104*0Sstevel@tonic-gate 			syslog(LOG_WARNING, WD_WD1_EXPIRED);
1105*0Sstevel@tonic-gate 			if (wd_debug & WD_TIME_DEBUG) {
1106*0Sstevel@tonic-gate 				syslog(LOG_ERR, " latest count : %d", count);
1107*0Sstevel@tonic-gate 				for (i = 0; i < NUMBER_OF_READINGS; i++) {
1108*0Sstevel@tonic-gate 					syslog(LOG_ERR, "i = %d, req_seq = %d,"
1109*0Sstevel@tonic-gate 					"res_seq = %d, time = %lld nsec",
1110*0Sstevel@tonic-gate 						i, time1[i].req_seq,
1111*0Sstevel@tonic-gate 						time1[i].res_seq,
1112*0Sstevel@tonic-gate 						time1[i].time);
1113*0Sstevel@tonic-gate 				}
1114*0Sstevel@tonic-gate 			}
1115*0Sstevel@tonic-gate 			if (wd_data.reboot_action) {
1116*0Sstevel@tonic-gate 				wd_data.reboot_action = 0;
1117*0Sstevel@tonic-gate 				(void) system(SHUTDOWN_CMD);
1118*0Sstevel@tonic-gate 			}
1119*0Sstevel@tonic-gate 		}
1120*0Sstevel@tonic-gate 		break;
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 		} /* switch */
1123*0Sstevel@tonic-gate 	}
1124*0Sstevel@tonic-gate 	/*NOTREACHED*/
1125*0Sstevel@tonic-gate 	return (NULL);
1126*0Sstevel@tonic-gate }
1127*0Sstevel@tonic-gate 
1128*0Sstevel@tonic-gate /*
1129*0Sstevel@tonic-gate  * This function reads the hardware state and gets the status of
1130*0Sstevel@tonic-gate  * watchdog-timers
1131*0Sstevel@tonic-gate  */
1132*0Sstevel@tonic-gate static int
wd_get_status(wd_state_t * state)1133*0Sstevel@tonic-gate wd_get_status(wd_state_t *state)
1134*0Sstevel@tonic-gate {
1135*0Sstevel@tonic-gate 	picl_errno_t	rc;
1136*0Sstevel@tonic-gate 	uchar_t		buffer[WD_REGISTER_LEN];
1137*0Sstevel@tonic-gate 
1138*0Sstevel@tonic-gate 	bzero(buffer, WD_REGISTER_LEN);
1139*0Sstevel@tonic-gate 	/* read watchdog registers */
1140*0Sstevel@tonic-gate 	if ((rc = wd_get_reg_dump(buffer)) != 0) {
1141*0Sstevel@tonic-gate 		return (rc);
1142*0Sstevel@tonic-gate 	}
1143*0Sstevel@tonic-gate 
1144*0Sstevel@tonic-gate 	/* get action */
1145*0Sstevel@tonic-gate 	state->action1 = buffer[1] & 0xF0; /* most significant 4 bits */
1146*0Sstevel@tonic-gate 	if (state->action1 == 0x0) {
1147*0Sstevel@tonic-gate 		state->action1 = WD_ACTION_NONE1;
1148*0Sstevel@tonic-gate 	}
1149*0Sstevel@tonic-gate 	state->action2 = buffer[1] & 0x0F; /* least significant 4 bits */
1150*0Sstevel@tonic-gate 	if (state->action2 == 0x0) {
1151*0Sstevel@tonic-gate 		state->action2 = WD_ACTION_NONE2;
1152*0Sstevel@tonic-gate 	}
1153*0Sstevel@tonic-gate 
1154*0Sstevel@tonic-gate 	state->timeout2 = buffer[2];
1155*0Sstevel@tonic-gate 	state->timeout1[0] = buffer[5];	/* MSB */
1156*0Sstevel@tonic-gate 	state->timeout1[1] = buffer[4];	/* LSB */
1157*0Sstevel@tonic-gate 
1158*0Sstevel@tonic-gate 	state->present_t1[0] = buffer[7]; /* MSB */
1159*0Sstevel@tonic-gate 	state->present_t1[1] = buffer[6]; /* LSB */
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate 	if (buffer[0] & WD_WD_RUNNING) {
1162*0Sstevel@tonic-gate 		state->present_state = WD_ARMED;
1163*0Sstevel@tonic-gate 		return (PICL_SUCCESS);
1164*0Sstevel@tonic-gate 	}
1165*0Sstevel@tonic-gate 
1166*0Sstevel@tonic-gate 	if (buffer[3] != 0) {
1167*0Sstevel@tonic-gate 		state->present_state = WD_EXPIRED;
1168*0Sstevel@tonic-gate 		return (PICL_SUCCESS);
1169*0Sstevel@tonic-gate 	} else {
1170*0Sstevel@tonic-gate 		state->present_state = WD_DISARMED;
1171*0Sstevel@tonic-gate 		return (PICL_SUCCESS);
1172*0Sstevel@tonic-gate 	}
1173*0Sstevel@tonic-gate }
1174*0Sstevel@tonic-gate 
1175*0Sstevel@tonic-gate /* read the smc hardware and intialize the internal state */
1176*0Sstevel@tonic-gate static void
wd_set_init_state()1177*0Sstevel@tonic-gate wd_set_init_state()
1178*0Sstevel@tonic-gate {
1179*0Sstevel@tonic-gate 	wd_state_t state;
1180*0Sstevel@tonic-gate 	uint16_t tmp1, tmp2, wd_time1;
1181*0Sstevel@tonic-gate 
1182*0Sstevel@tonic-gate 	if (wd_get_status(&state) != PICL_SUCCESS) {
1183*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_GET_STAT_ERR);
1184*0Sstevel@tonic-gate 		/* defualt state is expired ??? */
1185*0Sstevel@tonic-gate 		state.present_state = WD_EXPIRED;
1186*0Sstevel@tonic-gate 	}
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 	switch (state.present_state) {
1189*0Sstevel@tonic-gate 	case WD_EXPIRED:
1190*0Sstevel@tonic-gate 	case WD_DISARMED:
1191*0Sstevel@tonic-gate 		if (state.present_state == WD_EXPIRED)
1192*0Sstevel@tonic-gate 			wd_picl_update_state(WD1_2, WD_EXPIRED);
1193*0Sstevel@tonic-gate 		else
1194*0Sstevel@tonic-gate 			wd_picl_update_state(WD1_2, WD_DISARMED);
1195*0Sstevel@tonic-gate 		wd_data.wd_pat_state = WD_NORESET;
1196*0Sstevel@tonic-gate 		wd_data.wd1_action = state.action1;
1197*0Sstevel@tonic-gate 		wd_data.wd2_action = state.action2;
1198*0Sstevel@tonic-gate 		tmp1 = state.timeout1[0] << 8;
1199*0Sstevel@tonic-gate 		tmp2 = state.timeout1[1];
1200*0Sstevel@tonic-gate 		wd_time1 = tmp1 | tmp2;
1201*0Sstevel@tonic-gate 		wd_data.wd1_timeout = wd_time1 * WD_L1_RESOLUTION;
1202*0Sstevel@tonic-gate 		wd_data.wd2_timeout = state.timeout2 * WD_L2_RESOLUTION;
1203*0Sstevel@tonic-gate 		break;
1204*0Sstevel@tonic-gate 	case WD_ARMED:
1205*0Sstevel@tonic-gate 		/*
1206*0Sstevel@tonic-gate 		 * get the present values and restart the
1207*0Sstevel@tonic-gate 		 * watchdog from os level and continue to pat
1208*0Sstevel@tonic-gate 		 */
1209*0Sstevel@tonic-gate 		wd_picl_update_state(WD1_2, WD_ARMED);
1210*0Sstevel@tonic-gate 		wd_data.wd_pat_state = WD_RESET;
1211*0Sstevel@tonic-gate 		wd_data.wd1_action = (state.action1 << 4);
1212*0Sstevel@tonic-gate 		wd_data.wd2_action = state.action2;
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 		tmp1 = state.timeout1[0] << 8;
1215*0Sstevel@tonic-gate 		tmp2 = state.timeout1[1];
1216*0Sstevel@tonic-gate 		wd_time1 = tmp1 | tmp2;
1217*0Sstevel@tonic-gate 		wd_data.wd1_timeout = wd_time1 * WD_L1_RESOLUTION;
1218*0Sstevel@tonic-gate 		wd_data.wd2_timeout = state.timeout2 * WD_L2_RESOLUTION;
1219*0Sstevel@tonic-gate 		(void) wd_stop();
1220*0Sstevel@tonic-gate 	}
1221*0Sstevel@tonic-gate }
1222*0Sstevel@tonic-gate 
1223*0Sstevel@tonic-gate /*
1224*0Sstevel@tonic-gate  * wrapper for ptree interface to create property
1225*0Sstevel@tonic-gate  */
1226*0Sstevel@tonic-gate static int
wd_create_property(int ptype,int pmode,size_t psize,char * pname,int (* readfn)(ptree_rarg_t *,void *),int (* writefn)(ptree_warg_t *,const void *),picl_nodehdl_t nodeh,picl_prophdl_t * propp,void * vbuf)1227*0Sstevel@tonic-gate wd_create_property(
1228*0Sstevel@tonic-gate 	int		ptype,		/* PICL property type */
1229*0Sstevel@tonic-gate 	int		pmode,		/* PICL access mode */
1230*0Sstevel@tonic-gate 	size_t		psize,		/* size of PICL property */
1231*0Sstevel@tonic-gate 	char		*pname,		/* property name */
1232*0Sstevel@tonic-gate 	int		(*readfn)(ptree_rarg_t *, void *),
1233*0Sstevel@tonic-gate 	int		(*writefn)(ptree_warg_t *, const void *),
1234*0Sstevel@tonic-gate 	picl_nodehdl_t	nodeh,		/* node for property */
1235*0Sstevel@tonic-gate 	picl_prophdl_t	*propp,		/* pointer to prop_handle */
1236*0Sstevel@tonic-gate 	void		*vbuf)		/* initial value */
1237*0Sstevel@tonic-gate {
1238*0Sstevel@tonic-gate 	picl_errno_t		rc;
1239*0Sstevel@tonic-gate 	ptree_propinfo_t	propinfo;
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate 	rc = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
1242*0Sstevel@tonic-gate 		ptype, pmode, psize, pname, readfn, writefn);
1243*0Sstevel@tonic-gate 	if (rc != PICL_SUCCESS) {
1244*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_PROP_INIT_ERR, rc);
1245*0Sstevel@tonic-gate 		return (rc);
1246*0Sstevel@tonic-gate 	}
1247*0Sstevel@tonic-gate 
1248*0Sstevel@tonic-gate 	rc = ptree_create_and_add_prop(nodeh, &propinfo, vbuf, propp);
1249*0Sstevel@tonic-gate 	if (rc != PICL_SUCCESS) {
1250*0Sstevel@tonic-gate 		return (rc);
1251*0Sstevel@tonic-gate 	}
1252*0Sstevel@tonic-gate 
1253*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
1254*0Sstevel@tonic-gate }
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate /* Create and add Watchdog properties */
1257*0Sstevel@tonic-gate static void
wd_create_add_props()1258*0Sstevel@tonic-gate wd_create_add_props()
1259*0Sstevel@tonic-gate {
1260*0Sstevel@tonic-gate 	int rc;
1261*0Sstevel@tonic-gate 	picl_nodehdl_t	rooth, sysmgmt_h, platformh;
1262*0Sstevel@tonic-gate 	int32_t	timeout1 = 0;
1263*0Sstevel@tonic-gate 	int32_t	timeout2 = 0;
1264*0Sstevel@tonic-gate 	char		buf[PICL_WD_PROPVAL_MAX];
1265*0Sstevel@tonic-gate 
1266*0Sstevel@tonic-gate 	/* get picl root node handle */
1267*0Sstevel@tonic-gate 	if ((rc = ptree_get_root(&rooth)) != PICL_SUCCESS) {
1268*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 1, rc);
1269*0Sstevel@tonic-gate 		return;
1270*0Sstevel@tonic-gate 	}
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 	/* get picl platform node handle */
1273*0Sstevel@tonic-gate 	if ((rc = ptree_get_node_by_path(PLATFORM_PATH,
1274*0Sstevel@tonic-gate 		&platformh)) != PICL_SUCCESS) {
1275*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 2, rc);
1276*0Sstevel@tonic-gate 		return;
1277*0Sstevel@tonic-gate 	}
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 	/* get the picl sysmgmt node handle */
1280*0Sstevel@tonic-gate 	if ((rc = ptree_find_node(platformh, PICL_PROP_NAME,
1281*0Sstevel@tonic-gate 		PICL_PTYPE_CHARSTRING,
1282*0Sstevel@tonic-gate 		PICL_NODE_SYSMGMT, strlen(PICL_NODE_SYSMGMT),
1283*0Sstevel@tonic-gate 		&sysmgmt_h)) != PICL_SUCCESS) {
1284*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 3, rc);
1285*0Sstevel@tonic-gate 		return;
1286*0Sstevel@tonic-gate 	}
1287*0Sstevel@tonic-gate 
1288*0Sstevel@tonic-gate 	/* start creating the watchdog nodes and properties */
1289*0Sstevel@tonic-gate 	if ((rc = ptree_create_and_add_node(sysmgmt_h, PICL_NODE_WD_CONTROLLER,
1290*0Sstevel@tonic-gate 		PICL_CLASS_WATCHDOG_CONTROLLER,
1291*0Sstevel@tonic-gate 		&(wd_data.wd_ctrl_nodehdl))) != PICL_SUCCESS) {
1292*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 4, rc);
1293*0Sstevel@tonic-gate 		return;
1294*0Sstevel@tonic-gate 	}
1295*0Sstevel@tonic-gate 
1296*0Sstevel@tonic-gate 	/* Add wd-op property to watchdog controller node */
1297*0Sstevel@tonic-gate 	(void) strncpy(buf, "", sizeof (buf));
1298*0Sstevel@tonic-gate 	if ((rc = wd_create_property(PICL_PTYPE_CHARSTRING,
1299*0Sstevel@tonic-gate 		PICL_WRITE + PICL_VOLATILE,
1300*0Sstevel@tonic-gate 		PICL_PROPNAMELEN_MAX, PICL_PROP_WATCHDOG_OPERATION,
1301*0Sstevel@tonic-gate 		NULL, wd_write_op,
1302*0Sstevel@tonic-gate 		wd_data.wd_ctrl_nodehdl,
1303*0Sstevel@tonic-gate 		&(wd_data.wd_ops_hdl),
1304*0Sstevel@tonic-gate 		(void *)buf)) != PICL_SUCCESS) {
1305*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 5, rc);
1306*0Sstevel@tonic-gate 		return;
1307*0Sstevel@tonic-gate 	}
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 	/* create L1 node and add to controller */
1310*0Sstevel@tonic-gate 	if ((rc = ptree_create_and_add_node(wd_data.wd_ctrl_nodehdl,
1311*0Sstevel@tonic-gate 		PICL_NODE_WD_L1, PICL_CLASS_WATCHDOG_TIMER,
1312*0Sstevel@tonic-gate 		&(wd_data.wd1_nodehdl))) != PICL_SUCCESS) {
1313*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 6, rc);
1314*0Sstevel@tonic-gate 		return;
1315*0Sstevel@tonic-gate 	}
1316*0Sstevel@tonic-gate 
1317*0Sstevel@tonic-gate 	/* create L2 node and add to controller */
1318*0Sstevel@tonic-gate 	if ((rc = ptree_create_and_add_node(wd_data.wd_ctrl_nodehdl,
1319*0Sstevel@tonic-gate 		PICL_NODE_WD_L2, PICL_CLASS_WATCHDOG_TIMER,
1320*0Sstevel@tonic-gate 		&(wd_data.wd2_nodehdl))) != PICL_SUCCESS) {
1321*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 7, rc);
1322*0Sstevel@tonic-gate 		return;
1323*0Sstevel@tonic-gate 	}
1324*0Sstevel@tonic-gate 
1325*0Sstevel@tonic-gate 	/* create watchdog properties */
1326*0Sstevel@tonic-gate 	/* create state property here */
1327*0Sstevel@tonic-gate 	(void) strncpy(buf, PICL_PROPVAL_WD_STATE_DISARMED,
1328*0Sstevel@tonic-gate 		sizeof (buf));
1329*0Sstevel@tonic-gate 	if ((rc = wd_create_property(PICL_PTYPE_CHARSTRING,
1330*0Sstevel@tonic-gate 		PICL_READ + PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
1331*0Sstevel@tonic-gate 		PICL_PROP_STATE, wd1_read_status, NULLWRITE,
1332*0Sstevel@tonic-gate 		wd_data.wd1_nodehdl,
1333*0Sstevel@tonic-gate 		&(wd_data.wd1_state_hdl), (void *)buf)) != PICL_SUCCESS) {
1334*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 8, rc);
1335*0Sstevel@tonic-gate 		return;
1336*0Sstevel@tonic-gate 	}
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate 	if ((rc = wd_create_property(PICL_PTYPE_CHARSTRING,
1339*0Sstevel@tonic-gate 		PICL_READ + PICL_VOLATILE, PICL_PROPNAMELEN_MAX,
1340*0Sstevel@tonic-gate 		PICL_PROP_STATE, wd2_read_status, NULLWRITE,
1341*0Sstevel@tonic-gate 		wd_data.wd2_nodehdl,
1342*0Sstevel@tonic-gate 		&(wd_data.wd2_state_hdl), (void *)buf)) != PICL_SUCCESS) {
1343*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 9, rc);
1344*0Sstevel@tonic-gate 		return;
1345*0Sstevel@tonic-gate 	}
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate 	/* create timeout property here */
1348*0Sstevel@tonic-gate 	if ((rc = wd_create_property(PICL_PTYPE_UNSIGNED_INT,
1349*0Sstevel@tonic-gate 		PICL_READ + PICL_WRITE + PICL_VOLATILE,
1350*0Sstevel@tonic-gate 		sizeof (timeout1), PICL_PROP_WATCHDOG_TIMEOUT,
1351*0Sstevel@tonic-gate 		wd_read_timeout, wd_write_timeout, wd_data.wd1_nodehdl,
1352*0Sstevel@tonic-gate 		&(wd_data.wd1_timeout_hdl), (void *)&(timeout1))) !=
1353*0Sstevel@tonic-gate 		PICL_SUCCESS) {
1354*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 10, rc);
1355*0Sstevel@tonic-gate 		return;
1356*0Sstevel@tonic-gate 	}
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate 	if ((rc = wd_create_property(PICL_PTYPE_UNSIGNED_INT,
1359*0Sstevel@tonic-gate 		PICL_READ + PICL_WRITE + PICL_VOLATILE,
1360*0Sstevel@tonic-gate 		sizeof (wd_data.wd2_timeout), PICL_PROP_WATCHDOG_TIMEOUT,
1361*0Sstevel@tonic-gate 		wd_read_timeout, wd_write_timeout, wd_data.wd2_nodehdl,
1362*0Sstevel@tonic-gate 		&(wd_data.wd2_timeout_hdl), (void *)&(timeout2))) !=
1363*0Sstevel@tonic-gate 		PICL_SUCCESS) {
1364*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 11, rc);
1365*0Sstevel@tonic-gate 		return;
1366*0Sstevel@tonic-gate 	}
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 	/* create wd_action property here */
1369*0Sstevel@tonic-gate 	(void) strncpy(buf, PICL_PROPVAL_WD_ACTION_NONE,
1370*0Sstevel@tonic-gate 		sizeof (buf));
1371*0Sstevel@tonic-gate 	if ((rc = wd_create_property(PICL_PTYPE_CHARSTRING,
1372*0Sstevel@tonic-gate 		PICL_READ + PICL_WRITE + PICL_VOLATILE,
1373*0Sstevel@tonic-gate 		PICL_PROPNAMELEN_MAX, PICL_PROP_WATCHDOG_ACTION,
1374*0Sstevel@tonic-gate 		wd_read_action, wd_write_action,
1375*0Sstevel@tonic-gate 		wd_data.wd1_nodehdl, &(wd_data.wd1_action_hdl),
1376*0Sstevel@tonic-gate 		(void *)buf)) != PICL_SUCCESS) {
1377*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 12, rc);
1378*0Sstevel@tonic-gate 		return;
1379*0Sstevel@tonic-gate 	}
1380*0Sstevel@tonic-gate 
1381*0Sstevel@tonic-gate 	if ((rc = wd_create_property(PICL_PTYPE_CHARSTRING,
1382*0Sstevel@tonic-gate 		PICL_READ + PICL_WRITE + PICL_VOLATILE,
1383*0Sstevel@tonic-gate 		PICL_PROPNAMELEN_MAX, PICL_PROP_WATCHDOG_ACTION,
1384*0Sstevel@tonic-gate 		wd_read_action, wd_write_action,
1385*0Sstevel@tonic-gate 		wd_data.wd2_nodehdl, &(wd_data.wd2_action_hdl),
1386*0Sstevel@tonic-gate 		(void *)buf)) != PICL_SUCCESS) {
1387*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_NODE_INIT_ERR, 13, rc);
1388*0Sstevel@tonic-gate 		return;
1389*0Sstevel@tonic-gate 	}
1390*0Sstevel@tonic-gate }
1391*0Sstevel@tonic-gate 
1392*0Sstevel@tonic-gate static int
wd_ioctl(int fd,int cmd,int len,char * buf)1393*0Sstevel@tonic-gate wd_ioctl(int fd, int cmd, int len, char *buf)
1394*0Sstevel@tonic-gate {
1395*0Sstevel@tonic-gate 	int rtnval;
1396*0Sstevel@tonic-gate 	struct strioctl sioc;
1397*0Sstevel@tonic-gate 	sioc.ic_cmd = cmd;
1398*0Sstevel@tonic-gate 	sioc.ic_timout = 60;
1399*0Sstevel@tonic-gate 	sioc.ic_len = len;
1400*0Sstevel@tonic-gate 	sioc.ic_dp = buf;
1401*0Sstevel@tonic-gate 	rtnval = ioctl(fd, I_STR, &sioc);
1402*0Sstevel@tonic-gate 	return (rtnval);
1403*0Sstevel@tonic-gate }
1404*0Sstevel@tonic-gate 
1405*0Sstevel@tonic-gate static int
wd_open(int attr)1406*0Sstevel@tonic-gate wd_open(int attr)
1407*0Sstevel@tonic-gate {
1408*0Sstevel@tonic-gate 	int cc;
1409*0Sstevel@tonic-gate 	sc_cmdspec_t wd_cmdspec;
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	if ((wd_fd = open(SMC_NODE, attr)) < 0) {
1412*0Sstevel@tonic-gate 		return (-1);
1413*0Sstevel@tonic-gate 	}
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 	/* get exclusive access for set and reset commands of watchdog */
1416*0Sstevel@tonic-gate 	wd_cmdspec.args[0] = SMC_SET_WATCHDOG_TIMER;
1417*0Sstevel@tonic-gate 	wd_cmdspec.args[1] = SMC_RESET_WATCHDOG_TIMER;
1418*0Sstevel@tonic-gate 	wd_cmdspec.attribute = SC_ATTR_EXCLUSIVE;
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 	cc = wd_ioctl(wd_fd, SCIOC_MSG_SPEC, 3,
1421*0Sstevel@tonic-gate 		(char *)&wd_cmdspec);
1422*0Sstevel@tonic-gate 	if (cc < 0) {
1423*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_EXCLUSIVE_ACCESS_ERR);
1424*0Sstevel@tonic-gate 		return (-1);
1425*0Sstevel@tonic-gate 	}
1426*0Sstevel@tonic-gate 	return (wd_fd);
1427*0Sstevel@tonic-gate }
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate static int
wd_open_pollfd(int attr)1430*0Sstevel@tonic-gate wd_open_pollfd(int attr)
1431*0Sstevel@tonic-gate {
1432*0Sstevel@tonic-gate 	int cc;
1433*0Sstevel@tonic-gate 	sc_cmdspec_t wd_cmdspec;
1434*0Sstevel@tonic-gate 
1435*0Sstevel@tonic-gate 	if ((polling_fd = open(SMC_NODE, attr)) < 0) {
1436*0Sstevel@tonic-gate 		return (-1);
1437*0Sstevel@tonic-gate 	}
1438*0Sstevel@tonic-gate 
1439*0Sstevel@tonic-gate 	/* request for watchdog expiry notification	*/
1440*0Sstevel@tonic-gate 	wd_cmdspec.args[0] = SMC_EXPIRED_WATCHDOG_NOTIF;
1441*0Sstevel@tonic-gate 	wd_cmdspec.attribute = SC_ATTR_EXCLUSIVE;
1442*0Sstevel@tonic-gate 
1443*0Sstevel@tonic-gate 	cc = wd_ioctl(polling_fd, SCIOC_MSG_SPEC, 2,
1444*0Sstevel@tonic-gate 		(char *)&wd_cmdspec);
1445*0Sstevel@tonic-gate 	if (cc < 0) {
1446*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_SET_ATTR_FAILED);
1447*0Sstevel@tonic-gate 		return (-1);
1448*0Sstevel@tonic-gate 	}
1449*0Sstevel@tonic-gate 	return (polling_fd);
1450*0Sstevel@tonic-gate }
1451*0Sstevel@tonic-gate 
1452*0Sstevel@tonic-gate /* read the ENVIRONMENT variables and initialize tunables */
1453*0Sstevel@tonic-gate static void
wd_get_env()1454*0Sstevel@tonic-gate wd_get_env()
1455*0Sstevel@tonic-gate {
1456*0Sstevel@tonic-gate 	char *val;
1457*0Sstevel@tonic-gate 	int intval = 0;
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 	/* read frutree debug flag value */
1460*0Sstevel@tonic-gate 	if (val = getenv(WATCHDOG_DEBUG)) {
1461*0Sstevel@tonic-gate 		errno = 0;
1462*0Sstevel@tonic-gate 		intval = strtol(val, (char **)NULL, 0);
1463*0Sstevel@tonic-gate 		if (errno == 0) {
1464*0Sstevel@tonic-gate 			wd_debug = intval;
1465*0Sstevel@tonic-gate 		}
1466*0Sstevel@tonic-gate 	}
1467*0Sstevel@tonic-gate }
1468*0Sstevel@tonic-gate 
1469*0Sstevel@tonic-gate /*
1470*0Sstevel@tonic-gate  * PTREE Entry Points
1471*0Sstevel@tonic-gate  */
1472*0Sstevel@tonic-gate 
1473*0Sstevel@tonic-gate /* picl-state-change event handler */
1474*0Sstevel@tonic-gate /*ARGSUSED*/
1475*0Sstevel@tonic-gate static void
wd_state_change_evhandler(const char * ename,const void * earg,size_t size,void * cookie)1476*0Sstevel@tonic-gate wd_state_change_evhandler(const char *ename, const void *earg,
1477*0Sstevel@tonic-gate 			size_t size, void *cookie)
1478*0Sstevel@tonic-gate {
1479*0Sstevel@tonic-gate 	char 		*value;
1480*0Sstevel@tonic-gate 	picl_errno_t	rc;
1481*0Sstevel@tonic-gate 	nvlist_t	*nvlp;
1482*0Sstevel@tonic-gate 	picl_nodehdl_t  fruhdl;
1483*0Sstevel@tonic-gate 	static 		int spawn_threads = 1;
1484*0Sstevel@tonic-gate 	char 		name[PICL_PROPNAMELEN_MAX];
1485*0Sstevel@tonic-gate 
1486*0Sstevel@tonic-gate 	if (strcmp(ename, PICLEVENT_STATE_CHANGE)) {
1487*0Sstevel@tonic-gate 		return;
1488*0Sstevel@tonic-gate 	}
1489*0Sstevel@tonic-gate 
1490*0Sstevel@tonic-gate 	/* neglect all events if wd props are already created */
1491*0Sstevel@tonic-gate 	if (props_created && state_configured) {
1492*0Sstevel@tonic-gate 		return;
1493*0Sstevel@tonic-gate 	}
1494*0Sstevel@tonic-gate 
1495*0Sstevel@tonic-gate 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) {
1496*0Sstevel@tonic-gate 		return;
1497*0Sstevel@tonic-gate 	}
1498*0Sstevel@tonic-gate 	if ((nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE,
1499*0Sstevel@tonic-gate 		&fruhdl)) == -1) {
1500*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1501*0Sstevel@tonic-gate 		return;
1502*0Sstevel@tonic-gate 	}
1503*0Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_STATE, &value)) {
1504*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1505*0Sstevel@tonic-gate 		return;
1506*0Sstevel@tonic-gate 	}
1507*0Sstevel@tonic-gate 
1508*0Sstevel@tonic-gate 	rc = ptree_get_propval_by_name(fruhdl, PICL_PROP_NAME,
1509*0Sstevel@tonic-gate 		(void *)name, sizeof (name));
1510*0Sstevel@tonic-gate 	if (rc != PICL_SUCCESS) {
1511*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1512*0Sstevel@tonic-gate 		return;
1513*0Sstevel@tonic-gate 	}
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 	/* care for only events on chassis node */
1516*0Sstevel@tonic-gate 	if (strcmp(name, PICL_NODE_CHASSIS) != 0) {
1517*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1518*0Sstevel@tonic-gate 		return;
1519*0Sstevel@tonic-gate 	}
1520*0Sstevel@tonic-gate 
1521*0Sstevel@tonic-gate 	if (strcmp(value, PICLEVENTARGVAL_CONFIGURED) == 0) {
1522*0Sstevel@tonic-gate 		state_configured = 1;
1523*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1524*0Sstevel@tonic-gate 		return;
1525*0Sstevel@tonic-gate 	}
1526*0Sstevel@tonic-gate 
1527*0Sstevel@tonic-gate 	if (strcmp(value, PICLEVENTARGVAL_CONFIGURING) != 0) {
1528*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1529*0Sstevel@tonic-gate 		return;
1530*0Sstevel@tonic-gate 	}
1531*0Sstevel@tonic-gate 
1532*0Sstevel@tonic-gate 	if (wd_fd < 0) {
1533*0Sstevel@tonic-gate 		if ((wd_fd = wd_open(O_RDWR))  < 0) {
1534*0Sstevel@tonic-gate 			syslog(LOG_CRIT, WD_PICL_SMC_OPEN_ERR);
1535*0Sstevel@tonic-gate 			nvlist_free(nvlp);
1536*0Sstevel@tonic-gate 			return;
1537*0Sstevel@tonic-gate 		}
1538*0Sstevel@tonic-gate 	}
1539*0Sstevel@tonic-gate 
1540*0Sstevel@tonic-gate 	if (polling_fd < 0) {
1541*0Sstevel@tonic-gate 		if ((polling_fd = wd_open_pollfd(O_RDWR))  < 0) {
1542*0Sstevel@tonic-gate 			syslog(LOG_CRIT, WD_PICL_SMC_OPEN_ERR);
1543*0Sstevel@tonic-gate 			nvlist_free(nvlp);
1544*0Sstevel@tonic-gate 			return;
1545*0Sstevel@tonic-gate 		}
1546*0Sstevel@tonic-gate 	}
1547*0Sstevel@tonic-gate 
1548*0Sstevel@tonic-gate 	switch (wd_get_chassis_type()) {
1549*0Sstevel@tonic-gate 		case WD_HOST: /* is host */
1550*0Sstevel@tonic-gate 			wd_data.is_host = B_TRUE;
1551*0Sstevel@tonic-gate 			break;
1552*0Sstevel@tonic-gate 		case WD_STANDALONE: /* is satellite */
1553*0Sstevel@tonic-gate 			wd_data.is_host = B_FALSE;
1554*0Sstevel@tonic-gate 			break;
1555*0Sstevel@tonic-gate 		default:
1556*0Sstevel@tonic-gate 			nvlist_free(nvlp);
1557*0Sstevel@tonic-gate 			return;
1558*0Sstevel@tonic-gate 	}
1559*0Sstevel@tonic-gate 
1560*0Sstevel@tonic-gate 	(void) wd_create_add_props(); /* create and add properties */
1561*0Sstevel@tonic-gate 	props_created = 1;
1562*0Sstevel@tonic-gate 
1563*0Sstevel@tonic-gate 	/* read the hardware and initialize values */
1564*0Sstevel@tonic-gate 	(void) wd_set_init_state();
1565*0Sstevel@tonic-gate 
1566*0Sstevel@tonic-gate 	/* initialize wd-conf value */
1567*0Sstevel@tonic-gate 	(void) snprintf(wd_conf, sizeof (wd_conf), "%s/%s",
1568*0Sstevel@tonic-gate 		PICL_CONFIG_DIR, WD_CONF_FILE);
1569*0Sstevel@tonic-gate 
1570*0Sstevel@tonic-gate 	if (spawn_threads == 0) {
1571*0Sstevel@tonic-gate 		/* threads are already created */
1572*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1573*0Sstevel@tonic-gate 		return;
1574*0Sstevel@tonic-gate 	}
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate 	/* start monitoring for the events */
1577*0Sstevel@tonic-gate 	if (thr_create(NULL,  NULL,  wd_polling,
1578*0Sstevel@tonic-gate 		NULL,  THR_BOUND, &polling_thr_tid) != 0) {
1579*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_THREAD_CREATE_FAILED,
1580*0Sstevel@tonic-gate 			"polling");
1581*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1582*0Sstevel@tonic-gate 		return;
1583*0Sstevel@tonic-gate 	}
1584*0Sstevel@tonic-gate 
1585*0Sstevel@tonic-gate 	/* thread used to pat watchdog */
1586*0Sstevel@tonic-gate 	if (thr_create(NULL,  NULL,  wd_patting_thread,
1587*0Sstevel@tonic-gate 		NULL,  THR_BOUND, &patting_thr_tid) != 0) {
1588*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_THREAD_CREATE_FAILED,
1589*0Sstevel@tonic-gate 			"patting");
1590*0Sstevel@tonic-gate 		nvlist_free(nvlp);
1591*0Sstevel@tonic-gate 		return;
1592*0Sstevel@tonic-gate 	}
1593*0Sstevel@tonic-gate 	spawn_threads = 0;
1594*0Sstevel@tonic-gate 	nvlist_free(nvlp);
1595*0Sstevel@tonic-gate }
1596*0Sstevel@tonic-gate 
1597*0Sstevel@tonic-gate static void
wd_picl_register(void)1598*0Sstevel@tonic-gate wd_picl_register(void)
1599*0Sstevel@tonic-gate {
1600*0Sstevel@tonic-gate 	int rc = 0;
1601*0Sstevel@tonic-gate 	if ((rc = picld_plugin_register(&wd_reg_info)) != PICL_SUCCESS) {
1602*0Sstevel@tonic-gate 		syslog(LOG_ERR, WD_PICL_REG_ERR, rc);
1603*0Sstevel@tonic-gate 	}
1604*0Sstevel@tonic-gate }
1605*0Sstevel@tonic-gate 
1606*0Sstevel@tonic-gate /* entry point (initialization) */
1607*0Sstevel@tonic-gate static void
wd_picl_init(void)1608*0Sstevel@tonic-gate wd_picl_init(void)
1609*0Sstevel@tonic-gate {
1610*0Sstevel@tonic-gate 	/* initialize the wd_conf path and name */
1611*0Sstevel@tonic-gate 	(void) snprintf(wd_conf, sizeof (wd_conf), "%s/%s",
1612*0Sstevel@tonic-gate 		PICL_CONFIG_DIR, WD_CONF_FILE);
1613*0Sstevel@tonic-gate 
1614*0Sstevel@tonic-gate 	/* parse configuration file and set tunables */
1615*0Sstevel@tonic-gate 	wd_parse_config_file(wd_conf);
1616*0Sstevel@tonic-gate 
1617*0Sstevel@tonic-gate 	/* if watchdog-enable is set to false dont intialize wd subsystem */
1618*0Sstevel@tonic-gate 	if (wd_enable == 0) {
1619*0Sstevel@tonic-gate 		return;
1620*0Sstevel@tonic-gate 	}
1621*0Sstevel@tonic-gate 
1622*0Sstevel@tonic-gate 	/* read watchdog related environment variables */
1623*0Sstevel@tonic-gate 	wd_get_env();
1624*0Sstevel@tonic-gate 
1625*0Sstevel@tonic-gate 	/* event handler for state change notifications from frutree */
1626*0Sstevel@tonic-gate 	(void) ptree_register_handler(PICLEVENT_STATE_CHANGE,
1627*0Sstevel@tonic-gate 		wd_state_change_evhandler, NULL);
1628*0Sstevel@tonic-gate }
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate static void
wd_picl_fini(void)1631*0Sstevel@tonic-gate wd_picl_fini(void)
1632*0Sstevel@tonic-gate {
1633*0Sstevel@tonic-gate 	(void) ptree_unregister_handler(PICLEVENT_STATE_CHANGE,
1634*0Sstevel@tonic-gate 		wd_state_change_evhandler, NULL);
1635*0Sstevel@tonic-gate 
1636*0Sstevel@tonic-gate 	state_configured = 0;	/* chassis state */
1637*0Sstevel@tonic-gate 	props_created = 0;
1638*0Sstevel@tonic-gate 	(void) ptree_delete_node(wd_data.wd_ctrl_nodehdl);
1639*0Sstevel@tonic-gate 	(void) ptree_destroy_node(wd_data.wd_ctrl_nodehdl);
1640*0Sstevel@tonic-gate }
1641*0Sstevel@tonic-gate 
1642*0Sstevel@tonic-gate /*
1643*0Sstevel@tonic-gate  * volatile function to read the timeout
1644*0Sstevel@tonic-gate  */
1645*0Sstevel@tonic-gate static int
wd_read_timeout(ptree_rarg_t * parg,void * buf)1646*0Sstevel@tonic-gate wd_read_timeout(ptree_rarg_t *parg, void *buf)
1647*0Sstevel@tonic-gate {
1648*0Sstevel@tonic-gate 	/* update the buffer provided by user */
1649*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
1650*0Sstevel@tonic-gate 	if (parg->proph == wd_data.wd1_timeout_hdl) {
1651*0Sstevel@tonic-gate 		*(int32_t *)buf = wd_data.wd1_timeout;
1652*0Sstevel@tonic-gate 	} else if (parg->proph == wd_data.wd2_timeout_hdl) {
1653*0Sstevel@tonic-gate 		*(int32_t *)buf = wd_data.wd2_timeout;
1654*0Sstevel@tonic-gate 	}
1655*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
1656*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
1657*0Sstevel@tonic-gate }
1658*0Sstevel@tonic-gate 
1659*0Sstevel@tonic-gate /*
1660*0Sstevel@tonic-gate  * volatile function to read the action
1661*0Sstevel@tonic-gate  */
1662*0Sstevel@tonic-gate static int
wd_read_action(ptree_rarg_t * parg,void * buf)1663*0Sstevel@tonic-gate wd_read_action(ptree_rarg_t *parg, void *buf)
1664*0Sstevel@tonic-gate {
1665*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
1666*0Sstevel@tonic-gate 	if (parg->proph == wd_data.wd1_action_hdl) {
1667*0Sstevel@tonic-gate 		switch (wd_data.wd1_action) {
1668*0Sstevel@tonic-gate 		case WD_ACTION_HEALTHY_DOWN_HOST:
1669*0Sstevel@tonic-gate 		case WD_ACTION_HEALTHY_DOWN_SAT:
1670*0Sstevel@tonic-gate 		(void) strcpy((char *)buf,
1671*0Sstevel@tonic-gate 			PICL_PROPVAL_WD_ACTION_ALARM);
1672*0Sstevel@tonic-gate 		break;
1673*0Sstevel@tonic-gate 		case WD_ACTION_NONE1:
1674*0Sstevel@tonic-gate 		case WD_ACTION_NONE2:
1675*0Sstevel@tonic-gate 		if (wd_data.reboot_action == 1) {
1676*0Sstevel@tonic-gate 			(void) strcpy((char *)buf,
1677*0Sstevel@tonic-gate 				PICL_PROPVAL_WD_ACTION_REBOOT);
1678*0Sstevel@tonic-gate 		} else {
1679*0Sstevel@tonic-gate 			(void) strcpy((char *)buf,
1680*0Sstevel@tonic-gate 				PICL_PROPVAL_WD_ACTION_NONE);
1681*0Sstevel@tonic-gate 		}
1682*0Sstevel@tonic-gate 		break;
1683*0Sstevel@tonic-gate 		}
1684*0Sstevel@tonic-gate 	} else if (parg->proph == wd_data.wd2_action_hdl) {
1685*0Sstevel@tonic-gate 		switch (wd_data.wd2_action) {
1686*0Sstevel@tonic-gate 		case WD_ACTION_HARD_RESET:
1687*0Sstevel@tonic-gate 		(void) strcpy((char *)buf,
1688*0Sstevel@tonic-gate 			PICL_PROPVAL_WD_ACTION_RESET);
1689*0Sstevel@tonic-gate 		break;
1690*0Sstevel@tonic-gate 		case WD_ACTION_NONE2:
1691*0Sstevel@tonic-gate 		(void) strcpy((char *)buf, PICL_PROPVAL_WD_ACTION_NONE);
1692*0Sstevel@tonic-gate 		break;
1693*0Sstevel@tonic-gate 		}
1694*0Sstevel@tonic-gate 	}
1695*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
1696*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
1697*0Sstevel@tonic-gate }
1698*0Sstevel@tonic-gate 
1699*0Sstevel@tonic-gate /*
1700*0Sstevel@tonic-gate  * volatile function to write the action
1701*0Sstevel@tonic-gate  * this function validates the user value before programming the
1702*0Sstevel@tonic-gate  * action property. Properties can be modified only when watchdog
1703*0Sstevel@tonic-gate  * is in disarmed state.
1704*0Sstevel@tonic-gate  */
1705*0Sstevel@tonic-gate static int
wd_write_action(ptree_warg_t * parg,const void * buf)1706*0Sstevel@tonic-gate wd_write_action(ptree_warg_t *parg, const void *buf)
1707*0Sstevel@tonic-gate {
1708*0Sstevel@tonic-gate 	int flag = 0x0;
1709*0Sstevel@tonic-gate 	picl_errno_t rc = PICL_SUCCESS;
1710*0Sstevel@tonic-gate 	char wd_action[PICL_WD_PROPVAL_MAX];
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 	/* only super user can write this property */
1713*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != SUPER_USER) {
1714*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
1715*0Sstevel@tonic-gate 	}
1716*0Sstevel@tonic-gate 
1717*0Sstevel@tonic-gate 	if (parg->proph == wd_data.wd1_action_hdl) {
1718*0Sstevel@tonic-gate 		flag = WD1;
1719*0Sstevel@tonic-gate 	} else if (parg->proph == wd_data.wd2_action_hdl) {
1720*0Sstevel@tonic-gate 		flag = WD2;
1721*0Sstevel@tonic-gate 	}
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	/* dont allow any write operations when watchdog is armed */
1724*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
1725*0Sstevel@tonic-gate 	if (wd_data.wd1_run_state != WD_DISARMED ||
1726*0Sstevel@tonic-gate 		wd_data.wd2_run_state != WD_DISARMED) {
1727*0Sstevel@tonic-gate 		(void) mutex_unlock(&data_lock);
1728*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
1729*0Sstevel@tonic-gate 	}
1730*0Sstevel@tonic-gate 
1731*0Sstevel@tonic-gate 	/* validate the values and store in internal cache */
1732*0Sstevel@tonic-gate 	(void) strcpy(wd_action, (char *)buf);
1733*0Sstevel@tonic-gate 	switch (flag) {
1734*0Sstevel@tonic-gate 	case WD1:
1735*0Sstevel@tonic-gate 	if (strcmp(wd_action, PICL_PROPVAL_WD_ACTION_ALARM) == 0) {
1736*0Sstevel@tonic-gate 		if (wd_data.is_host)
1737*0Sstevel@tonic-gate 			wd_data.wd1_action = WD_ACTION_HEALTHY_DOWN_HOST;
1738*0Sstevel@tonic-gate 		else
1739*0Sstevel@tonic-gate 			wd_data.wd1_action = WD_ACTION_HEALTHY_DOWN_SAT;
1740*0Sstevel@tonic-gate 		wd_data.reboot_action = 0;
1741*0Sstevel@tonic-gate 	} else if (strcmp(wd_action, PICL_PROPVAL_WD_ACTION_NONE) == 0) {
1742*0Sstevel@tonic-gate 		wd_data.wd1_action = WD_ACTION_NONE1;
1743*0Sstevel@tonic-gate 		wd_data.reboot_action = 0;
1744*0Sstevel@tonic-gate 	} else if (strcmp(wd_action, PICL_PROPVAL_WD_ACTION_REBOOT) == 0) {
1745*0Sstevel@tonic-gate 		wd_data.wd1_action = WD_ACTION_NONE1;
1746*0Sstevel@tonic-gate 		wd_data.reboot_action = 1;
1747*0Sstevel@tonic-gate 	} else {
1748*0Sstevel@tonic-gate 		rc = PICL_INVALIDARG;
1749*0Sstevel@tonic-gate 	}
1750*0Sstevel@tonic-gate 	break;
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate 	case WD2:
1753*0Sstevel@tonic-gate 	if (strcmp(wd_action, PICL_PROPVAL_WD_ACTION_RESET) == 0) {
1754*0Sstevel@tonic-gate 		wd_data.wd2_action = WD_ACTION_HARD_RESET;
1755*0Sstevel@tonic-gate 	} else if (strcmp(wd_action, PICL_PROPVAL_WD_ACTION_NONE) == 0) {
1756*0Sstevel@tonic-gate 		wd_data.wd2_action = WD_ACTION_NONE2;
1757*0Sstevel@tonic-gate 	} else {
1758*0Sstevel@tonic-gate 		rc = PICL_INVALIDARG;
1759*0Sstevel@tonic-gate 	}
1760*0Sstevel@tonic-gate 	break;
1761*0Sstevel@tonic-gate 	}
1762*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
1763*0Sstevel@tonic-gate 	return (rc);
1764*0Sstevel@tonic-gate }
1765*0Sstevel@tonic-gate 
1766*0Sstevel@tonic-gate /*
1767*0Sstevel@tonic-gate  * volatile function to write the timeout
1768*0Sstevel@tonic-gate  * this function validates the user value before programming the
1769*0Sstevel@tonic-gate  * timeout property. Properties can be modified only when watchdog
1770*0Sstevel@tonic-gate  * is in disarmed state.
1771*0Sstevel@tonic-gate  */
1772*0Sstevel@tonic-gate static int
wd_write_timeout(ptree_warg_t * parg,const void * buf)1773*0Sstevel@tonic-gate wd_write_timeout(ptree_warg_t *parg, const void *buf)
1774*0Sstevel@tonic-gate {
1775*0Sstevel@tonic-gate 	int32_t timeout;
1776*0Sstevel@tonic-gate 	int flag = 0x0;
1777*0Sstevel@tonic-gate 
1778*0Sstevel@tonic-gate 	/* only super user can write this property */
1779*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != SUPER_USER) {
1780*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
1781*0Sstevel@tonic-gate 	}
1782*0Sstevel@tonic-gate 
1783*0Sstevel@tonic-gate 	/* dont allow any write operations when watchdog is armed */
1784*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
1785*0Sstevel@tonic-gate 	if (wd_data.wd1_run_state != WD_DISARMED ||
1786*0Sstevel@tonic-gate 		wd_data.wd2_run_state != WD_DISARMED) {
1787*0Sstevel@tonic-gate 		(void) mutex_unlock(&data_lock);
1788*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
1789*0Sstevel@tonic-gate 	}
1790*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
1791*0Sstevel@tonic-gate 
1792*0Sstevel@tonic-gate 	if (parg->proph == wd_data.wd1_timeout_hdl) {
1793*0Sstevel@tonic-gate 		flag = WD1;
1794*0Sstevel@tonic-gate 	} else if (parg->proph == wd_data.wd2_timeout_hdl) {
1795*0Sstevel@tonic-gate 		flag = WD2;
1796*0Sstevel@tonic-gate 	}
1797*0Sstevel@tonic-gate 
1798*0Sstevel@tonic-gate 	/* validate the timeout values */
1799*0Sstevel@tonic-gate 	timeout = *(int32_t *)buf;
1800*0Sstevel@tonic-gate 	if (timeout < -1) {
1801*0Sstevel@tonic-gate 		return (PICL_INVALIDARG);
1802*0Sstevel@tonic-gate 	}
1803*0Sstevel@tonic-gate 
1804*0Sstevel@tonic-gate 	if (timeout > 0) {
1805*0Sstevel@tonic-gate 		switch (flag) {
1806*0Sstevel@tonic-gate 		case WD1:
1807*0Sstevel@tonic-gate 		if ((timeout % WD_L1_RESOLUTION) != 0) {
1808*0Sstevel@tonic-gate 			return (PICL_INVALIDARG);
1809*0Sstevel@tonic-gate 		}
1810*0Sstevel@tonic-gate 		if ((timeout/WD_L1_RESOLUTION) > WD_MAX_L1) {
1811*0Sstevel@tonic-gate 			return (PICL_INVALIDARG);
1812*0Sstevel@tonic-gate 		}
1813*0Sstevel@tonic-gate 		break;
1814*0Sstevel@tonic-gate 		case WD2:
1815*0Sstevel@tonic-gate 		if ((timeout % WD_L2_RESOLUTION) != 0) {
1816*0Sstevel@tonic-gate 			return (PICL_INVALIDARG);
1817*0Sstevel@tonic-gate 		}
1818*0Sstevel@tonic-gate 		if ((timeout/WD_L2_RESOLUTION) > WD_MAX_L2) {
1819*0Sstevel@tonic-gate 							/* 255 sec */
1820*0Sstevel@tonic-gate 			return (PICL_INVALIDARG);
1821*0Sstevel@tonic-gate 		}
1822*0Sstevel@tonic-gate 		}
1823*0Sstevel@tonic-gate 	}
1824*0Sstevel@tonic-gate 
1825*0Sstevel@tonic-gate 	/* update the internal cache */
1826*0Sstevel@tonic-gate 	(void) mutex_lock(&data_lock);
1827*0Sstevel@tonic-gate 	switch (flag) {
1828*0Sstevel@tonic-gate 	case WD1:
1829*0Sstevel@tonic-gate 		wd_data.wd1_timeout = timeout;
1830*0Sstevel@tonic-gate 		break;
1831*0Sstevel@tonic-gate 	case WD2:
1832*0Sstevel@tonic-gate 		wd_data.wd2_timeout = timeout;
1833*0Sstevel@tonic-gate 		break;
1834*0Sstevel@tonic-gate 	}
1835*0Sstevel@tonic-gate 	(void) mutex_unlock(&data_lock);
1836*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
1837*0Sstevel@tonic-gate }
1838