From tejblum@tejblum.yandex.ru  Tue Jan 13 18:35:32 2009
Return-Path: <tejblum@tejblum.yandex.ru>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 43247106564A
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 13 Jan 2009 18:35:32 +0000 (UTC)
	(envelope-from tejblum@tejblum.yandex.ru)
Received: from tejblum.yandex.ru (dhcp250-161.yandex.ru [87.250.250.161])
	by mx1.freebsd.org (Postfix) with ESMTP id BF3B38FC21
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 13 Jan 2009 18:35:31 +0000 (UTC)
	(envelope-from tejblum@tejblum.yandex.ru)
Received: from tejblum.yandex.ru (localhost [127.0.0.1])
	by tejblum.yandex.ru (8.14.1/8.13.4) with ESMTP id n0DILhmH002433
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 13 Jan 2009 21:21:43 +0300 (MSK)
	(envelope-from tejblum@tejblum.yandex.ru)
Received: (from tejblum@localhost)
	by tejblum.yandex.ru (8.14.1/8.13.4/Submit) id n0DILhf6002432;
	Tue, 13 Jan 2009 21:21:43 +0300 (MSK)
	(envelope-from tejblum)
Message-Id: <200901131821.n0DILhf6002432@tejblum.yandex.ru>
Date: Tue, 13 Jan 2009 21:21:43 +0300 (MSK)
From: Dmitrij Tejblum <tejblum@tejblum.yandex.ru>
Reply-To: Dmitrij Tejblum <tejblum@tejblum.yandex.ru>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [patch] Various mistakes in IPMI watchdog handling
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         130512
>Category:       kern
>Synopsis:       [ipmi] [patch] Various mistakes in IPMI watchdog handling
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    ru
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jan 13 18:40:00 UTC 2009
>Closed-Date:    Mon Dec 21 14:00:58 UTC 2009
>Last-Modified:  Mon Dec 21 14:10:02 UTC 2009
>Originator:     Dmitrij Tejblum
>Release:        FreeBSD 7.1-PRERELEASE i386
>Organization:
OOO Yandex
>Environment:

>Description:

Watchdog handling in the ipmi driver has several problems.

1. Incorrect timeout setting:
To get the most significant byte of a 2-byte number (i.e. sec*10) you 
should divide the number by 256, not 2550.
Also, a second contains 1000000000 nanoseconds, not 1800000000 nanoseconds.
(This change is verified by the "ipmitool" program and by testing when the 
watchdog actually fire.)

2. Due to rounding error, setting watchdog to a really small timeout 
(< 1 sec) was turning the watchdog off. It should set the watchdog to 
a small timeout instead.

3. The error checking was missed.

>How-To-Repeat:

Use ipmitool program from ports/sysutils/ipmitool
(ipmitool bmc watchdog get) to see actual watchdog settings.
Use different values of '-s' option to watchdogd to see when the timeout
actually fires.

>Fix:

--- dev/ipmi/ipmi.c	2008-10-13 18:43:46.000000000 +0400
+++ dev/ipmi/ipmi.c	2009-01-13 21:15:49.000000000 +0300
@@ -588,7 +588,7 @@
  * Watchdog event handler.
  */
 
-static void
+static int
 ipmi_set_watchdog(struct ipmi_softc *sc, int sec)
 {
 	struct ipmi_request *req;
@@ -604,7 +604,7 @@
 		req->ir_request[2] = 0;
 		req->ir_request[3] = 0;	/* Timer use */
 		req->ir_request[4] = (sec * 10) & 0xff;
-		req->ir_request[5] = (sec * 10) / 2550;
+		req->ir_request[5] = (sec * 10) / 256;
 	} else {
 		req->ir_request[0] = IPMI_SET_WD_TIMER_SMS_OS;
 		req->ir_request[1] = 0;
@@ -631,6 +631,7 @@
 	}
 
 	ipmi_free_request(req);
+	return error;
 	/*
 	dump_watchdog(sc);
 	*/
@@ -641,14 +642,22 @@
 {
 	struct ipmi_softc *sc = arg;
 	unsigned int timeout;
+	int e;
 
 	cmd &= WD_INTERVAL;
 	if (cmd > 0 && cmd <= 63) {
-		timeout = ((uint64_t)1 << cmd) / 1800000000;
-		ipmi_set_watchdog(sc, timeout);
-		*error = 0;
+		timeout = ((uint64_t)1 << cmd) / 1000000000;
+		if (timeout == 0)
+			timeout = 1;
+		e = ipmi_set_watchdog(sc, timeout);
+		if (e == 0)
+			*error = 0;
+		else
+			ipmi_set_watchdog(sc, 0);
 	} else {
-		ipmi_set_watchdog(sc, 0);
+		e = ipmi_set_watchdog(sc, 0);
+		if (e != 0)
+			*error = EOPNOTSUPP;
 	}
 }
 
>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->patched 
State-Changed-By: ru 
State-Changed-When: Fri Dec 18 12:11:19 UTC 2009 
State-Changed-Why:  
Fixed in 9.0-CURRENT. 


Responsible-Changed-From-To: freebsd-bugs->ru 
Responsible-Changed-By: ru 
Responsible-Changed-When: Fri Dec 18 12:11:19 UTC 2009 
Responsible-Changed-Why:  

http://www.freebsd.org/cgi/query-pr.cgi?pr=130512 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/130512: commit references a PR
Date: Fri, 18 Dec 2009 12:10:56 +0000 (UTC)

 Author: ru
 Date: Fri Dec 18 12:10:42 2009
 New Revision: 200666
 URL: http://svn.freebsd.org/changeset/base/200666
 
 Log:
   - Fixed incorrect watchdog timeout setting: MSB of a 2-byte
     value is obtained by dividing it by 256, not by 2550; also,
     one second is 10^9 nanoseconds, not 1800000000 nanoseconds.
   
   - Due to rounding error, setting watchdog to a really small
     timeout (<1 sec) was turning the watchdog off.  It should
     set the watchdog to a small timeout instead.
   
   - Implemented error checking in ipmi_wd_event(), as required
     by watchdog(9).
   
   PR:		kern/130512
   Submitted by:	Dmitrij Tejblum
   
   - Additionally, check that the timeout value is within the
     supported range, and if it's too large, act as required by
     watchdog(9).
   
   MFC after:	3 days
 
 Modified:
   head/sys/dev/ipmi/ipmi.c
 
 Modified: head/sys/dev/ipmi/ipmi.c
 ==============================================================================
 --- head/sys/dev/ipmi/ipmi.c	Fri Dec 18 12:09:44 2009	(r200665)
 +++ head/sys/dev/ipmi/ipmi.c	Fri Dec 18 12:10:42 2009	(r200666)
 @@ -588,12 +588,15 @@ ipmi_polled_enqueue_request(struct ipmi_
   * Watchdog event handler.
   */
  
 -static void
 -ipmi_set_watchdog(struct ipmi_softc *sc, int sec)
 +static int
 +ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
  {
  	struct ipmi_request *req;
  	int error;
  
 +	if (sec > 0xffff / 10)
 +		return (EINVAL);
 +
  	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
  	    IPMI_SET_WDOG, 6, 0);
  
 @@ -604,7 +607,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  		req->ir_request[2] = 0;
  		req->ir_request[3] = 0;	/* Timer use */
  		req->ir_request[4] = (sec * 10) & 0xff;
 -		req->ir_request[5] = (sec * 10) / 2550;
 +		req->ir_request[5] = (sec * 10) >> 8;
  	} else {
  		req->ir_request[0] = IPMI_SET_WD_TIMER_SMS_OS;
  		req->ir_request[1] = 0;
 @@ -617,8 +620,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  	error = ipmi_submit_driver_request(sc, req, 0);
  	if (error)
  		device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
 -
 -	if (error == 0 && sec) {
 +	else if (sec) {
  		ipmi_free_request(req);
  
  		req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
 @@ -631,6 +633,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  	}
  
  	ipmi_free_request(req);
 +	return (error);
  	/*
  	dump_watchdog(sc);
  	*/
 @@ -641,14 +644,22 @@ ipmi_wd_event(void *arg, unsigned int cm
  {
  	struct ipmi_softc *sc = arg;
  	unsigned int timeout;
 +	int e;
  
  	cmd &= WD_INTERVAL;
  	if (cmd > 0 && cmd <= 63) {
 -		timeout = ((uint64_t)1 << cmd) / 1800000000;
 -		ipmi_set_watchdog(sc, timeout);
 -		*error = 0;
 +		timeout = ((uint64_t)1 << cmd) / 1000000000;
 +		if (timeout == 0)
 +			timeout = 1;
 +		e = ipmi_set_watchdog(sc, timeout);
 +		if (e == 0)
 +			*error = 0;
 +		else
 +			(void)ipmi_set_watchdog(sc, 0);
  	} else {
 -		ipmi_set_watchdog(sc, 0);
 +		e = ipmi_set_watchdog(sc, 0);
 +		if (e != 0 && cmd == 0)
 +			*error = EOPNOTSUPP;
  	}
  }
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: ru 
State-Changed-When: Mon Dec 21 13:58:38 UTC 2009 
State-Changed-Why:  
Fixed in 7.2-STABLE and 8.0-STABLE. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130512 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/130512: commit references a PR
Date: Mon, 21 Dec 2009 13:53:45 +0000 (UTC)

 Author: ru
 Date: Mon Dec 21 13:53:33 2009
 New Revision: 200772
 URL: http://svn.freebsd.org/changeset/base/200772
 
 Log:
   MFC r200666: Fixed incorrect watchdog timeout setting.
   
   PR:		kern/130512
 
 Modified:
   stable/8/sys/dev/ipmi/ipmi.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
   stable/8/sys/dev/xen/xenpci/   (props changed)
 
 Changes in other areas also in this revision:
 Modified:
   stable/7/sys/dev/ipmi/ipmi.c
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/8/sys/dev/ipmi/ipmi.c
 ==============================================================================
 --- stable/8/sys/dev/ipmi/ipmi.c	Mon Dec 21 12:32:13 2009	(r200771)
 +++ stable/8/sys/dev/ipmi/ipmi.c	Mon Dec 21 13:53:33 2009	(r200772)
 @@ -588,12 +588,15 @@ ipmi_polled_enqueue_request(struct ipmi_
   * Watchdog event handler.
   */
  
 -static void
 -ipmi_set_watchdog(struct ipmi_softc *sc, int sec)
 +static int
 +ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
  {
  	struct ipmi_request *req;
  	int error;
  
 +	if (sec > 0xffff / 10)
 +		return (EINVAL);
 +
  	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
  	    IPMI_SET_WDOG, 6, 0);
  
 @@ -604,7 +607,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  		req->ir_request[2] = 0;
  		req->ir_request[3] = 0;	/* Timer use */
  		req->ir_request[4] = (sec * 10) & 0xff;
 -		req->ir_request[5] = (sec * 10) / 2550;
 +		req->ir_request[5] = (sec * 10) >> 8;
  	} else {
  		req->ir_request[0] = IPMI_SET_WD_TIMER_SMS_OS;
  		req->ir_request[1] = 0;
 @@ -617,8 +620,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  	error = ipmi_submit_driver_request(sc, req, 0);
  	if (error)
  		device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
 -
 -	if (error == 0 && sec) {
 +	else if (sec) {
  		ipmi_free_request(req);
  
  		req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
 @@ -631,6 +633,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  	}
  
  	ipmi_free_request(req);
 +	return (error);
  	/*
  	dump_watchdog(sc);
  	*/
 @@ -641,14 +644,22 @@ ipmi_wd_event(void *arg, unsigned int cm
  {
  	struct ipmi_softc *sc = arg;
  	unsigned int timeout;
 +	int e;
  
  	cmd &= WD_INTERVAL;
  	if (cmd > 0 && cmd <= 63) {
 -		timeout = ((uint64_t)1 << cmd) / 1800000000;
 -		ipmi_set_watchdog(sc, timeout);
 -		*error = 0;
 +		timeout = ((uint64_t)1 << cmd) / 1000000000;
 +		if (timeout == 0)
 +			timeout = 1;
 +		e = ipmi_set_watchdog(sc, timeout);
 +		if (e == 0)
 +			*error = 0;
 +		else
 +			(void)ipmi_set_watchdog(sc, 0);
  	} else {
 -		ipmi_set_watchdog(sc, 0);
 +		e = ipmi_set_watchdog(sc, 0);
 +		if (e != 0 && cmd == 0)
 +			*error = EOPNOTSUPP;
  	}
  }
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/130512: commit references a PR
Date: Mon, 21 Dec 2009 13:53:59 +0000 (UTC)

 Author: ru
 Date: Mon Dec 21 13:53:33 2009
 New Revision: 200772
 URL: http://svn.freebsd.org/changeset/base/200772
 
 Log:
   MFC r200666: Fixed incorrect watchdog timeout setting.
   
   PR:		kern/130512
 
 Modified:
   stable/7/sys/dev/ipmi/ipmi.c
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Changes in other areas also in this revision:
 Modified:
   stable/8/sys/dev/ipmi/ipmi.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
   stable/8/sys/dev/xen/xenpci/   (props changed)
 
 Modified: stable/7/sys/dev/ipmi/ipmi.c
 ==============================================================================
 --- stable/7/sys/dev/ipmi/ipmi.c	Mon Dec 21 12:32:13 2009	(r200771)
 +++ stable/7/sys/dev/ipmi/ipmi.c	Mon Dec 21 13:53:33 2009	(r200772)
 @@ -588,12 +588,15 @@ ipmi_polled_enqueue_request(struct ipmi_
   * Watchdog event handler.
   */
  
 -static void
 -ipmi_set_watchdog(struct ipmi_softc *sc, int sec)
 +static int
 +ipmi_set_watchdog(struct ipmi_softc *sc, unsigned int sec)
  {
  	struct ipmi_request *req;
  	int error;
  
 +	if (sec > 0xffff / 10)
 +		return (EINVAL);
 +
  	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
  	    IPMI_SET_WDOG, 6, 0);
  
 @@ -604,7 +607,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  		req->ir_request[2] = 0;
  		req->ir_request[3] = 0;	/* Timer use */
  		req->ir_request[4] = (sec * 10) & 0xff;
 -		req->ir_request[5] = (sec * 10) / 2550;
 +		req->ir_request[5] = (sec * 10) >> 8;
  	} else {
  		req->ir_request[0] = IPMI_SET_WD_TIMER_SMS_OS;
  		req->ir_request[1] = 0;
 @@ -617,8 +620,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  	error = ipmi_submit_driver_request(sc, req, 0);
  	if (error)
  		device_printf(sc->ipmi_dev, "Failed to set watchdog\n");
 -
 -	if (error == 0 && sec) {
 +	else if (sec) {
  		ipmi_free_request(req);
  
  		req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
 @@ -631,6 +633,7 @@ ipmi_set_watchdog(struct ipmi_softc *sc,
  	}
  
  	ipmi_free_request(req);
 +	return (error);
  	/*
  	dump_watchdog(sc);
  	*/
 @@ -641,14 +644,22 @@ ipmi_wd_event(void *arg, unsigned int cm
  {
  	struct ipmi_softc *sc = arg;
  	unsigned int timeout;
 +	int e;
  
  	cmd &= WD_INTERVAL;
  	if (cmd > 0 && cmd <= 63) {
 -		timeout = ((uint64_t)1 << cmd) / 1800000000;
 -		ipmi_set_watchdog(sc, timeout);
 -		*error = 0;
 +		timeout = ((uint64_t)1 << cmd) / 1000000000;
 +		if (timeout == 0)
 +			timeout = 1;
 +		e = ipmi_set_watchdog(sc, timeout);
 +		if (e == 0)
 +			*error = 0;
 +		else
 +			(void)ipmi_set_watchdog(sc, 0);
  	} else {
 -		ipmi_set_watchdog(sc, 0);
 +		e = ipmi_set_watchdog(sc, 0);
 +		if (e != 0 && cmd == 0)
 +			*error = EOPNOTSUPP;
  	}
  }
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
