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

📄 ipmi_msghandler.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
int ipmi_register_for_cmd(ipmi_user_t   user,			  unsigned char netfn,			  unsigned char cmd){	ipmi_smi_t      intf = user->intf;	struct cmd_rcvr *rcvr;	struct cmd_rcvr *entry;	int             rv = 0;	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);	if (! rcvr)		return -ENOMEM;	rcvr->cmd = cmd;	rcvr->netfn = netfn;	rcvr->user = user;	down(&intf->cmd_rcvrs_lock);	/* Make sure the command/netfn is not already registered. */	entry = find_cmd_rcvr(intf, netfn, cmd);	if (entry) {		rv = -EBUSY;		goto out_unlock;	}	list_add_rcu(&rcvr->link, &intf->cmd_rcvrs); out_unlock:	up(&intf->cmd_rcvrs_lock);	if (rv)		kfree(rcvr);	return rv;}int ipmi_unregister_for_cmd(ipmi_user_t   user,			    unsigned char netfn,			    unsigned char cmd){	ipmi_smi_t      intf = user->intf;	struct cmd_rcvr *rcvr;	down(&intf->cmd_rcvrs_lock);	/* Make sure the command/netfn is not already registered. */	rcvr = find_cmd_rcvr(intf, netfn, cmd);	if ((rcvr) && (rcvr->user == user)) {		list_del_rcu(&rcvr->link);		up(&intf->cmd_rcvrs_lock);		synchronize_rcu();		kfree(rcvr);		return 0;	} else {		up(&intf->cmd_rcvrs_lock);		return -ENOENT;	}}void ipmi_user_set_run_to_completion(ipmi_user_t user, int val){	ipmi_smi_t intf = user->intf;	intf->handlers->set_run_to_completion(intf->send_info, val);}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 kernel_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;}static inline void format_lan_msg(struct ipmi_smi_msg   *smi_msg,				  struct kernel_ipmi_msg *msg,				  struct ipmi_lan_addr  *lan_addr,				  long                  msgid,				  unsigned char         ipmb_seq,				  unsigned char         source_lun){	/* 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] = lan_addr->channel;	smi_msg->data[3] = lan_addr->session_handle;	smi_msg->data[4] = lan_addr->remote_SWID;	smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3);	smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2);	smi_msg->data[7] = lan_addr->local_SWID;	smi_msg->data[8] = (ipmb_seq << 2) | source_lun;	smi_msg->data[9] = msg->cmd;	/* Now tack on the data to the message. */	if (msg->data_len > 0)		memcpy(&(smi_msg->data[10]), msg->data,		       msg->data_len);	smi_msg->data_size = msg->data_len + 10;	/* Now calculate the checksum and tack it on. */	smi_msg->data[smi_msg->data_size]		= ipmb_checksum(&(smi_msg->data[7]),				smi_msg->data_size-7);	/* Add on the checksum size and the offset from the	   broadcast. */	smi_msg->data_size += 1;	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 int i_ipmi_request(ipmi_user_t          user,			  ipmi_smi_t           intf,			  struct ipmi_addr     *addr,			  long                 msgid,			  struct kernel_ipmi_msg *msg,			  void                 *user_msg_data,			  void                 *supplied_smi,			  struct ipmi_recv_msg *supplied_recv,			  int                  priority,			  unsigned char        source_address,			  unsigned char        source_lun,			  int                  retries,			  unsigned int         retry_time_ms){	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;		}	}	recv_msg->user_msg_data = user_msg_data;	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;		}	}	recv_msg->user = user;	if (user)		kref_get(&user->refcount);	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;		if (msg->netfn & 1) {			/* Responses are not allowed to the SMI. */			rv = -EINVAL;			goto out_err;		}		smi_addr = (struct ipmi_system_interface_addr *) addr;		if (smi_addr->lun > 3) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		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. */			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			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;		spin_lock_irqsave(&intf->counter_lock, flags);		intf->sent_local_commands++;		spin_unlock_irqrestore(&intf->counter_lock, flags);	} 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 = 0;		if (addr->channel >= IPMI_MAX_CHANNELS) {		        spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		if (intf->channels[addr->channel].medium		    != IPMI_CHANNEL_MEDIUM_IPMB)		{			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		if (retries < 0) {		    if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)			retries = 0; /* Don't retry broadcasts. */		    else			retries = 4;		}		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;		}		/* Default to 1 second retries. */		if (retry_time_ms == 0)		    retry_time_ms = 1000;		/* 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) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EMSGSIZE;			goto out_err;		}		ipmb_addr = (struct ipmi_ipmb_addr *) addr;		if (ipmb_addr->lun > 3) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			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. */			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_ipmb_responses++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,					msgid, broadcast,					source_address, source_lun);			/* Save the receive message so we can use it			   to deliver the response. */			smi_msg->user_data = recv_msg;		} else {			/* It's a command, so get a sequence for it. */			spin_lock_irqsave(&(intf->seq_lock), flags);			spin_lock(&intf->counter_lock);			intf->sent_ipmb_commands++;			spin_unlock(&intf->counter_lock);			/* Create a sequence number with a 1 second                           timeout and 4 retries. */			rv = intf_next_seq(intf,					   recv_msg,					   retry_time_ms,					   retries,					   broadcast,					   &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 if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {		struct ipmi_lan_addr  *lan_addr;		unsigned char         ipmb_seq;		long                  seqid;		if (addr->channel >= IPMI_NUM_CHANNELS) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		if ((intf->channels[addr->channel].medium		    != IPMI_CHANNEL_MEDIUM_8023LAN)		    && (intf->channels[addr->channel].medium			!= IPMI_CHANNEL_MEDIUM_ASYNC))		{			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		retries = 4;		/* Default to 1 second retries. */		if (retry_time_ms == 0)		    retry_time_ms = 1000;		/* 11 for the header and 1 for the checksum. */		if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EMSGSIZE;			goto out_err;		}		lan_addr = (struct ipmi_lan_addr *) addr;		if (lan_addr->lun > 3) {			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_invalid_commands++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			rv = -EINVAL;			goto out_err;		}		memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));		if (recv_msg->msg.netfn & 0x1) {			/* It's a response, so use the user's sequence                           from msgid. */			spin_lock_irqsave(&intf->counter_lock, flags);			intf->sent_lan_responses++;			spin_unlock_irqrestore(&intf->counter_lock, flags);			format_lan_msg(smi_msg, msg, lan_addr, msgid,				       msgid, source_lun);			/* Save the receive message so we can use it			   to deliver the response. */			smi_msg->user_data = recv_msg;		} else {			/* It's a command, so get a sequence for it. */			spin_lock_irqsave(&(intf->seq_lock), flags);			spin_lock(&intf->counter_lock);			intf->sent_lan_commands++;			spin_unlock(&intf->counter_lock);			/* Create a sequence number with a 1 second                           timeout and 4 retries. */			rv = intf_next_seq(intf,					   recv_msg,					   retry_time_ms,					   retries,					   0,					   &ipmb_seq,					   &seqid);			if (rv) {

⌨️ 快捷键说明

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