]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/char/ipmi/ipmi_kcs_sm.c
IPMI: Convert system interface defines to an enum
[karo-tx-linux.git] / drivers / char / ipmi / ipmi_kcs_sm.c
index dc83365ede4abbf3e25f9055182235eb2e51186e..c1b8228cb7b685c619d437fac98f01ef68169437 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/string.h>
+#include <linux/jiffies.h>
 #include <linux/ipmi_msgdefs.h>                /* for completion codes */
 #include "ipmi_si_sm.h"
 
@@ -92,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
 {
@@ -115,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,
@@ -187,6 +190,7 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason)
                        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;
        }
 }
@@ -223,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");
@@ -257,12 +261,14 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data,
 {
        unsigned int i;
 
-       if ((size < 2) || (size > MAX_KCS_WRITE_SIZE)) {
-               return -1;
-       }
-       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 ++) {
@@ -403,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 {
@@ -423,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;
@@ -439,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);
@@ -454,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);