⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipmi_msghandler.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * ipmi_msghandler.c * * Incoming and outgoing message routing for an IPMI interface. * * Author: MontaVista Software, Inc. *         Corey Minyard <minyard@mvista.com> *         source@mvista.com * * Copyright 2002 MontaVista Software Inc. * *  This program is free software; you can redistribute it and/or modify it *  under the terms of the GNU General Public License as published by the *  Free Software Foundation; either version 2 of the License, or (at your *  option) any later version. * * *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  You should have received a copy of the GNU General Public License along *  with this program; if not, write to the Free Software Foundation, Inc., *  675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <asm/system.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/ipmi.h>#include <linux/ipmi_smi.h>#include <linux/notifier.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/rcupdate.h>#define PFX "IPMI message handler: "#define IPMI_DRIVER_VERSION "38.0"static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);static int ipmi_init_msghandler(void);static int initialized = 0;#ifdef CONFIG_PROC_FSstruct proc_dir_entry *proc_ipmi_root = NULL;#endif /* CONFIG_PROC_FS */#define MAX_EVENTS_IN_QUEUE	25/* Don't let a message sit in a queue forever, always time it with at lest   the max message timer.  This is in milliseconds. */#define MAX_MSG_TIMEOUT		60000/* * The main "user" data structure. */struct ipmi_user{	struct list_head link;	/* Set to "0" when the user is destroyed. */	int valid;	struct kref refcount;	/* The upper layer that handles receive messages. */	struct ipmi_user_hndl *handler;	void             *handler_data;	/* The interface this user is bound to. */	ipmi_smi_t intf;	/* Does this interface receive IPMI events? */	int gets_events;};struct cmd_rcvr{	struct list_head link;	ipmi_user_t   user;	unsigned char netfn;	unsigned char cmd;	/*	 * This is used to form a linked lised during mass deletion.	 * Since this is in an RCU list, we cannot use the link above	 * or change any data until the RCU period completes.  So we	 * use this next variable during mass deletion so we can have	 * a list and don't have to wait and restart the search on	 * every individual deletion of a command. */	struct cmd_rcvr *next;};struct seq_table{	unsigned int         inuse : 1;	unsigned int         broadcast : 1;	unsigned long        timeout;	unsigned long        orig_timeout;	unsigned int         retries_left;	/* To verify on an incoming send message response that this is           the message that the response is for, we keep a sequence id           and increment it every time we send a message. */	long                 seqid;	/* This is held so we can properly respond to the message on a           timeout, and it is used to hold the temporary data for           retransmission, too. */	struct ipmi_recv_msg *recv_msg;};/* Store the information in a msgid (long) to allow us to find a   sequence table entry from the msgid. */#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \	do {								\		seq = ((msgid >> 26) & 0x3f);				\		seqid = (msgid & 0x3fffff);				\        } while (0)#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)struct ipmi_channel{	unsigned char medium;	unsigned char protocol;	/* My slave address.  This is initialized to IPMI_BMC_SLAVE_ADDR,	   but may be changed by the user. */	unsigned char address;	/* My LUN.  This should generally stay the SMS LUN, but just in	   case... */	unsigned char lun;};#ifdef CONFIG_PROC_FSstruct ipmi_proc_entry{	char                   *name;	struct ipmi_proc_entry *next;};#endif#define IPMI_IPMB_NUM_SEQ	64#define IPMI_MAX_CHANNELS       16struct ipmi_smi{	/* What interface number are we? */	int intf_num;	struct kref refcount;	/* The list of upper layers that are using me.  seq_lock	 * protects this. */	struct list_head users;	/* Used for wake ups at startup. */	wait_queue_head_t waitq;	/* The IPMI version of the BMC on the other end. */	unsigned char       version_major;	unsigned char       version_minor;	/* This is the lower-layer's sender routine. */	struct ipmi_smi_handlers *handlers;	void                     *send_info;#ifdef CONFIG_PROC_FS	/* 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. */	spinlock_t             proc_entry_lock;	struct ipmi_proc_entry *proc_entries;#endif	/* 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           is called periodically to time the items in this list. */	spinlock_t       seq_lock;	struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];	int curr_seq;	/* Messages that were delayed for some reason (out of memory,           for instance), will go in here to be processed later in a           periodic timer interrupt. */	spinlock_t       waiting_msgs_lock;	struct list_head waiting_msgs;	/* The list of command receivers that are registered for commands	   on this interface. */	struct semaphore cmd_rcvrs_lock;	struct list_head cmd_rcvrs;	/* Events that were queues because no one was there to receive           them. */	spinlock_t       events_lock; /* For dealing with event stuff. */	struct list_head waiting_events;	unsigned int     waiting_events_count; /* How many events in queue? */	/* The event receiver for my BMC, only really used at panic	   shutdown as a place to store this. */	unsigned char event_receiver;	unsigned char event_receiver_lun;	unsigned char local_sel_device;	unsigned char local_event_generator;	/* A cheap hack, if this is non-null and a message to an	   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_recv_msg *msg);	/* When we are scanning the channels for an SMI, this will	   tell which channel we are scanning. */	int curr_channel;	/* Channel information */	struct ipmi_channel channels[IPMI_MAX_CHANNELS];	/* Proc FS stuff. */	struct proc_dir_entry *proc_dir;	char                  proc_dir_name[10];	spinlock_t   counter_lock; /* For making counters atomic. */	/* Commands we got that were invalid. */	unsigned int sent_invalid_commands;	/* Commands we sent to the MC. */	unsigned int sent_local_commands;	/* Responses from the MC that were delivered to a user. */	unsigned int handled_local_responses;	/* Responses from the MC that were not delivered to a user. */	unsigned int unhandled_local_responses;	/* Commands we sent out to the IPMB bus. */	unsigned int sent_ipmb_commands;	/* Commands sent on the IPMB that had errors on the SEND CMD */	unsigned int sent_ipmb_command_errs;	/* Each retransmit increments this count. */	unsigned int retransmitted_ipmb_commands;	/* When a message times out (runs out of retransmits) this is           incremented. */	unsigned int timed_out_ipmb_commands;	/* This is like above, but for broadcasts.  Broadcasts are           *not* included in the above count (they are expected to           time out). */	unsigned int timed_out_ipmb_broadcasts;	/* Responses I have sent to the IPMB bus. */	unsigned int sent_ipmb_responses;	/* The response was delivered to the user. */	unsigned int handled_ipmb_responses;	/* The response had invalid data in it. */	unsigned int invalid_ipmb_responses;	/* The response didn't have anyone waiting for it. */	unsigned int unhandled_ipmb_responses;	/* Commands we sent out to the IPMB bus. */	unsigned int sent_lan_commands;	/* Commands sent on the IPMB that had errors on the SEND CMD */	unsigned int sent_lan_command_errs;	/* Each retransmit increments this count. */	unsigned int retransmitted_lan_commands;	/* When a message times out (runs out of retransmits) this is           incremented. */	unsigned int timed_out_lan_commands;	/* Responses I have sent to the IPMB bus. */	unsigned int sent_lan_responses;	/* The response was delivered to the user. */	unsigned int handled_lan_responses;	/* The response had invalid data in it. */	unsigned int invalid_lan_responses;	/* The response didn't have anyone waiting for it. */	unsigned int unhandled_lan_responses;	/* The command was delivered to the user. */	unsigned int handled_commands;	/* The command had invalid data in it. */	unsigned int invalid_commands;	/* The command didn't have anyone waiting for it. */	unsigned int unhandled_commands;	/* Invalid data in an event. */	unsigned int invalid_events;	/* Events that were received with the proper format. */	unsigned int events;};/* Used to mark an interface entry that cannot be used but is not a * free entry, either, primarily used at creation and deletion time so * a slot doesn't get reused too quickly. */#define IPMI_INVALID_INTERFACE_ENTRY ((ipmi_smi_t) ((long) 1))#define IPMI_INVALID_INTERFACE(i) (((i) == NULL) \				   || (i == IPMI_INVALID_INTERFACE_ENTRY))#define MAX_IPMI_INTERFACES 4static ipmi_smi_t ipmi_interfaces[MAX_IPMI_INTERFACES];/* Directly protects the ipmi_interfaces data structure. */static DEFINE_SPINLOCK(interfaces_lock);/* List of watchers that want to know when smi's are added and   deleted. */static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers);static DECLARE_RWSEM(smi_watchers_sem);static void free_recv_msg_list(struct list_head *q){	struct ipmi_recv_msg *msg, *msg2;	list_for_each_entry_safe(msg, msg2, q, link) {		list_del(&msg->link);		ipmi_free_recv_msg(msg);	}}static void clean_up_interface_data(ipmi_smi_t intf){	int              i;	struct cmd_rcvr  *rcvr, *rcvr2;	struct list_head list;	free_recv_msg_list(&intf->waiting_msgs);	free_recv_msg_list(&intf->waiting_events);	/* Wholesale remove all the entries from the list in the	 * interface and wait for RCU to know that none are in use. */	down(&intf->cmd_rcvrs_lock);	list_add_rcu(&list, &intf->cmd_rcvrs);	list_del_rcu(&intf->cmd_rcvrs);	up(&intf->cmd_rcvrs_lock);	synchronize_rcu();	list_for_each_entry_safe(rcvr, rcvr2, &list, link)		kfree(rcvr);	for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {		if ((intf->seq_table[i].inuse)		    && (intf->seq_table[i].recv_msg))		{			ipmi_free_recv_msg(intf->seq_table[i].recv_msg);		}	}}static void intf_free(struct kref *ref){	ipmi_smi_t intf = container_of(ref, struct ipmi_smi, refcount);	clean_up_interface_data(intf);	kfree(intf);}int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher){	int           i;	unsigned long flags;	down_write(&smi_watchers_sem);	list_add(&(watcher->link), &smi_watchers);	up_write(&smi_watchers_sem);	spin_lock_irqsave(&interfaces_lock, flags);	for (i = 0; i < MAX_IPMI_INTERFACES; i++) {		ipmi_smi_t intf = ipmi_interfaces[i];		if (IPMI_INVALID_INTERFACE(intf))			continue;		spin_unlock_irqrestore(&interfaces_lock, flags);		watcher->new_smi(i);		spin_lock_irqsave(&interfaces_lock, flags);	}	spin_unlock_irqrestore(&interfaces_lock, flags);	return 0;}int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher){	down_write(&smi_watchers_sem);	list_del(&(watcher->link));	up_write(&smi_watchers_sem);	return 0;}static voidcall_smi_watchers(int i){	struct ipmi_smi_watcher *w;	down_read(&smi_watchers_sem);	list_for_each_entry(w, &smi_watchers, link) {		if (try_module_get(w->owner)) {			w->new_smi(i);			module_put(w->owner);		}	}	up_read(&smi_watchers_sem);}static intipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2){	if (addr1->addr_type != addr2->addr_type)		return 0;	if (addr1->channel != addr2->channel)		return 0;	if (addr1->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {		struct ipmi_system_interface_addr *smi_addr1		    = (struct ipmi_system_interface_addr *) addr1;		struct ipmi_system_interface_addr *smi_addr2		    = (struct ipmi_system_interface_addr *) addr2;		return (smi_addr1->lun == smi_addr2->lun);	}	if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)	    || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))	{		struct ipmi_ipmb_addr *ipmb_addr1		    = (struct ipmi_ipmb_addr *) addr1;		struct ipmi_ipmb_addr *ipmb_addr2		    = (struct ipmi_ipmb_addr *) addr2;		return ((ipmb_addr1->slave_addr == ipmb_addr2->slave_addr)			&& (ipmb_addr1->lun == ipmb_addr2->lun));	}	if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {		struct ipmi_lan_addr *lan_addr1			= (struct ipmi_lan_addr *) addr1;		struct ipmi_lan_addr *lan_addr2		    = (struct ipmi_lan_addr *) addr2;		return ((lan_addr1->remote_SWID == lan_addr2->remote_SWID)			&& (lan_addr1->local_SWID == lan_addr2->local_SWID)			&& (lan_addr1->session_handle			    == lan_addr2->session_handle)			&& (lan_addr1->lun == lan_addr2->lun));	}	return 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -