lkml.org 
[lkml]   [2020]   [Sep]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 3/3] ipmi: Add timeout waiting for channel information
Date
We have observed hosts with misbehaving BMCs that receive a Get Channel
Info command but don't respond. This leads to an indefinite wait in the
ipmi_msghandler's __scan_channels function, showing up as hung task
messages for modprobe.

Add a timeout waiting for the channel scan to complete. If the scan
fails to complete within that time, treat that like IPMI 1.0 and only
assume the presence of the primary IPMB channel at channel number 0.

Signed-off-by: Stefan Nuernberger <snu@amazon.com>
Signed-off-by: Markus Boehme <markubo@amazon.com>
---
drivers/char/ipmi/ipmi_msghandler.c | 72 ++++++++++++++++++++-----------------
1 file changed, 39 insertions(+), 33 deletions(-)

diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 2a2e8b2..9de9ba6 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -3315,46 +3315,52 @@ channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
*/
static int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id)
{
- int rv;
+ long rv;
+ unsigned int set;

- if (ipmi_version_major(id) > 1
- || (ipmi_version_major(id) == 1
- && ipmi_version_minor(id) >= 5)) {
- unsigned int set;
+ if (ipmi_version_major(id) == 1 && ipmi_version_minor(id) < 5) {
+ set = intf->curr_working_cset;
+ goto single_ipmb_channel;
+ }

- /*
- * Start scanning the channels to see what is
- * available.
- */
- set = !intf->curr_working_cset;
- intf->curr_working_cset = set;
- memset(&intf->wchannels[set], 0,
- sizeof(struct ipmi_channel_set));
-
- intf->null_user_handler = channel_handler;
- intf->curr_channel = 0;
- rv = send_channel_info_cmd(intf, 0);
- if (rv) {
- dev_warn(intf->si_dev,
- "Error sending channel information for channel 0, %d\n",
- rv);
- intf->null_user_handler = NULL;
- return -EIO;
- }
+ /*
+ * Start scanning the channels to see what is
+ * available.
+ */
+ set = !intf->curr_working_cset;
+ intf->curr_working_cset = set;
+ memset(&intf->wchannels[set], 0, sizeof(struct ipmi_channel_set));

- /* Wait for the channel info to be read. */
- wait_event(intf->waitq, intf->channels_ready);
+ intf->null_user_handler = channel_handler;
+ intf->curr_channel = 0;
+ rv = send_channel_info_cmd(intf, 0);
+ if (rv) {
+ dev_warn(intf->si_dev,
+ "Error sending channel information for channel 0, %ld\n",
+ rv);
intf->null_user_handler = NULL;
- } else {
- unsigned int set = intf->curr_working_cset;
+ return -EIO;
+ }

- /* Assume a single IPMB channel at zero. */
- intf->wchannels[set].c[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
- intf->wchannels[set].c[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
- intf->channel_list = intf->wchannels + set;
- intf->channels_ready = true;
+ /* Wait for the channel info to be read. */
+ rv = wait_event_timeout(intf->waitq, intf->channels_ready, 5 * HZ);
+ if (rv == 0) {
+ dev_warn(intf->si_dev,
+ "Timed out waiting for channel information. Assuming a single IPMB channel at 0.\n");
+ goto single_ipmb_channel;
}

+ goto out;
+
+single_ipmb_channel:
+ /* Assume a single IPMB channel at zero. */
+ intf->wchannels[set].c[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
+ intf->wchannels[set].c[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
+ intf->channel_list = intf->wchannels + set;
+ intf->channels_ready = true;
+
+out:
+ intf->null_user_handler = NULL;
return 0;
}

--
2.7.4
\
 
 \ /
  Last update: 2020-09-07 18:28    [W:0.102 / U:0.168 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site