#include <linux/init.h>
#include <linux/proc_fs.h>
-#define IPMI_MSGHANDLER_VERSION "v32"
+#define PFX "IPMI message handler: "
+#define IPMI_MSGHANDLER_VERSION "v33"
-struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
+static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
static int initialized = 0;
unsigned int events;
};
-int
-ipmi_register_all_cmd_rcvr(ipmi_user_t user)
-{
- unsigned long flags;
- int rv = -EBUSY;
-
- write_lock_irqsave(&(user->intf->users_lock), flags);
- write_lock(&(user->intf->cmd_rcvr_lock));
- if ((user->intf->all_cmd_rcvr == NULL)
- && (list_empty(&(user->intf->cmd_rcvrs))))
- {
- user->intf->all_cmd_rcvr = user;
- rv = 0;
- }
- write_unlock(&(user->intf->cmd_rcvr_lock));
- write_unlock_irqrestore(&(user->intf->users_lock), flags);
- return rv;
-}
-
-int
-ipmi_unregister_all_cmd_rcvr(ipmi_user_t user)
-{
- unsigned long flags;
- int rv = -EINVAL;
-
- write_lock_irqsave(&(user->intf->users_lock), flags);
- write_lock(&(user->intf->cmd_rcvr_lock));
- if (user->intf->all_cmd_rcvr == user)
- {
- user->intf->all_cmd_rcvr = NULL;
- rv = 0;
- }
- write_unlock(&(user->intf->cmd_rcvr_lock));
- write_unlock_irqrestore(&(user->intf->users_lock), flags);
- return rv;
-}
-
-
#define MAX_IPMI_INTERFACES 4
static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];
/* Directly protects the ipmi_interfaces data structure. This is
claimed in the timer interrupt. */
-static spinlock_t interfaces_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(interfaces_lock);
/* List of watchers that want to know when smi's are added and
deleted. */
up_read(&smi_watchers_sem);
}
-int
+static int
ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
{
if (addr1->addr_type != addr2->addr_type)
return sizeof(struct ipmi_ipmb_addr);
}
+ if (addr_type == IPMI_LAN_ADDR_TYPE)
+ return sizeof(struct ipmi_lan_addr);
+
return 0;
}
return rv;
}
+void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
+{
+ user->intf->handlers->set_run_to_completion(user->intf->send_info,
+ val);
+}
+
static unsigned char
ipmb_checksum(unsigned char *data, int size)
{
return rv;
}
-int ipmi_request(ipmi_user_t user,
- struct ipmi_addr *addr,
- long msgid,
- struct kernel_ipmi_msg *msg,
- void *user_msg_data,
- int priority)
-{
- return i_ipmi_request(user,
- user->intf,
- addr,
- msgid,
- msg,
- user_msg_data,
- NULL, NULL,
- priority,
- user->intf->my_address,
- user->intf->my_lun,
- -1, 0);
-}
-
int ipmi_request_settime(ipmi_user_t user,
struct ipmi_addr *addr,
long msgid,
-1, 0);
}
-int ipmi_request_with_source(ipmi_user_t user,
- struct ipmi_addr *addr,
- long msgid,
- struct kernel_ipmi_msg *msg,
- void *user_msg_data,
- int priority,
- unsigned char source_address,
- unsigned char source_lun)
-{
- return i_ipmi_request(user,
- user->intf,
- addr,
- msgid,
- msg,
- user_msg_data,
- NULL, NULL,
- priority,
- source_address,
- source_lun,
- -1, 0);
-}
-
static int ipmb_file_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
intf->curr_channel = IPMI_MAX_CHANNELS;
wake_up(&intf->waitq);
- printk(KERN_WARNING "ipmi_msghandler: Error sending"
- "channel information: %d\n",
+ printk(KERN_WARNING PFX
+ "Error sending channel information: %d\n",
rv);
}
}
return;
}
-void ipmi_poll_interface(ipmi_user_t user)
-{
- ipmi_smi_t intf = user->intf;
-
- if (intf->handlers->poll)
- intf->handlers->poll(intf->send_info);
-}
-
int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
void *send_info,
unsigned char version_major,
} else {
/* There's too many things in the queue, discard this
message. */
- printk(KERN_WARNING "ipmi: Event queue full, discarding an"
+ printk(KERN_WARNING PFX "Event queue full, discarding an"
" incoming event\n");
}
if (!found) {
/* Special handling for NULL users. */
- if (!recv_msg->user && intf->null_user_handler)
+ if (!recv_msg->user && intf->null_user_handler){
intf->null_user_handler(intf, msg);
- /* The user for the message went away, so give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->handled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ }else{
+ /* The user for the message went away, so give up. */
+ spin_lock_irqsave(&intf->counter_lock, flags);
+ intf->unhandled_local_responses++;
+ spin_unlock_irqrestore(&intf->counter_lock, flags);
+ }
ipmi_free_recv_msg(recv_msg);
} else {
struct ipmi_system_interface_addr *smi_addr;
#endif
if (msg->rsp_size < 2) {
/* Message is too small to be correct. */
- requeue = 0;
- } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
- && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
- && (msg->user_data != NULL))
+ printk(KERN_WARNING PFX "BMC returned to small a message"
+ " for netfn %x cmd %x, got %d bytes\n",
+ (msg->data[0] >> 2) | 1, msg->data[1], msg->rsp_size);
+
+ /* Generate an error response for the message. */
+ msg->rsp[0] = msg->data[0] | (1 << 2);
+ msg->rsp[1] = msg->data[1];
+ msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
+ msg->rsp_size = 3;
+ } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
+ || (msg->rsp[1] != msg->data[1])) /* Command */
+ {
+ /* The response is not even marginally correct. */
+ printk(KERN_WARNING PFX "BMC returned incorrect response,"
+ " expected netfn %x cmd %x, got netfn %x cmd %x\n",
+ (msg->data[0] >> 2) | 1, msg->data[1],
+ msg->rsp[0] >> 2, msg->rsp[1]);
+
+ /* Generate an error response for the message. */
+ msg->rsp[0] = msg->data[0] | (1 << 2);
+ msg->rsp[1] = msg->data[1];
+ msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
+ msg->rsp_size = 3;
+ }
+
+ if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
+ && (msg->rsp[1] == IPMI_SEND_MSG_CMD)
+ && (msg->user_data != NULL))
{
/* It's a response to a response we sent. For this we
deliver a send message response to the user. */
requeue = 0;
}
- } else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) {
+ } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
+ && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
+ {
/* It's an asyncronous event. */
requeue = handle_read_event_rsp(intf, msg);
} else {
}
static struct notifier_block panic_block = {
- panic_event,
- NULL,
- 200 /* priority: INT_MAX >= x >= 0 */
+ .notifier_call = panic_event,
+ .next = NULL,
+ .priority = 200 /* priority: INT_MAX >= x >= 0 */
};
static int ipmi_init_msghandler(void)
proc_ipmi_root = proc_mkdir("ipmi", NULL);
if (!proc_ipmi_root) {
- printk("Unable to create IPMI proc dir");
+ printk(KERN_ERR PFX "Unable to create IPMI proc dir");
return -ENOMEM;
}
/* Check for buffer leaks. */
count = atomic_read(&smi_msg_inuse_count);
if (count != 0)
- printk("ipmi_msghandler: SMI message count %d at exit\n",
+ printk(KERN_WARNING PFX "SMI message count %d at exit\n",
count);
count = atomic_read(&recv_msg_inuse_count);
if (count != 0)
- printk("ipmi_msghandler: recv message count %d at exit\n",
+ printk(KERN_WARNING PFX "recv message count %d at exit\n",
count);
}
module_exit(cleanup_ipmi);
module_init(ipmi_init_msghandler_mod);
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(ipmi_alloc_recv_msg);
EXPORT_SYMBOL(ipmi_create_user);
EXPORT_SYMBOL(ipmi_destroy_user);
EXPORT_SYMBOL(ipmi_get_version);
-EXPORT_SYMBOL(ipmi_request);
EXPORT_SYMBOL(ipmi_request_settime);
EXPORT_SYMBOL(ipmi_request_supply_msgs);
-EXPORT_SYMBOL(ipmi_request_with_source);
-EXPORT_SYMBOL(ipmi_poll_interface);
EXPORT_SYMBOL(ipmi_register_smi);
EXPORT_SYMBOL(ipmi_unregister_smi);
EXPORT_SYMBOL(ipmi_register_for_cmd);
EXPORT_SYMBOL(ipmi_smi_msg_received);
EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
EXPORT_SYMBOL(ipmi_alloc_smi_msg);
-EXPORT_SYMBOL(ipmi_register_all_cmd_rcvr);
-EXPORT_SYMBOL(ipmi_unregister_all_cmd_rcvr);
EXPORT_SYMBOL(ipmi_addr_length);
EXPORT_SYMBOL(ipmi_validate_addr);
EXPORT_SYMBOL(ipmi_set_gets_events);
-EXPORT_SYMBOL(ipmi_addr_equal);
EXPORT_SYMBOL(ipmi_smi_watcher_register);
EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
EXPORT_SYMBOL(ipmi_set_my_address);
EXPORT_SYMBOL(ipmi_set_my_LUN);
EXPORT_SYMBOL(ipmi_get_my_LUN);
EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
+EXPORT_SYMBOL(ipmi_user_set_run_to_completion);