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

📄 ipmi_msghandler.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 4 页
字号:
{	return i_ipmi_request(user,			      user->intf,			      addr,			      msgid,			      msg,			      NULL, NULL,			      priority,			      source_address,			      source_lun);}int ipmi_register_smi(struct ipmi_smi_handlers *handlers,		      void		       *send_info,		      unsigned char            version_major,		      unsigned char            version_minor,		      ipmi_smi_t               *intf){	int              i, j;	int              rv;	ipmi_smi_t       new_intf;	struct list_head *entry;	unsigned long    flags;	/* Make sure the driver is actually initialized, this handles	   problems with initialization order. */	if (!initialized) {		rv = ipmi_init_msghandler();		if (rv)			return rv;		/* The init code doesn't return an error if it was turned		   off, but it won't initialize.  Check that. */		if (!initialized)			return -ENODEV;	}	new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL);	if (!new_intf)		return -ENOMEM;	rv = -ENOMEM;	down_write(&interfaces_sem);	for (i=0; i<MAX_IPMI_INTERFACES; i++) {		if (ipmi_interfaces[i] == NULL) {			new_intf->version_major = version_major;			new_intf->version_minor = version_minor;			new_intf->my_address = IPMI_BMC_SLAVE_ADDR;			new_intf->my_lun = 2;  /* the SMS LUN. */			rwlock_init(&(new_intf->users_lock));			INIT_LIST_HEAD(&(new_intf->users));			new_intf->handlers = handlers;			new_intf->send_info = send_info;			spin_lock_init(&(new_intf->seq_lock));			for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {				new_intf->seq_table[j].inuse = 0;				new_intf->seq_table[j].seqid = 0;			}			new_intf->curr_seq = 0;			spin_lock_init(&(new_intf->waiting_msgs_lock));			INIT_LIST_HEAD(&(new_intf->waiting_msgs));			spin_lock_init(&(new_intf->events_lock));			INIT_LIST_HEAD(&(new_intf->waiting_events));			new_intf->waiting_events_count = 0;			rwlock_init(&(new_intf->cmd_rcvr_lock));			INIT_LIST_HEAD(&(new_intf->cmd_rcvrs));			new_intf->all_cmd_rcvr = NULL;			spin_lock_irqsave(&interfaces_lock, flags);			ipmi_interfaces[i] = new_intf;			spin_unlock_irqrestore(&interfaces_lock, flags);			rv = 0;			*intf = new_intf;			break;		}	}	/* We convert to a read semaphore here.  It's possible the	   interface was removed between the calls, we have to recheck	   afterwards. */	up_write(&interfaces_sem);	down_read(&interfaces_sem);	if (ipmi_interfaces[i] != new_intf)		/* Well, it went away.  Just return. */		goto out;	if (rv == 0) {		/* Call all the watcher interfaces to tell them that a		   new interface is available. */		down_read(&smi_watchers_sem);		list_for_each(entry, &smi_watchers) {			struct ipmi_smi_watcher *w;			w = list_entry(entry, struct ipmi_smi_watcher, link);			w->new_smi(i);		}		up_read(&smi_watchers_sem);	} out:	up_read(&interfaces_sem);	if (rv)		kfree(new_intf);	return rv;}static void free_recv_msg_list(struct list_head *q){	struct list_head     *entry, *entry2;	struct ipmi_recv_msg *msg;	list_for_each_safe(entry, entry2, q) {		msg = list_entry(entry, struct ipmi_recv_msg, link);		list_del(entry);		ipmi_free_recv_msg(msg);	}}static void free_cmd_rcvr_list(struct list_head *q){	struct list_head *entry, *entry2;	struct cmd_rcvr  *rcvr;	list_for_each_safe(entry, entry2, q) {		rcvr = list_entry(entry, struct cmd_rcvr, link);		list_del(entry);		kfree(rcvr);	}}static void clean_up_interface_data(ipmi_smi_t intf){	int i;	free_recv_msg_list(&(intf->waiting_msgs));	free_recv_msg_list(&(intf->waiting_events));	free_cmd_rcvr_list(&(intf->cmd_rcvrs));	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);		}		}}int ipmi_unregister_smi(ipmi_smi_t intf){	int              rv = -ENODEV;	int              i;	struct list_head *entry;	unsigned long    flags;	down_write(&interfaces_sem);	if (list_empty(&(intf->users)))	{		for (i=0; i<MAX_IPMI_INTERFACES; i++) {			if (ipmi_interfaces[i] == intf) {				spin_lock_irqsave(&interfaces_lock, flags);				ipmi_interfaces[i] = NULL;				clean_up_interface_data(intf);				spin_unlock_irqrestore(&interfaces_lock,flags);				kfree(intf);				rv = 0;				goto out_call_watcher;			}		}	} else {		rv = -EBUSY;	}	up_write(&interfaces_sem);	return rv; out_call_watcher:	/* Convert to a read semaphore so callbacks don't bite us. */	up_write(&interfaces_sem);	down_read(&interfaces_sem);	/* Call all the watcher interfaces to tell them that	   an interface is gone. */	down_read(&smi_watchers_sem);	list_for_each(entry, &smi_watchers) {		struct ipmi_smi_watcher *w;		w = list_entry(entry,			       struct ipmi_smi_watcher,			       link);		w->smi_gone(i);	}	up_read(&smi_watchers_sem);	up_read(&interfaces_sem);	return 0;}static int handle_get_msg_rsp(ipmi_smi_t          intf,			      struct ipmi_smi_msg *msg){	struct ipmi_ipmb_addr ipmb_addr;	struct ipmi_recv_msg  *recv_msg;		if (msg->rsp_size < 11)		/* Message not big enough, just ignore it. */		return 0;	if (msg->rsp[2] != 0)		/* An error getting the response, just ignore it. */		return 0;	ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE;	ipmb_addr.slave_addr = msg->rsp[6];	ipmb_addr.channel = msg->rsp[3] & 0x0f;	ipmb_addr.lun = msg->rsp[7] & 3;	/* It's a response from a remote entity.  Look up the sequence	   number and handle the response. */	if (intf_find_seq(intf,			  msg->rsp[7] >> 2,			  msg->rsp[3] & 0x0f,			  msg->rsp[8],			  (msg->rsp[4] >> 2) & (~1),			  (struct ipmi_addr *) &(ipmb_addr),			  &recv_msg))	{		/* We were unable to find the sequence number,		   so just nuke the message. */		return 0;	}	memcpy(recv_msg->msg_data,	       &(msg->rsp[9]),	       msg->rsp_size - 9);	/* THe other fields matched, so no need to set them, except           for netfn, which needs to be the response that was           returned, not the request value. */	recv_msg->msg.netfn = msg->rsp[4] >> 2;	recv_msg->msg.data = recv_msg->msg_data;	recv_msg->msg.data_len = msg->rsp_size - 10;	recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;	deliver_response(recv_msg);	return 0;}static int handle_get_msg_cmd(ipmi_smi_t          intf,			      struct ipmi_smi_msg *msg){	struct list_head *entry;	struct cmd_rcvr       *rcvr;	int              rv = 0;	unsigned char    netfn;	unsigned char    cmd;	ipmi_user_t      user = NULL;	struct ipmi_ipmb_addr *ipmb_addr;	struct ipmi_recv_msg  *recv_msg;	if (msg->rsp_size < 10)		/* Message not big enough, just ignore it. */		return 0;	if (msg->rsp[2] != 0) {		/* An error getting the response, just ignore it. */		return 0;	}	netfn = msg->rsp[4] >> 2;	cmd = msg->rsp[8];	read_lock(&(intf->cmd_rcvr_lock));		if (intf->all_cmd_rcvr) {		user = intf->all_cmd_rcvr;	} else {		/* Find the command/netfn. */		list_for_each(entry, &(intf->cmd_rcvrs)) {			rcvr = list_entry(entry, struct cmd_rcvr, link);			if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) {				user = rcvr->user;				break;			}		}	}	read_unlock(&(intf->cmd_rcvr_lock));	if (user == NULL) {		/* We didn't find a user, deliver an error response. */		msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);		msg->data[1] = IPMI_SEND_MSG_CMD;		msg->data[2] = msg->rsp[3];		msg->data[3] = msg->rsp[6];                msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);		msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);		msg->data[6] = intf->my_address;                /* rqseq/lun */                msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);		msg->data[8] = msg->rsp[8]; /* cmd */		msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;		msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);		msg->data_size = 11;		intf->handlers->sender(intf->send_info, msg, 0);		rv = -1; /* We used the message, so return the value that			    causes it to not be freed or queued. */	} else {		/* Deliver the message to the user. */		recv_msg = ipmi_alloc_recv_msg();		if (! recv_msg) {			/* We couldn't allocate memory for the                           message, so requeue it for handling                           later. */			rv = 1;		} else {			ipmb_addr = (struct ipmi_ipmb_addr *) &recv_msg->addr;			ipmb_addr->addr_type = IPMI_IPMB_ADDR_TYPE;			ipmb_addr->slave_addr = msg->rsp[6];			ipmb_addr->lun = msg->rsp[7] & 3;			ipmb_addr->channel = msg->rsp[3];			recv_msg->user = user;			recv_msg->recv_type = IPMI_CMD_RECV_TYPE;			recv_msg->msgid = msg->rsp[7] >> 2;			recv_msg->msg.netfn = msg->rsp[4] >> 2;			recv_msg->msg.cmd = msg->rsp[8];			recv_msg->msg.data = recv_msg->msg_data;			recv_msg->msg.data_len = msg->rsp_size - 10;			memcpy(recv_msg->msg_data,			       &(msg->rsp[9]),			       msg->rsp_size - 10);			deliver_response(recv_msg);		}	}	return rv;}static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,				     struct ipmi_smi_msg  *msg){	struct ipmi_system_interface_addr *smi_addr;		recv_msg->msgid = 0;	smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);	smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;	smi_addr->channel = IPMI_BMC_CHANNEL;	smi_addr->lun = msg->rsp[0] & 3;	recv_msg->recv_type = IPMI_ASYNC_EVENT_RECV_TYPE;	recv_msg->msg.netfn = msg->rsp[0] >> 2;	recv_msg->msg.cmd = msg->rsp[1];	memcpy(recv_msg->msg_data, &(msg->rsp[3]), msg->rsp_size - 3);	recv_msg->msg.data = recv_msg->msg_data;	recv_msg->msg.data_len = msg->rsp_size - 3;}/* This will be called with the intf->users_lock read-locked, so no need   to do that here. */static int handle_read_event_rsp(ipmi_smi_t          intf,				 struct ipmi_smi_msg *msg){	struct ipmi_recv_msg *recv_msg;	struct list_head     msgs;	struct list_head     *entry, *entry2;	ipmi_user_t          user;	int                  rv = 0;	int                  deliver_count = 0;	unsigned long        flags;	if (msg->rsp_size < 19) {		/* Message is too small to be an IPMB event. */		return 0;	}	if (msg->rsp[2] != 0) {		/* An error getting the event, just ignore it. */		return 0;	}	INIT_LIST_HEAD(&msgs);	spin_lock_irqsave(&(intf->events_lock), flags);	/* Allocate and fill in one message for every user that is getting	   events. */	list_for_each(entry, &(intf->users)) {		user = list_entry(entry, struct ipmi_user, link);		if (! user->gets_events)			continue;		recv_msg = ipmi_alloc_recv_msg();		if (! recv_msg) {			list_for_each_safe(entry, entry2, &msgs) {				recv_msg = list_entry(entry,						      struct ipmi_recv_msg,						      link);				list_del(entry);				ipmi_free_recv_msg(recv_msg);			}			/* We couldn't allocate memory for the                           message, so requeue it for handling                           later. */			rv = 1;			goto out;		}		deliver_count++;		copy_event_into_recv_msg(recv_msg, msg);		recv_msg->user = user;		list_add_tail(&(recv_msg->link), &msgs);	}	if (deliver_count) {		/* Now deliver all the messages. */		list_for_each_safe(entry, entry2, &msgs) {			recv_msg = list_entry(entry,					      struct ipmi_recv_msg,					      link);			list_del(entry);			deliver_response(recv_msg);		}	} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {		/* No one to receive the message, put it in queue if there's		   not already too many things in the queue. */		recv_msg = ipmi_alloc_recv_msg();		if (! recv_msg) {			/* We couldn't allocate memory for the                           message, so requeue it for handling                           later. */			rv = 1;			goto out;		}		copy_event_into_recv_msg(recv_msg, msg);		list_add_tail(&(recv_msg->link), &(intf->waiting_events));	} else {		/* There's too many things in the queue, discard this		   message. */		printk(KERN_WARNING "ipmi: Event queue full, discarding an"		       " incoming event\n");	} out:	spin_unlock_irqrestore(&(intf->events_lock), flags);	return rv;}static int handle_bmc_rsp(ipmi_smi_t          intf,			  struct ipmi_smi_msg *msg){	struct ipmi_recv_msg *recv_msg;	int                  found = 0;	struct list_head     *entry;	recv_msg = (struct ipmi_recv_msg *) msg->user_data;	/* Make sure the user still exists. */	list_for_each(entry, &(intf->users)) {		if (list_entry(entry, struct ipmi_user, link)		    == recv_msg->user)		{			/* Found it, so we can deliver it */			found = 1;			break;		}	}	if (!found) {		/* The user for the message went away, so give up. */		ipmi_free_recv_msg(recv_msg);	} else {		struct ipmi_system_interface_addr *smi_addr;		recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;		recv_msg->msgid = msg->msgid;		smi_addr = ((struct ipmi_system_interface_addr *)			    &(recv_msg->addr));		smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;		smi_addr->channel = IPMI_BMC_CHANNEL;		smi_addr->lun = msg->rsp[0] & 3;		recv_msg->msg.netfn = msg->rsp[0] >> 2;		recv_msg->msg.cmd = msg->rsp[1];		memcpy(recv_msg->msg_data,		       &(msg->rsp[2]),		       msg->rsp_size - 2);		recv_msg->msg.data = recv_msg->msg_data;		recv_msg->msg.data_len = msg->rsp_size - 2;		deliver_response(recv_msg);	}	return 0;}/* Handle a new message.  Return 1 if the message should be requeued,   0 if the message should be freed, or -1 if the message should not

⌨️ 快捷键说明

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