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

📄 ipmi_msghandler.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	up_read(&interfaces_sem);	return rv;}static int ipmi_destroy_user_nolock(ipmi_user_t user){	int              rv = -ENODEV;	ipmi_user_t      t_user;	struct list_head *entry, *entry2;	int              i;	unsigned long    flags;	/* Find the user and delete them from the list. */	list_for_each(entry, &(user->intf->users)) {		t_user = list_entry(entry, struct ipmi_user, link);		if (t_user == user) {			list_del(entry);			rv = 0;			break;		}	}	if (rv) {		goto out_unlock;	}	/* 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++) {		if (user->intf->seq_table[i].inuse		    && (user->intf->seq_table[i].recv_msg->user == user))		{			user->intf->seq_table[i].inuse = 0;		}	}	spin_unlock_irqrestore(&(user->intf->seq_lock), flags);	/* Remove the user from the command receiver's table. */	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);	list_for_each_safe(entry, entry2, &(user->intf->cmd_rcvrs)) {		struct cmd_rcvr *rcvr;		rcvr = list_entry(entry, struct cmd_rcvr, link);		if (rcvr->user == user) {			list_del(entry);			kfree(rcvr);		}	}	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);	kfree(user); out_unlock:	return rv;}int ipmi_destroy_user(ipmi_user_t user){	int           rv;	ipmi_smi_t    intf = user->intf;	unsigned long flags;	down_read(&interfaces_sem);	write_lock_irqsave(&(intf->users_lock), flags);	rv = ipmi_destroy_user_nolock(user);	if (!rv)		intf->handlers->user_left(intf->send_info);			write_unlock_irqrestore(&(intf->users_lock), flags);	up_read(&interfaces_sem);	return rv;}void ipmi_get_version(ipmi_user_t   user,		      unsigned char *major,		      unsigned char *minor){	*major = user->intf->version_major;	*minor = user->intf->version_minor;}void ipmi_set_my_address(ipmi_user_t   user,			 unsigned char address){	user->intf->my_address = address;}unsigned char ipmi_get_my_address(ipmi_user_t user){	return user->intf->my_address;}void ipmi_set_my_LUN(ipmi_user_t   user,		     unsigned char LUN){	user->intf->my_lun = LUN & 0x3;}unsigned char ipmi_get_my_LUN(ipmi_user_t user){	return user->intf->my_lun;}int ipmi_set_gets_events(ipmi_user_t user, int val){	unsigned long         flags;	struct list_head      *e, *e2;	struct ipmi_recv_msg  *msg;	read_lock(&(user->intf->users_lock));	spin_lock_irqsave(&(user->intf->events_lock), flags);	user->gets_events = val;	if (val) {		/* Deliver any queued events. */		list_for_each_safe(e, e2, &(user->intf->waiting_events)) {			msg = list_entry(e, struct ipmi_recv_msg, link);			list_del(e);			msg->user = user;			deliver_response(msg);		}	}		spin_unlock_irqrestore(&(user->intf->events_lock), flags);	read_unlock(&(user->intf->users_lock));	return 0;}int ipmi_register_for_cmd(ipmi_user_t   user,			  unsigned char netfn,			  unsigned char cmd){	struct list_head *entry;	unsigned long    flags;	struct cmd_rcvr  *rcvr;	int              rv = 0;	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);	if (! rcvr)		return -ENOMEM;	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, &(user->intf->cmd_rcvrs)) {		struct cmd_rcvr *cmp;		cmp = list_entry(entry, struct cmd_rcvr, link);		if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) {			rv = -EBUSY;			break;		}	}	if (! rv) {		rcvr->cmd = cmd;		rcvr->netfn = netfn;		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));	if (rv)		kfree(rcvr);	return rv;}int ipmi_unregister_for_cmd(ipmi_user_t   user,			    unsigned char netfn,			    unsigned char cmd){	struct list_head *entry;	unsigned long    flags;	struct cmd_rcvr  *rcvr;	int              rv = -ENOENT;	read_lock(&(user->intf->users_lock));	write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags);	/* Make sure the command/netfn is not already registered. */	list_for_each(entry, &(user->intf->cmd_rcvrs)) {		rcvr = list_entry(entry, struct cmd_rcvr, link);		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {			rv = 0;			list_del(entry);			kfree(rcvr);			break;		}	}	write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags);	read_unlock(&(user->intf->users_lock));	return rv;}static unsigned charipmb_checksum(unsigned char *data, int size){	unsigned char csum = 0;		for (; size > 0; size--, data++)		csum += *data;	return -csum;}static inline void format_ipmb_msg(struct ipmi_smi_msg   *smi_msg,				   struct ipmi_msg       *msg,				   struct ipmi_ipmb_addr *ipmb_addr,				   long                  msgid,				   unsigned char         ipmb_seq,				   int                   broadcast,				   unsigned char         source_address,				   unsigned char         source_lun){	int i = broadcast;	/* Format the IPMB header data. */	smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);	smi_msg->data[1] = IPMI_SEND_MSG_CMD;	smi_msg->data[2] = ipmb_addr->channel;	if (broadcast)		smi_msg->data[3] = 0;	smi_msg->data[i+3] = ipmb_addr->slave_addr;	smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3);	smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2);	smi_msg->data[i+6] = source_address;	smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun;	smi_msg->data[i+8] = msg->cmd;	/* Now tack on the data to the message. */	if (msg->data_len > 0)		memcpy(&(smi_msg->data[i+9]), msg->data,		       msg->data_len);	smi_msg->data_size = msg->data_len + 9;	/* Now calculate the checksum and tack it on. */	smi_msg->data[i+smi_msg->data_size]		= ipmb_checksum(&(smi_msg->data[i+6]),				smi_msg->data_size-6);	/* Add on the checksum size and the offset from the	   broadcast. */	smi_msg->data_size += 1 + i;	smi_msg->msgid = msgid;}/* Separate from ipmi_request so that the user does not have to be   supplied in certain circumstances (mainly at panic time).  If   messages are supplied, they will be freed, even if an error   occurs. */static inline int i_ipmi_request(ipmi_user_t          user,				 ipmi_smi_t           intf,				 struct ipmi_addr     *addr,				 long                 msgid,				 struct ipmi_msg      *msg,				 void                 *supplied_smi,				 struct ipmi_recv_msg *supplied_recv,				 int                  priority,				 unsigned char        source_address,				 unsigned char        source_lun){	int                  rv = 0;	struct ipmi_smi_msg  *smi_msg;	struct ipmi_recv_msg *recv_msg;	unsigned long        flags;	if (supplied_recv) {		recv_msg = supplied_recv;	} else {		recv_msg = ipmi_alloc_recv_msg();		if (recv_msg == NULL) {			return -ENOMEM;		}	}	if (supplied_smi) {		smi_msg = (struct ipmi_smi_msg *) supplied_smi;	} else {		smi_msg = ipmi_alloc_smi_msg();		if (smi_msg == NULL) {			ipmi_free_recv_msg(recv_msg);			return -ENOMEM;		}	}	if (addr->channel > IPMI_NUM_CHANNELS) {	    rv = -EINVAL;	    goto out_err;	}	recv_msg->user = user;	recv_msg->msgid = msgid;	/* Store the message to send in the receive message so timeout	   responses can get the proper response data. */	recv_msg->msg = *msg;	if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {		struct ipmi_system_interface_addr *smi_addr;		smi_addr = (struct ipmi_system_interface_addr *) addr;		if (smi_addr->lun > 3)			return -EINVAL;		memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr));		if ((msg->netfn == IPMI_NETFN_APP_REQUEST)		    && ((msg->cmd == IPMI_SEND_MSG_CMD)			|| (msg->cmd == IPMI_GET_MSG_CMD)			|| (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))		{			/* We don't let the user do these, since we manage			   the sequence numbers. */			rv = -EINVAL;			goto out_err;		}		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {			rv = -EMSGSIZE;			goto out_err;		}		smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3);		smi_msg->data[1] = msg->cmd;		smi_msg->msgid = msgid;		smi_msg->user_data = recv_msg;		if (msg->data_len > 0)			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);		smi_msg->data_size = msg->data_len + 2;	} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)		   || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))	{		struct ipmi_ipmb_addr *ipmb_addr;		unsigned char         ipmb_seq;		long                  seqid;		int                   broadcast;		int                   retries;		if (addr == NULL) {			rv = -EINVAL;			goto out_err;		}		if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {		    /* Broadcasts add a zero at the beginning of the		       message, but otherwise is the same as an IPMB		       address. */		    addr->addr_type = IPMI_IPMB_ADDR_TYPE;		    broadcast = 1;		    retries = 0; /* Don't retry broadcasts. */		} else {		    broadcast = 0;		    retries = 4;		}		/* 9 for the header and 1 for the checksum, plus                   possibly one for the broadcast. */		if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {			rv = -EMSGSIZE;			goto out_err;		}		ipmb_addr = (struct ipmi_ipmb_addr *) addr;		if (ipmb_addr->lun > 3) {			rv = -EINVAL;			goto out_err;		}		memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));		if (recv_msg->msg.netfn & 0x1) {			/* It's a response, so use the user's sequence                           from msgid. */			format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,					msgid, broadcast,					source_address, source_lun);		} else {			/* It's a command, so get a sequence for it. */			spin_lock_irqsave(&(intf->seq_lock), flags);			/* Create a sequence number with a 1 second                           timeout and 4 retries. */			/* FIXME - magic number for the timeout. */			rv = intf_next_seq(intf,					   recv_msg,					   1000,					   retries,					   &ipmb_seq,					   &seqid);			if (rv) {				/* We have used up all the sequence numbers,				   probably, so abort. */				spin_unlock_irqrestore(&(intf->seq_lock),						       flags);				goto out_err;			}			/* Store the sequence number in the message,                           so that when the send message response                           comes back we can start the timer. */			format_ipmb_msg(smi_msg, msg, ipmb_addr,					STORE_SEQ_IN_MSGID(ipmb_seq, seqid),					ipmb_seq, broadcast,					source_address, source_lun);			/* Copy the message into the recv message data, so we			   can retransmit it later if necessary. */			memcpy(recv_msg->msg_data, smi_msg->data,			       smi_msg->data_size);			recv_msg->msg.data = recv_msg->msg_data;			recv_msg->msg.data_len = smi_msg->data_size;			/* We don't unlock until here, because we need                           to copy the completed message into the                           recv_msg before we release the lock.                           Otherwise, race conditions may bite us.  I                           know that's pretty paranoid, but I prefer                           to be correct. */			spin_unlock_irqrestore(&(intf->seq_lock), flags);		}	} else {	    /* Unknown address type. */	    rv = -EINVAL;	    goto out_err;	}#if DEBUG_MSGING	{	    int m;	    for (m=0; m<smi_msg->data_size; m++)		printk(" %2.2x", smi_msg->data[m]);	    printk("\n");	}#endif	intf->handlers->sender(intf->send_info, smi_msg, priority);	return 0; out_err:	ipmi_free_smi_msg(smi_msg);	ipmi_free_recv_msg(recv_msg);	return rv;}int ipmi_request(ipmi_user_t      user,		 struct ipmi_addr *addr,		 long             msgid,		 struct ipmi_msg  *msg,		 int              priority){	return i_ipmi_request(user,			      user->intf,			      addr,			      msgid,			      msg,			      NULL, NULL,			      priority,			      user->intf->my_address,			      user->intf->my_lun);}int ipmi_request_supply_msgs(ipmi_user_t          user,			     struct ipmi_addr     *addr,			     long                 msgid,			     struct ipmi_msg      *msg,			     void                 *supplied_smi,			     struct ipmi_recv_msg *supplied_recv,			     int                  priority){	return i_ipmi_request(user,			      user->intf,			      addr,			      msgid,			      msg,			      supplied_smi,			      supplied_recv,			      priority,			      user->intf->my_address,			      user->intf->my_lun);}int ipmi_request_with_source(ipmi_user_t      user,			     struct ipmi_addr *addr,			     long             msgid,			     struct ipmi_msg  *msg,			     int              priority,			     unsigned char    source_address,			     unsigned char    source_lun)

⌨️ 快捷键说明

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