mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-21 06:01:23 +00:00
ipmi: add oem message handling
Enable userspace to receive messages that a BMC transmits using an OEM medium. This is used by the HP iLO2. Based on code originally written by Patrick Schoeller. Signed-off-by: dann frazier <dannf@hp.com> Signed-off-by: Corey Minyard <cminyard@mvista.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
25176ed670
commit
4dec302ff7
3 changed files with 137 additions and 5 deletions
|
@ -3284,6 +3284,114 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine will handle "Get Message" command responses with
|
||||||
|
* channels that use an OEM Medium. The message format belongs to
|
||||||
|
* the OEM. See IPMI 2.0 specification, Chapter 6 and
|
||||||
|
* Chapter 22, sections 22.6 and 22.24 for more details.
|
||||||
|
*/
|
||||||
|
static int handle_oem_get_msg_cmd(ipmi_smi_t intf,
|
||||||
|
struct ipmi_smi_msg *msg)
|
||||||
|
{
|
||||||
|
struct cmd_rcvr *rcvr;
|
||||||
|
int rv = 0;
|
||||||
|
unsigned char netfn;
|
||||||
|
unsigned char cmd;
|
||||||
|
unsigned char chan;
|
||||||
|
ipmi_user_t user = NULL;
|
||||||
|
struct ipmi_system_interface_addr *smi_addr;
|
||||||
|
struct ipmi_recv_msg *recv_msg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We expect the OEM SW to perform error checking
|
||||||
|
* so we just do some basic sanity checks
|
||||||
|
*/
|
||||||
|
if (msg->rsp_size < 4) {
|
||||||
|
/* Message not big enough, just ignore it. */
|
||||||
|
ipmi_inc_stat(intf, invalid_commands);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->rsp[2] != 0) {
|
||||||
|
/* An error getting the response, just ignore it. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is an OEM Message so the OEM needs to know how
|
||||||
|
* handle the message. We do no interpretation.
|
||||||
|
*/
|
||||||
|
netfn = msg->rsp[0] >> 2;
|
||||||
|
cmd = msg->rsp[1];
|
||||||
|
chan = msg->rsp[3] & 0xf;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
|
||||||
|
if (rcvr) {
|
||||||
|
user = rcvr->user;
|
||||||
|
kref_get(&user->refcount);
|
||||||
|
} else
|
||||||
|
user = NULL;
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
if (user == NULL) {
|
||||||
|
/* We didn't find a user, just give up. */
|
||||||
|
ipmi_inc_stat(intf, unhandled_commands);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't do anything with these messages, just allow
|
||||||
|
* them to be freed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rv = 0;
|
||||||
|
} else {
|
||||||
|
/* Deliver the message to the user. */
|
||||||
|
ipmi_inc_stat(intf, handled_commands);
|
||||||
|
|
||||||
|
recv_msg = ipmi_alloc_recv_msg();
|
||||||
|
if (!recv_msg) {
|
||||||
|
/*
|
||||||
|
* We couldn't allocate memory for the
|
||||||
|
* message, so requeue it for handling
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
rv = 1;
|
||||||
|
kref_put(&user->refcount, free_user);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* OEM Messages are expected to be delivered via
|
||||||
|
* the system interface to SMS software. We might
|
||||||
|
* need to visit this again depending on OEM
|
||||||
|
* requirements
|
||||||
|
*/
|
||||||
|
smi_addr = ((struct ipmi_system_interface_addr *)
|
||||||
|
&(recv_msg->addr));
|
||||||
|
smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
|
||||||
|
smi_addr->channel = IPMI_BMC_CHANNEL;
|
||||||
|
smi_addr->lun = msg->rsp[0] & 3;
|
||||||
|
|
||||||
|
recv_msg->user = user;
|
||||||
|
recv_msg->user_msg_data = NULL;
|
||||||
|
recv_msg->recv_type = IPMI_OEM_RECV_TYPE;
|
||||||
|
recv_msg->msg.netfn = msg->rsp[0] >> 2;
|
||||||
|
recv_msg->msg.cmd = msg->rsp[1];
|
||||||
|
recv_msg->msg.data = recv_msg->msg_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The message starts at byte 4 which follows the
|
||||||
|
* the Channel Byte in the "GET MESSAGE" command
|
||||||
|
*/
|
||||||
|
recv_msg->msg.data_len = msg->rsp_size - 4;
|
||||||
|
memcpy(recv_msg->msg_data,
|
||||||
|
&(msg->rsp[4]),
|
||||||
|
msg->rsp_size - 4);
|
||||||
|
deliver_response(recv_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
|
static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
|
||||||
struct ipmi_smi_msg *msg)
|
struct ipmi_smi_msg *msg)
|
||||||
{
|
{
|
||||||
|
@ -3539,6 +3647,17 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** We need to make sure the channels have been initialized.
|
||||||
|
** The channel_handler routine will set the "curr_channel"
|
||||||
|
** equal to or greater than IPMI_MAX_CHANNELS when all the
|
||||||
|
** channels for this interface have been initialized.
|
||||||
|
*/
|
||||||
|
if (intf->curr_channel < IPMI_MAX_CHANNELS) {
|
||||||
|
requeue = 1; /* Just put the message back for now */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
switch (intf->channels[chan].medium) {
|
switch (intf->channels[chan].medium) {
|
||||||
case IPMI_CHANNEL_MEDIUM_IPMB:
|
case IPMI_CHANNEL_MEDIUM_IPMB:
|
||||||
if (msg->rsp[4] & 0x04) {
|
if (msg->rsp[4] & 0x04) {
|
||||||
|
@ -3574,12 +3693,21 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
/* Check for OEM Channels. Clients had better
|
||||||
|
register for these commands. */
|
||||||
|
if ((intf->channels[chan].medium
|
||||||
|
>= IPMI_CHANNEL_MEDIUM_OEM_MIN)
|
||||||
|
&& (intf->channels[chan].medium
|
||||||
|
<= IPMI_CHANNEL_MEDIUM_OEM_MAX)) {
|
||||||
|
requeue = handle_oem_get_msg_cmd(intf, msg);
|
||||||
|
} else {
|
||||||
/*
|
/*
|
||||||
* We don't handle the channel type, so just
|
* We don't handle the channel type, so just
|
||||||
* free the message.
|
* free the message.
|
||||||
*/
|
*/
|
||||||
requeue = 0;
|
requeue = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
|
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
|
||||||
&& (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
|
&& (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
|
||||||
|
|
|
@ -198,6 +198,8 @@ struct kernel_ipmi_msg {
|
||||||
response. When you send a
|
response. When you send a
|
||||||
response message, this will
|
response message, this will
|
||||||
be returned. */
|
be returned. */
|
||||||
|
#define IPMI_OEM_RECV_TYPE 5 /* The response for OEM Channels */
|
||||||
|
|
||||||
/* Note that async events and received commands do not have a completion
|
/* Note that async events and received commands do not have a completion
|
||||||
code as the first byte of the incoming data, unlike a response. */
|
code as the first byte of the incoming data, unlike a response. */
|
||||||
|
|
||||||
|
|
|
@ -115,5 +115,7 @@
|
||||||
#define IPMI_CHANNEL_MEDIUM_USB1 10
|
#define IPMI_CHANNEL_MEDIUM_USB1 10
|
||||||
#define IPMI_CHANNEL_MEDIUM_USB2 11
|
#define IPMI_CHANNEL_MEDIUM_USB2 11
|
||||||
#define IPMI_CHANNEL_MEDIUM_SYSINTF 12
|
#define IPMI_CHANNEL_MEDIUM_SYSINTF 12
|
||||||
|
#define IPMI_CHANNEL_MEDIUM_OEM_MIN 0x60
|
||||||
|
#define IPMI_CHANNEL_MEDIUM_OEM_MAX 0x7f
|
||||||
|
|
||||||
#endif /* __LINUX_IPMI_MSGDEFS_H */
|
#endif /* __LINUX_IPMI_MSGDEFS_H */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue