X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fipmi%2Fipmi_kcs_sm.c;h=c1b8228cb7b685c619d437fac98f01ef68169437;hb=refs%2Fheads%2Fvserver;hp=48cce24329bea516b62a0f3578ea162a48b73556;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 48cce2432..c1b8228cb 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -38,18 +38,25 @@ */ #include /* For printk. */ +#include +#include #include +#include #include /* for completion codes */ #include "ipmi_si_sm.h" -#define IPMI_KCS_VERSION "v33" - -/* Set this if you want a printout of why the state machine was hosed - when it gets hosed. */ -#define DEBUG_HOSED_REASON +/* kcs_debug is a bit-field + * KCS_DEBUG_ENABLE - turned on for now + * KCS_DEBUG_MSG - commands and their responses + * KCS_DEBUG_STATES - state machine + */ +#define KCS_DEBUG_STATES 4 +#define KCS_DEBUG_MSG 2 +#define KCS_DEBUG_ENABLE 1 -/* Print the state machine state on entry every time. */ -#undef DEBUG_STATE +static int kcs_debug; +module_param(kcs_debug, int, 0644); +MODULE_PARM_DESC(kcs_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); /* The states the KCS driver may be in. */ enum kcs_states { @@ -86,13 +93,14 @@ enum kcs_states { state machine. */ }; -#define MAX_KCS_READ_SIZE 80 -#define MAX_KCS_WRITE_SIZE 80 +#define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH +#define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH /* Timeouts in microseconds. */ #define IBF_RETRY_TIMEOUT 1000000 #define OBF_RETRY_TIMEOUT 1000000 #define MAX_ERROR_RETRIES 10 +#define ERROR0_OBF_WAIT_JIFFIES (2*HZ) struct si_sm_data { @@ -109,6 +117,7 @@ struct si_sm_data unsigned int error_retries; long ibf_timeout; long obf_timeout; + unsigned long error0_timeout; }; static unsigned int init_kcs_data(struct si_sm_data *kcs, @@ -177,11 +186,11 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason) { (kcs->error_retries)++; if (kcs->error_retries > MAX_ERROR_RETRIES) { -#ifdef DEBUG_HOSED_REASON - printk("ipmi_kcs_sm: kcs hosed: %s\n", reason); -#endif + if (kcs_debug & KCS_DEBUG_ENABLE) + printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason); kcs->state = KCS_HOSED; } else { + kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES; kcs->state = KCS_ERROR0; } } @@ -218,7 +227,7 @@ static inline int check_ibf(struct si_sm_data *kcs, unsigned char status, static inline int check_obf(struct si_sm_data *kcs, unsigned char status, long time) { - if (! GET_STATUS_OBF(status)) { + if (!GET_STATUS_OBF(status)) { kcs->obf_timeout -= time; if (kcs->obf_timeout < 0) { start_error_recovery(kcs, "OBF not ready in time"); @@ -250,14 +259,23 @@ static void restart_kcs_transaction(struct si_sm_data *kcs) static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, unsigned int size) { - if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) { - return -1; - } + unsigned int i; - if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) { - return -2; - } + if (size < 2) + return IPMI_REQ_LEN_INVALID_ERR; + if (size > MAX_KCS_WRITE_SIZE) + return IPMI_REQ_LEN_EXCEEDED_ERR; + if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) + return IPMI_NOT_IN_MY_STATE_ERR; + + if (kcs_debug & KCS_DEBUG_MSG) { + printk(KERN_DEBUG "start_kcs_transaction -"); + for (i = 0; i < size; i ++) { + printk(" %02x", (unsigned char) (data [i])); + } + printk ("\n"); + } kcs->error_retries = 0; memcpy(kcs->write_data, data, size); kcs->write_count = size; @@ -307,9 +325,9 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) status = read_status(kcs); -#ifdef DEBUG_STATE - printk(" State = %d, %x\n", kcs->state, status); -#endif + if (kcs_debug & KCS_DEBUG_STATES) + printk(KERN_DEBUG "KCS: State = %d, %x\n", kcs->state, status); + /* All states wait for ibf, so just do it here. */ if (!check_ibf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; @@ -391,7 +409,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) } if (state == KCS_READ_STATE) { - if (! check_obf(kcs, status, time)) + if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; read_next_byte(kcs); } else { @@ -411,6 +429,10 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) case KCS_ERROR0: clear_obf(kcs, status); + status = read_status(kcs); + if (GET_STATUS_OBF(status)) /* controller isn't responding */ + if (time_before(jiffies, kcs->error0_timeout)) + return SI_SM_CALL_WITH_TICK_DELAY; write_cmd(kcs, KCS_GET_STATUS_ABORT); kcs->state = KCS_ERROR1; break; @@ -427,7 +449,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) "Not in read state for error2"); break; } - if (! check_obf(kcs, status, time)) + if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); @@ -442,7 +464,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) break; } - if (! check_obf(kcs, status, time)) + if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); @@ -489,7 +511,6 @@ static void kcs_cleanup(struct si_sm_data *kcs) struct si_sm_handlers kcs_smi_handlers = { - .version = IPMI_KCS_VERSION, .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result,