diff options
author | Corey Minyard <minyard@acm.org> | 2005-11-07 03:59:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-07 10:53:44 -0500 |
commit | c4edff1c19ef23e15aae64ca03f32c6719822d54 (patch) | |
tree | 06858fc7330b433b629827347c63ad890c715b3e /drivers | |
parent | 393d2cc354d150b8b4bb888a9da7db4c935e12bd (diff) |
[PATCH] ipmi: various si cleanup
A number of small changes for the various system interface drivers,
consolidated from a number of patches from Matt Domsch.
Clear B2H_ATN and drain the BMC message buffer on command timeout. This
prevents further commands from failing after a timeout.
Add bt_debug and smic_debug module parameters, expose them in sysfs. This
lets you enable and disable debugging messages at runtime.
Unsigned jiffies math in ipmi_si_intf.c causes a too-large value to be passed
to ->event() after jiffies wrap-around. The BT driver had caught this, but
didn't know how to fix it. Now all calls to ->event() use a sane value for
time.
Increase timeout for commands handed to the BT driver from 2 seconds to 5
seconds. This is necessary particularly when the previous command was a
"Clear SEL", as that command completes, yet the BMC isn't really ready to
handle another command yet.
Silence BT debugging messages which were being printed on the console.
Increase SMIC timeout form 1/10s to 2s. This is needed on Dell PowerEdge 2650
and PowerEdge 750 with ERA/O cards to allow commands to complete without
timing out.
Adds kcs_debug module param, to match behavior of BT and SMIC. This also
prevents messages from being sent to the console unless explicitly requested.
Signed-off-by: Matt Domsch <Matt_Domsch@dell.com>
Signed-off-by: Corey Minyard <minyard@acm.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/ipmi/ipmi_bt_sm.c | 34 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_kcs_sm.c | 40 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 4 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_smic_sm.c | 6 |
4 files changed, 47 insertions, 37 deletions
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 33862670e285..7c4a195dfc9a 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c | |||
@@ -28,6 +28,8 @@ | |||
28 | 28 | ||
29 | #include <linux/kernel.h> /* For printk. */ | 29 | #include <linux/kernel.h> /* For printk. */ |
30 | #include <linux/string.h> | 30 | #include <linux/string.h> |
31 | #include <linux/module.h> | ||
32 | #include <linux/moduleparam.h> | ||
31 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ | 33 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ |
32 | #include "ipmi_si_sm.h" | 34 | #include "ipmi_si_sm.h" |
33 | 35 | ||
@@ -36,6 +38,8 @@ static int bt_debug = 0x00; /* Production value 0, see following flags */ | |||
36 | #define BT_DEBUG_ENABLE 1 | 38 | #define BT_DEBUG_ENABLE 1 |
37 | #define BT_DEBUG_MSG 2 | 39 | #define BT_DEBUG_MSG 2 |
38 | #define BT_DEBUG_STATES 4 | 40 | #define BT_DEBUG_STATES 4 |
41 | module_param(bt_debug, int, 0644); | ||
42 | MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); | ||
39 | 43 | ||
40 | /* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, | 44 | /* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, |
41 | and 64 byte buffers. However, one HP implementation wants 255 bytes of | 45 | and 64 byte buffers. However, one HP implementation wants 255 bytes of |
@@ -43,7 +47,7 @@ static int bt_debug = 0x00; /* Production value 0, see following flags */ | |||
43 | Since the Open IPMI architecture is single-message oriented at this | 47 | Since the Open IPMI architecture is single-message oriented at this |
44 | stage, the queue depth of BT is of no concern. */ | 48 | stage, the queue depth of BT is of no concern. */ |
45 | 49 | ||
46 | #define BT_NORMAL_TIMEOUT 2000000 /* seconds in microseconds */ | 50 | #define BT_NORMAL_TIMEOUT 5000000 /* seconds in microseconds */ |
47 | #define BT_RETRY_LIMIT 2 | 51 | #define BT_RETRY_LIMIT 2 |
48 | #define BT_RESET_DELAY 6000000 /* 6 seconds after warm reset */ | 52 | #define BT_RESET_DELAY 6000000 /* 6 seconds after warm reset */ |
49 | 53 | ||
@@ -202,7 +206,7 @@ static int bt_get_result(struct si_sm_data *bt, | |||
202 | msg_len = bt->read_count - 2; /* account for length & seq */ | 206 | msg_len = bt->read_count - 2; /* account for length & seq */ |
203 | /* Always NetFn, Cmd, cCode */ | 207 | /* Always NetFn, Cmd, cCode */ |
204 | if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) { | 208 | if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) { |
205 | printk(KERN_WARNING "BT results: bad msg_len = %d\n", msg_len); | 209 | printk(KERN_DEBUG "BT results: bad msg_len = %d\n", msg_len); |
206 | data[0] = bt->write_data[1] | 0x4; /* Kludge a response */ | 210 | data[0] = bt->write_data[1] | 0x4; /* Kludge a response */ |
207 | data[1] = bt->write_data[3]; | 211 | data[1] = bt->write_data[3]; |
208 | data[2] = IPMI_ERR_UNSPECIFIED; | 212 | data[2] = IPMI_ERR_UNSPECIFIED; |
@@ -240,7 +244,7 @@ static void reset_flags(struct si_sm_data *bt) | |||
240 | BT_CONTROL(BT_B_BUSY); | 244 | BT_CONTROL(BT_B_BUSY); |
241 | BT_CONTROL(BT_CLR_WR_PTR); | 245 | BT_CONTROL(BT_CLR_WR_PTR); |
242 | BT_CONTROL(BT_SMS_ATN); | 246 | BT_CONTROL(BT_SMS_ATN); |
243 | #ifdef DEVELOPMENT_ONLY_NOT_FOR_PRODUCTION | 247 | |
244 | if (BT_STATUS & BT_B2H_ATN) { | 248 | if (BT_STATUS & BT_B2H_ATN) { |
245 | int i; | 249 | int i; |
246 | BT_CONTROL(BT_H_BUSY); | 250 | BT_CONTROL(BT_H_BUSY); |
@@ -250,7 +254,6 @@ static void reset_flags(struct si_sm_data *bt) | |||
250 | BMC2HOST; | 254 | BMC2HOST; |
251 | BT_CONTROL(BT_H_BUSY); | 255 | BT_CONTROL(BT_H_BUSY); |
252 | } | 256 | } |
253 | #endif | ||
254 | } | 257 | } |
255 | 258 | ||
256 | static inline void write_all_bytes(struct si_sm_data *bt) | 259 | static inline void write_all_bytes(struct si_sm_data *bt) |
@@ -295,7 +298,7 @@ static inline int read_all_bytes(struct si_sm_data *bt) | |||
295 | printk ("\n"); | 298 | printk ("\n"); |
296 | } | 299 | } |
297 | if (bt->seq != bt->write_data[2]) /* idiot check */ | 300 | if (bt->seq != bt->write_data[2]) /* idiot check */ |
298 | printk(KERN_WARNING "BT: internal error: sequence mismatch\n"); | 301 | printk(KERN_DEBUG "BT: internal error: sequence mismatch\n"); |
299 | 302 | ||
300 | /* per the spec, the (NetFn, Seq, Cmd) tuples should match */ | 303 | /* per the spec, the (NetFn, Seq, Cmd) tuples should match */ |
301 | if ((bt->read_data[3] == bt->write_data[3]) && /* Cmd */ | 304 | if ((bt->read_data[3] == bt->write_data[3]) && /* Cmd */ |
@@ -321,18 +324,18 @@ static void error_recovery(struct si_sm_data *bt, char *reason) | |||
321 | bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */ | 324 | bt->timeout = BT_NORMAL_TIMEOUT; /* various places want to retry */ |
322 | 325 | ||
323 | status = BT_STATUS; | 326 | status = BT_STATUS; |
324 | printk(KERN_WARNING "BT: %s in %s %s ", reason, STATE2TXT, | 327 | printk(KERN_DEBUG "BT: %s in %s %s\n", reason, STATE2TXT, |
325 | STATUS2TXT(buf)); | 328 | STATUS2TXT(buf)); |
326 | 329 | ||
327 | (bt->error_retries)++; | 330 | (bt->error_retries)++; |
328 | if (bt->error_retries > BT_RETRY_LIMIT) { | 331 | if (bt->error_retries > BT_RETRY_LIMIT) { |
329 | printk("retry limit (%d) exceeded\n", BT_RETRY_LIMIT); | 332 | printk(KERN_DEBUG "retry limit (%d) exceeded\n", BT_RETRY_LIMIT); |
330 | bt->state = BT_STATE_HOSED; | 333 | bt->state = BT_STATE_HOSED; |
331 | if (!bt->nonzero_status) | 334 | if (!bt->nonzero_status) |
332 | printk(KERN_ERR "IPMI: BT stuck, try power cycle\n"); | 335 | printk(KERN_ERR "IPMI: BT stuck, try power cycle\n"); |
333 | else if (bt->seq == FIRST_SEQ + BT_RETRY_LIMIT) { | 336 | else if (bt->seq == FIRST_SEQ + BT_RETRY_LIMIT) { |
334 | /* most likely during insmod */ | 337 | /* most likely during insmod */ |
335 | printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n"); | 338 | printk(KERN_DEBUG "IPMI: BT reset (takes 5 secs)\n"); |
336 | bt->state = BT_STATE_RESET1; | 339 | bt->state = BT_STATE_RESET1; |
337 | } | 340 | } |
338 | return; | 341 | return; |
@@ -340,11 +343,11 @@ static void error_recovery(struct si_sm_data *bt, char *reason) | |||
340 | 343 | ||
341 | /* Sometimes the BMC queues get in an "off-by-one" state...*/ | 344 | /* Sometimes the BMC queues get in an "off-by-one" state...*/ |
342 | if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) { | 345 | if ((bt->state == BT_STATE_B2H_WAIT) && (status & BT_B2H_ATN)) { |
343 | printk("retry B2H_WAIT\n"); | 346 | printk(KERN_DEBUG "retry B2H_WAIT\n"); |
344 | return; | 347 | return; |
345 | } | 348 | } |
346 | 349 | ||
347 | printk("restart command\n"); | 350 | printk(KERN_DEBUG "restart command\n"); |
348 | bt->state = BT_STATE_RESTART; | 351 | bt->state = BT_STATE_RESTART; |
349 | } | 352 | } |
350 | 353 | ||
@@ -372,17 +375,6 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) | |||
372 | return SI_SM_HOSED; | 375 | return SI_SM_HOSED; |
373 | 376 | ||
374 | if (bt->state != BT_STATE_IDLE) { /* do timeout test */ | 377 | if (bt->state != BT_STATE_IDLE) { /* do timeout test */ |
375 | |||
376 | /* Certain states, on error conditions, can lock up a CPU | ||
377 | because they are effectively in an infinite loop with | ||
378 | CALL_WITHOUT_DELAY (right back here with time == 0). | ||
379 | Prevent infinite lockup by ALWAYS decrementing timeout. */ | ||
380 | |||
381 | /* FIXME: bt_event is sometimes called with time > BT_NORMAL_TIMEOUT | ||
382 | (noticed in ipmi_smic_sm.c January 2004) */ | ||
383 | |||
384 | if ((time <= 0) || (time >= BT_NORMAL_TIMEOUT)) | ||
385 | time = 100; | ||
386 | bt->timeout -= time; | 378 | bt->timeout -= time; |
387 | if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { | 379 | if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) { |
388 | error_recovery(bt, "timed out"); | 380 | error_recovery(bt, "timed out"); |
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index d21853a594a3..dc83365ede4a 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c | |||
@@ -38,16 +38,24 @@ | |||
38 | */ | 38 | */ |
39 | 39 | ||
40 | #include <linux/kernel.h> /* For printk. */ | 40 | #include <linux/kernel.h> /* For printk. */ |
41 | #include <linux/module.h> | ||
42 | #include <linux/moduleparam.h> | ||
41 | #include <linux/string.h> | 43 | #include <linux/string.h> |
42 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ | 44 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ |
43 | #include "ipmi_si_sm.h" | 45 | #include "ipmi_si_sm.h" |
44 | 46 | ||
45 | /* Set this if you want a printout of why the state machine was hosed | 47 | /* kcs_debug is a bit-field |
46 | when it gets hosed. */ | 48 | * KCS_DEBUG_ENABLE - turned on for now |
47 | #define DEBUG_HOSED_REASON | 49 | * KCS_DEBUG_MSG - commands and their responses |
50 | * KCS_DEBUG_STATES - state machine | ||
51 | */ | ||
52 | #define KCS_DEBUG_STATES 4 | ||
53 | #define KCS_DEBUG_MSG 2 | ||
54 | #define KCS_DEBUG_ENABLE 1 | ||
48 | 55 | ||
49 | /* Print the state machine state on entry every time. */ | 56 | static int kcs_debug; |
50 | #undef DEBUG_STATE | 57 | module_param(kcs_debug, int, 0644); |
58 | MODULE_PARM_DESC(kcs_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); | ||
51 | 59 | ||
52 | /* The states the KCS driver may be in. */ | 60 | /* The states the KCS driver may be in. */ |
53 | enum kcs_states { | 61 | enum kcs_states { |
@@ -175,9 +183,8 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason) | |||
175 | { | 183 | { |
176 | (kcs->error_retries)++; | 184 | (kcs->error_retries)++; |
177 | if (kcs->error_retries > MAX_ERROR_RETRIES) { | 185 | if (kcs->error_retries > MAX_ERROR_RETRIES) { |
178 | #ifdef DEBUG_HOSED_REASON | 186 | if (kcs_debug & KCS_DEBUG_ENABLE) |
179 | printk("ipmi_kcs_sm: kcs hosed: %s\n", reason); | 187 | printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason); |
180 | #endif | ||
181 | kcs->state = KCS_HOSED; | 188 | kcs->state = KCS_HOSED; |
182 | } else { | 189 | } else { |
183 | kcs->state = KCS_ERROR0; | 190 | kcs->state = KCS_ERROR0; |
@@ -248,14 +255,21 @@ static void restart_kcs_transaction(struct si_sm_data *kcs) | |||
248 | static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, | 255 | static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, |
249 | unsigned int size) | 256 | unsigned int size) |
250 | { | 257 | { |
258 | unsigned int i; | ||
259 | |||
251 | if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) { | 260 | if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) { |
252 | return -1; | 261 | return -1; |
253 | } | 262 | } |
254 | |||
255 | if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) { | 263 | if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) { |
256 | return -2; | 264 | return -2; |
257 | } | 265 | } |
258 | 266 | if (kcs_debug & KCS_DEBUG_MSG) { | |
267 | printk(KERN_DEBUG "start_kcs_transaction -"); | ||
268 | for (i = 0; i < size; i ++) { | ||
269 | printk(" %02x", (unsigned char) (data [i])); | ||
270 | } | ||
271 | printk ("\n"); | ||
272 | } | ||
259 | kcs->error_retries = 0; | 273 | kcs->error_retries = 0; |
260 | memcpy(kcs->write_data, data, size); | 274 | memcpy(kcs->write_data, data, size); |
261 | kcs->write_count = size; | 275 | kcs->write_count = size; |
@@ -305,9 +319,9 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) | |||
305 | 319 | ||
306 | status = read_status(kcs); | 320 | status = read_status(kcs); |
307 | 321 | ||
308 | #ifdef DEBUG_STATE | 322 | if (kcs_debug & KCS_DEBUG_STATES) |
309 | printk(" State = %d, %x\n", kcs->state, status); | 323 | printk(KERN_DEBUG "KCS: State = %d, %x\n", kcs->state, status); |
310 | #endif | 324 | |
311 | /* All states wait for ibf, so just do it here. */ | 325 | /* All states wait for ibf, so just do it here. */ |
312 | if (!check_ibf(kcs, status, time)) | 326 | if (!check_ibf(kcs, status, time)) |
313 | return SI_SM_CALL_WITH_DELAY; | 327 | return SI_SM_CALL_WITH_DELAY; |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b6e5cbfb09f8..204e2e987e90 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -819,7 +819,7 @@ static void smi_timeout(unsigned long data) | |||
819 | enum si_sm_result smi_result; | 819 | enum si_sm_result smi_result; |
820 | unsigned long flags; | 820 | unsigned long flags; |
821 | unsigned long jiffies_now; | 821 | unsigned long jiffies_now; |
822 | unsigned long time_diff; | 822 | long time_diff; |
823 | #ifdef DEBUG_TIMING | 823 | #ifdef DEBUG_TIMING |
824 | struct timeval t; | 824 | struct timeval t; |
825 | #endif | 825 | #endif |
@@ -835,7 +835,7 @@ static void smi_timeout(unsigned long data) | |||
835 | printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); | 835 | printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); |
836 | #endif | 836 | #endif |
837 | jiffies_now = jiffies; | 837 | jiffies_now = jiffies; |
838 | time_diff = ((jiffies_now - smi_info->last_timeout_jiffies) | 838 | time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies) |
839 | * SI_USEC_PER_JIFFY); | 839 | * SI_USEC_PER_JIFFY); |
840 | smi_result = smi_event_handler(smi_info, time_diff); | 840 | smi_result = smi_event_handler(smi_info, time_diff); |
841 | 841 | ||
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index add2aa2732f0..f17043da9dd5 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c | |||
@@ -43,6 +43,8 @@ | |||
43 | 43 | ||
44 | #include <linux/kernel.h> /* For printk. */ | 44 | #include <linux/kernel.h> /* For printk. */ |
45 | #include <linux/string.h> | 45 | #include <linux/string.h> |
46 | #include <linux/module.h> | ||
47 | #include <linux/moduleparam.h> | ||
46 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ | 48 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ |
47 | #include "ipmi_si_sm.h" | 49 | #include "ipmi_si_sm.h" |
48 | 50 | ||
@@ -56,6 +58,8 @@ | |||
56 | #define SMIC_DEBUG_ENABLE 1 | 58 | #define SMIC_DEBUG_ENABLE 1 |
57 | 59 | ||
58 | static int smic_debug = 1; | 60 | static int smic_debug = 1; |
61 | module_param(smic_debug, int, 0644); | ||
62 | MODULE_PARM_DESC(smic_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); | ||
59 | 63 | ||
60 | enum smic_states { | 64 | enum smic_states { |
61 | SMIC_IDLE, | 65 | SMIC_IDLE, |
@@ -76,7 +80,7 @@ enum smic_states { | |||
76 | #define SMIC_MAX_ERROR_RETRIES 3 | 80 | #define SMIC_MAX_ERROR_RETRIES 3 |
77 | 81 | ||
78 | /* Timeouts in microseconds. */ | 82 | /* Timeouts in microseconds. */ |
79 | #define SMIC_RETRY_TIMEOUT 100000 | 83 | #define SMIC_RETRY_TIMEOUT 2000000 |
80 | 84 | ||
81 | /* SMIC Flags Register Bits */ | 85 | /* SMIC Flags Register Bits */ |
82 | #define SMIC_RX_DATA_READY 0x80 | 86 | #define SMIC_RX_DATA_READY 0x80 |