vserver 1.9.5.x5
[linux-2.6.git] / drivers / char / ipmi / ipmi_msghandler.c
index c1e4abf..fe02300 100644 (file)
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 
-#define IPMI_MSGHANDLER_VERSION "v31"
+#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;
@@ -123,6 +124,12 @@ struct ipmi_channel
        unsigned char protocol;
 };
 
+struct ipmi_proc_entry
+{
+       char                   *name;
+       struct ipmi_proc_entry *next;
+};
+
 #define IPMI_IPMB_NUM_SEQ      64
 #define IPMI_MAX_CHANNELS       8
 struct ipmi_smi
@@ -149,6 +156,11 @@ struct ipmi_smi
        struct ipmi_smi_handlers *handlers;
        void                     *send_info;
 
+       /* A list of proc entries for this interface.  This does not
+          need a lock, only one thread creates it and only one thread
+          destroys it. */
+       struct ipmi_proc_entry *proc_entries;
+
        /* A table of sequence numbers for this interface.  We use the
            sequence numbers for IPMB messages that go out of the
            interface to match them up with their responses.  A routine
@@ -282,44 +294,6 @@ struct ipmi_smi
        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];
 
@@ -330,7 +304,7 @@ static DECLARE_RWSEM(interfaces_sem);
 
 /* 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. */
@@ -377,7 +351,7 @@ call_smi_watchers(int i)
        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)
@@ -469,6 +443,9 @@ unsigned int ipmi_addr_length(int addr_type)
                return sizeof(struct ipmi_ipmb_addr);
        }
 
+       if (addr_type == IPMI_LAN_ADDR_TYPE)
+               return sizeof(struct ipmi_lan_addr);
+
        return 0;
 }
 
@@ -884,6 +861,12 @@ int ipmi_unregister_for_cmd(ipmi_user_t   user,
        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)
 {
@@ -896,7 +879,7 @@ ipmb_checksum(unsigned char *data, int size)
 }
 
 static inline void format_ipmb_msg(struct ipmi_smi_msg   *smi_msg,
-                                  struct ipmi_msg       *msg,
+                                  struct kernel_ipmi_msg *msg,
                                   struct ipmi_ipmb_addr *ipmb_addr,
                                   long                  msgid,
                                   unsigned char         ipmb_seq,
@@ -938,7 +921,7 @@ static inline void format_ipmb_msg(struct ipmi_smi_msg   *smi_msg,
 }
 
 static inline void format_lan_msg(struct ipmi_smi_msg   *smi_msg,
-                                 struct ipmi_msg       *msg,
+                                 struct kernel_ipmi_msg *msg,
                                  struct ipmi_lan_addr  *lan_addr,
                                  long                  msgid,
                                  unsigned char         ipmb_seq,
@@ -982,7 +965,7 @@ static inline int i_ipmi_request(ipmi_user_t          user,
                                 ipmi_smi_t           intf,
                                 struct ipmi_addr     *addr,
                                 long                 msgid,
-                                struct ipmi_msg      *msg,
+                                struct kernel_ipmi_msg *msg,
                                 void                 *user_msg_data,
                                 void                 *supplied_smi,
                                 struct ipmi_recv_msg *supplied_recv,
@@ -1324,7 +1307,7 @@ static inline int i_ipmi_request(ipmi_user_t          user,
                goto out_err;
        }
 
-#if DEBUG_MSGING
+#ifdef DEBUG_MSGING
        {
                int m;
                for (m=0; m<smi_msg->data_size; m++)
@@ -1342,30 +1325,10 @@ static inline int i_ipmi_request(ipmi_user_t          user,
        return rv;
 }
 
-int ipmi_request(ipmi_user_t      user,
-                struct ipmi_addr *addr,
-                long             msgid,
-                struct 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,
-                        struct ipmi_msg  *msg,
+                        struct kernel_ipmi_msg  *msg,
                         void             *user_msg_data,
                         int              priority,
                         int              retries,
@@ -1388,7 +1351,7 @@ int ipmi_request_settime(ipmi_user_t      user,
 int ipmi_request_supply_msgs(ipmi_user_t          user,
                             struct ipmi_addr     *addr,
                             long                 msgid,
-                            struct ipmi_msg      *msg,
+                            struct kernel_ipmi_msg *msg,
                             void                 *user_msg_data,
                             void                 *supplied_smi,
                             struct ipmi_recv_msg *supplied_recv,
@@ -1408,28 +1371,6 @@ int ipmi_request_supply_msgs(ipmi_user_t          user,
                              -1, 0);
 }
 
-int ipmi_request_with_source(ipmi_user_t      user,
-                            struct ipmi_addr *addr,
-                            long             msgid,
-                            struct 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)
 {
@@ -1515,18 +1456,36 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
                            read_proc_t *read_proc, write_proc_t *write_proc,
                            void *data, struct module *owner)
 {
-       struct proc_dir_entry *file;
-       int                   rv = 0;
+       struct proc_dir_entry  *file;
+       int                    rv = 0;
+       struct ipmi_proc_entry *entry;
+
+       /* Create a list element. */
+       entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+       entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
+       if (!entry->name) {
+               kfree(entry);
+               return -ENOMEM;
+       }
+       strcpy(entry->name, name);
 
        file = create_proc_entry(name, 0, smi->proc_dir);
-       if (!file)
+       if (!file) {
+               kfree(entry->name);
+               kfree(entry);
                rv = -ENOMEM;
-       else {
+       else {
                file->nlink = 1;
                file->data = data;
                file->read_proc = read_proc;
                file->write_proc = write_proc;
                file->owner = owner;
+
+               /* Stick it on the list. */
+               entry->next = smi->proc_entries;
+               smi->proc_entries = entry;
        }
 
        return rv;
@@ -1562,10 +1521,25 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
        return rv;
 }
 
+static void remove_proc_entries(ipmi_smi_t smi)
+{
+       struct ipmi_proc_entry *entry;
+
+       while (smi->proc_entries) {
+               entry = smi->proc_entries;
+               smi->proc_entries = entry->next;
+
+               remove_proc_entry(entry->name, smi->proc_dir);
+               kfree(entry->name);
+               kfree(entry);
+       }
+       remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
+}
+
 static int
 send_channel_info_cmd(ipmi_smi_t intf, int chan)
 {
-       struct ipmi_msg                   msg;
+       struct kernel_ipmi_msg            msg;
        unsigned char                     data[1];
        struct ipmi_system_interface_addr si;
 
@@ -1604,6 +1578,22 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
                /* It's the one we want */
                if (msg->rsp[2] != 0) {
                        /* Got an error from the channel, just go on. */
+
+                       if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) {
+                               /* If the MC does not support this
+                                  command, that is legal.  We just
+                                  assume it has one IPMB at channel
+                                  zero. */
+                               intf->channels[0].medium
+                                       = IPMI_CHANNEL_MEDIUM_IPMB;
+                               intf->channels[0].protocol
+                                       = IPMI_CHANNEL_PROTOCOL_IPMB;
+                               rv = -ENOSYS;
+
+                               intf->curr_channel = IPMI_MAX_CHANNELS;
+                               wake_up(&intf->waitq);
+                               goto out;
+                       }
                        goto next_channel;
                }
                if (msg->rsp_size < 6) {
@@ -1626,11 +1616,13 @@ channel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
                        intf->curr_channel = IPMI_MAX_CHANNELS;
                        wake_up(&intf->waitq);
 
-                       printk(KERN_WARNING "ipmi_msghandler: Error sending"
-                              "channel information: 0x%x\n",
+                       printk(KERN_WARNING PFX
+                              "Error sending channel information: %d\n",
                               rv);
                }
        }
+ out:
+       return;
 }
 
 int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
@@ -1749,8 +1741,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
 
        if (rv) {
                if (new_intf->proc_dir)
-                       remove_proc_entry(new_intf->proc_dir_name,
-                                         proc_ipmi_root);
+                       remove_proc_entries(new_intf);
                kfree(new_intf);
        }
 
@@ -1806,8 +1797,7 @@ int ipmi_unregister_smi(ipmi_smi_t intf)
        {
                for (i=0; i<MAX_IPMI_INTERFACES; i++) {
                        if (ipmi_interfaces[i] == intf) {
-                               remove_proc_entry(intf->proc_dir_name,
-                                                 proc_ipmi_root);
+                               remove_proc_entries(intf);
                                spin_lock_irqsave(&interfaces_lock, flags);
                                ipmi_interfaces[i] = NULL;
                                clean_up_interface_data(intf);
@@ -1965,7 +1955,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t          intf,
                msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
                msg->data_size = 11;
 
-#if DEBUG_MSGING
+#ifdef DEBUG_MSGING
        {
                int m;
                printk("Invalid command:");
@@ -2283,7 +2273,7 @@ static int handle_read_event_rsp(ipmi_smi_t          intf,
        } 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");
        }
 
@@ -2314,12 +2304,17 @@ static int handle_bmc_rsp(ipmi_smi_t          intf,
 
        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;
@@ -2356,7 +2351,7 @@ static int handle_new_recv_msg(ipmi_smi_t          intf,
        int requeue;
        int chan;
 
-#if DEBUG_MSGING
+#ifdef DEBUG_MSGING
        int m;
        printk("Recv:");
        for (m=0; m<msg->rsp_size; m++)
@@ -2365,10 +2360,34 @@ static int handle_new_recv_msg(ipmi_smi_t          intf,
 #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. */
@@ -2434,7 +2453,9 @@ static int handle_new_recv_msg(ipmi_smi_t          intf,
                        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 {
@@ -2571,7 +2592,7 @@ send_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
           MC, which don't get resent. */
        intf->handlers->sender(intf->send_info, smi_msg, 0);
 
-#if DEBUG_MSGING
+#ifdef DEBUG_MSGING
        {
                int m;
                printk("Resend: ");
@@ -2805,7 +2826,7 @@ static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
 
 static void send_panic_events(char *str)
 {
-       struct ipmi_msg                   msg;
+       struct kernel_ipmi_msg            msg;
        ipmi_smi_t                        intf;
        unsigned char                     data[16];
        int                               i;
@@ -3025,12 +3046,12 @@ static int panic_event(struct notifier_block *this,
 }
 
 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 __init int ipmi_init_msghandler(void)
+static int ipmi_init_msghandler(void)
 {
        int i;
 
@@ -3044,9 +3065,9 @@ static __init int ipmi_init_msghandler(void)
                ipmi_interfaces[i] = NULL;
        }
 
-       proc_ipmi_root = proc_mkdir("ipmi", 0);
+       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;
        }
 
@@ -3065,6 +3086,12 @@ static __init int ipmi_init_msghandler(void)
        return 0;
 }
 
+static __init int ipmi_init_msghandler_mod(void)
+{
+       ipmi_init_msghandler();
+       return 0;
+}
+
 static __exit void cleanup_ipmi(void)
 {
        int count;
@@ -3092,26 +3119,23 @@ static __exit void cleanup_ipmi(void)
        /* 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);
+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_register_smi);
 EXPORT_SYMBOL(ipmi_unregister_smi);
 EXPORT_SYMBOL(ipmi_register_for_cmd);
@@ -3119,12 +3143,9 @@ EXPORT_SYMBOL(ipmi_unregister_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);
@@ -3132,3 +3153,4 @@ EXPORT_SYMBOL(ipmi_get_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);