mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-15 22:31:47 -04:00
ipmi:msghandler: Export and fix panic messaging capability
Don't have the other users that do things at panic time (the watchdog) do all this themselves, provide a function to do it. Also, with the new design where most stuff happens at thread context, a few things needed to be fixed to avoid doing locking in a panic context. Signed-off-by: Corey Minyard <cminyard@mvista.com>
This commit is contained in:
@@ -2284,6 +2284,7 @@ static int i_ipmi_request(struct ipmi_user *user,
|
||||
{
|
||||
struct ipmi_smi_msg *smi_msg;
|
||||
struct ipmi_recv_msg *recv_msg;
|
||||
int run_to_completion = READ_ONCE(intf->run_to_completion);
|
||||
int rv = 0;
|
||||
|
||||
if (user) {
|
||||
@@ -2317,7 +2318,8 @@ static int i_ipmi_request(struct ipmi_user *user,
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&intf->users_mutex);
|
||||
if (!run_to_completion)
|
||||
mutex_lock(&intf->users_mutex);
|
||||
if (intf->in_shutdown) {
|
||||
rv = -ENODEV;
|
||||
goto out_err;
|
||||
@@ -2363,7 +2365,8 @@ static int i_ipmi_request(struct ipmi_user *user,
|
||||
|
||||
smi_send(intf, intf->handlers, smi_msg, priority);
|
||||
}
|
||||
mutex_unlock(&intf->users_mutex);
|
||||
if (!run_to_completion)
|
||||
mutex_unlock(&intf->users_mutex);
|
||||
|
||||
out:
|
||||
if (rv && user)
|
||||
@@ -4559,7 +4562,7 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
|
||||
&& (msg->data[1] == IPMI_SEND_MSG_CMD)
|
||||
&& (msg->user_data == NULL)) {
|
||||
|
||||
if (intf->in_shutdown)
|
||||
if (intf->in_shutdown || intf->run_to_completion)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@@ -4631,6 +4634,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
|
||||
*/
|
||||
struct ipmi_recv_msg *recv_msg;
|
||||
|
||||
if (intf->run_to_completion)
|
||||
goto out;
|
||||
|
||||
chan = msg->data[2] & 0x0f;
|
||||
if (chan >= IPMI_MAX_CHANNELS)
|
||||
/* Invalid channel number */
|
||||
@@ -4653,6 +4659,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
|
||||
&& (msg->rsp[1] == IPMI_GET_MSG_CMD)) {
|
||||
struct ipmi_channel *chans;
|
||||
|
||||
if (intf->run_to_completion)
|
||||
goto out;
|
||||
|
||||
/* It's from the receive queue. */
|
||||
chan = msg->rsp[3] & 0xf;
|
||||
if (chan >= IPMI_MAX_CHANNELS) {
|
||||
@@ -4727,6 +4736,9 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
|
||||
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
|
||||
&& (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
|
||||
/* It's an asynchronous event. */
|
||||
if (intf->run_to_completion)
|
||||
goto out;
|
||||
|
||||
requeue = handle_read_event_rsp(intf, msg);
|
||||
} else {
|
||||
/* It's a response from the local BMC. */
|
||||
@@ -4855,15 +4867,6 @@ static void smi_work(struct work_struct *t)
|
||||
|
||||
list_del(&msg->link);
|
||||
|
||||
/*
|
||||
* I would like for this check (and user->destroyed)
|
||||
* to go away, but it's possible that an interface is
|
||||
* processing a message that belongs to the user while
|
||||
* the user is being deleted. When that response
|
||||
* comes back, it could be queued after the user is
|
||||
* destroyed. This is simpler than handling it in the
|
||||
* interface.
|
||||
*/
|
||||
if (refcount_read(&user->destroyed) == 0) {
|
||||
ipmi_free_recv_msg(msg);
|
||||
} else {
|
||||
@@ -5222,9 +5225,9 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
|
||||
/*
|
||||
* Inside a panic, send a message and wait for a response.
|
||||
*/
|
||||
static void ipmi_panic_request_and_wait(struct ipmi_smi *intf,
|
||||
struct ipmi_addr *addr,
|
||||
struct kernel_ipmi_msg *msg)
|
||||
static void _ipmi_panic_request_and_wait(struct ipmi_smi *intf,
|
||||
struct ipmi_addr *addr,
|
||||
struct kernel_ipmi_msg *msg)
|
||||
{
|
||||
struct ipmi_smi_msg smi_msg;
|
||||
struct ipmi_recv_msg recv_msg;
|
||||
@@ -5254,6 +5257,15 @@ static void ipmi_panic_request_and_wait(struct ipmi_smi *intf,
|
||||
ipmi_poll(intf);
|
||||
}
|
||||
|
||||
void ipmi_panic_request_and_wait(struct ipmi_user *user,
|
||||
struct ipmi_addr *addr,
|
||||
struct kernel_ipmi_msg *msg)
|
||||
{
|
||||
user->intf->run_to_completion = 1;
|
||||
_ipmi_panic_request_and_wait(user->intf, addr, msg);
|
||||
}
|
||||
EXPORT_SYMBOL(ipmi_panic_request_and_wait);
|
||||
|
||||
static void event_receiver_fetcher(struct ipmi_smi *intf,
|
||||
struct ipmi_recv_msg *msg)
|
||||
{
|
||||
@@ -5322,7 +5334,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
|
||||
}
|
||||
|
||||
/* Send the event announcing the panic. */
|
||||
ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
_ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
|
||||
/*
|
||||
* On every interface, dump a bunch of OEM event holding the
|
||||
@@ -5358,7 +5370,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
|
||||
msg.data = NULL;
|
||||
msg.data_len = 0;
|
||||
intf->null_user_handler = device_id_fetcher;
|
||||
ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
_ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
|
||||
if (intf->local_event_generator) {
|
||||
/* Request the event receiver from the local MC. */
|
||||
@@ -5367,7 +5379,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
|
||||
msg.data = NULL;
|
||||
msg.data_len = 0;
|
||||
intf->null_user_handler = event_receiver_fetcher;
|
||||
ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
_ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
}
|
||||
intf->null_user_handler = NULL;
|
||||
|
||||
@@ -5419,7 +5431,7 @@ static void send_panic_events(struct ipmi_smi *intf, char *str)
|
||||
memcpy_and_pad(data+5, 11, p, size, '\0');
|
||||
p += size;
|
||||
|
||||
ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
_ipmi_panic_request_and_wait(intf, &addr, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -344,4 +344,14 @@ extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data);
|
||||
/* Helper function for computing the IPMB checksum of some data. */
|
||||
unsigned char ipmb_checksum(unsigned char *data, int size);
|
||||
|
||||
/*
|
||||
* For things that must send messages at panic time, like the IPMI watchdog
|
||||
* driver that extends the reset time on a panic, use this to send messages
|
||||
* from panic context. Note that this puts the driver into a mode that
|
||||
* only works at panic time, so only use it then.
|
||||
*/
|
||||
void ipmi_panic_request_and_wait(struct ipmi_user *user,
|
||||
struct ipmi_addr *addr,
|
||||
struct kernel_ipmi_msg *msg);
|
||||
|
||||
#endif /* __LINUX_IPMI_H */
|
||||
|
||||
Reference in New Issue
Block a user