You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
[PATCH] IPMI: Fix BT long busy
The IPMI BT subdriver has been patched to survive "long busy" timeouts seen during firmware upgrades and resets. The patch never returns the HOSED state, synthesizes response messages with meaningful completion codes, and recovers gracefully when the hardware finishes the long busy. The subdriver now issues a "Get BT Capabilities" command and properly uses those results. More informative completion codes are returned on error from transaction starts; this logic was propogated to the KCS and SMIC subdrivers. Finally, indent and other style quirks were normalized. Signed-off-by: Rocky Craig <rocky.craig@hp.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>
This commit is contained in:
committed by
Linus Torvalds
parent
168b35a7f6
commit
4d7cbac7c8
+389
-244
File diff suppressed because it is too large
Load Diff
@@ -261,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 ++) {
|
||||
|
||||
@@ -247,14 +247,18 @@ static void deliver_recv_msg(struct smi_info *smi_info,
|
||||
spin_lock(&(smi_info->si_lock));
|
||||
}
|
||||
|
||||
static void return_hosed_msg(struct smi_info *smi_info)
|
||||
static void return_hosed_msg(struct smi_info *smi_info, int cCode)
|
||||
{
|
||||
struct ipmi_smi_msg *msg = smi_info->curr_msg;
|
||||
|
||||
if (cCode < 0 || cCode > IPMI_ERR_UNSPECIFIED)
|
||||
cCode = IPMI_ERR_UNSPECIFIED;
|
||||
/* else use it as is */
|
||||
|
||||
/* Make it a reponse */
|
||||
msg->rsp[0] = msg->data[0] | 4;
|
||||
msg->rsp[1] = msg->data[1];
|
||||
msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
|
||||
msg->rsp[2] = cCode;
|
||||
msg->rsp_size = 3;
|
||||
|
||||
smi_info->curr_msg = NULL;
|
||||
@@ -305,7 +309,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
|
||||
smi_info->curr_msg->data,
|
||||
smi_info->curr_msg->data_size);
|
||||
if (err) {
|
||||
return_hosed_msg(smi_info);
|
||||
return_hosed_msg(smi_info, err);
|
||||
}
|
||||
|
||||
rv = SI_SM_CALL_WITHOUT_DELAY;
|
||||
@@ -647,7 +651,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
|
||||
/* If we were handling a user message, format
|
||||
a response to send to the upper layer to
|
||||
tell it about the error. */
|
||||
return_hosed_msg(smi_info);
|
||||
return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED);
|
||||
}
|
||||
si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
|
||||
}
|
||||
|
||||
@@ -141,12 +141,14 @@ static int start_smic_transaction(struct si_sm_data *smic,
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if ((size < 2) || (size > MAX_SMIC_WRITE_SIZE)) {
|
||||
return -1;
|
||||
}
|
||||
if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) {
|
||||
return -2;
|
||||
}
|
||||
if (size < 2)
|
||||
return IPMI_REQ_LEN_INVALID_ERR;
|
||||
if (size > MAX_SMIC_WRITE_SIZE)
|
||||
return IPMI_REQ_LEN_EXCEEDED_ERR;
|
||||
|
||||
if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED))
|
||||
return IPMI_NOT_IN_MY_STATE_ERR;
|
||||
|
||||
if (smic_debug & SMIC_DEBUG_MSG) {
|
||||
printk(KERN_INFO "start_smic_transaction -");
|
||||
for (i = 0; i < size; i ++) {
|
||||
|
||||
@@ -71,14 +71,18 @@
|
||||
/* The BT interface on high-end HP systems supports up to 255 bytes in
|
||||
* one transfer. Its "virtual" BMC supports some commands that are longer
|
||||
* than 128 bytes. Use the full 256, plus NetFn/LUN, Cmd, cCode, plus
|
||||
* some overhead. It would be nice to base this on the "BT Capabilities"
|
||||
* but that's too hard to propagate to the rest of the driver. */
|
||||
* some overhead; it's not worth the effort to dynamically size this based
|
||||
* on the results of the "Get BT Capabilities" command. */
|
||||
#define IPMI_MAX_MSG_LENGTH 272 /* multiple of 16 */
|
||||
|
||||
#define IPMI_CC_NO_ERROR 0x00
|
||||
#define IPMI_NODE_BUSY_ERR 0xc0
|
||||
#define IPMI_INVALID_COMMAND_ERR 0xc1
|
||||
#define IPMI_TIMEOUT_ERR 0xc3
|
||||
#define IPMI_ERR_MSG_TRUNCATED 0xc6
|
||||
#define IPMI_REQ_LEN_INVALID_ERR 0xc7
|
||||
#define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8
|
||||
#define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */
|
||||
#define IPMI_LOST_ARBITRATION_ERR 0x81
|
||||
#define IPMI_BUS_ERR 0x82
|
||||
#define IPMI_NAK_ON_WRITE_ERR 0x83
|
||||
|
||||
Reference in New Issue
Block a user