author: Linus Torvalds <torvalds@linux-foundation.org> 2020-10-14 15:00:20 -0700
committer: Linus Torvalds <torvalds@linux-foundation.org> 2020-10-14 15:00:20 -0700
commit: 6e4dc3d59284ea3bc7c3e40694bce84d988b01af
parent: 2f6c6d0891b472bbda70dfcc51fbb3147b6f54a0
Commit Summary:
Diffstat:
5 files changed, 87 insertions, 35 deletions
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index f3f216cdf686..f41f78972b9c 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -213,8 +213,10 @@ static int bt_start_transaction(struct si_sm_data *bt,
if (bt->state == BT_STATE_LONG_BUSY)
return IPMI_NODE_BUSY_ERR;
- if (bt->state != BT_STATE_IDLE)
+ if (bt->state != BT_STATE_IDLE) {
+ dev_warn(bt->io->dev, "BT in invalid state %d\n", bt->state);
return IPMI_NOT_IN_MY_STATE_ERR;
+ }
if (bt_debug & BT_DEBUG_MSG) {
dev_dbg(bt->io->dev, "+++++++++++++++++ New command\n");
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index 2e7cda08b079..efda90dcf5b3 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -17,6 +17,8 @@
* that document.
*/
+#define DEBUG /* So dev_dbg() is always available. */
+
#include <linux/kernel.h> /* For printk. */
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -187,8 +189,8 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason)
(kcs->error_retries)++;
if (kcs->error_retries > MAX_ERROR_RETRIES) {
if (kcs_debug & KCS_DEBUG_ENABLE)
- printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n",
- reason);
+ dev_dbg(kcs->io->dev, "ipmi_kcs_sm: kcs hosed: %s\n",
+ reason);
kcs->state = KCS_HOSED;
} else {
kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES;
@@ -268,11 +270,13 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data,
if (size > MAX_KCS_WRITE_SIZE)
return IPMI_REQ_LEN_EXCEEDED_ERR;
- if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED))
+ if ((kcs->state != KCS_IDLE) && (kcs->state != KCS_HOSED)) {
+ dev_warn(kcs->io->dev, "KCS in invalid state %d\n", kcs->state);
return IPMI_NOT_IN_MY_STATE_ERR;
+ }
if (kcs_debug & KCS_DEBUG_MSG) {
- printk(KERN_DEBUG "start_kcs_transaction -");
+ dev_dbg(kcs->io->dev, "%s -", __func__);
for (i = 0; i < size; i++)
pr_cont(" %02x", data[i]);
pr_cont("\n");
@@ -331,7 +335,8 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
status = read_status(kcs);
if (kcs_debug & KCS_DEBUG_STATES)
- printk(KERN_DEBUG "KCS: State = %d, %x\n", kcs->state, status);
+ dev_dbg(kcs->io->dev,
+ "KCS: State = %d, %x\n", kcs->state, status);
/* All states wait for ibf, so just do it here. */
if (!check_ibf(kcs, status, time))
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 737c0b6b24ea..8774a3b8ff95 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -34,12 +34,13 @@
#include <linux/uuid.h>
#include <linux/nospec.h>
#include <linux/vmalloc.h>
+#include <linux/delay.h>
#define IPMI_DRIVER_VERSION "39.2"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
-static void smi_recv_tasklet(unsigned long);
+static void smi_recv_tasklet(struct tasklet_struct *t);
static void handle_new_recv_msgs(struct ipmi_smi *intf);
static void need_waiter(struct ipmi_smi *intf);
static int handle_one_recv_msg(struct ipmi_smi *intf,
@@ -60,6 +61,7 @@ enum ipmi_panic_event_op {
#else
#define IPMI_PANIC_DEFAULT IPMI_SEND_PANIC_EVENT_NONE
#endif
+
static enum ipmi_panic_event_op ipmi_send_panic_event = IPMI_PANIC_DEFAULT;
static int panic_op_write_handler(const char *val,
@@ -89,19 +91,19 @@ static int panic_op_read_handler(char *buffer, const struct kernel_param *kp)
{
switch (ipmi_send_panic_event) {
case IPMI_SEND_PANIC_EVENT_NONE:
- strcpy(buffer, "none");
+ strcpy(buffer, "none\n");
break;
case IPMI_SEND_PANIC_EVENT:
- strcpy(buffer, "event");
+ strcpy(buffer, "event\n");
break;
case IPMI_SEND_PANIC_EVENT_STRING:
- strcpy(buffer, "string");
+ strcpy(buffer, "string\n");
break;
default:
- strcpy(buffer, "???");
+ strcpy(buffer, "???\n");
break;
}
@@ -317,6 +319,7 @@ struct bmc_device {
int dyn_guid_set;
struct kref usecount;
struct work_struct remove_work;
+ unsigned char cc; /* completion code */
};
#define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev)
@@ -2381,6 +2384,8 @@ static void bmc_device_id_handler(struct ipmi_smi *intf,
msg->msg.data, msg->msg.data_len, &intf->bmc->fetch_id);
if (rv) {
dev_warn(intf->si_dev, "device id demangle failed: %d\n", rv);
+ /* record completion code when error */
+ intf->bmc->cc = msg->msg.data[0];
intf->bmc->dyn_id_set = 0;
} else {
/*
@@ -2426,23 +2431,39 @@ send_get_device_id_cmd(struct ipmi_smi *intf)
static int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc)
{
int rv;
-
- bmc->dyn_id_set = 2;
+ unsigned int retry_count = 0;
intf->null_user_handler = bmc_device_id_handler;
+retry:
+ bmc->cc = 0;
+ bmc->dyn_id_set = 2;
+
rv = send_get_device_id_cmd(intf);
if (rv)
- return rv;
+ goto out_reset_handler;
wait_event(intf->waitq, bmc->dyn_id_set != 2);
- if (!bmc->dyn_id_set)
+ if (!bmc->dyn_id_set) {
+ if ((bmc->cc == IPMI_DEVICE_IN_FW_UPDATE_ERR
+ || bmc->cc == IPMI_DEVICE_IN_INIT_ERR
+ || bmc->cc == IPMI_NOT_IN_MY_STATE_ERR)
+ && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) {
+ msleep(500);
+ dev_warn(intf->si_dev,
+ "BMC returned 0x%2.2x, retry get bmc device id\n",
+ bmc->cc);
+ goto retry;
+ }
+
rv = -EIO; /* Something went wrong in the fetch. */
+ }
/* dyn_id_set makes the id data available. */
smp_rmb();
+out_reset_handler:
intf->null_user_handler = NULL;
return rv;
@@ -3245,7 +3266,6 @@ channel_handler(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
/* It's the one we want */
if (msg->msg.data[0] != 0) {
/* Got an error from the channel, just go on. */
-
if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
/*
* If the MC does not support this
@@ -3329,6 +3349,7 @@ static int __scan_channels(struct ipmi_smi *intf, struct ipmi_device_id *id)
dev_warn(intf->si_dev,
"Error sending channel information for channel 0, %d\n",
rv);
+ intf->null_user_handler = NULL;
return -EIO;
}
@@ -3430,9 +3451,8 @@ int ipmi_add_smi(struct module *owner,
intf->curr_seq = 0;
spin_lock_init(&intf->waiting_rcv_msgs_lock);
INIT_LIST_HEAD(&intf->waiting_rcv_msgs);
- tasklet_init(&intf->recv_tasklet,
- smi_recv_tasklet,
- (unsigned long) intf);
+ tasklet_setup(&intf->recv_tasklet,
+ smi_recv_tasklet);
atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);
spin_lock_init(&intf->xmit_msgs_lock);
INIT_LIST_HEAD(&intf->xmit_msgs);
@@ -4467,10 +4487,10 @@ static void handle_new_recv_msgs(struct ipmi_smi *intf)
}
}
-static void smi_recv_tasklet(unsigned long val)
+static void smi_recv_tasklet(struct tasklet_struct *t)
{
unsigned long flags = 0; /* keep us warning-free. */
- struct ipmi_smi *intf = (struct ipmi_smi *) val;
+ struct ipmi_smi *intf = from_tasklet(intf, t, recv_tasklet);
int run_to_completion = intf->run_to_completion;
struct ipmi_smi_msg *newmsg = NULL;
@@ -4542,7 +4562,7 @@ void ipmi_smi_msg_received(struct ipmi_smi *intf,
spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
if (run_to_completion)
- smi_recv_tasklet((unsigned long) intf);
+ smi_recv_tasklet(&intf->recv_tasklet);
else
tasklet_schedule(&intf->recv_tasklet);
}
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 77b8d551ae7f..5eac94cf4ff8 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1316,6 +1316,7 @@ static int try_get_dev_id(struct smi_info *smi_info)
unsigned char *resp;
unsigned long resp_len;
int rv = 0;
+ unsigned int retry_count = 0;
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
if (!resp)
@@ -1327,6 +1328,8 @@ static int try_get_dev_id(struct smi_info *smi_info)
*/
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_DEVICE_ID_CMD;
+
+retry:
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
rv = wait_for_msg_done(smi_info);
@@ -1339,6 +1342,20 @@ static int try_get_dev_id(struct smi_info *smi_info)
/* Check and record info from the get device id, in case we need it. */
rv = ipmi_demangle_device_id(resp[0] >> 2, resp[1],
resp + 2, resp_len - 2, &smi_info->device_id);
+ if (rv) {
+ /* record completion code */
+ unsigned char cc = *(resp + 2);
+
+ if ((cc == IPMI_DEVICE_IN_FW_UPDATE_ERR
+ || cc == IPMI_DEVICE_IN_INIT_ERR
+ || cc == IPMI_NOT_IN_MY_STATE_ERR)
+ && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) {
+ dev_warn(smi_info->io.dev,
+ "BMC returned 0x%2.2x, retry get bmc device id\n",
+ cc);
+ goto retry;
+ }
+ }
out:
kfree(resp);
@@ -1963,7 +1980,7 @@ static int try_smi_init(struct smi_info *new_smi)
/* Do this early so it's available for logs. */
if (!new_smi->io.dev) {
pr_err("IPMI interface added with no device\n");
- rv = EIO;
+ rv = -EIO;
goto out_err;
}
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index b6225bba2532..bfea500d6f5f 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -21,6 +21,8 @@
* 2001 Hewlett-Packard Company
*/
+#define DEBUG /* So dev_dbg() is always available. */
+
#include <linux/kernel.h> /* For printk. */
#include <linux/string.h>
#include <linux/module.h>
@@ -126,11 +128,14 @@ static int start_smic_transaction(struct si_sm_data *smic,
if (size > MAX_SMIC_WRITE_SIZE)
return IPMI_REQ_LEN_EXCEEDED_ERR;
- if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED))
+ if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) {
+ dev_warn(smic->io->dev,
+ "SMIC in invalid state %d\n", smic->state);
return IPMI_NOT_IN_MY_STATE_ERR;
+ }
if (smic_debug & SMIC_DEBUG_MSG) {
- printk(KERN_DEBUG "start_smic_transaction -");
+ dev_dbg(smic->io->dev, "%s -", __func__);
for (i = 0; i < size; i++)
pr_cont(" %02x", data[i]);
pr_cont("\n");
@@ -152,7 +157,7 @@ static int smic_get_result(struct si_sm_data *smic,
int i;
if (smic_debug & SMIC_DEBUG_MSG) {
- printk(KERN_DEBUG "smic_get result -");
+ dev_dbg(smic->io->dev, "smic_get result -");
for (i = 0; i < smic->read_pos; i++)
pr_cont(" %02x", smic->read_data[i]);
pr_cont("\n");
@@ -324,9 +329,9 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
}
if (smic->state != SMIC_IDLE) {
if (smic_debug & SMIC_DEBUG_STATES)
- printk(KERN_DEBUG
- "smic_event - smic->smic_timeout = %ld, time = %ld\n",
- smic->smic_timeout, time);
+ dev_dbg(smic->io->dev,
+ "%s - smic->smic_timeout = %ld, time = %ld\n",
+ __func__, smic->smic_timeout, time);
/*
* FIXME: smic_event is sometimes called with time >
* SMIC_RETRY_TIMEOUT
@@ -345,8 +350,9 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
status = read_smic_status(smic);
if (smic_debug & SMIC_DEBUG_STATES)
- printk(KERN_DEBUG "smic_event - state = %d, flags = 0x%02x, status = 0x%02x\n",
- smic->state, flags, status);
+ dev_dbg(smic->io->dev,
+ "%s - state = %d, flags = 0x%02x, status = 0x%02x\n",
+ __func__, smic->state, flags, status);
switch (smic->state) {
case SMIC_IDLE:
@@ -436,8 +442,9 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
data = read_smic_data(smic);
if (data != 0) {
if (smic_debug & SMIC_DEBUG_ENABLE)
- printk(KERN_DEBUG "SMIC_WRITE_END: data = %02x\n",
- data);
+ dev_dbg(smic->io->dev,
+ "SMIC_WRITE_END: data = %02x\n",
+ data);
start_error_recovery(smic,
"state = SMIC_WRITE_END, "
"data != SUCCESS");
@@ -516,8 +523,9 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
/* data register holds an error code */
if (data != 0) {
if (smic_debug & SMIC_DEBUG_ENABLE)
- printk(KERN_DEBUG "SMIC_READ_END: data = %02x\n",
- data);
+ dev_dbg(smic->io->dev,
+ "SMIC_READ_END: data = %02x\n",
+ data);
start_error_recovery(smic,
"state = SMIC_READ_END, "
"data != SUCCESS");
@@ -533,7 +541,8 @@ static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
default:
if (smic_debug & SMIC_DEBUG_ENABLE) {
- printk(KERN_DEBUG "smic->state = %d\n", smic->state);
+ dev_dbg(smic->io->dev,
+ "smic->state = %d\n", smic->state);
start_error_recovery(smic, "state = UNKNOWN");
return SI_SM_CALL_WITH_DELAY;
}