#define DEBUG /* So dev_dbg() is always available. */
#include <linux/kernel.h> /* For printk. */ #include <linux/string.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ipmi_msgdefs.h> /* for completion codes */ #include"ipmi_si_sm.h"
#define BT_DEBUG_OFF 0/* Used in production */ #define BT_DEBUG_ENABLE 1/* Generic messages */ #define BT_DEBUG_MSG 2/* Prints all request/response buffers */ #define BT_DEBUG_STATES 4/* Verbose look at state changes */ /* *BT_DEBUG_OFFmustbezerotocorrespondtothedefaultuninitialized *value
*/
enum bt_states {
BT_STATE_IDLE = 0, /* Order is critical in this list */
BT_STATE_XACTION_START,
BT_STATE_WRITE_BYTES,
BT_STATE_WRITE_CONSUME,
BT_STATE_READ_WAIT,
BT_STATE_CLEAR_B2H,
BT_STATE_READ_BYTES,
BT_STATE_RESET1, /* These must come last */
BT_STATE_RESET2,
BT_STATE_RESET3,
BT_STATE_RESTART,
BT_STATE_PRINTME,
BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */
};
struct si_sm_data { enum bt_states state; unsignedchar seq; /* BT sequence number */ struct si_sm_io *io; unsignedchar write_data[IPMI_MAX_MSG_LENGTH + 2]; /* +2 for memcpy */ int write_count; unsignedchar read_data[IPMI_MAX_MSG_LENGTH + 2]; /* +2 for memcpy */ int read_count; int truncated; long timeout; /* microseconds countdown */ int error_retries; /* end of "common" fields */ int nonzero_status; /* hung BMCs stay all 0 */ enum bt_states complete; /* to divert the state machine */ long BT_CAP_req2rsp; int BT_CAP_retries; /* Recommended retries */
};
staticchar *state2txt(unsignedchar state)
{ switch (state) { case BT_STATE_IDLE: return("IDLE"); case BT_STATE_XACTION_START: return("XACTION"); case BT_STATE_WRITE_BYTES: return("WR_BYTES"); case BT_STATE_WRITE_CONSUME: return("WR_CONSUME"); case BT_STATE_READ_WAIT: return("RD_WAIT"); case BT_STATE_CLEAR_B2H: return("CLEAR_B2H"); case BT_STATE_READ_BYTES: return("RD_BYTES"); case BT_STATE_RESET1: return("RESET1"); case BT_STATE_RESET2: return("RESET2"); case BT_STATE_RESET3: return("RESET3"); case BT_STATE_RESTART: return("RESTART"); case BT_STATE_LONG_BUSY: return("LONG_BUSY");
} return("BAD STATE");
} #define STATE2TXT state2txt(bt->state)
staticvoid drain_BMC2HOST(struct si_sm_data *bt)
{ int i, size;
if (!(BT_STATUS & BT_B2H_ATN)) /* Not signalling a response */ return;
BT_CONTROL(BT_H_BUSY); /* now set */
BT_CONTROL(BT_B2H_ATN); /* always clear */
BT_STATUS; /* pause */
BT_CONTROL(BT_B2H_ATN); /* some BMCs are stubborn */
BT_CONTROL(BT_CLR_RD_PTR); /* always reset */ if (bt_debug)
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)
pr_cont("drained %d bytes\n", size + 1);
}
staticinlinevoid write_all_bytes(struct si_sm_data *bt)
{ int i;
if (bt_debug & BT_DEBUG_MSG) {
dev_dbg(bt->io->dev, "write %d bytes seq=0x%02X",
bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++)
pr_cont(" %02x", bt->write_data[i]);
pr_cont("\n");
} for (i = 0; i < bt->write_count; i++)
HOST2BMC(bt->write_data[i]);
}
if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) { if (bt_debug & BT_DEBUG_MSG)
dev_dbg(bt->io->dev, "bad raw rsp len=%d\n", bt->read_count);
bt->truncated = 1; return1; /* let next XACTION START clean it up */
} for (i = 1; i <= bt->read_count; i++)
bt->read_data[i] = BMC2HOST;
bt->read_count++; /* Account internally for length byte */
if (bt_debug & BT_DEBUG_MSG) { int max = bt->read_count;
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++)
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 */ if ((bt->read_data[3] == bt->write_data[3]) &&
(bt->read_data[2] == bt->write_data[2]) &&
((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8))) return1;
case BT_STATE_IDLE: if (status & BT_SMS_ATN) {
BT_CONTROL(BT_SMS_ATN); /* clear it */ return SI_SM_ATTN;
}
if (status & BT_H_BUSY) /* clear a leftover H_BUSY */
BT_CONTROL(BT_H_BUSY);
BT_SI_SM_RETURN(SI_SM_IDLE);
case BT_STATE_XACTION_START: if (status & (BT_B_BUSY | BT_H2B_ATN))
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); if (BT_STATUS & BT_H_BUSY)
BT_CONTROL(BT_H_BUSY); /* force clear */
BT_STATE_CHANGE(BT_STATE_WRITE_BYTES,
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_WRITE_BYTES: if (status & BT_H_BUSY)
BT_CONTROL(BT_H_BUSY); /* clear */
BT_CONTROL(BT_CLR_WR_PTR);
write_all_bytes(bt);
BT_CONTROL(BT_H2B_ATN); /* can clear too fast to catch */
BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME,
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_WRITE_CONSUME: if (status & (BT_B_BUSY | BT_H2B_ATN))
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
BT_STATE_CHANGE(BT_STATE_READ_WAIT,
SI_SM_CALL_WITHOUT_DELAY);
/* Spinning hard can suppress B2H_ATN and force a timeout */
case BT_STATE_READ_WAIT: if (!(status & BT_B2H_ATN))
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
BT_CONTROL(BT_H_BUSY); /* set */
BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */
BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_CLEAR_B2H: if (status & BT_B2H_ATN) { /* keep hitting it */
BT_CONTROL(BT_B2H_ATN);
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
}
BT_STATE_CHANGE(BT_STATE_READ_BYTES,
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_READ_BYTES: if (!(status & BT_H_BUSY)) /* check in case of retry */
BT_CONTROL(BT_H_BUSY);
BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */
i = read_all_bytes(bt); /* true == packet seq match */
BT_CONTROL(BT_H_BUSY); /* NOW clear */ if (!i) /* Not my message */
BT_STATE_CHANGE(BT_STATE_READ_WAIT,
SI_SM_CALL_WITHOUT_DELAY);
bt->state = bt->complete; return bt->state == BT_STATE_IDLE ? /* where to next? */
SI_SM_TRANSACTION_COMPLETE : /* normal */
SI_SM_CALL_WITHOUT_DELAY; /* Startup magic */
case BT_STATE_LONG_BUSY: /* For example: after FW update */ if (!(status & BT_B_BUSY)) {
reset_flags(bt); /* next state is now IDLE */
bt_init_data(bt, bt->io);
} return SI_SM_CALL_WITH_DELAY; /* No repeat printing */
case BT_STATE_RESET1:
reset_flags(bt);
drain_BMC2HOST(bt);
BT_STATE_CHANGE(BT_STATE_RESET2,
SI_SM_CALL_WITH_DELAY);
case BT_STATE_RESET2: /* Send a soft reset */
BT_CONTROL(BT_CLR_WR_PTR);
HOST2BMC(3); /* number of bytes following */
HOST2BMC(0x18); /* NetFn/LUN == Application, LUN 0 */
HOST2BMC(42); /* Sequence number */
HOST2BMC(3); /* Cmd == Soft reset */
BT_CONTROL(BT_H2B_ATN);
bt->timeout = BT_RESET_DELAY * USEC_PER_SEC;
BT_STATE_CHANGE(BT_STATE_RESET3,
SI_SM_CALL_WITH_DELAY);
case BT_STATE_RESET3: /* Hold off everything for a bit */ if (bt->timeout > 0) return SI_SM_CALL_WITH_DELAY;
drain_BMC2HOST(bt);
BT_STATE_CHANGE(BT_STATE_RESTART,
SI_SM_CALL_WITH_DELAY);
case BT_STATE_RESTART: /* don't reset retries or seq! */
bt->read_count = 0;
bt->nonzero_status = 0;
bt->timeout = bt->BT_CAP_req2rsp;
BT_STATE_CHANGE(BT_STATE_XACTION_START,
SI_SM_CALL_WITH_DELAY);
default: /* should never occur */ return error_recovery(bt,
status,
IPMI_ERR_UNSPECIFIED);
} return SI_SM_CALL_WITH_DELAY;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.