Commit 42c2dc7e authored by Corey Minyard's avatar Corey Minyard

ipmi: Break up i_ipmi_request

It was huge, and easily broken into pieces.
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
parent 6dc1181f
...@@ -1703,81 +1703,25 @@ static bool is_maintenance_mode_cmd(struct kernel_ipmi_msg *msg) ...@@ -1703,81 +1703,25 @@ static bool is_maintenance_mode_cmd(struct kernel_ipmi_msg *msg)
|| (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)); || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST));
} }
/* static int i_ipmi_req_sysintf(ipmi_smi_t intf,
* Separate from ipmi_request so that the user does not have to be
* supplied in certain circumstances (mainly at panic time). If
* messages are supplied, they will be freed, even if an error
* occurs.
*/
static int i_ipmi_request(ipmi_user_t user,
ipmi_smi_t intf,
struct ipmi_addr *addr, struct ipmi_addr *addr,
long msgid, long msgid,
struct kernel_ipmi_msg *msg, struct kernel_ipmi_msg *msg,
void *user_msg_data, struct ipmi_smi_msg *smi_msg,
void *supplied_smi, struct ipmi_recv_msg *recv_msg,
struct ipmi_recv_msg *supplied_recv,
int priority,
unsigned char source_address,
unsigned char source_lun,
int retries, int retries,
unsigned int retry_time_ms) unsigned int retry_time_ms)
{ {
int rv = 0;
struct ipmi_smi_msg *smi_msg;
struct ipmi_recv_msg *recv_msg;
unsigned long flags;
if (supplied_recv)
recv_msg = supplied_recv;
else {
recv_msg = ipmi_alloc_recv_msg();
if (recv_msg == NULL)
return -ENOMEM;
}
recv_msg->user_msg_data = user_msg_data;
if (supplied_smi)
smi_msg = (struct ipmi_smi_msg *) supplied_smi;
else {
smi_msg = ipmi_alloc_smi_msg();
if (smi_msg == NULL) {
ipmi_free_recv_msg(recv_msg);
return -ENOMEM;
}
}
rcu_read_lock();
if (intf->in_shutdown) {
rv = -ENODEV;
goto out_err;
}
recv_msg->user = user;
if (user)
kref_get(&user->refcount);
recv_msg->msgid = msgid;
/*
* Store the message to send in the receive message so timeout
* responses can get the proper response data.
*/
recv_msg->msg = *msg;
if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
struct ipmi_system_interface_addr *smi_addr; struct ipmi_system_interface_addr *smi_addr;
if (msg->netfn & 1) { if (msg->netfn & 1)
/* Responses are not allowed to the SMI. */ /* Responses are not allowed to the SMI. */
rv = -EINVAL; return -EINVAL;
goto out_err;
}
smi_addr = (struct ipmi_system_interface_addr *) addr; smi_addr = (struct ipmi_system_interface_addr *) addr;
if (smi_addr->lun > 3) { if (smi_addr->lun > 3) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr)); memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));
...@@ -1791,11 +1735,12 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1791,11 +1735,12 @@ static int i_ipmi_request(ipmi_user_t user,
* the sequence numbers. * the sequence numbers.
*/ */
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
if (is_maintenance_mode_cmd(msg)) { if (is_maintenance_mode_cmd(msg)) {
unsigned long flags;
spin_lock_irqsave(&intf->maintenance_mode_lock, flags); spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
intf->auto_maintenance_timeout intf->auto_maintenance_timeout
= maintenance_mode_timeout_ms; = maintenance_mode_timeout_ms;
...@@ -1808,10 +1753,9 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1808,10 +1753,9 @@ static int i_ipmi_request(ipmi_user_t user,
flags); flags);
} }
if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { if (msg->data_len + 2 > IPMI_MAX_MSG_LENGTH) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE; return -EMSGSIZE;
goto out_err;
} }
smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3); smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);
...@@ -1819,28 +1763,41 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1819,28 +1763,41 @@ static int i_ipmi_request(ipmi_user_t user,
smi_msg->msgid = msgid; smi_msg->msgid = msgid;
smi_msg->user_data = recv_msg; smi_msg->user_data = recv_msg;
if (msg->data_len > 0) if (msg->data_len > 0)
memcpy(&(smi_msg->data[2]), msg->data, msg->data_len); memcpy(&smi_msg->data[2], msg->data, msg->data_len);
smi_msg->data_size = msg->data_len + 2; smi_msg->data_size = msg->data_len + 2;
ipmi_inc_stat(intf, sent_local_commands); ipmi_inc_stat(intf, sent_local_commands);
} else if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {
return 0;
}
static int i_ipmi_req_ipmb(ipmi_smi_t intf,
struct ipmi_addr *addr,
long msgid,
struct kernel_ipmi_msg *msg,
struct ipmi_smi_msg *smi_msg,
struct ipmi_recv_msg *recv_msg,
unsigned char source_address,
unsigned char source_lun,
int retries,
unsigned int retry_time_ms)
{
struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_ipmb_addr *ipmb_addr;
unsigned char ipmb_seq; unsigned char ipmb_seq;
long seqid; long seqid;
int broadcast = 0; int broadcast = 0;
struct ipmi_channel *chans; struct ipmi_channel *chans;
int rv = 0;
if (addr->channel >= IPMI_MAX_CHANNELS) { if (addr->channel >= IPMI_MAX_CHANNELS) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
chans = READ_ONCE(intf->channel_list)->c; chans = READ_ONCE(intf->channel_list)->c;
if (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB) { if (chans[addr->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) { if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
...@@ -1860,15 +1817,13 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1860,15 +1817,13 @@ static int i_ipmi_request(ipmi_user_t user,
*/ */
if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) { if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE; return -EMSGSIZE;
goto out_err;
} }
ipmb_addr = (struct ipmi_ipmb_addr *) addr; ipmb_addr = (struct ipmi_ipmb_addr *) addr;
if (ipmb_addr->lun > 3) { if (ipmb_addr->lun > 3) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr)); memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
...@@ -1890,15 +1845,15 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1890,15 +1845,15 @@ static int i_ipmi_request(ipmi_user_t user,
smi_msg->user_data = recv_msg; smi_msg->user_data = recv_msg;
} else { } else {
/* It's a command, so get a sequence for it. */ /* It's a command, so get a sequence for it. */
unsigned long flags;
spin_lock_irqsave(&(intf->seq_lock), flags); spin_lock_irqsave(&intf->seq_lock, flags);
if (is_maintenance_mode_cmd(msg)) if (is_maintenance_mode_cmd(msg))
intf->ipmb_maintenance_mode_timeout = intf->ipmb_maintenance_mode_timeout =
maintenance_mode_timeout_ms; maintenance_mode_timeout_ms;
if (intf->ipmb_maintenance_mode_timeout && if (intf->ipmb_maintenance_mode_timeout && retry_time_ms == 0)
retry_time_ms == 0)
/* Different default in maintenance mode */ /* Different default in maintenance mode */
retry_time_ms = default_maintenance_retry_ms; retry_time_ms = default_maintenance_retry_ms;
...@@ -1913,15 +1868,12 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1913,15 +1868,12 @@ static int i_ipmi_request(ipmi_user_t user,
broadcast, broadcast,
&ipmb_seq, &ipmb_seq,
&seqid); &seqid);
if (rv) { if (rv)
/* /*
* We have used up all the sequence numbers, * We have used up all the sequence numbers,
* probably, so abort. * probably, so abort.
*/ */
spin_unlock_irqrestore(&(intf->seq_lock),
flags);
goto out_err; goto out_err;
}
ipmi_inc_stat(intf, sent_ipmb_commands); ipmi_inc_stat(intf, sent_ipmb_commands);
...@@ -1952,18 +1904,32 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1952,18 +1904,32 @@ static int i_ipmi_request(ipmi_user_t user,
* know that's pretty paranoid, but I prefer * know that's pretty paranoid, but I prefer
* to be correct. * to be correct.
*/ */
spin_unlock_irqrestore(&(intf->seq_lock), flags); out_err:
spin_unlock_irqrestore(&intf->seq_lock, flags);
} }
} else if (is_lan_addr(addr)) {
return rv;
}
static int i_ipmi_req_lan(ipmi_smi_t intf,
struct ipmi_addr *addr,
long msgid,
struct kernel_ipmi_msg *msg,
struct ipmi_smi_msg *smi_msg,
struct ipmi_recv_msg *recv_msg,
unsigned char source_lun,
int retries,
unsigned int retry_time_ms)
{
struct ipmi_lan_addr *lan_addr; struct ipmi_lan_addr *lan_addr;
unsigned char ipmb_seq; unsigned char ipmb_seq;
long seqid; long seqid;
struct ipmi_channel *chans; struct ipmi_channel *chans;
int rv = 0;
if (addr->channel >= IPMI_MAX_CHANNELS) { if (addr->channel >= IPMI_MAX_CHANNELS) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
chans = READ_ONCE(intf->channel_list)->c; chans = READ_ONCE(intf->channel_list)->c;
...@@ -1973,22 +1939,19 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -1973,22 +1939,19 @@ static int i_ipmi_request(ipmi_user_t user,
&& (chans[addr->channel].medium && (chans[addr->channel].medium
!= IPMI_CHANNEL_MEDIUM_ASYNC)) { != IPMI_CHANNEL_MEDIUM_ASYNC)) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
/* 11 for the header and 1 for the checksum. */ /* 11 for the header and 1 for the checksum. */
if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) { if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE; return -EMSGSIZE;
goto out_err;
} }
lan_addr = (struct ipmi_lan_addr *) addr; lan_addr = (struct ipmi_lan_addr *) addr;
if (lan_addr->lun > 3) { if (lan_addr->lun > 3) {
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; return -EINVAL;
goto out_err;
} }
memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr)); memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
...@@ -2009,8 +1972,9 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -2009,8 +1972,9 @@ static int i_ipmi_request(ipmi_user_t user,
smi_msg->user_data = recv_msg; smi_msg->user_data = recv_msg;
} else { } else {
/* It's a command, so get a sequence for it. */ /* It's a command, so get a sequence for it. */
unsigned long flags;
spin_lock_irqsave(&(intf->seq_lock), flags); spin_lock_irqsave(&intf->seq_lock, flags);
/* /*
* Create a sequence number with a 1 second * Create a sequence number with a 1 second
...@@ -2023,15 +1987,12 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -2023,15 +1987,12 @@ static int i_ipmi_request(ipmi_user_t user,
0, 0,
&ipmb_seq, &ipmb_seq,
&seqid); &seqid);
if (rv) { if (rv)
/* /*
* We have used up all the sequence numbers, * We have used up all the sequence numbers,
* probably, so abort. * probably, so abort.
*/ */
spin_unlock_irqrestore(&(intf->seq_lock),
flags);
goto out_err; goto out_err;
}
ipmi_inc_stat(intf, sent_lan_commands); ipmi_inc_stat(intf, sent_lan_commands);
...@@ -2061,26 +2022,99 @@ static int i_ipmi_request(ipmi_user_t user, ...@@ -2061,26 +2022,99 @@ static int i_ipmi_request(ipmi_user_t user,
* know that's pretty paranoid, but I prefer * know that's pretty paranoid, but I prefer
* to be correct. * to be correct.
*/ */
spin_unlock_irqrestore(&(intf->seq_lock), flags); out_err:
spin_unlock_irqrestore(&intf->seq_lock, flags);
} }
return rv;
}
/*
* Separate from ipmi_request so that the user does not have to be
* supplied in certain circumstances (mainly at panic time). If
* messages are supplied, they will be freed, even if an error
* occurs.
*/
static int i_ipmi_request(ipmi_user_t user,
ipmi_smi_t intf,
struct ipmi_addr *addr,
long msgid,
struct kernel_ipmi_msg *msg,
void *user_msg_data,
void *supplied_smi,
struct ipmi_recv_msg *supplied_recv,
int priority,
unsigned char source_address,
unsigned char source_lun,
int retries,
unsigned int retry_time_ms)
{
struct ipmi_smi_msg *smi_msg;
struct ipmi_recv_msg *recv_msg;
int rv = 0;
if (supplied_recv)
recv_msg = supplied_recv;
else {
recv_msg = ipmi_alloc_recv_msg();
if (recv_msg == NULL)
return -ENOMEM;
}
recv_msg->user_msg_data = user_msg_data;
if (supplied_smi)
smi_msg = (struct ipmi_smi_msg *) supplied_smi;
else {
smi_msg = ipmi_alloc_smi_msg();
if (smi_msg == NULL) {
ipmi_free_recv_msg(recv_msg);
return -ENOMEM;
}
}
rcu_read_lock();
if (intf->in_shutdown) {
rv = -ENODEV;
goto out_err;
}
recv_msg->user = user;
if (user)
kref_get(&user->refcount);
recv_msg->msgid = msgid;
/*
* Store the message to send in the receive message so timeout
* responses can get the proper response data.
*/
recv_msg->msg = *msg;
if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
rv = i_ipmi_req_sysintf(intf, addr, msgid, msg, smi_msg,
recv_msg, retries, retry_time_ms);
} else if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {
rv = i_ipmi_req_ipmb(intf, addr, msgid, msg, smi_msg, recv_msg,
source_address, source_lun,
retries, retry_time_ms);
} else if (is_lan_addr(addr)) {
rv = i_ipmi_req_lan(intf, addr, msgid, msg, smi_msg, recv_msg,
source_lun, retries, retry_time_ms);
} else { } else {
/* Unknown address type. */ /* Unknown address type. */
ipmi_inc_stat(intf, sent_invalid_commands); ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL; rv = -EINVAL;
goto out_err;
} }
if (rv) {
out_err:
ipmi_free_smi_msg(smi_msg);
ipmi_free_recv_msg(recv_msg);
} else {
ipmi_debug_msg("Send", smi_msg->data, smi_msg->data_size); ipmi_debug_msg("Send", smi_msg->data, smi_msg->data_size);
smi_send(intf, intf->handlers, smi_msg, priority); smi_send(intf, intf->handlers, smi_msg, priority);
}
rcu_read_unlock(); rcu_read_unlock();
return 0;
out_err:
rcu_read_unlock();
ipmi_free_smi_msg(smi_msg);
ipmi_free_recv_msg(recv_msg);
return rv; return rv;
} }
......
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