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