ipmi_msghandler.c

来自「linux 内核源代码」· C语言 代码 · 共 2,407 行 · 第 1/5 页

C
2,407
字号
int ipmi_get_my_address(ipmi_user_t   user,			unsigned int  channel,			unsigned char *address){	if (channel >= IPMI_MAX_CHANNELS)		return -EINVAL;	*address = user->intf->channels[channel].address;	return 0;}int ipmi_set_my_LUN(ipmi_user_t   user,		    unsigned int  channel,		    unsigned char LUN){	if (channel >= IPMI_MAX_CHANNELS)		return -EINVAL;	user->intf->channels[channel].lun = LUN & 0x3;	return 0;}int ipmi_get_my_LUN(ipmi_user_t   user,		    unsigned int  channel,		    unsigned char *address){	if (channel >= IPMI_MAX_CHANNELS)		return -EINVAL;	*address = user->intf->channels[channel].lun;	return 0;}int ipmi_get_maintenance_mode(ipmi_user_t user){	int           mode;	unsigned long flags;	spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags);	mode = user->intf->maintenance_mode;	spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags);	return mode;}EXPORT_SYMBOL(ipmi_get_maintenance_mode);static void maintenance_mode_update(ipmi_smi_t intf){	if (intf->handlers->set_maintenance_mode)		intf->handlers->set_maintenance_mode(			intf->send_info, intf->maintenance_mode_enable);}int ipmi_set_maintenance_mode(ipmi_user_t user, int mode){	int           rv = 0;	unsigned long flags;	ipmi_smi_t    intf = user->intf;	spin_lock_irqsave(&intf->maintenance_mode_lock, flags);	if (intf->maintenance_mode != mode) {		switch (mode) {		case IPMI_MAINTENANCE_MODE_AUTO:			intf->maintenance_mode = mode;			intf->maintenance_mode_enable				= (intf->auto_maintenance_timeout > 0);			break;		case IPMI_MAINTENANCE_MODE_OFF:			intf->maintenance_mode = mode;			intf->maintenance_mode_enable = 0;			break;		case IPMI_MAINTENANCE_MODE_ON:			intf->maintenance_mode = mode;			intf->maintenance_mode_enable = 1;			break;		default:			rv = -EINVAL;			goto out_unlock;		}		maintenance_mode_update(intf);	} out_unlock:	spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags);	return rv;}EXPORT_SYMBOL(ipmi_set_maintenance_mode);int ipmi_set_gets_events(ipmi_user_t user, int val){	unsigned long        flags;	ipmi_smi_t           intf = user->intf;	struct ipmi_recv_msg *msg, *msg2;	struct list_head     msgs;	INIT_LIST_HEAD(&msgs);	spin_lock_irqsave(&intf->events_lock, flags);	user->gets_events = val;	if (intf->delivering_events)		/*		 * Another thread is delivering events for this, so		 * let it handle any new events.		 */		goto out;	/* Deliver any queued events. */	while (user->gets_events && !list_empty(&intf->waiting_events)) {		list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)			list_move_tail(&msg->link, &msgs);		intf->waiting_events_count = 0;		intf->delivering_events = 1;		spin_unlock_irqrestore(&intf->events_lock, flags);		list_for_each_entry_safe(msg, msg2, &msgs, link) {			msg->user = user;			kref_get(&user->refcount);			deliver_response(msg);		}		spin_lock_irqsave(&intf->events_lock, flags);		intf->delivering_events = 0;	} out:	spin_unlock_irqrestore(&intf->events_lock, flags);	return 0;}static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t    intf,				      unsigned char netfn,				      unsigned char cmd,				      unsigned char chan){	struct cmd_rcvr *rcvr;	list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)					&& (rcvr->chans & (1 << chan)))			return rcvr;	}	return NULL;}static int is_cmd_rcvr_exclusive(ipmi_smi_t    intf,				 unsigned char netfn,				 unsigned char cmd,				 unsigned int  chans){	struct cmd_rcvr *rcvr;	list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {		if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)					&& (rcvr->chans & chans))			return 0;	}	return 1;}int ipmi_register_for_cmd(ipmi_user_t   user,			  unsigned char netfn,			  unsigned char cmd,			  unsigned int  chans){	ipmi_smi_t      intf = user->intf;	struct cmd_rcvr *rcvr;	int             rv = 0;	rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL);	if (!rcvr)		return -ENOMEM;	rcvr->cmd = cmd;	rcvr->netfn = netfn;	rcvr->chans = chans;	rcvr->user = user;	mutex_lock(&intf->cmd_rcvrs_mutex);	/* Make sure the command/netfn is not already registered. */	if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {		rv = -EBUSY;		goto out_unlock;	}	list_add_rcu(&rcvr->link, &intf->cmd_rcvrs); out_unlock:	mutex_unlock(&intf->cmd_rcvrs_mutex);	if (rv)		kfree(rcvr);	return rv;}int ipmi_unregister_for_cmd(ipmi_user_t   user,			    unsigned char netfn,			    unsigned char cmd,			    unsigned int  chans){	ipmi_smi_t      intf = user->intf;	struct cmd_rcvr *rcvr;	struct cmd_rcvr *rcvrs = NULL;	int i, rv = -ENOENT;	mutex_lock(&intf->cmd_rcvrs_mutex);	for (i = 0; i < IPMI_NUM_CHANNELS; i++) {		if (((1 << i) & chans) == 0)			continue;		rcvr = find_cmd_rcvr(intf, netfn, cmd, i);		if (rcvr == NULL)			continue;		if (rcvr->user == user) {			rv = 0;			rcvr->chans &= ~chans;			if (rcvr->chans == 0) {				list_del_rcu(&rcvr->link);				rcvr->next = rcvrs;				rcvrs = rcvr;			}		}	}	mutex_unlock(&intf->cmd_rcvrs_mutex);	synchronize_rcu();	while (rcvrs) {		rcvr = rcvrs;		rcvrs = rcvr->next;		kfree(rcvr);	}	return rv;}void ipmi_user_set_run_to_completion(ipmi_user_t user, int val){	ipmi_smi_t intf = user->intf;	if (intf->handlers)		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;	struct ipmi_smi_handlers *handlers;	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;		}	}	rcu_read_lock();	handlers = intf->handlers;	if (!handlers) {		rv = -ENODEV;		goto out_err;	}	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->netfn == IPMI_NETFN_APP_REQUEST)		      && ((msg->cmd == IPMI_COLD_RESET_CMD)			  || (msg->cmd == IPMI_WARM_RESET_CMD)))		     || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))		{			spin_lock_irqsave(&intf->maintenance_mode_lock, flags);			intf->auto_maintenance_timeout				= IPMI_MAINTENANCE_MODE_TIMEOUT;			if (!intf->maintenance_mode			    && !intf->maintenance_mode_enable)			{				intf->maintenance_mode_enable = 1;				maintenance_mode_update(intf);			}			spin_unlock_irqrestore(&intf->maintenance_mode_lock,					       flags);		}		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);

⌨️ 快捷键说明

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