]> err.no Git - linux-2.6/blobdiff - drivers/char/ipmi/ipmi_msghandler.c
Merge ../torvalds-2.6/
[linux-2.6] / drivers / char / ipmi / ipmi_msghandler.c
index 84d477c6f925f996ab6d42c85e0630e97469314d..463351d4f9423c388d424231326b8bbe23a60cd0 100644 (file)
@@ -47,7 +47,8 @@
 #include <linux/proc_fs.h>
 
 #define PFX "IPMI message handler: "
-#define IPMI_MSGHANDLER_VERSION "v33"
+
+#define IPMI_DRIVER_VERSION "36.0"
 
 static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
@@ -116,7 +117,7 @@ struct seq_table
        do {                                                            \
                seq = ((msgid >> 26) & 0x3f);                           \
                seqid = (msgid & 0x3fffff);                             \
-        } while(0)
+        } while (0)
 
 #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
 
@@ -201,12 +202,6 @@ struct ipmi_smi
        struct list_head waiting_events;
        unsigned int     waiting_events_count; /* How many events in queue? */
 
-       /* This will be non-null if someone registers to receive all
-          IPMI commands (this is for interface emulation).  There
-          may not be any things in the cmd_rcvrs list above when
-          this is registered. */
-       ipmi_user_t all_cmd_rcvr;
-
        /* The event receiver for my BMC, only really used at panic
           shutdown as a place to store this. */
        unsigned char event_receiver;
@@ -218,7 +213,7 @@ struct ipmi_smi
           interface comes in with a NULL user, call this routine with
           it.  Note that the message will still be freed by the
           caller.  This only works on the system interface. */
-       void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
+       void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg);
 
        /* When we are scanning the channels for an SMI, this will
           tell which channel we are scanning. */
@@ -325,7 +320,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher)
        down_read(&interfaces_sem);
        down_write(&smi_watchers_sem);
        list_add(&(watcher->link), &smi_watchers);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                if (ipmi_interfaces[i] != NULL) {
                        watcher->new_smi(i);
                }
@@ -458,7 +453,27 @@ unsigned int ipmi_addr_length(int addr_type)
 
 static void deliver_response(struct ipmi_recv_msg *msg)
 {
-       msg->user->handler->ipmi_recv_hndl(msg, msg->user->handler_data);
+       if (! msg->user) {
+               ipmi_smi_t    intf = msg->user_msg_data;
+               unsigned long flags;
+
+               /* Special handling for NULL users. */
+               if (intf->null_user_handler) {
+                       intf->null_user_handler(intf, msg);
+                       spin_lock_irqsave(&intf->counter_lock, flags);
+                       intf->handled_local_responses++;
+                       spin_unlock_irqrestore(&intf->counter_lock, flags);
+               } else {
+                       /* No handler, 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(msg);
+       } else {
+               msg->user->handler->ipmi_recv_hndl(msg,
+                                                  msg->user->handler_data);
+       }
 }
 
 /* Find the next sequence number not being used and add the given
@@ -475,9 +490,9 @@ static int intf_next_seq(ipmi_smi_t           intf,
        int          rv = 0;
        unsigned int i;
 
-       for (i=intf->curr_seq;
+       for (i = intf->curr_seq;
             (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
-            i=(i+1)%IPMI_IPMB_NUM_SEQ)
+            i = (i+1)%IPMI_IPMB_NUM_SEQ)
        {
                if (! intf->seq_table[i].inuse)
                        break;
@@ -712,7 +727,7 @@ static int ipmi_destroy_user_nolock(ipmi_user_t user)
 
        /* Remove the user from the interfaces sequence table. */
        spin_lock_irqsave(&(user->intf->seq_lock), flags);
-       for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+       for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
                if (user->intf->seq_table[i].inuse
                    && (user->intf->seq_table[i].recv_msg->user == user))
                {
@@ -846,11 +861,6 @@ int ipmi_register_for_cmd(ipmi_user_t   user,
 
        read_lock(&(user->intf->users_lock));
        write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);
-       if (user->intf->all_cmd_rcvr != NULL) {
-               rv = -EBUSY;
-               goto out_unlock;
-       }
-
        /* Make sure the command/netfn is not already registered. */
        list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) {
                if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {
@@ -865,7 +875,7 @@ int ipmi_register_for_cmd(ipmi_user_t   user,
                rcvr->user = user;
                list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs));
        }
- out_unlock:
+
        write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);
        read_unlock(&(user->intf->users_lock));
 
@@ -1349,7 +1359,7 @@ static inline int i_ipmi_request(ipmi_user_t          user,
 #ifdef DEBUG_MSGING
        {
                int m;
-               for (m=0; m<smi_msg->data_size; m++)
+               for (m = 0; m < smi_msg->data_size; m++)
                        printk(" %2.2x", smi_msg->data[m]);
                printk("\n");
        }
@@ -1388,6 +1398,8 @@ int ipmi_request_settime(ipmi_user_t      user,
        unsigned char saddr, lun;
        int           rv;
 
+       if (! user)
+               return -EINVAL;
        rv = check_addr(user->intf, addr, &saddr, &lun);
        if (rv)
                return rv;
@@ -1417,6 +1429,8 @@ int ipmi_request_supply_msgs(ipmi_user_t          user,
        unsigned char saddr, lun;
        int           rv;
 
+       if (! user)
+               return -EINVAL;
        rv = check_addr(user->intf, addr, &saddr, &lun);
        if (rv)
                return rv;
@@ -1442,7 +1456,7 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off,
        int        i;
        int        rv= 0;
 
-       for (i=0; i<IPMI_MAX_CHANNELS; i++)
+       for (i = 0; i < IPMI_MAX_CHANNELS; i++)
                rv += sprintf(out+rv, "%x ", intf->channels[i].address);
        out[rv-1] = '\n'; /* Replace the final space with a newline */
        out[rv] = '\0';
@@ -1637,7 +1651,7 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
                              (struct ipmi_addr *) &si,
                              0,
                              &msg,
-                             NULL,
+                             intf,
                              NULL,
                              NULL,
                              0,
@@ -1647,19 +1661,20 @@ send_channel_info_cmd(ipmi_smi_t intf, int chan)
 }
 
 static void
-channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 {
        int rv = 0;
        int chan;
 
-       if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
-           && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD))
+       if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+           && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+           && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD))
        {
                /* It's the one we want */
-               if (msg->rsp[2] != 0) {
+               if (msg->msg.data[0] != 0) {
                        /* Got an error from the channel, just go on. */
 
-                       if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
+                       if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) {
                                /* If the MC does not support this
                                   command, that is legal.  We just
                                   assume it has one IPMB at channel
@@ -1676,13 +1691,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
                        }
                        goto next_channel;
                }
-               if (msg->rsp_size < 6) {
+               if (msg->msg.data_len < 4) {
                        /* Message not big enough, just go on. */
                        goto next_channel;
                }
                chan = intf->curr_channel;
-               intf->channels[chan].medium = msg->rsp[4] & 0x7f;
-               intf->channels[chan].protocol = msg->rsp[5] & 0x1f;
+               intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
+               intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
 
        next_channel:
                intf->curr_channel++;
@@ -1740,12 +1755,12 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
        rv = -ENOMEM;
 
        down_write(&interfaces_sem);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                if (ipmi_interfaces[i] == NULL) {
                        new_intf->intf_num = i;
                        new_intf->version_major = version_major;
                        new_intf->version_minor = version_minor;
-                       for (j=0; j<IPMI_MAX_CHANNELS; j++) {
+                       for (j = 0; j < IPMI_MAX_CHANNELS; j++) {
                                new_intf->channels[j].address
                                        = IPMI_BMC_SLAVE_ADDR;
                                new_intf->channels[j].lun = 2;
@@ -1757,7 +1772,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
                        new_intf->handlers = handlers;
                        new_intf->send_info = send_info;
                        spin_lock_init(&(new_intf->seq_lock));
-                       for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+                       for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
                                new_intf->seq_table[j].inuse = 0;
                                new_intf->seq_table[j].seqid = 0;
                        }
@@ -1773,7 +1788,6 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
                        rwlock_init(&(new_intf->cmd_rcvr_lock));
                        init_waitqueue_head(&new_intf->waitq);
                        INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));
-                       new_intf->all_cmd_rcvr = NULL;
 
                        spin_lock_init(&(new_intf->counter_lock));
 
@@ -1865,7 +1879,7 @@ static void clean_up_interface_data(ipmi_smi_t intf)
        free_recv_msg_list(&(intf->waiting_events));
        free_cmd_rcvr_list(&(intf->cmd_rcvrs));
 
-       for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) {
+       for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
                if ((intf->seq_table[i].inuse)
                    && (intf->seq_table[i].recv_msg))
                {
@@ -1884,7 +1898,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
        down_write(&interfaces_sem);
        if (list_empty(&(intf->users)))
        {
-               for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+               for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                        if (ipmi_interfaces[i] == intf) {
                                remove_proc_entries(intf);
                                spin_lock_irqsave(&interfaces_lock, flags);
@@ -2011,15 +2025,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
 
        read_lock(&(intf->cmd_rcvr_lock));
        
-       if (intf->all_cmd_rcvr) {
-               user = intf->all_cmd_rcvr;
-       } else {
-               /* Find the command/netfn. */
-               list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
-                       if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
-                               user = rcvr->user;
-                               break;
-                       }
+       /* Find the command/netfn. */
+       list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+               if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+                       user = rcvr->user;
+                       break;
                }
        }
        read_unlock(&(intf->cmd_rcvr_lock));
@@ -2048,7 +2058,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
        {
                int m;
                printk("Invalid command:");
-               for (m=0; m<msg->data_size; m++)
+               for (m = 0; m < msg->data_size; m++)
                        printk(" %2.2x", msg->data[m]);
                printk("\n");
        }
@@ -2196,15 +2206,11 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t          intf,
 
        read_lock(&(intf->cmd_rcvr_lock));
 
-       if (intf->all_cmd_rcvr) {
-               user = intf->all_cmd_rcvr;
-       } else {
-               /* Find the command/netfn. */
-               list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
-                       if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
-                               user = rcvr->user;
-                               break;
-                       }
+       /* Find the command/netfn. */
+       list_for_each_entry(rcvr, &(intf->cmd_rcvrs), link) {
+               if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {
+                       user = rcvr->user;
+                       break;
                }
        }
        read_unlock(&(intf->cmd_rcvr_lock));
@@ -2381,6 +2387,14 @@ static int handle_bmc_rsp(ipmi_smi_t          intf,
        unsigned long        flags;
 
        recv_msg = (struct ipmi_recv_msg *) msg->user_data;
+       if (recv_msg == NULL)
+       {
+               printk(KERN_WARNING"IPMI message received with no owner. This\n"
+                       "could be because of a malformed message, or\n"
+                       "because of a hardware error.  Contact your\n"
+                       "hardware vender for assistance\n");
+               return 0;
+       }
 
        /* Make sure the user still exists. */
        list_for_each_entry(user, &(intf->users), link) {
@@ -2391,19 +2405,11 @@ static int handle_bmc_rsp(ipmi_smi_t          intf,
                }
        }
 
-       if (!found) {
-               /* Special handling for NULL users. */
-               if (!recv_msg->user && intf->null_user_handler){
-                       intf->null_user_handler(intf, msg);
-                       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);
-               }
+       if ((! found) && recv_msg->user) {
+               /* 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;
@@ -2443,7 +2449,7 @@ static int handle_new_recv_msg(ipmi_smi_t          intf,
 #ifdef DEBUG_MSGING
        int m;
        printk("Recv:");
-       for (m=0; m<msg->rsp_size; m++)
+       for (m = 0; m < msg->rsp_size; m++)
                printk(" %2.2x", msg->rsp[m]);
        printk("\n");
 #endif
@@ -2677,7 +2683,7 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
        {
                int m;
                printk("Resend: ");
-               for (m=0; m<smi_msg->data_size; m++)
+               for (m = 0; m < smi_msg->data_size; m++)
                        printk(" %2.2x", smi_msg->data[m]);
                printk("\n");
        }
@@ -2698,7 +2704,7 @@ ipmi_timeout_handler(long timeout_period)
        INIT_LIST_HEAD(&timeouts);
 
        spin_lock(&interfaces_lock);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -2723,7 +2729,7 @@ ipmi_timeout_handler(long timeout_period)
                   have timed out, putting them in the timeouts
                   list. */
                spin_lock_irqsave(&(intf->seq_lock), flags);
-               for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {
+               for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) {
                        struct seq_table *ent = &(intf->seq_table[j]);
                        if (!ent->inuse)
                                continue;
@@ -2763,7 +2769,7 @@ ipmi_timeout_handler(long timeout_period)
                                spin_unlock(&intf->counter_lock);
                                smi_msg = smi_from_recv_msg(intf,
                                                ent->recv_msg, j, ent->seqid);
-                               if(!smi_msg)
+                               if (! smi_msg)
                                        continue;
 
                                spin_unlock_irqrestore(&(intf->seq_lock),flags);
@@ -2794,7 +2800,7 @@ static void ipmi_request_event(void)
        int        i;
 
        spin_lock(&interfaces_lock);
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -2889,28 +2895,30 @@ static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
 }
 
 #ifdef CONFIG_IPMI_PANIC_STRING
-static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 {
-       if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
-           && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
-           && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+       if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+           && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE)
+           && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD)
+           && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
        {
                /* A get event receiver command, save it. */
-               intf->event_receiver = msg->rsp[3];
-               intf->event_receiver_lun = msg->rsp[4] & 0x3;
+               intf->event_receiver = msg->msg.data[1];
+               intf->event_receiver_lun = msg->msg.data[2] & 0x3;
        }
 }
 
-static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
 {
-       if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
-           && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
-           && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+       if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE)
+           && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE)
+           && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD)
+           && (msg->msg.data[0] == IPMI_CC_NO_ERROR))
        {
                /* A get device id command, save if we are an event
                   receiver or generator. */
-               intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
-               intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
+               intf->local_sel_device = (msg->msg.data[6] >> 2) & 1;
+               intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
        }
 }
 #endif
@@ -2954,7 +2962,7 @@ static void send_panic_events(char *str)
        recv_msg.done = dummy_recv_done_handler;
 
        /* For every registered interface, send the event. */
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -2966,7 +2974,7 @@ static void send_panic_events(char *str)
                               &addr,
                               0,
                               &msg,
-                              NULL,
+                              intf,
                               &smi_msg,
                               &recv_msg,
                               0,
@@ -2981,7 +2989,7 @@ static void send_panic_events(char *str)
        if (!str) 
                return;
 
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                char                  *p = str;
                struct ipmi_ipmb_addr *ipmb;
                int                   j;
@@ -3012,7 +3020,7 @@ static void send_panic_events(char *str)
                               &addr,
                               0,
                               &msg,
-                              NULL,
+                              intf,
                               &smi_msg,
                               &recv_msg,
                               0,
@@ -3032,7 +3040,7 @@ static void send_panic_events(char *str)
                                       &addr,
                                       0,
                                       &msg,
-                                      NULL,
+                                      intf,
                                       &smi_msg,
                                       &recv_msg,
                                       0,
@@ -3094,7 +3102,7 @@ static void send_panic_events(char *str)
                                       &addr,
                                       0,
                                       &msg,
-                                      NULL,
+                                      intf,
                                       &smi_msg,
                                       &recv_msg,
                                       0,
@@ -3121,7 +3129,7 @@ static int panic_event(struct notifier_block *this,
        has_paniced = 1;
 
        /* For every registered interface, set it to run to completion. */
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                intf = ipmi_interfaces[i];
                if (intf == NULL)
                        continue;
@@ -3150,9 +3158,9 @@ static int ipmi_init_msghandler(void)
                return 0;
 
        printk(KERN_INFO "ipmi message handler version "
-              IPMI_MSGHANDLER_VERSION "\n");
+              IPMI_DRIVER_VERSION "\n");
 
-       for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+       for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
                ipmi_interfaces[i] = NULL;
        }
 
@@ -3222,6 +3230,9 @@ module_exit(cleanup_ipmi);
 
 module_init(ipmi_init_msghandler_mod);
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface.");
+MODULE_VERSION(IPMI_DRIVER_VERSION);
 
 EXPORT_SYMBOL(ipmi_create_user);
 EXPORT_SYMBOL(ipmi_destroy_user);