diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_bt_sm.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_bt_sm.c | 158 |
1 files changed, 82 insertions, 76 deletions
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index a3397664f800..f3f216cdf686 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -8,6 +8,8 @@ * Author: Rocky Craig <first.last@hp.com> */ +#define DEBUG /* So dev_dbg() is always available. */ + #include <linux/kernel.h> /* For printk. */ #include <linux/string.h> #include <linux/module.h> @@ -59,8 +61,6 @@ enum bt_states { BT_STATE_RESET3, BT_STATE_RESTART, BT_STATE_PRINTME, - BT_STATE_CAPABILITIES_BEGIN, - BT_STATE_CAPABILITIES_END, BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */ }; @@ -86,7 +86,6 @@ struct si_sm_data { int error_retries; /* end of "common" fields */ int nonzero_status; /* hung BMCs stay all 0 */ enum bt_states complete; /* to divert the state machine */ - int BT_CAP_outreqs; long BT_CAP_req2rsp; int BT_CAP_retries; /* Recommended retries */ }; @@ -137,8 +136,6 @@ static char *state2txt(unsigned char state) case BT_STATE_RESET3: return("RESET3"); case BT_STATE_RESTART: return("RESTART"); case BT_STATE_LONG_BUSY: return("LONG_BUSY"); - case BT_STATE_CAPABILITIES_BEGIN: return("CAP_BEGIN"); - case BT_STATE_CAPABILITIES_END: return("CAP_END"); } return("BAD STATE"); } @@ -185,7 +182,6 @@ static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) bt->complete = BT_STATE_IDLE; /* end here */ bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * USEC_PER_SEC; bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT; - /* BT_CAP_outreqs == zero is a flag to read BT Capabilities */ return 3; /* We claim 3 bytes of space; ought to check SPMI table */ } @@ -221,11 +217,11 @@ static int bt_start_transaction(struct si_sm_data *bt, return IPMI_NOT_IN_MY_STATE_ERR; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); - printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); + dev_dbg(bt->io->dev, "+++++++++++++++++ New command\n"); + dev_dbg(bt->io->dev, "NetFn/LUN CMD [%d data]:", size - 2); for (i = 0; i < size; i ++) - printk(" %02x", data[i]); - printk("\n"); + pr_cont(" %02x", data[i]); + pr_cont("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ bt->write_data[1] = *data; /* NetFn/LUN */ @@ -266,10 +262,10 @@ static int bt_get_result(struct si_sm_data *bt, memcpy(data + 2, bt->read_data + 4, msg_len - 2); if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: result %d bytes:", msg_len); + dev_dbg(bt->io->dev, "result %d bytes:", msg_len); for (i = 0; i < msg_len; i++) - printk(" %02x", data[i]); - printk("\n"); + pr_cont(" %02x", data[i]); + pr_cont("\n"); } return msg_len; } @@ -280,8 +276,7 @@ static int bt_get_result(struct si_sm_data *bt, static void reset_flags(struct si_sm_data *bt) { if (bt_debug) - printk(KERN_WARNING "IPMI BT: flag reset %s\n", - status2txt(BT_STATUS)); + dev_dbg(bt->io->dev, "flag reset %s\n", status2txt(BT_STATUS)); if (BT_STATUS & BT_H_BUSY) BT_CONTROL(BT_H_BUSY); /* force clear */ BT_CONTROL(BT_CLR_WR_PTR); /* always reset */ @@ -307,14 +302,14 @@ static void drain_BMC2HOST(struct si_sm_data *bt) BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */ BT_CONTROL(BT_CLR_RD_PTR); /* always reset */ if (bt_debug) - printk(KERN_WARNING "IPMI BT: stale response %s; ", + dev_dbg(bt->io->dev, "stale response %s; ", status2txt(BT_STATUS)); size = BMC2HOST; for (i = 0; i < size ; i++) BMC2HOST; BT_CONTROL(BT_H_BUSY); /* now clear */ if (bt_debug) - printk("drained %d bytes\n", size + 1); + pr_cont("drained %d bytes\n", size + 1); } static inline void write_all_bytes(struct si_sm_data *bt) @@ -322,11 +317,11 @@ static inline void write_all_bytes(struct si_sm_data *bt) int i; if (bt_debug & BT_DEBUG_MSG) { - printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", + dev_dbg(bt->io->dev, "write %d bytes seq=0x%02X", bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++) - printk(" %02x", bt->write_data[i]); - printk("\n"); + pr_cont(" %02x", bt->write_data[i]); + pr_cont("\n"); } for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]); @@ -346,8 +341,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) { if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "BT: bad raw rsp len=%d\n", - bt->read_count); + dev_dbg(bt->io->dev, + "bad raw rsp len=%d\n", bt->read_count); bt->truncated = 1; return 1; /* let next XACTION START clean it up */ } @@ -358,13 +353,13 @@ static inline int read_all_bytes(struct si_sm_data *bt) if (bt_debug & BT_DEBUG_MSG) { int max = bt->read_count; - printk(KERN_WARNING "BT: got %d bytes seq=0x%02X", - max, bt->read_data[2]); + dev_dbg(bt->io->dev, + "got %d bytes seq=0x%02X", max, bt->read_data[2]); if (max > 16) max = 16; for (i = 0; i < max; i++) - printk(KERN_CONT " %02x", bt->read_data[i]); - printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ..."); + pr_cont(" %02x", bt->read_data[i]); + pr_cont("%s\n", bt->read_count == max ? "" : " ..."); } /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ @@ -374,10 +369,11 @@ static inline int read_all_bytes(struct si_sm_data *bt) return 1; if (bt_debug & BT_DEBUG_MSG) - printk(KERN_WARNING "IPMI BT: bad packet: " - "want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", - bt->write_data[1] | 0x04, bt->write_data[2], bt->write_data[3], - bt->read_data[1], bt->read_data[2], bt->read_data[3]); + dev_dbg(bt->io->dev, + "IPMI BT: bad packet: want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n", + bt->write_data[1] | 0x04, bt->write_data[2], + bt->write_data[3], + bt->read_data[1], bt->read_data[2], bt->read_data[3]); return 0; } @@ -400,8 +396,8 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, break; } - printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ - reason, STATE2TXT, STATUS2TXT); + dev_warn(bt->io->dev, "IPMI BT: %s in %s %s ", /* open-ended line */ + reason, STATE2TXT, STATUS2TXT); /* * Per the IPMI spec, retries are based on the sequence number @@ -409,20 +405,20 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, */ (bt->error_retries)++; if (bt->error_retries < bt->BT_CAP_retries) { - printk("%d retries left\n", + pr_cont("%d retries left\n", bt->BT_CAP_retries - bt->error_retries); bt->state = BT_STATE_RESTART; return SI_SM_CALL_WITHOUT_DELAY; } - printk(KERN_WARNING "failed %d retries, sending error response\n", - bt->BT_CAP_retries); + dev_warn(bt->io->dev, "failed %d retries, sending error response\n", + bt->BT_CAP_retries); if (!bt->nonzero_status) - printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); + dev_err(bt->io->dev, "stuck, try power cycle\n"); /* this is most likely during insmod */ else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) { - printk(KERN_WARNING "IPMI: BT reset (takes 5 secs)\n"); + dev_warn(bt->io->dev, "BT reset (takes 5 secs)\n"); bt->state = BT_STATE_RESET1; return SI_SM_CALL_WITHOUT_DELAY; } @@ -451,14 +447,14 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, static enum si_sm_result bt_event(struct si_sm_data *bt, long time) { - unsigned char status, BT_CAP[8]; + unsigned char status; static enum bt_states last_printed = BT_STATE_PRINTME; int i; status = BT_STATUS; bt->nonzero_status |= status; if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) { - printk(KERN_WARNING "BT: %s %s TO=%ld - %ld \n", + dev_dbg(bt->io->dev, "BT: %s %s TO=%ld - %ld\n", STATE2TXT, STATUS2TXT, bt->timeout, @@ -504,12 +500,6 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); - bt->timeout = bt->BT_CAP_req2rsp; - - /* Read BT capabilities if it hasn't been done yet */ - if (!bt->BT_CAP_outreqs) - BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, - SI_SM_CALL_WITHOUT_DELAY); BT_SI_SM_RETURN(SI_SM_IDLE); case BT_STATE_XACTION_START: @@ -614,37 +604,6 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_STATE_CHANGE(BT_STATE_XACTION_START, SI_SM_CALL_WITH_DELAY); - /* - * Get BT Capabilities, using timing of upper level state machine. - * Set outreqs to prevent infinite loop on timeout. - */ - case BT_STATE_CAPABILITIES_BEGIN: - bt->BT_CAP_outreqs = 1; - { - unsigned char GetBT_CAP[] = { 0x18, 0x36 }; - bt->state = BT_STATE_IDLE; - bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP)); - } - bt->complete = BT_STATE_CAPABILITIES_END; - BT_STATE_CHANGE(BT_STATE_XACTION_START, - SI_SM_CALL_WITH_DELAY); - - case BT_STATE_CAPABILITIES_END: - i = bt_get_result(bt, BT_CAP, sizeof(BT_CAP)); - bt_init_data(bt, bt->io); - if ((i == 8) && !BT_CAP[2]) { - bt->BT_CAP_outreqs = BT_CAP[3]; - bt->BT_CAP_req2rsp = BT_CAP[6] * USEC_PER_SEC; - bt->BT_CAP_retries = BT_CAP[7]; - } else - printk(KERN_WARNING "IPMI BT: using default values\n"); - if (!bt->BT_CAP_outreqs) - bt->BT_CAP_outreqs = 1; - printk(KERN_WARNING "IPMI BT: req2rsp=%ld secs retries=%d\n", - bt->BT_CAP_req2rsp / USEC_PER_SEC, bt->BT_CAP_retries); - bt->timeout = bt->BT_CAP_req2rsp; - return SI_SM_CALL_WITHOUT_DELAY; - default: /* should never occur */ return error_recovery(bt, status, @@ -655,6 +614,11 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) static int bt_detect(struct si_sm_data *bt) { + unsigned char GetBT_CAP[] = { 0x18, 0x36 }; + unsigned char BT_CAP[8]; + enum si_sm_result smi_result; + int rv; + /* * It's impossible for the BT status and interrupt registers to be * all 1's, (assuming a properly functioning, self-initialized BMC) @@ -665,6 +629,48 @@ static int bt_detect(struct si_sm_data *bt) if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1; reset_flags(bt); + + /* + * Try getting the BT capabilities here. + */ + rv = bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP)); + if (rv) { + dev_warn(bt->io->dev, + "Can't start capabilities transaction: %d\n", rv); + goto out_no_bt_cap; + } + + smi_result = SI_SM_CALL_WITHOUT_DELAY; + for (;;) { + if (smi_result == SI_SM_CALL_WITH_DELAY || + smi_result == SI_SM_CALL_WITH_TICK_DELAY) { + schedule_timeout_uninterruptible(1); + smi_result = bt_event(bt, jiffies_to_usecs(1)); + } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { + smi_result = bt_event(bt, 0); + } else + break; + } + + rv = bt_get_result(bt, BT_CAP, sizeof(BT_CAP)); + bt_init_data(bt, bt->io); + if (rv < 8) { + dev_warn(bt->io->dev, "bt cap response too short: %d\n", rv); + goto out_no_bt_cap; + } + + if (BT_CAP[2]) { + dev_warn(bt->io->dev, "Error fetching bt cap: %x\n", BT_CAP[2]); +out_no_bt_cap: + dev_warn(bt->io->dev, "using default values\n"); + } else { + bt->BT_CAP_req2rsp = BT_CAP[6] * USEC_PER_SEC; + bt->BT_CAP_retries = BT_CAP[7]; + } + + dev_info(bt->io->dev, "req2rsp=%ld secs retries=%d\n", + bt->BT_CAP_req2rsp / USEC_PER_SEC, bt->BT_CAP_retries); + return 0; } |