Commit 40112ae7 authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds

ipmi: test for event buffer before using

The IPMI driver would attempt to use the event buffer even if that
didn't exist on the BMC.  This patch modified the IPMI driver to check
for the event buffer's existence before trying to use it.
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8b32b5d0
...@@ -82,12 +82,6 @@ ...@@ -82,12 +82,6 @@
#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a #define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a
short timeout */ short timeout */
/* Bit for BMC global enables. */
#define IPMI_BMC_RCV_MSG_INTR 0x01
#define IPMI_BMC_EVT_MSG_INTR 0x02
#define IPMI_BMC_EVT_MSG_BUFF 0x04
#define IPMI_BMC_SYS_LOG 0x08
enum si_intf_state { enum si_intf_state {
SI_NORMAL, SI_NORMAL,
SI_GETTING_FLAGS, SI_GETTING_FLAGS,
...@@ -220,6 +214,9 @@ struct smi_info { ...@@ -220,6 +214,9 @@ struct smi_info {
OEM2_DATA_AVAIL) OEM2_DATA_AVAIL)
unsigned char msg_flags; unsigned char msg_flags;
/* Does the BMC have an event buffer? */
char has_event_buffer;
/* /*
* If set to true, this will request events the next time the * If set to true, this will request events the next time the
* state machine is idle. * state machine is idle.
...@@ -968,7 +965,8 @@ static void request_events(void *send_info) ...@@ -968,7 +965,8 @@ static void request_events(void *send_info)
{ {
struct smi_info *smi_info = send_info; struct smi_info *smi_info = send_info;
if (atomic_read(&smi_info->stop_operation)) if (atomic_read(&smi_info->stop_operation) ||
!smi_info->has_event_buffer)
return; return;
atomic_set(&smi_info->req_events, 1); atomic_set(&smi_info->req_events, 1);
...@@ -2407,26 +2405,9 @@ static struct of_platform_driver ipmi_of_platform_driver = { ...@@ -2407,26 +2405,9 @@ static struct of_platform_driver ipmi_of_platform_driver = {
}; };
#endif /* CONFIG_PPC_OF */ #endif /* CONFIG_PPC_OF */
static int wait_for_msg_done(struct smi_info *smi_info)
static int try_get_dev_id(struct smi_info *smi_info)
{ {
unsigned char msg[2];
unsigned char *resp;
unsigned long resp_len;
enum si_sm_result smi_result; enum si_sm_result smi_result;
int rv = 0;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
if (!resp)
return -ENOMEM;
/*
* Do a Get Device ID command, since it comes back with some
* useful info.
*/
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_DEVICE_ID_CMD;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
smi_result = smi_info->handlers->event(smi_info->si_sm, 0); smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
for (;;) { for (;;) {
...@@ -2441,16 +2422,39 @@ static int try_get_dev_id(struct smi_info *smi_info) ...@@ -2441,16 +2422,39 @@ static int try_get_dev_id(struct smi_info *smi_info)
} else } else
break; break;
} }
if (smi_result == SI_SM_HOSED) { if (smi_result == SI_SM_HOSED)
/* /*
* We couldn't get the state machine to run, so whatever's at * We couldn't get the state machine to run, so whatever's at
* the port is probably not an IPMI SMI interface. * the port is probably not an IPMI SMI interface.
*/ */
rv = -ENODEV; return -ENODEV;
return 0;
}
static int try_get_dev_id(struct smi_info *smi_info)
{
unsigned char msg[2];
unsigned char *resp;
unsigned long resp_len;
int rv = 0;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
if (!resp)
return -ENOMEM;
/*
* Do a Get Device ID command, since it comes back with some
* useful info.
*/
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_DEVICE_ID_CMD;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
rv = wait_for_msg_done(smi_info);
if (rv)
goto out; goto out;
}
/* Otherwise, we got some data. */
resp_len = smi_info->handlers->get_result(smi_info->si_sm, resp_len = smi_info->handlers->get_result(smi_info->si_sm,
resp, IPMI_MAX_MSG_LENGTH); resp, IPMI_MAX_MSG_LENGTH);
...@@ -2462,6 +2466,88 @@ static int try_get_dev_id(struct smi_info *smi_info) ...@@ -2462,6 +2466,88 @@ static int try_get_dev_id(struct smi_info *smi_info)
return rv; return rv;
} }
static int try_enable_event_buffer(struct smi_info *smi_info)
{
unsigned char msg[3];
unsigned char *resp;
unsigned long resp_len;
int rv = 0;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
if (!resp)
return -ENOMEM;
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
rv = wait_for_msg_done(smi_info);
if (rv) {
printk(KERN_WARNING
"ipmi_si: Error getting response from get global,"
" enables command, the event buffer is not"
" enabled.\n");
goto out;
}
resp_len = smi_info->handlers->get_result(smi_info->si_sm,
resp, IPMI_MAX_MSG_LENGTH);
if (resp_len < 4 ||
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD ||
resp[2] != 0) {
printk(KERN_WARNING
"ipmi_si: Invalid return from get global"
" enables command, cannot enable the event"
" buffer.\n");
rv = -EINVAL;
goto out;
}
if (resp[3] & IPMI_BMC_EVT_MSG_BUFF)
/* buffer is already enabled, nothing to do. */
goto out;
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
rv = wait_for_msg_done(smi_info);
if (rv) {
printk(KERN_WARNING
"ipmi_si: Error getting response from set global,"
" enables command, the event buffer is not"
" enabled.\n");
goto out;
}
resp_len = smi_info->handlers->get_result(smi_info->si_sm,
resp, IPMI_MAX_MSG_LENGTH);
if (resp_len < 3 ||
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
printk(KERN_WARNING
"ipmi_si: Invalid return from get global,"
"enables command, not enable the event"
" buffer.\n");
rv = -EINVAL;
goto out;
}
if (resp[2] != 0)
/*
* An error when setting the event buffer bit means
* that the event buffer is not supported.
*/
rv = -ENOENT;
out:
kfree(resp);
return rv;
}
static int type_file_read_proc(char *page, char **start, off_t off, static int type_file_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
...@@ -2847,6 +2933,10 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2847,6 +2933,10 @@ static int try_smi_init(struct smi_info *new_smi)
new_smi->intf_num = smi_num; new_smi->intf_num = smi_num;
smi_num++; smi_num++;
rv = try_enable_event_buffer(new_smi);
if (rv == 0)
new_smi->has_event_buffer = 1;
/* /*
* Start clearing the flags before we enable interrupts or the * Start clearing the flags before we enable interrupts or the
* timer to avoid racing with the timer. * timer to avoid racing with the timer.
......
...@@ -58,6 +58,12 @@ ...@@ -58,6 +58,12 @@
#define IPMI_READ_EVENT_MSG_BUFFER_CMD 0x35 #define IPMI_READ_EVENT_MSG_BUFFER_CMD 0x35
#define IPMI_GET_CHANNEL_INFO_CMD 0x42 #define IPMI_GET_CHANNEL_INFO_CMD 0x42
/* Bit for BMC global enables. */
#define IPMI_BMC_RCV_MSG_INTR 0x01
#define IPMI_BMC_EVT_MSG_INTR 0x02
#define IPMI_BMC_EVT_MSG_BUFF 0x04
#define IPMI_BMC_SYS_LOG 0x08
#define IPMI_NETFN_STORAGE_REQUEST 0x0a #define IPMI_NETFN_STORAGE_REQUEST 0x0a
#define IPMI_NETFN_STORAGE_RESPONSE 0x0b #define IPMI_NETFN_STORAGE_RESPONSE 0x0b
#define IPMI_ADD_SEL_ENTRY_CMD 0x44 #define IPMI_ADD_SEL_ENTRY_CMD 0x44
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment