#include <asm/apic.h>
#endif
-#define IPMI_WATCHDOG_VERSION "v31"
+#define PFX "IPMI Watchdog: "
+
+#define IPMI_WATCHDOG_VERSION "v33"
/*
* The IPMI command/response information for the watchdog timer.
#define WDIOC_GET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 22, int)
#endif
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout;
+#endif
+
static ipmi_user_t watchdog_user = NULL;
/* Default the timeout to 10 seconds. */
static unsigned char preop_val = WDOG_PREOP_NONE;
static char preop[16] = "preop_none";
-static spinlock_t ipmi_read_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ipmi_read_lock);
static char data_to_read = 0;
static DECLARE_WAIT_QUEUE_HEAD(read_q);
static struct fasync_struct *fasync_q = NULL;
static char pretimeout_since_last_heartbeat = 0;
+static char expect_close;
/* If true, the driver will start running as soon as it is configured
and ready. */
module_param(start_now, int, 0);
MODULE_PARM_DESC(start_now, "Set to 1 to start the watchdog as"
"soon as the driver is loaded.");
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
/* Default state of the timer. */
static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
static int ipmi_ignore_heartbeat = 0;
/* Is someone using the watchdog? Only one user is allowed. */
-static int ipmi_wdog_open = 0;
+static unsigned long ipmi_wdog_open = 0;
/* If set to 1, the heartbeat command will set the state to reset and
start the timer. The timer doesn't normally run when the driver is
struct ipmi_recv_msg *recv_msg,
int *send_heartbeat_now)
{
- struct ipmi_msg msg;
+ struct kernel_ipmi_msg msg;
unsigned char data[6];
int rv;
struct ipmi_system_interface_addr addr;
recv_msg,
1);
if (rv) {
- printk(KERN_WARNING "IPMI Watchdog, set timeout error: %d\n",
+ printk(KERN_WARNING PFX "set timeout error: %d\n",
rv);
}
}
}
-/* Do a delayed shutdown, with the delay in milliseconds. If power_off is
- false, do a reset. If power_off is true, do a power down. This is
- primarily for the IMB code's shutdown. */
-void ipmi_delayed_shutdown(long delay, int power_off)
-{
- ipmi_ignore_heartbeat = 1;
- if (power_off)
- ipmi_watchdog_state = WDOG_TIMEOUT_POWER_DOWN;
- else
- ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
- timeout = delay;
- ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
-}
-
/* We use a semaphore to make sure that only one thing can send a
heartbeat at one time, because we only have one copy of the data.
The semaphore is claimed when the set_timeout is sent and freed
static int ipmi_heartbeat(void)
{
- struct ipmi_msg msg;
+ struct kernel_ipmi_msg msg;
int rv;
struct ipmi_system_interface_addr addr;
1);
if (rv) {
up(&heartbeat_lock);
- printk(KERN_WARNING "IPMI Watchdog, heartbeat failure: %d\n",
+ printk(KERN_WARNING PFX "heartbeat failure: %d\n",
rv);
return rv;
}
static void panic_halt_ipmi_heartbeat(void)
{
- struct ipmi_msg msg;
+ struct kernel_ipmi_msg msg;
struct ipmi_system_interface_addr addr;
static struct watchdog_info ident=
{
- 0, /* WDIOF_SETTIMEOUT, */
- 1,
- "IPMI"
+ .options = 0, /* WDIOF_SETTIMEOUT, */
+ .firmware_version = 1,
+ .identity = "IPMI"
};
static int ipmi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ void __user *argp = (void __user *)arg;
int i;
int val;
switch(cmd) {
case WDIOC_GETSUPPORT:
- i = copy_to_user((void*)arg, &ident, sizeof(ident));
+ i = copy_to_user(argp, &ident, sizeof(ident));
return i ? -EFAULT : 0;
case WDIOC_SETTIMEOUT:
- i = copy_from_user(&val, (void *) arg, sizeof(int));
+ i = copy_from_user(&val, argp, sizeof(int));
if (i)
return -EFAULT;
timeout = val;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
case WDIOC_GETTIMEOUT:
- i = copy_to_user((void *) arg,
- &timeout,
- sizeof(timeout));
+ i = copy_to_user(argp, &timeout, sizeof(timeout));
if (i)
return -EFAULT;
return 0;
case WDIOC_SET_PRETIMEOUT:
- i = copy_from_user(&val, (void *) arg, sizeof(int));
+ i = copy_from_user(&val, argp, sizeof(int));
if (i)
return -EFAULT;
pretimeout = val;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
case WDIOC_GET_PRETIMEOUT:
- i = copy_to_user((void *) arg,
- &pretimeout,
- sizeof(pretimeout));
+ i = copy_to_user(argp, &pretimeout, sizeof(pretimeout));
if (i)
return -EFAULT;
return 0;
return ipmi_heartbeat();
case WDIOC_SETOPTIONS:
- i = copy_from_user(&val, (void *) arg, sizeof(int));
+ i = copy_from_user(&val, argp, sizeof(int));
if (i)
return -EFAULT;
if (val & WDIOS_DISABLECARD)
case WDIOC_GETSTATUS:
val = 0;
- i = copy_to_user((void *) arg, &val, sizeof(val));
+ i = copy_to_user(argp, &val, sizeof(val));
if (i)
return -EFAULT;
return 0;
}
static ssize_t ipmi_write(struct file *file,
- const char *buf,
+ const char __user *buf,
size_t len,
loff_t *ppos)
{
int rv;
- /* Can't seek (pwrite) on this device */
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ expect_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
rv = ipmi_heartbeat();
if (rv)
return rv;
}
static ssize_t ipmi_read(struct file *file,
- char *buf,
+ char __user *buf,
size_t count,
loff_t *ppos)
{
int rv = 0;
wait_queue_t wait;
- /* Can't seek (pread) on this device */
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
if (count <= 0)
return 0;
switch (iminor(ino))
{
case WATCHDOG_MINOR:
- if (ipmi_wdog_open)
+ if(test_and_set_bit(0, &ipmi_wdog_open))
return -EBUSY;
- ipmi_wdog_open = 1;
-
/* Don't start the timer now, let it start on the
first heartbeat. */
ipmi_start_timer_on_heartbeat = 1;
- return(0);
+ return nonseekable_open(ino, filep);
default:
return (-ENODEV);
{
if (iminor(ino)==WATCHDOG_MINOR)
{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
- ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
- ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
-#endif
- ipmi_wdog_open = 0;
+ if (expect_close == 42) {
+ ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+ ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
+ clear_bit(0, &ipmi_wdog_open);
+ } else {
+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ ipmi_heartbeat();
+ }
}
ipmi_fasync (-1, filep, 0);
+ expect_close = 0;
return 0;
}
};
static struct miscdevice ipmi_wdog_miscdev = {
- WATCHDOG_MINOR,
- "watchdog",
- &ipmi_wdog_fops
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &ipmi_wdog_fops
};
static DECLARE_RWSEM(register_sem);
void *handler_data)
{
if (msg->msg.data[0] != 0) {
- printk(KERN_ERR "IPMI Watchdog response: Error %x on cmd %x\n",
+ printk(KERN_ERR PFX "response: Error %x on cmd %x\n",
msg->msg.data[0],
msg->msg.cmd);
}
rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);
if (rv < 0) {
- printk("IPMI watchdog: Unable to register with ipmi\n");
+ printk(KERN_CRIT PFX "Unable to register with ipmi\n");
goto out;
}
if (rv < 0) {
ipmi_destroy_user(watchdog_user);
watchdog_user = NULL;
- printk("IPMI watchdog: Unable to register misc device\n");
+ printk(KERN_CRIT PFX "Unable to register misc device\n");
}
out:
start_now = 0; /* Disable this function after first startup. */
ipmi_watchdog_state = action_val;
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
- printk("Starting IPMI Watchdog now!\n");
+ printk(KERN_INFO PFX "Starting now!\n");
}
}
/* If no one else handled the NMI, we assume it was the IPMI
watchdog. */
if ((!handled) && (preop_val == WDOG_PREOP_PANIC))
- panic("IPMI watchdog pre-timeout");
+ panic(PFX "pre-timeout");
/* On some machines, the heartbeat will give
an error and not work unless we re-enable
}
static struct notifier_block wdog_reboot_notifier = {
- wdog_reboot_handler,
- NULL,
- 0
+ .notifier_call = wdog_reboot_handler,
+ .next = NULL,
+ .priority = 0
};
-extern int panic_timeout; /* Why isn't this defined anywhere? */
-
static int wdog_panic_handler(struct notifier_block *this,
unsigned long event,
void *unused)
/* On a panic, if we have a panic timeout, make sure that the thing
reboots, even if it hangs during that panic. */
- if (watchdog_user && !panic_event_handled && (panic_timeout > 0)) {
+ if (watchdog_user && !panic_event_handled) {
/* Make sure the panic doesn't hang, and make sure we
do this only once. */
panic_event_handled = 1;
- timeout = panic_timeout + 120;
- if (timeout > 255)
- timeout = 255;
+ timeout = 255;
pretimeout = 0;
ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
panic_halt_ipmi_set_timeout();
}
static struct notifier_block wdog_panic_notifier = {
- wdog_panic_handler,
- NULL,
- 150 /* priority: INT_MAX >= x >= 0 */
+ .notifier_call = wdog_panic_handler,
+ .next = NULL,
+ .priority = 150 /* priority: INT_MAX >= x >= 0 */
};
{
int rv;
- printk(KERN_INFO "IPMI watchdog driver version "
+ printk(KERN_INFO PFX "driver version "
IPMI_WATCHDOG_VERSION "\n");
if (strcmp(action, "reset") == 0) {
action_val = WDOG_TIMEOUT_POWER_DOWN;
} else {
action_val = WDOG_TIMEOUT_RESET;
- printk("ipmi_watchdog: Unknown action '%s', defaulting to"
+ printk(KERN_INFO PFX "Unknown action '%s', defaulting to"
" reset\n", action);
}
preaction_val = WDOG_PRETIMEOUT_MSG_INT;
} else {
preaction_val = WDOG_PRETIMEOUT_NONE;
- printk("ipmi_watchdog: Unknown preaction '%s', defaulting to"
+ printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to"
" none\n", preaction);
}
preop_val = WDOG_PREOP_GIVE_DATA;
} else {
preop_val = WDOG_PREOP_NONE;
- printk("ipmi_watchdog: Unknown preop '%s', defaulting to"
+ printk(KERN_INFO PFX "Unknown preop '%s', defaulting to"
" none\n", preop);
}
#ifdef HAVE_NMI_HANDLER
if (preaction_val == WDOG_PRETIMEOUT_NMI) {
if (preop_val == WDOG_PREOP_GIVE_DATA) {
- printk(KERN_WARNING
- "ipmi_watchdog: Pretimeout op is to give data"
+ printk(KERN_WARNING PFX "Pretimeout op is to give data"
" but NMI pretimeout is enabled, setting"
" pretimeout op to none\n");
preop_val = WDOG_PREOP_NONE;
}
#ifdef CONFIG_X86_LOCAL_APIC
if (nmi_watchdog == NMI_IO_APIC) {
- printk(KERN_WARNING
- "ipmi_watchdog: nmi_watchdog is set to IO APIC"
+ printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC"
" mode (value is %d), that is incompatible"
" with using NMI in the IPMI watchdog."
" Disabling IPMI nmi pretimeout.\n",
#endif
rv = request_nmi(&ipmi_nmi_handler);
if (rv) {
- printk(KERN_WARNING
- "ipmi_watchdog: Can't register nmi handler\n");
+ printk(KERN_WARNING PFX "Can't register nmi handler\n");
return rv;
}
#ifdef CONFIG_X86_LOCAL_APIC
if (preaction_val == WDOG_PRETIMEOUT_NMI)
release_nmi(&ipmi_nmi_handler);
#endif
- printk(KERN_WARNING
- "ipmi_watchdog: can't register smi watcher\n");
+ printk(KERN_WARNING PFX "can't register smi watcher\n");
return rv;
}
/* Make sure no one can call us any more. */
misc_deregister(&ipmi_wdog_miscdev);
- /* Disable the timer. */
- ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
- ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
-
/* Wait to make sure the message makes it out. The lower layer has
pointers to our buffers, we want to make sure they are done before
we release our memory. */
/* Disconnect from IPMI. */
rv = ipmi_destroy_user(watchdog_user);
if (rv) {
- printk(KERN_WARNING
- "IPMI Watchdog, error unlinking from IPMI: %d\n",
+ printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n",
rv);
}
watchdog_user = NULL;
ipmi_unregister_watchdog();
}
module_exit(ipmi_wdog_exit);
-
-EXPORT_SYMBOL(ipmi_delayed_shutdown);
-
module_init(ipmi_wdog_init);
MODULE_LICENSE("GPL");