mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 16:41:39 +00:00
Bug fix pull for IPMI for 5.10
Some minor bug fixes, return values, cleanups of prints, conversion of tasklets to the new API. The biggest change is retrying the initial information fetch from the management controller. If that fails, the iterface is not operational, and one group was having trouble with the management controller not being ready when the OS started up. So a retry was added. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE/Q1c5nzg9ZpmiCaGYfOMkJGb/4EFAl+Fzb0ACgkQYfOMkJGb /4F84w//RX/gaI1LkhkMKjrvtepNOElijAePFdPdCNYHvE+c50cADNHLstiQVaGk 3URa/F1ba9LNlYsof9Y2L4PT5m6UUhmzWbJ3i0CZRJoqZUB4cZAzwrzHAG4oDqdG C8bO4mSHsglE5uTeZ7WPquzqfF7Jjq53tmVHRUYAc9MhAFph2x+8uW+zpyU/Y47a QMVdn3cE69B80IuZPa6puAlRKhF6M4RpfGCFgKzBXz4Hbf+3V290hI5ulwU60PV7 MLrnsHbQzNybdKRN78nnBVB0bXIZDxz92Nk4HYjYIJhZYleVdZVH6BiFOa2ZpkxP F2rrsztjhaKV1fSXfxGivFATsrmcZ9zw7crYSmZBMoRQcr4gjG4LqPI+feBFZ3oy V8LtNcLQHM7v62iOfGIP83mOezhgF9S0I/HuCliB0V5GXRJv7MfrMKmmgCzCchuK koFgcWBGFzTDPRhjUeK1YyMxyM/F1JjRs8fK7qaG9e4hmqtGyE6nlg0W15VlPCt6 jBGjy4Vn4WMNSdn/XBd/i4UEL1yOCaHbUrLexZc2+q3dlpWOcQ19JwQTkSLY95bM IrIKjLy7Rbnnnji1tAYgzqV2RzY3g35/Vv4T7XI9HDPplasCWUV/7+BDMNy2A8ec kq/bvwl3aoPiXKXDe512SyPR1R0b/SJWkdzLdznMGtOIqNnjjac= =t7Qa -----END PGP SIGNATURE----- Merge tag 'for-linus-5.10-1' of git://github.com/cminyard/linux-ipmi Pull IPMI updates from Corey Minyard: "Some minor bug fixes, return values, cleanups of prints, conversion of tasklets to the new API. The biggest change is retrying the initial information fetch from the management controller. If that fails, the iterface is not operational, and one group was having trouble with the management controller not being ready when the OS started up. So a retry was added" * tag 'for-linus-5.10-1' of git://github.com/cminyard/linux-ipmi: ipmi_si: Fix wrong return value in try_smi_init() ipmi: msghandler: Fix a signedness bug ipmi: add retry in try_get_dev_id() ipmi: Clean up some printks ipmi:msghandler: retry to get device id on an error ipmi:sm: Print current state when the state is invalid ipmi: Reset response handler when failing to send the command ipmi: add a newline when printing parameter 'panic_op' by sysfs char: ipmi: convert tasklets to use new tasklet_setup() API
This commit is contained in:
commit
6e4dc3d592
@ -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");
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -333,4 +333,6 @@ struct ipmi_smi_info {
|
||||
/* This is to get the private info of struct ipmi_smi */
|
||||
extern int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data);
|
||||
|
||||
#define GET_DEVICE_ID_MAX_RETRY 5
|
||||
|
||||
#endif /* __LINUX_IPMI_H */
|
||||
|
@ -69,6 +69,8 @@
|
||||
#define IPMI_ERR_MSG_TRUNCATED 0xc6
|
||||
#define IPMI_REQ_LEN_INVALID_ERR 0xc7
|
||||
#define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8
|
||||
#define IPMI_DEVICE_IN_FW_UPDATE_ERR 0xd1
|
||||
#define IPMI_DEVICE_IN_INIT_ERR 0xd2
|
||||
#define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */
|
||||
#define IPMI_LOST_ARBITRATION_ERR 0x81
|
||||
#define IPMI_BUS_ERR 0x82
|
||||
|
Loading…
Reference in New Issue
Block a user