diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_watchdog.c')
| -rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 41 | 
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index c2917ffad2c..34767a6d7f4 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -139,6 +139,8 @@  #define IPMI_WDOG_SET_TIMER		0x24  #define IPMI_WDOG_GET_TIMER		0x25 +#define IPMI_WDOG_TIMER_NOT_INIT_RESP	0x80 +  /* These are here until the real ones get into the watchdog.h interface. */  #ifndef WDIOC_GETTIMEOUT  #define	WDIOC_GETTIMEOUT        _IOW(WATCHDOG_IOCTL_BASE, 20, int) @@ -596,6 +598,7 @@ static int ipmi_heartbeat(void)  	struct kernel_ipmi_msg            msg;  	int                               rv;  	struct ipmi_system_interface_addr addr; +	int				  timeout_retries = 0;  	if (ipmi_ignore_heartbeat)  		return 0; @@ -616,6 +619,7 @@ static int ipmi_heartbeat(void)  	mutex_lock(&heartbeat_lock); +restart:  	atomic_set(&heartbeat_tofree, 2);  	/* @@ -653,7 +657,33 @@ static int ipmi_heartbeat(void)  	/* Wait for the heartbeat to be sent. */  	wait_for_completion(&heartbeat_wait); -	if (heartbeat_recv_msg.msg.data[0] != 0) { +	if (heartbeat_recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP)  { +		timeout_retries++; +		if (timeout_retries > 3) { +			printk(KERN_ERR PFX ": Unable to restore the IPMI" +			       " watchdog's settings, giving up.\n"); +			rv = -EIO; +			goto out_unlock; +		} + +		/* +		 * The timer was not initialized, that means the BMC was +		 * probably reset and lost the watchdog information.  Attempt +		 * to restore the timer's info.  Note that we still hold +		 * the heartbeat lock, to keep a heartbeat from happening +		 * in this process, so must say no heartbeat to avoid a +		 * deadlock on this mutex. +		 */ +		rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); +		if (rv) { +			printk(KERN_ERR PFX ": Unable to send the command to" +			       " set the watchdog's settings, giving up.\n"); +			goto out_unlock; +		} + +		/* We might need a new heartbeat, so do it now */ +		goto restart; +	} else if (heartbeat_recv_msg.msg.data[0] != 0) {  		/*  		 * Got an error in the heartbeat response.  It was already  		 * reported in ipmi_wdog_msg_handler, but we should return @@ -662,6 +692,7 @@ static int ipmi_heartbeat(void)  		rv = -EINVAL;  	} +out_unlock:  	mutex_unlock(&heartbeat_lock);  	return rv; @@ -922,11 +953,15 @@ static struct miscdevice ipmi_wdog_miscdev = {  static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg,  				  void                 *handler_data)  { -	if (msg->msg.data[0] != 0) { +	if (msg->msg.cmd == IPMI_WDOG_RESET_TIMER && +			msg->msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) +		printk(KERN_INFO PFX "response: The IPMI controller appears" +		       " to have been reset, will attempt to reinitialize" +		       " the watchdog timer\n"); +	else if (msg->msg.data[0] != 0)  		printk(KERN_ERR PFX "response: Error %x on cmd %x\n",  		       msg->msg.data[0],  		       msg->msg.cmd); -	}  	ipmi_free_recv_msg(msg);  }  |