blob: 806106b8c98013aa4fba7cb1024bd7ada3abaa5d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ipmi_watchdog.c
3 *
4 * A watchdog timer based upon the IPMI interface.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002 MontaVista Software Inc.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/ipmi.h>
37#include <linux/ipmi_smi.h>
38#include <linux/watchdog.h>
39#include <linux/miscdevice.h>
40#include <linux/init.h>
Corey Minyardd6dfd132006-03-31 02:30:41 -080041#include <linux/completion.h>
Christoph Hellwig1eeb66a2007-05-08 00:27:03 -070042#include <linux/kdebug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/rwsem.h>
44#include <linux/errno.h>
45#include <asm/uaccess.h>
46#include <linux/notifier.h>
47#include <linux/nmi.h>
48#include <linux/reboot.h>
49#include <linux/wait.h>
50#include <linux/poll.h>
Corey Minyardcc4673e2005-11-07 00:59:57 -080051#include <linux/string.h>
52#include <linux/ctype.h>
Corey Minyardb3856762005-11-07 01:00:05 -080053#include <asm/atomic.h>
Corey Minyardf64da952007-05-08 00:23:58 -070054
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -070055#ifdef CONFIG_X86_LOCAL_APIC
56#include <asm/apic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#endif
58
59#define PFX "IPMI Watchdog: "
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061/*
62 * The IPMI command/response information for the watchdog timer.
63 */
64
65/* values for byte 1 of the set command, byte 2 of the get response. */
66#define WDOG_DONT_LOG (1 << 7)
67#define WDOG_DONT_STOP_ON_SET (1 << 6)
68#define WDOG_SET_TIMER_USE(byte, use) \
69 byte = ((byte) & 0xf8) | ((use) & 0x7)
70#define WDOG_GET_TIMER_USE(byte) ((byte) & 0x7)
71#define WDOG_TIMER_USE_BIOS_FRB2 1
72#define WDOG_TIMER_USE_BIOS_POST 2
73#define WDOG_TIMER_USE_OS_LOAD 3
74#define WDOG_TIMER_USE_SMS_OS 4
75#define WDOG_TIMER_USE_OEM 5
76
77/* values for byte 2 of the set command, byte 3 of the get response. */
78#define WDOG_SET_PRETIMEOUT_ACT(byte, use) \
79 byte = ((byte) & 0x8f) | (((use) & 0x7) << 4)
80#define WDOG_GET_PRETIMEOUT_ACT(byte) (((byte) >> 4) & 0x7)
81#define WDOG_PRETIMEOUT_NONE 0
82#define WDOG_PRETIMEOUT_SMI 1
83#define WDOG_PRETIMEOUT_NMI 2
84#define WDOG_PRETIMEOUT_MSG_INT 3
85
86/* Operations that can be performed on a pretimout. */
87#define WDOG_PREOP_NONE 0
88#define WDOG_PREOP_PANIC 1
89#define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to
90 read. Doesn't work in NMI
91 mode. */
92
93/* Actions to perform on a full timeout. */
94#define WDOG_SET_TIMEOUT_ACT(byte, use) \
95 byte = ((byte) & 0xf8) | ((use) & 0x7)
96#define WDOG_GET_TIMEOUT_ACT(byte) ((byte) & 0x7)
97#define WDOG_TIMEOUT_NONE 0
98#define WDOG_TIMEOUT_RESET 1
99#define WDOG_TIMEOUT_POWER_DOWN 2
100#define WDOG_TIMEOUT_POWER_CYCLE 3
101
102/* Byte 3 of the get command, byte 4 of the get response is the
103 pre-timeout in seconds. */
104
105/* Bits for setting byte 4 of the set command, byte 5 of the get response. */
106#define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1)
107#define WDOG_EXPIRE_CLEAR_BIOS_POST (1 << 2)
108#define WDOG_EXPIRE_CLEAR_OS_LOAD (1 << 3)
109#define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4)
110#define WDOG_EXPIRE_CLEAR_OEM (1 << 5)
111
112/* Setting/getting the watchdog timer value. This is for bytes 5 and
113 6 (the timeout time) of the set command, and bytes 6 and 7 (the
114 timeout time) and 8 and 9 (the current countdown value) of the
115 response. The timeout value is given in seconds (in the command it
116 is 100ms intervals). */
117#define WDOG_SET_TIMEOUT(byte1, byte2, val) \
118 (byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8)
119#define WDOG_GET_TIMEOUT(byte1, byte2) \
120 (((byte1) | ((byte2) << 8)) / 10)
121
122#define IPMI_WDOG_RESET_TIMER 0x22
123#define IPMI_WDOG_SET_TIMER 0x24
124#define IPMI_WDOG_GET_TIMER 0x25
125
126/* These are here until the real ones get into the watchdog.h interface. */
127#ifndef WDIOC_GETTIMEOUT
128#define WDIOC_GETTIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 20, int)
129#endif
130#ifndef WDIOC_SET_PRETIMEOUT
131#define WDIOC_SET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 21, int)
132#endif
133#ifndef WDIOC_GET_PRETIMEOUT
134#define WDIOC_GET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 22, int)
135#endif
136
Andrey Panin4bfdf372005-07-27 11:43:58 -0700137static int nowayout = WATCHDOG_NOWAYOUT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800139static ipmi_user_t watchdog_user;
Corey Minyardb2c03942006-12-06 20:41:00 -0800140static int watchdog_ifnum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142/* Default the timeout to 10 seconds. */
143static int timeout = 10;
144
145/* The pre-timeout is disabled by default. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800146static int pretimeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148/* Default action is to reset the board on a timeout. */
149static unsigned char action_val = WDOG_TIMEOUT_RESET;
150
151static char action[16] = "reset";
152
153static unsigned char preaction_val = WDOG_PRETIMEOUT_NONE;
154
155static char preaction[16] = "pre_none";
156
157static unsigned char preop_val = WDOG_PREOP_NONE;
158
159static char preop[16] = "preop_none";
160static DEFINE_SPINLOCK(ipmi_read_lock);
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800161static char data_to_read;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static DECLARE_WAIT_QUEUE_HEAD(read_q);
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800163static struct fasync_struct *fasync_q;
164static char pretimeout_since_last_heartbeat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static char expect_close;
166
Corey Minyardb2c03942006-12-06 20:41:00 -0800167static int ifnum_to_use = -1;
168
Corey Minyardcc4673e2005-11-07 00:59:57 -0800169/* Parameters to ipmi_set_timeout */
170#define IPMI_SET_TIMEOUT_NO_HB 0
171#define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1
172#define IPMI_SET_TIMEOUT_FORCE_HB 2
173
174static int ipmi_set_timeout(int do_heartbeat);
Corey Minyardb2c03942006-12-06 20:41:00 -0800175static void ipmi_register_watchdog(int ipmi_intf);
176static void ipmi_unregister_watchdog(int ipmi_intf);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178/* If true, the driver will start running as soon as it is configured
179 and ready. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800180static int start_now;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Corey Minyardcc4673e2005-11-07 00:59:57 -0800182static int set_param_int(const char *val, struct kernel_param *kp)
183{
184 char *endp;
185 int l;
186 int rv = 0;
187
188 if (!val)
189 return -EINVAL;
190 l = simple_strtoul(val, &endp, 0);
191 if (endp == val)
192 return -EINVAL;
193
Corey Minyardcc4673e2005-11-07 00:59:57 -0800194 *((int *)kp->arg) = l;
195 if (watchdog_user)
196 rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800197
198 return rv;
199}
200
201static int get_param_int(char *buffer, struct kernel_param *kp)
202{
203 return sprintf(buffer, "%i", *((int *)kp->arg));
204}
205
206typedef int (*action_fn)(const char *intval, char *outval);
207
208static int action_op(const char *inval, char *outval);
209static int preaction_op(const char *inval, char *outval);
210static int preop_op(const char *inval, char *outval);
211static void check_parms(void);
212
213static int set_param_str(const char *val, struct kernel_param *kp)
214{
215 action_fn fn = (action_fn) kp->arg;
216 int rv = 0;
Sebastien Dugué43cdff92006-12-29 16:46:53 -0800217 char valcp[16];
218 char *s;
Corey Minyardcc4673e2005-11-07 00:59:57 -0800219
Sebastien Dugué43cdff92006-12-29 16:46:53 -0800220 strncpy(valcp, val, 16);
221 valcp[15] = '\0';
Pekka Enberg66f969d2006-06-23 02:05:45 -0700222
Sebastien Dugué43cdff92006-12-29 16:46:53 -0800223 s = strstrip(valcp);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800224
Pekka Enberg66f969d2006-06-23 02:05:45 -0700225 rv = fn(s, NULL);
Corey Minyardcc4673e2005-11-07 00:59:57 -0800226 if (rv)
Corey Minyardf8fbcd32007-10-18 03:07:08 -0700227 goto out;
Corey Minyardcc4673e2005-11-07 00:59:57 -0800228
229 check_parms();
230 if (watchdog_user)
231 rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
232
Corey Minyardf8fbcd32007-10-18 03:07:08 -0700233 out:
Corey Minyardcc4673e2005-11-07 00:59:57 -0800234 return rv;
235}
236
237static int get_param_str(char *buffer, struct kernel_param *kp)
238{
239 action_fn fn = (action_fn) kp->arg;
240 int rv;
241
242 rv = fn(NULL, buffer);
243 if (rv)
244 return rv;
245 return strlen(buffer);
246}
247
Corey Minyardb2c03942006-12-06 20:41:00 -0800248
249static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp)
250{
251 int rv = param_set_int(val, kp);
252 if (rv)
253 return rv;
254 if ((ifnum_to_use < 0) || (ifnum_to_use == watchdog_ifnum))
255 return 0;
256
257 ipmi_unregister_watchdog(watchdog_ifnum);
258 ipmi_register_watchdog(ifnum_to_use);
259 return 0;
260}
261
262module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int,
263 &ifnum_to_use, 0644);
264MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
265 "timer. Setting to -1 defaults to the first registered "
266 "interface");
267
Corey Minyardcc4673e2005-11-07 00:59:57 -0800268module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800270
271module_param_call(pretimeout, set_param_int, get_param_int, &pretimeout, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800273
274module_param_call(action, set_param_str, get_param_str, action_op, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275MODULE_PARM_DESC(action, "Timeout action. One of: "
276 "reset, none, power_cycle, power_off.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800277
278module_param_call(preaction, set_param_str, get_param_str, preaction_op, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279MODULE_PARM_DESC(preaction, "Pretimeout action. One of: "
280 "pre_none, pre_smi, pre_nmi, pre_int.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800281
282module_param_call(preop, set_param_str, get_param_str, preop_op, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: "
284 "preop_none, preop_panic, preop_give_data.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800285
Corey Minyardb2c03942006-12-06 20:41:00 -0800286module_param(start_now, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as"
288 "soon as the driver is loaded.");
Corey Minyardcc4673e2005-11-07 00:59:57 -0800289
290module_param(nowayout, int, 0644);
Corey Minyardb2c03942006-12-06 20:41:00 -0800291MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
292 "(default=CONFIG_WATCHDOG_NOWAYOUT)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294/* Default state of the timer. */
295static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
296
297/* If shutting down via IPMI, we ignore the heartbeat. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800298static int ipmi_ignore_heartbeat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300/* Is someone using the watchdog? Only one user is allowed. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800301static unsigned long ipmi_wdog_open;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303/* If set to 1, the heartbeat command will set the state to reset and
304 start the timer. The timer doesn't normally run when the driver is
305 first opened until the heartbeat is set the first time, this
306 variable is used to accomplish this. */
Randy Dunlap0c8204b2006-12-10 02:19:06 -0800307static int ipmi_start_timer_on_heartbeat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309/* IPMI version of the BMC. */
310static unsigned char ipmi_version_major;
311static unsigned char ipmi_version_minor;
312
Corey Minyardb3856762005-11-07 01:00:05 -0800313/* If a pretimeout occurs, this is used to allow only one panic to happen. */
314static atomic_t preop_panic_excl = ATOMIC_INIT(-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316static int ipmi_heartbeat(void);
317static void panic_halt_ipmi_heartbeat(void);
318
319
Corey Minyardd6dfd132006-03-31 02:30:41 -0800320/* We use a mutex to make sure that only one thing can send a set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 timeout at one time, because we only have one copy of the data.
Corey Minyardd6dfd132006-03-31 02:30:41 -0800322 The mutex is claimed when the set_timeout is sent and freed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 when both messages are free. */
324static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800325static DEFINE_MUTEX(set_timeout_lock);
326static DECLARE_COMPLETION(set_timeout_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
328{
329 if (atomic_dec_and_test(&set_timeout_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800330 complete(&set_timeout_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
333{
334 if (atomic_dec_and_test(&set_timeout_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800335 complete(&set_timeout_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336}
337static struct ipmi_smi_msg set_timeout_smi_msg =
338{
339 .done = set_timeout_free_smi
340};
341static struct ipmi_recv_msg set_timeout_recv_msg =
342{
343 .done = set_timeout_free_recv
344};
345
346static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
347 struct ipmi_recv_msg *recv_msg,
348 int *send_heartbeat_now)
349{
350 struct kernel_ipmi_msg msg;
351 unsigned char data[6];
352 int rv;
353 struct ipmi_system_interface_addr addr;
354 int hbnow = 0;
355
356
357 data[0] = 0;
358 WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
359
360 if ((ipmi_version_major > 1)
361 || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5)))
362 {
363 /* This is an IPMI 1.5-only feature. */
364 data[0] |= WDOG_DONT_STOP_ON_SET;
365 } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
366 /* In ipmi 1.0, setting the timer stops the watchdog, we
367 need to start it back up again. */
368 hbnow = 1;
369 }
370
371 data[1] = 0;
372 WDOG_SET_TIMEOUT_ACT(data[1], ipmi_watchdog_state);
Corey Minyard8f05ee92005-09-06 15:18:39 -0700373 if ((pretimeout > 0) && (ipmi_watchdog_state != WDOG_TIMEOUT_NONE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 WDOG_SET_PRETIMEOUT_ACT(data[1], preaction_val);
375 data[2] = pretimeout;
376 } else {
377 WDOG_SET_PRETIMEOUT_ACT(data[1], WDOG_PRETIMEOUT_NONE);
378 data[2] = 0; /* No pretimeout. */
379 }
380 data[3] = 0;
381 WDOG_SET_TIMEOUT(data[4], data[5], timeout);
382
383 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
384 addr.channel = IPMI_BMC_CHANNEL;
385 addr.lun = 0;
386
387 msg.netfn = 0x06;
388 msg.cmd = IPMI_WDOG_SET_TIMER;
389 msg.data = data;
390 msg.data_len = sizeof(data);
391 rv = ipmi_request_supply_msgs(watchdog_user,
392 (struct ipmi_addr *) &addr,
393 0,
394 &msg,
395 NULL,
396 smi_msg,
397 recv_msg,
398 1);
399 if (rv) {
400 printk(KERN_WARNING PFX "set timeout error: %d\n",
401 rv);
402 }
403
404 if (send_heartbeat_now)
405 *send_heartbeat_now = hbnow;
406
407 return rv;
408}
409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410static int ipmi_set_timeout(int do_heartbeat)
411{
412 int send_heartbeat_now;
413 int rv;
414
415
416 /* We can only send one of these at a time. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800417 mutex_lock(&set_timeout_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 atomic_set(&set_timeout_tofree, 2);
420
421 rv = i_ipmi_set_timeout(&set_timeout_smi_msg,
422 &set_timeout_recv_msg,
423 &send_heartbeat_now);
424 if (rv) {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800425 mutex_unlock(&set_timeout_lock);
426 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 }
428
Corey Minyardd6dfd132006-03-31 02:30:41 -0800429 wait_for_completion(&set_timeout_wait);
430
431 if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
432 || ((send_heartbeat_now)
433 && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700434 {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800435 rv = ipmi_heartbeat();
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700436 }
437 mutex_unlock(&set_timeout_lock);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800438
439out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 return rv;
441}
442
443static void dummy_smi_free(struct ipmi_smi_msg *msg)
444{
445}
446static void dummy_recv_free(struct ipmi_recv_msg *msg)
447{
448}
449static struct ipmi_smi_msg panic_halt_smi_msg =
450{
451 .done = dummy_smi_free
452};
453static struct ipmi_recv_msg panic_halt_recv_msg =
454{
455 .done = dummy_recv_free
456};
457
458/* Special call, doesn't claim any locks. This is only to be called
459 at panic or halt time, in run-to-completion mode, when the caller
460 is the only CPU and the only thing that will be going is these IPMI
461 calls. */
462static void panic_halt_ipmi_set_timeout(void)
463{
464 int send_heartbeat_now;
465 int rv;
466
467 rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
468 &panic_halt_recv_msg,
469 &send_heartbeat_now);
470 if (!rv) {
471 if (send_heartbeat_now)
472 panic_halt_ipmi_heartbeat();
473 }
474}
475
476/* We use a semaphore to make sure that only one thing can send a
477 heartbeat at one time, because we only have one copy of the data.
478 The semaphore is claimed when the set_timeout is sent and freed
479 when both messages are free. */
480static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
Corey Minyardd6dfd132006-03-31 02:30:41 -0800481static DEFINE_MUTEX(heartbeat_lock);
482static DECLARE_COMPLETION(heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
484{
485 if (atomic_dec_and_test(&heartbeat_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800486 complete(&heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487}
488static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
489{
490 if (atomic_dec_and_test(&heartbeat_tofree))
Corey Minyardd6dfd132006-03-31 02:30:41 -0800491 complete(&heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492}
493static struct ipmi_smi_msg heartbeat_smi_msg =
494{
495 .done = heartbeat_free_smi
496};
497static struct ipmi_recv_msg heartbeat_recv_msg =
498{
499 .done = heartbeat_free_recv
500};
501
502static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
503{
504 .done = dummy_smi_free
505};
506static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
507{
508 .done = dummy_recv_free
509};
510
511static int ipmi_heartbeat(void)
512{
513 struct kernel_ipmi_msg msg;
514 int rv;
515 struct ipmi_system_interface_addr addr;
516
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700517 if (ipmi_ignore_heartbeat) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 return 0;
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 if (ipmi_start_timer_on_heartbeat) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700522 ipmi_start_timer_on_heartbeat = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 ipmi_watchdog_state = action_val;
524 return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
525 } else if (pretimeout_since_last_heartbeat) {
526 /* A pretimeout occurred, make sure we set the timeout.
527 We don't want to set the action, though, we want to
528 leave that alone (thus it can't be combined with the
529 above operation. */
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700530 pretimeout_since_last_heartbeat = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
532 }
533
Corey Minyardd6dfd132006-03-31 02:30:41 -0800534 mutex_lock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 atomic_set(&heartbeat_tofree, 2);
537
538 /* Don't reset the timer if we have the timer turned off, that
539 re-enables the watchdog. */
540 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800541 mutex_unlock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 return 0;
543 }
544
545 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
546 addr.channel = IPMI_BMC_CHANNEL;
547 addr.lun = 0;
548
549 msg.netfn = 0x06;
550 msg.cmd = IPMI_WDOG_RESET_TIMER;
551 msg.data = NULL;
552 msg.data_len = 0;
553 rv = ipmi_request_supply_msgs(watchdog_user,
554 (struct ipmi_addr *) &addr,
555 0,
556 &msg,
557 NULL,
558 &heartbeat_smi_msg,
559 &heartbeat_recv_msg,
560 1);
561 if (rv) {
Corey Minyardd6dfd132006-03-31 02:30:41 -0800562 mutex_unlock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 printk(KERN_WARNING PFX "heartbeat failure: %d\n",
564 rv);
565 return rv;
566 }
567
568 /* Wait for the heartbeat to be sent. */
Corey Minyardd6dfd132006-03-31 02:30:41 -0800569 wait_for_completion(&heartbeat_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 if (heartbeat_recv_msg.msg.data[0] != 0) {
572 /* Got an error in the heartbeat response. It was already
573 reported in ipmi_wdog_msg_handler, but we should return
574 an error here. */
575 rv = -EINVAL;
576 }
577
Corey Minyardd6dfd132006-03-31 02:30:41 -0800578 mutex_unlock(&heartbeat_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 return rv;
581}
582
583static void panic_halt_ipmi_heartbeat(void)
584{
585 struct kernel_ipmi_msg msg;
586 struct ipmi_system_interface_addr addr;
587
588
589 /* Don't reset the timer if we have the timer turned off, that
590 re-enables the watchdog. */
591 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
592 return;
593
594 addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
595 addr.channel = IPMI_BMC_CHANNEL;
596 addr.lun = 0;
597
598 msg.netfn = 0x06;
599 msg.cmd = IPMI_WDOG_RESET_TIMER;
600 msg.data = NULL;
601 msg.data_len = 0;
602 ipmi_request_supply_msgs(watchdog_user,
603 (struct ipmi_addr *) &addr,
604 0,
605 &msg,
606 NULL,
607 &panic_halt_heartbeat_smi_msg,
608 &panic_halt_heartbeat_recv_msg,
609 1);
610}
611
Corey Minyard8a3628d2006-03-31 02:30:40 -0800612static struct watchdog_info ident =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
614 .options = 0, /* WDIOF_SETTIMEOUT, */
615 .firmware_version = 1,
616 .identity = "IPMI"
617};
618
619static int ipmi_ioctl(struct inode *inode, struct file *file,
620 unsigned int cmd, unsigned long arg)
621{
622 void __user *argp = (void __user *)arg;
623 int i;
624 int val;
625
626 switch(cmd) {
627 case WDIOC_GETSUPPORT:
628 i = copy_to_user(argp, &ident, sizeof(ident));
629 return i ? -EFAULT : 0;
630
631 case WDIOC_SETTIMEOUT:
632 i = copy_from_user(&val, argp, sizeof(int));
633 if (i)
634 return -EFAULT;
635 timeout = val;
636 return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
637
638 case WDIOC_GETTIMEOUT:
639 i = copy_to_user(argp, &timeout, sizeof(timeout));
640 if (i)
641 return -EFAULT;
642 return 0;
643
644 case WDIOC_SET_PRETIMEOUT:
645 i = copy_from_user(&val, argp, sizeof(int));
646 if (i)
647 return -EFAULT;
648 pretimeout = val;
649 return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
650
651 case WDIOC_GET_PRETIMEOUT:
652 i = copy_to_user(argp, &pretimeout, sizeof(pretimeout));
653 if (i)
654 return -EFAULT;
655 return 0;
656
657 case WDIOC_KEEPALIVE:
658 return ipmi_heartbeat();
659
660 case WDIOC_SETOPTIONS:
661 i = copy_from_user(&val, argp, sizeof(int));
662 if (i)
663 return -EFAULT;
664 if (val & WDIOS_DISABLECARD)
665 {
666 ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
667 ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
668 ipmi_start_timer_on_heartbeat = 0;
669 }
670
671 if (val & WDIOS_ENABLECARD)
672 {
673 ipmi_watchdog_state = action_val;
674 ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
675 }
676 return 0;
677
678 case WDIOC_GETSTATUS:
679 val = 0;
680 i = copy_to_user(argp, &val, sizeof(val));
681 if (i)
682 return -EFAULT;
683 return 0;
684
685 default:
686 return -ENOIOCTLCMD;
687 }
688}
689
690static ssize_t ipmi_write(struct file *file,
691 const char __user *buf,
692 size_t len,
693 loff_t *ppos)
694{
695 int rv;
696
697 if (len) {
698 if (!nowayout) {
699 size_t i;
700
701 /* In case it was set long ago */
702 expect_close = 0;
703
704 for (i = 0; i != len; i++) {
705 char c;
706
707 if (get_user(c, buf + i))
708 return -EFAULT;
709 if (c == 'V')
710 expect_close = 42;
711 }
712 }
713 rv = ipmi_heartbeat();
714 if (rv)
715 return rv;
716 return 1;
717 }
718 return 0;
719}
720
721static ssize_t ipmi_read(struct file *file,
722 char __user *buf,
723 size_t count,
724 loff_t *ppos)
725{
726 int rv = 0;
727 wait_queue_t wait;
728
729 if (count <= 0)
730 return 0;
731
732 /* Reading returns if the pretimeout has gone off, and it only does
733 it once per pretimeout. */
734 spin_lock(&ipmi_read_lock);
735 if (!data_to_read) {
736 if (file->f_flags & O_NONBLOCK) {
737 rv = -EAGAIN;
738 goto out;
739 }
740
741 init_waitqueue_entry(&wait, current);
742 add_wait_queue(&read_q, &wait);
743 while (!data_to_read) {
744 set_current_state(TASK_INTERRUPTIBLE);
745 spin_unlock(&ipmi_read_lock);
746 schedule();
747 spin_lock(&ipmi_read_lock);
748 }
749 remove_wait_queue(&read_q, &wait);
750
751 if (signal_pending(current)) {
752 rv = -ERESTARTSYS;
753 goto out;
754 }
755 }
756 data_to_read = 0;
757
758 out:
759 spin_unlock(&ipmi_read_lock);
760
761 if (rv == 0) {
762 if (copy_to_user(buf, &data_to_read, 1))
763 rv = -EFAULT;
764 else
765 rv = 1;
766 }
767
768 return rv;
769}
770
771static int ipmi_open(struct inode *ino, struct file *filep)
772{
Corey Minyarde8b33612005-09-06 15:18:45 -0700773 switch (iminor(ino)) {
774 case WATCHDOG_MINOR:
775 if (test_and_set_bit(0, &ipmi_wdog_open))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 return -EBUSY;
777
Corey Minyarde8b33612005-09-06 15:18:45 -0700778 /* Don't start the timer now, let it start on the
779 first heartbeat. */
780 ipmi_start_timer_on_heartbeat = 1;
781 return nonseekable_open(ino, filep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
Corey Minyarde8b33612005-09-06 15:18:45 -0700783 default:
784 return (-ENODEV);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 }
786}
787
788static unsigned int ipmi_poll(struct file *file, poll_table *wait)
789{
790 unsigned int mask = 0;
791
792 poll_wait(file, &read_q, wait);
793
794 spin_lock(&ipmi_read_lock);
795 if (data_to_read)
796 mask |= (POLLIN | POLLRDNORM);
797 spin_unlock(&ipmi_read_lock);
798
799 return mask;
800}
801
802static int ipmi_fasync(int fd, struct file *file, int on)
803{
804 int result;
805
806 result = fasync_helper(fd, file, on, &fasync_q);
807
808 return (result);
809}
810
811static int ipmi_close(struct inode *ino, struct file *filep)
812{
Corey Minyard8a3628d2006-03-31 02:30:40 -0800813 if (iminor(ino) == WATCHDOG_MINOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 if (expect_close == 42) {
815 ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
816 ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 } else {
Corey Minyard8a3628d2006-03-31 02:30:40 -0800818 printk(KERN_CRIT PFX
819 "Unexpected close, not stopping watchdog!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 ipmi_heartbeat();
821 }
Corey Minyardec26d792005-05-01 08:59:11 -0700822 clear_bit(0, &ipmi_wdog_open);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
824
825 ipmi_fasync (-1, filep, 0);
826 expect_close = 0;
827
828 return 0;
829}
830
Arjan van de Ven62322d22006-07-03 00:24:21 -0700831static const struct file_operations ipmi_wdog_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 .owner = THIS_MODULE,
833 .read = ipmi_read,
834 .poll = ipmi_poll,
835 .write = ipmi_write,
836 .ioctl = ipmi_ioctl,
837 .open = ipmi_open,
838 .release = ipmi_close,
839 .fasync = ipmi_fasync,
840};
841
842static struct miscdevice ipmi_wdog_miscdev = {
843 .minor = WATCHDOG_MINOR,
844 .name = "watchdog",
845 .fops = &ipmi_wdog_fops
846};
847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,
849 void *handler_data)
850{
851 if (msg->msg.data[0] != 0) {
852 printk(KERN_ERR PFX "response: Error %x on cmd %x\n",
853 msg->msg.data[0],
854 msg->msg.cmd);
855 }
856
857 ipmi_free_recv_msg(msg);
858}
859
860static void ipmi_wdog_pretimeout_handler(void *handler_data)
861{
862 if (preaction_val != WDOG_PRETIMEOUT_NONE) {
Corey Minyardb3856762005-11-07 01:00:05 -0800863 if (preop_val == WDOG_PREOP_PANIC) {
864 if (atomic_inc_and_test(&preop_panic_excl))
865 panic("Watchdog pre-timeout");
866 } else if (preop_val == WDOG_PREOP_GIVE_DATA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 spin_lock(&ipmi_read_lock);
868 data_to_read = 1;
869 wake_up_interruptible(&read_q);
870 kill_fasync(&fasync_q, SIGIO, POLL_IN);
871
872 spin_unlock(&ipmi_read_lock);
873 }
874 }
875
876 /* On some machines, the heartbeat will give
877 an error and not work unless we re-enable
878 the timer. So do so. */
879 pretimeout_since_last_heartbeat = 1;
880}
881
882static struct ipmi_user_hndl ipmi_hndlrs =
883{
884 .ipmi_recv_hndl = ipmi_wdog_msg_handler,
885 .ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
886};
887
888static void ipmi_register_watchdog(int ipmi_intf)
889{
890 int rv = -EBUSY;
891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (watchdog_user)
893 goto out;
894
Corey Minyardb2c03942006-12-06 20:41:00 -0800895 if ((ifnum_to_use >= 0) && (ifnum_to_use != ipmi_intf))
896 goto out;
897
898 watchdog_ifnum = ipmi_intf;
899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
901 if (rv < 0) {
902 printk(KERN_CRIT PFX "Unable to register with ipmi\n");
903 goto out;
904 }
905
906 ipmi_get_version(watchdog_user,
907 &ipmi_version_major,
908 &ipmi_version_minor);
909
910 rv = misc_register(&ipmi_wdog_miscdev);
911 if (rv < 0) {
912 ipmi_destroy_user(watchdog_user);
913 watchdog_user = NULL;
914 printk(KERN_CRIT PFX "Unable to register misc device\n");
915 }
916
917 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if ((start_now) && (rv == 0)) {
919 /* Run from startup, so start the timer now. */
920 start_now = 0; /* Disable this function after first startup. */
921 ipmi_watchdog_state = action_val;
922 ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
923 printk(KERN_INFO PFX "Starting now!\n");
924 }
925}
926
Corey Minyardb2c03942006-12-06 20:41:00 -0800927static void ipmi_unregister_watchdog(int ipmi_intf)
928{
929 int rv;
930
Corey Minyardb2c03942006-12-06 20:41:00 -0800931 if (!watchdog_user)
932 goto out;
933
934 if (watchdog_ifnum != ipmi_intf)
935 goto out;
936
937 /* Make sure no one can call us any more. */
938 misc_deregister(&ipmi_wdog_miscdev);
939
940 /* Wait to make sure the message makes it out. The lower layer has
941 pointers to our buffers, we want to make sure they are done before
942 we release our memory. */
943 while (atomic_read(&set_timeout_tofree))
944 schedule_timeout_uninterruptible(1);
945
946 /* Disconnect from IPMI. */
947 rv = ipmi_destroy_user(watchdog_user);
948 if (rv) {
949 printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n",
950 rv);
951 }
952 watchdog_user = NULL;
953
954 out:
Corey Minyardf8fbcd32007-10-18 03:07:08 -0700955 return;
Corey Minyardb2c03942006-12-06 20:41:00 -0800956}
957
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700958#ifdef HAVE_NMI_HANDLER
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959static int
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700960ipmi_nmi(void *dev_id, int cpu, int handled)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
Corey Minyard8f05ee92005-09-06 15:18:39 -0700962 /* If we are not expecting a timeout, ignore it. */
963 if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700964 return NOTIFY_DONE;
Corey Minyard8f05ee92005-09-06 15:18:39 -0700965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 /* If no one else handled the NMI, we assume it was the IPMI
967 watchdog. */
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700968 if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
Corey Minyard8f05ee92005-09-06 15:18:39 -0700969 /* On some machines, the heartbeat will give
970 an error and not work unless we re-enable
971 the timer. So do so. */
972 pretimeout_since_last_heartbeat = 1;
Corey Minyardb3856762005-11-07 01:00:05 -0800973 if (atomic_inc_and_test(&preop_panic_excl))
974 panic(PFX "pre-timeout");
Corey Minyard8f05ee92005-09-06 15:18:39 -0700975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700977 return NOTIFY_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978}
979
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700980static struct nmi_handler ipmi_nmi_handler =
981{
982 .link = LIST_HEAD_INIT(ipmi_nmi_handler.link),
983 .dev_name = "ipmi_watchdog",
984 .dev_id = NULL,
985 .handler = ipmi_nmi,
986 .priority = 0, /* Call us last. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987};
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -0700988int nmi_handler_registered;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989#endif
990
991static int wdog_reboot_handler(struct notifier_block *this,
992 unsigned long code,
993 void *unused)
994{
995 static int reboot_event_handled = 0;
996
997 if ((watchdog_user) && (!reboot_event_handled)) {
998 /* Make sure we only do this once. */
999 reboot_event_handled = 1;
1000
1001 if (code == SYS_DOWN || code == SYS_HALT) {
1002 /* Disable the WDT if we are shutting down. */
1003 ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
1004 panic_halt_ipmi_set_timeout();
Corey Minyard96febe92006-06-28 04:26:55 -07001005 } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 /* Set a long timer to let the reboot happens, but
Corey Minyard96febe92006-06-28 04:26:55 -07001007 reboot if it hangs, but only if the watchdog
1008 timer was already running. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 timeout = 120;
1010 pretimeout = 0;
1011 ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
1012 panic_halt_ipmi_set_timeout();
1013 }
1014 }
1015 return NOTIFY_OK;
1016}
1017
1018static struct notifier_block wdog_reboot_notifier = {
1019 .notifier_call = wdog_reboot_handler,
1020 .next = NULL,
1021 .priority = 0
1022};
1023
1024static int wdog_panic_handler(struct notifier_block *this,
1025 unsigned long event,
1026 void *unused)
1027{
1028 static int panic_event_handled = 0;
1029
Corey Minyard96febe92006-06-28 04:26:55 -07001030 /* On a panic, if we have a panic timeout, make sure to extend
1031 the watchdog timer to a reasonable value to complete the
1032 panic, if the watchdog timer is running. Plus the
1033 pretimeout is meaningless at panic time. */
1034 if (watchdog_user && !panic_event_handled &&
1035 ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
1036 /* Make sure we do this only once. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 panic_event_handled = 1;
1038
1039 timeout = 255;
1040 pretimeout = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 panic_halt_ipmi_set_timeout();
1042 }
1043
1044 return NOTIFY_OK;
1045}
1046
1047static struct notifier_block wdog_panic_notifier = {
1048 .notifier_call = wdog_panic_handler,
1049 .next = NULL,
1050 .priority = 150 /* priority: INT_MAX >= x >= 0 */
1051};
1052
1053
Corey Minyard50c812b2006-03-26 01:37:21 -08001054static void ipmi_new_smi(int if_num, struct device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
1056 ipmi_register_watchdog(if_num);
1057}
1058
1059static void ipmi_smi_gone(int if_num)
1060{
Corey Minyardb2c03942006-12-06 20:41:00 -08001061 ipmi_unregister_watchdog(if_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062}
1063
1064static struct ipmi_smi_watcher smi_watcher =
1065{
1066 .owner = THIS_MODULE,
1067 .new_smi = ipmi_new_smi,
1068 .smi_gone = ipmi_smi_gone
1069};
1070
Corey Minyardcc4673e2005-11-07 00:59:57 -08001071static int action_op(const char *inval, char *outval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
Corey Minyardcc4673e2005-11-07 00:59:57 -08001073 if (outval)
1074 strcpy(outval, action);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Corey Minyardcc4673e2005-11-07 00:59:57 -08001076 if (!inval)
1077 return 0;
1078
1079 if (strcmp(inval, "reset") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 action_val = WDOG_TIMEOUT_RESET;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001081 else if (strcmp(inval, "none") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 action_val = WDOG_TIMEOUT_NONE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001083 else if (strcmp(inval, "power_cycle") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 action_val = WDOG_TIMEOUT_POWER_CYCLE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001085 else if (strcmp(inval, "power_off") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 action_val = WDOG_TIMEOUT_POWER_DOWN;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001087 else
1088 return -EINVAL;
1089 strcpy(action, inval);
1090 return 0;
1091}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Corey Minyardcc4673e2005-11-07 00:59:57 -08001093static int preaction_op(const char *inval, char *outval)
1094{
1095 if (outval)
1096 strcpy(outval, preaction);
1097
1098 if (!inval)
1099 return 0;
1100
1101 if (strcmp(inval, "pre_none") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 preaction_val = WDOG_PRETIMEOUT_NONE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001103 else if (strcmp(inval, "pre_smi") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 preaction_val = WDOG_PRETIMEOUT_SMI;
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001105#ifdef HAVE_NMI_HANDLER
Corey Minyardcc4673e2005-11-07 00:59:57 -08001106 else if (strcmp(inval, "pre_nmi") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 preaction_val = WDOG_PRETIMEOUT_NMI;
1108#endif
Corey Minyardcc4673e2005-11-07 00:59:57 -08001109 else if (strcmp(inval, "pre_int") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 preaction_val = WDOG_PRETIMEOUT_MSG_INT;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001111 else
1112 return -EINVAL;
1113 strcpy(preaction, inval);
1114 return 0;
1115}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Corey Minyardcc4673e2005-11-07 00:59:57 -08001117static int preop_op(const char *inval, char *outval)
1118{
1119 if (outval)
1120 strcpy(outval, preop);
1121
1122 if (!inval)
1123 return 0;
1124
1125 if (strcmp(inval, "preop_none") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 preop_val = WDOG_PREOP_NONE;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001127 else if (strcmp(inval, "preop_panic") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 preop_val = WDOG_PREOP_PANIC;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001129 else if (strcmp(inval, "preop_give_data") == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 preop_val = WDOG_PREOP_GIVE_DATA;
Corey Minyardcc4673e2005-11-07 00:59:57 -08001131 else
1132 return -EINVAL;
1133 strcpy(preop, inval);
1134 return 0;
1135}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Corey Minyardcc4673e2005-11-07 00:59:57 -08001137static void check_parms(void)
1138{
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001139#ifdef HAVE_NMI_HANDLER
Corey Minyardcc4673e2005-11-07 00:59:57 -08001140 int do_nmi = 0;
1141 int rv;
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 if (preaction_val == WDOG_PRETIMEOUT_NMI) {
Corey Minyardcc4673e2005-11-07 00:59:57 -08001144 do_nmi = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 if (preop_val == WDOG_PREOP_GIVE_DATA) {
1146 printk(KERN_WARNING PFX "Pretimeout op is to give data"
1147 " but NMI pretimeout is enabled, setting"
1148 " pretimeout op to none\n");
Corey Minyardcc4673e2005-11-07 00:59:57 -08001149 preop_op("preop_none", NULL);
1150 do_nmi = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 }
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001152#ifdef CONFIG_X86_LOCAL_APIC
1153 if (nmi_watchdog == NMI_IO_APIC) {
1154 printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC"
1155 " mode (value is %d), that is incompatible"
1156 " with using NMI in the IPMI watchdog."
1157 " Disabling IPMI nmi pretimeout.\n",
1158 nmi_watchdog);
1159 preaction_val = WDOG_PRETIMEOUT_NONE;
1160 do_nmi = 0;
1161 }
1162#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
Corey Minyardcc4673e2005-11-07 00:59:57 -08001164 if (do_nmi && !nmi_handler_registered) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001165 rv = request_nmi(&ipmi_nmi_handler);
Corey Minyardcc4673e2005-11-07 00:59:57 -08001166 if (rv) {
1167 printk(KERN_WARNING PFX
1168 "Can't register nmi handler\n");
1169 return;
1170 } else
1171 nmi_handler_registered = 1;
1172 } else if (!do_nmi && nmi_handler_registered) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001173 release_nmi(&ipmi_nmi_handler);
Corey Minyardcc4673e2005-11-07 00:59:57 -08001174 nmi_handler_registered = 0;
1175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176#endif
Corey Minyardcc4673e2005-11-07 00:59:57 -08001177}
1178
1179static int __init ipmi_wdog_init(void)
1180{
1181 int rv;
1182
1183 if (action_op(action, NULL)) {
1184 action_op("reset", NULL);
1185 printk(KERN_INFO PFX "Unknown action '%s', defaulting to"
1186 " reset\n", action);
1187 }
1188
1189 if (preaction_op(preaction, NULL)) {
1190 preaction_op("pre_none", NULL);
1191 printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to"
1192 " none\n", preaction);
1193 }
1194
1195 if (preop_op(preop, NULL)) {
1196 preop_op("preop_none", NULL);
1197 printk(KERN_INFO PFX "Unknown preop '%s', defaulting to"
1198 " none\n", preop);
1199 }
1200
1201 check_parms();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
Corey Minyardb2c03942006-12-06 20:41:00 -08001203 register_reboot_notifier(&wdog_reboot_notifier);
1204 atomic_notifier_chain_register(&panic_notifier_list,
1205 &wdog_panic_notifier);
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 rv = ipmi_smi_watcher_register(&smi_watcher);
1208 if (rv) {
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001209#ifdef HAVE_NMI_HANDLER
1210 if (preaction_val == WDOG_PRETIMEOUT_NMI)
1211 release_nmi(&ipmi_nmi_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212#endif
Corey Minyardb2c03942006-12-06 20:41:00 -08001213 atomic_notifier_chain_unregister(&panic_notifier_list,
1214 &wdog_panic_notifier);
1215 unregister_reboot_notifier(&wdog_reboot_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 printk(KERN_WARNING PFX "can't register smi watcher\n");
1217 return rv;
1218 }
1219
Corey Minyard1fdd75b2005-09-06 15:18:42 -07001220 printk(KERN_INFO PFX "driver initialized\n");
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 return 0;
1223}
1224
Corey Minyardb2c03942006-12-06 20:41:00 -08001225static void __exit ipmi_wdog_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226{
Corey Minyardb2c03942006-12-06 20:41:00 -08001227 ipmi_smi_watcher_unregister(&smi_watcher);
1228 ipmi_unregister_watchdog(watchdog_ifnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001230#ifdef HAVE_NMI_HANDLER
Corey Minyardcc4673e2005-11-07 00:59:57 -08001231 if (nmi_handler_registered)
Linus Torvaldsfaa8b6c2007-05-14 15:24:24 -07001232 release_nmi(&ipmi_nmi_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233#endif
1234
Alan Sterne041c682006-03-27 01:16:30 -08001235 atomic_notifier_chain_unregister(&panic_notifier_list,
Corey Minyardb2c03942006-12-06 20:41:00 -08001236 &wdog_panic_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 unregister_reboot_notifier(&wdog_reboot_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238}
1239module_exit(ipmi_wdog_exit);
1240module_init(ipmi_wdog_init);
1241MODULE_LICENSE("GPL");
Corey Minyard1fdd75b2005-09-06 15:18:42 -07001242MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
1243MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");