diff options
Diffstat (limited to 'drivers/char/ipmi/ipmi_msghandler.c')
-rw-r--r-- | drivers/char/ipmi/ipmi_msghandler.c | 176 |
1 files changed, 86 insertions, 90 deletions
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 6707659cffd6..cad9563f8f48 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -44,25 +44,6 @@ static void need_waiter(struct ipmi_smi *intf); static int handle_one_recv_msg(struct ipmi_smi *intf, struct ipmi_smi_msg *msg); -#ifdef DEBUG -static void ipmi_debug_msg(const char *title, unsigned char *data, - unsigned int len) -{ - int i, pos; - char buf[100]; - - pos = snprintf(buf, sizeof(buf), "%s: ", title); - for (i = 0; i < len; i++) - pos += snprintf(buf + pos, sizeof(buf) - pos, - " %2.2x", data[i]); - pr_debug("%s\n", buf); -} -#else -static void ipmi_debug_msg(const char *title, unsigned char *data, - unsigned int len) -{ } -#endif - static bool initialized; static bool drvregistered; @@ -448,6 +429,8 @@ enum ipmi_stat_indexes { #define IPMI_IPMB_NUM_SEQ 64 struct ipmi_smi { + struct module *owner; + /* What interface number are we? */ int intf_num; @@ -904,12 +887,14 @@ static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg) rv = -EINVAL; } ipmi_free_recv_msg(msg); - } else if (!oops_in_progress) { + } else if (oops_in_progress) { /* * If we are running in the panic context, calling the * receive handler doesn't much meaning and has a deadlock * risk. At this moment, simply skip it in that case. */ + ipmi_free_recv_msg(msg); + } else { int index; struct ipmi_user *user = acquire_ipmi_user(msg->user, &index); @@ -1218,6 +1203,11 @@ int ipmi_create_user(unsigned int if_num, if (rv) goto out_kfree; + if (!try_module_get(intf->owner)) { + rv = -ENODEV; + goto out_kfree; + } + /* Note that each existing user holds a refcount to the interface. */ kref_get(&intf->refcount); @@ -1347,6 +1337,7 @@ static void _ipmi_destroy_user(struct ipmi_user *user) } kref_put(&intf->refcount, intf_free); + module_put(intf->owner); } int ipmi_destroy_user(struct ipmi_user *user) @@ -2220,7 +2211,8 @@ static int i_ipmi_request(struct ipmi_user *user, else { smi_msg = ipmi_alloc_smi_msg(); if (smi_msg == NULL) { - ipmi_free_recv_msg(recv_msg); + if (!supplied_recv) + ipmi_free_recv_msg(recv_msg); rv = -ENOMEM; goto out; } @@ -2264,7 +2256,7 @@ out_err: ipmi_free_smi_msg(smi_msg); ipmi_free_recv_msg(recv_msg); } else { - ipmi_debug_msg("Send", smi_msg->data, smi_msg->data_size); + pr_debug("Send: %*ph\n", smi_msg->data_size, smi_msg->data); smi_send(intf, intf->handlers, smi_msg, priority); } @@ -2456,7 +2448,7 @@ static int __get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc) * been recently fetched, this will just use the cached data. Otherwise * it will run a new fetch. * - * Except for the first time this is called (in ipmi_register_smi()), + * Except for the first time this is called (in ipmi_add_smi()), * this will always return good data; */ static int __bmc_get_device_id(struct ipmi_smi *intf, struct bmc_device *bmc, @@ -3028,8 +3020,11 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, bmc->pdev.name = "ipmi_bmc"; rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL); - if (rv < 0) + if (rv < 0) { + kfree(bmc); goto out; + } + bmc->pdev.dev.driver = &ipmidriver.driver; bmc->pdev.id = rv; bmc->pdev.dev.release = release_bmc_device; @@ -3374,10 +3369,11 @@ static void redo_bmc_reg(struct work_struct *work) kref_put(&intf->refcount, intf_free); } -int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, - void *send_info, - struct device *si_dev, - unsigned char slave_addr) +int ipmi_add_smi(struct module *owner, + const struct ipmi_smi_handlers *handlers, + void *send_info, + struct device *si_dev, + unsigned char slave_addr) { int i, j; int rv; @@ -3403,7 +3399,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, return rv; } - + intf->owner = owner; intf->bmc = &intf->tmp_bmc; INIT_LIST_HEAD(&intf->bmc->intfs); mutex_init(&intf->bmc->dyn_mutex); @@ -3511,7 +3507,7 @@ int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, return rv; } -EXPORT_SYMBOL(ipmi_register_smi); +EXPORT_SYMBOL(ipmi_add_smi); static void deliver_smi_err_response(struct ipmi_smi *intf, struct ipmi_smi_msg *msg, @@ -3727,7 +3723,7 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *intf, msg->data[10] = ipmb_checksum(&msg->data[6], 4); msg->data_size = 11; - ipmi_debug_msg("Invalid command:", msg->data, msg->data_size); + pr_debug("Invalid command: %*ph\n", msg->data_size, msg->data); rcu_read_lock(); if (!intf->in_shutdown) { @@ -4214,8 +4210,54 @@ static int handle_one_recv_msg(struct ipmi_smi *intf, int requeue; int chan; - ipmi_debug_msg("Recv:", msg->rsp, msg->rsp_size); - if (msg->rsp_size < 2) { + pr_debug("Recv: %*ph\n", msg->rsp_size, msg->rsp); + + if ((msg->data_size >= 2) + && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) + && (msg->data[1] == IPMI_SEND_MSG_CMD) + && (msg->user_data == NULL)) { + + if (intf->in_shutdown) + goto free_msg; + + /* + * This is the local response to a command send, start + * the timer for these. The user_data will not be + * NULL if this is a response send, and we will let + * response sends just go through. + */ + + /* + * Check for errors, if we get certain errors (ones + * that mean basically we can try again later), we + * ignore them and start the timer. Otherwise we + * report the error immediately. + */ + if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) + && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) + && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) + && (msg->rsp[2] != IPMI_BUS_ERR) + && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { + int ch = msg->rsp[3] & 0xf; + struct ipmi_channel *chans; + + /* Got an error sending the message, handle it. */ + + chans = READ_ONCE(intf->channel_list)->c; + if ((chans[ch].medium == IPMI_CHANNEL_MEDIUM_8023LAN) + || (chans[ch].medium == IPMI_CHANNEL_MEDIUM_ASYNC)) + ipmi_inc_stat(intf, sent_lan_command_errs); + else + ipmi_inc_stat(intf, sent_ipmb_command_errs); + intf_err_seq(intf, msg->msgid, msg->rsp[2]); + } else + /* The message was sent, start the timer. */ + intf_start_seq_timer(intf, msg->msgid); +free_msg: + requeue = 0; + goto out; + + } else if (msg->rsp_size < 2) { /* Message is too small to be correct. */ dev_warn(intf->si_dev, "BMC returned too small a message for netfn %x cmd %x, got %d bytes\n", @@ -4472,62 +4514,16 @@ void ipmi_smi_msg_received(struct ipmi_smi *intf, unsigned long flags = 0; /* keep us warning-free. */ int run_to_completion = intf->run_to_completion; - if ((msg->data_size >= 2) - && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) - && (msg->data[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data == NULL)) { - - if (intf->in_shutdown) - goto free_msg; - - /* - * This is the local response to a command send, start - * the timer for these. The user_data will not be - * NULL if this is a response send, and we will let - * response sends just go through. - */ - - /* - * Check for errors, if we get certain errors (ones - * that mean basically we can try again later), we - * ignore them and start the timer. Otherwise we - * report the error immediately. - */ - if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) - && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) - && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) - && (msg->rsp[2] != IPMI_BUS_ERR) - && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { - int ch = msg->rsp[3] & 0xf; - struct ipmi_channel *chans; - - /* Got an error sending the message, handle it. */ - - chans = READ_ONCE(intf->channel_list)->c; - if ((chans[ch].medium == IPMI_CHANNEL_MEDIUM_8023LAN) - || (chans[ch].medium == IPMI_CHANNEL_MEDIUM_ASYNC)) - ipmi_inc_stat(intf, sent_lan_command_errs); - else - ipmi_inc_stat(intf, sent_ipmb_command_errs); - intf_err_seq(intf, msg->msgid, msg->rsp[2]); - } else - /* The message was sent, start the timer. */ - intf_start_seq_timer(intf, msg->msgid); - -free_msg: - ipmi_free_smi_msg(msg); - } else { - /* - * To preserve message order, we keep a queue and deliver from - * a tasklet. - */ - if (!run_to_completion) - spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags); - list_add_tail(&msg->link, &intf->waiting_rcv_msgs); - if (!run_to_completion) - spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock, - flags); - } + /* + * To preserve message order, we keep a queue and deliver from + * a tasklet. + */ + if (!run_to_completion) + spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags); + list_add_tail(&msg->link, &intf->waiting_rcv_msgs); + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock, + flags); if (!run_to_completion) spin_lock_irqsave(&intf->xmit_msgs_lock, flags); @@ -4573,7 +4569,7 @@ smi_from_recv_msg(struct ipmi_smi *intf, struct ipmi_recv_msg *recv_msg, smi_msg->data_size = recv_msg->msg.data_len; smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); - ipmi_debug_msg("Resend: ", smi_msg->data, smi_msg->data_size); + pr_debug("Resend: %*ph\n", smi_msg->data_size, smi_msg->data); return smi_msg; } |