diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/ipmi/ipmi_bt_sm.c | 4 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_kcs_sm.c | 15 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 52 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 19 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_smic_sm.c | 35 |
5 files changed, 89 insertions, 36 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; } |