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

📄 ipmi_msghandler.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 4 页
字号:
   be freed or requeued. */static int handle_new_recv_msg(ipmi_smi_t          intf,			       struct ipmi_smi_msg *msg){	int requeue;	if (msg->rsp_size < 2) {		/* Message is too small to be correct. */		requeue = 0;	} else if (msg->rsp[1] == IPMI_GET_MSG_CMD) {#if DEBUG_MSGING		int m;		printk("Response:");		for (m=0; m<msg->rsp_size; m++)			printk(" %2.2x", msg->rsp[m]);		printk("\n");#endif		/* It's from the receive queue. */		if (msg->rsp[4] & 0x04) {			/* It's a response, so find the			   requesting message and send it up. */			requeue = handle_get_msg_rsp(intf, msg);		} else {			/* It's a command to the SMS from some other			   entity.  Handle that. */			requeue = handle_get_msg_cmd(intf, msg);		}	} else if (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD) {		/* It's an asyncronous event. */		requeue = handle_read_event_rsp(intf, msg);	} else {		/* It's a response from the local BMC. */		requeue = handle_bmc_rsp(intf, msg);	}	return requeue;}/* Handle a new message from the lower layer. */void ipmi_smi_msg_received(ipmi_smi_t          intf,			   struct ipmi_smi_msg *msg){	unsigned long flags;	int           rv;	/* Lock the user lock so the user can't go away while we are	   working on it. */	read_lock(&(intf->users_lock));	if ((msg->data_size >= 2) && (msg->data[1] == IPMI_SEND_MSG_CMD)) {		/* This is the local response to a send, start the                   timer for these. */		intf_start_seq_timer(intf, msg->msgid);		ipmi_free_smi_msg(msg);		goto out_unlock;	}	/* To preserve message order, if the list is not empty, we           tack this message onto the end of the list. */	spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);	if (!list_empty(&(intf->waiting_msgs))) {		list_add_tail(&(msg->link), &(intf->waiting_msgs));		spin_unlock(&(intf->waiting_msgs_lock));		goto out_unlock;	}	spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);			rv = handle_new_recv_msg(intf, msg);	if (rv > 0) {		/* Could not handle the message now, just add it to a                   list to handle later. */		spin_lock(&(intf->waiting_msgs_lock));		list_add_tail(&(msg->link), &(intf->waiting_msgs));		spin_unlock(&(intf->waiting_msgs_lock));	} else if (rv == 0) {		ipmi_free_smi_msg(msg);	} out_unlock:	read_unlock(&(intf->users_lock));}void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf){	struct list_head *entry;	ipmi_user_t      user;	read_lock(&(intf->users_lock));	list_for_each(entry, &(intf->users)) {		user = list_entry(entry, struct ipmi_user, link);		if (! user->handler->ipmi_watchdog_pretimeout)			continue;		user->handler->ipmi_watchdog_pretimeout(user->handler_data);	}	read_unlock(&(intf->users_lock));}static voidhandle_msg_timeout(struct ipmi_recv_msg *msg){	msg->recv_type = IPMI_RESPONSE_RECV_TYPE;	msg->msg_data[0] = IPMI_TIMEOUT_COMPLETION_CODE;	msg->msg.netfn |= 1; /* Convert to a response. */	msg->msg.data_len = 1;	msg->msg.data = msg->msg_data;	deliver_response(msg);}static voidsend_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,		   struct ipmi_smi_msg *smi_msg,		   unsigned char seq, long seqid){	if (!smi_msg)		smi_msg = ipmi_alloc_smi_msg();	if (!smi_msg)		/* If we can't allocate the message, then just return, we		   get 4 retries, so this should be ok. */		return;	memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);	smi_msg->data_size = recv_msg->msg.data_len;	smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);			/* Send the new message.  We send with a zero priority.  It	   timed out, I doubt time is that critical now, and high	   priority messages are really only for messages to the local	   MC, which don't get resent. */	intf->handlers->sender(intf->send_info, smi_msg, 0);#if DEBUG_MSGING	{		int m;		printk("Resend: ");		for (m=0; m<smi_msg->data_size; m++)			printk(" %2.2x", smi_msg->data[m]);		printk("\n");	}#endif}static voidipmi_timeout_handler(long timeout_period){	ipmi_smi_t           intf;	struct list_head     timeouts;	struct ipmi_recv_msg *msg;	struct ipmi_smi_msg  *smi_msg;	unsigned long        flags;	struct list_head     *entry, *entry2;	int                  i, j;	INIT_LIST_HEAD(&timeouts);	spin_lock(&interfaces_lock);	for (i=0; i<MAX_IPMI_INTERFACES; i++) {		intf = ipmi_interfaces[i];		if (intf == NULL)			continue;		read_lock(&(intf->users_lock));		/* See if any waiting messages need to be processed. */		spin_lock_irqsave(&(intf->waiting_msgs_lock), flags);		list_for_each_safe(entry, entry2, &(intf->waiting_msgs)) {			smi_msg = list_entry(entry, struct ipmi_smi_msg, link);			if (! handle_new_recv_msg(intf, smi_msg)) {				list_del(entry);				ipmi_free_smi_msg(smi_msg);			} else {				/* To preserve message order, quit if we				   can't handle a message. */				break;			}		}		spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags);		/* Go through the seq table and find any messages that		   have timed out, putting them in the timeouts		   list. */		spin_lock_irqsave(&(intf->seq_lock), flags);		for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) {			struct seq_table *ent = &(intf->seq_table[j]);			if (!ent->inuse)				continue;			ent->timeout -= timeout_period;			if (ent->timeout > 0)				continue;			if (ent->retries_left == 0) {				/* The message has used all its retries. */				ent->inuse = 0;				msg = ent->recv_msg;				list_add_tail(&(msg->link), &timeouts);			} else {				/* More retries, send again. */				/* Start with the max timer, set to normal				   timer after the message is sent. */				ent->timeout = MAX_MSG_TIMEOUT;				ent->retries_left--;				send_from_recv_msg(intf, ent->recv_msg, NULL,						   j, ent->seqid);			}		}		spin_unlock_irqrestore(&(intf->seq_lock), flags);		list_for_each_safe(entry, entry2, &timeouts) {			msg = list_entry(entry, struct ipmi_recv_msg, link);			handle_msg_timeout(msg);		}		read_unlock(&(intf->users_lock));	}	spin_unlock(&interfaces_lock);}static void ipmi_request_event(void){	ipmi_smi_t intf;	int        i;	spin_lock(&interfaces_lock);	for (i=0; i<MAX_IPMI_INTERFACES; i++) {		intf = ipmi_interfaces[i];		if (intf == NULL)			continue;		intf->handlers->request_events(intf->send_info);	}	spin_unlock(&interfaces_lock);}static struct timer_list ipmi_timer;/* Call every 100 ms. */#define IPMI_TIMEOUT_TIME	100#define IPMI_TIMEOUT_JIFFIES	(IPMI_TIMEOUT_TIME/(1000/HZ))/* Request events from the queue every second.  Hopefully, in the   future, IPMI will add a way to know immediately if an event is   in the queue. */#define IPMI_REQUEST_EV_TIME	(1000 / (IPMI_TIMEOUT_TIME))static volatile int stop_operation = 0;static volatile int timer_stopped = 0;static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;static void ipmi_timeout(unsigned long data){	if (stop_operation) {		timer_stopped = 1;		return;	}	ticks_to_req_ev--;	if (ticks_to_req_ev == 0) {		ipmi_request_event();		ticks_to_req_ev = IPMI_REQUEST_EV_TIME;	}	ipmi_timeout_handler(IPMI_TIMEOUT_TIME);	ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES;	add_timer(&ipmi_timer);}static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);/* FIXME - convert these to slabs. */static void free_smi_msg(struct ipmi_smi_msg *msg){	atomic_dec(&smi_msg_inuse_count);	kfree(msg);}struct ipmi_smi_msg *ipmi_alloc_smi_msg(void){	struct ipmi_smi_msg *rv;	rv = kmalloc(sizeof(struct ipmi_smi_msg), GFP_ATOMIC);	if (rv) {		rv->done = free_smi_msg;		atomic_inc(&smi_msg_inuse_count);	}	return rv;}static void free_recv_msg(struct ipmi_recv_msg *msg){	atomic_dec(&recv_msg_inuse_count);	kfree(msg);}struct ipmi_recv_msg *ipmi_alloc_recv_msg(void){	struct ipmi_recv_msg *rv;	rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);	if (rv) {		rv->done = free_recv_msg;		atomic_inc(&recv_msg_inuse_count);	}	return rv;}#ifdef CONFIG_IPMI_PANIC_EVENTstatic void dummy_smi_done_handler(struct ipmi_smi_msg *msg){}static void dummy_recv_done_handler(struct ipmi_recv_msg *msg){}static void send_panic_events(void){	struct ipmi_msg                   msg;	ipmi_smi_t                        intf;	unsigned char                     data[8];	int                               i;	struct ipmi_system_interface_addr addr;	struct ipmi_smi_msg               smi_msg;	struct ipmi_recv_msg              recv_msg;	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;	addr.channel = IPMI_BMC_CHANNEL;	/* Fill in an event telling that we have failed. */	msg.netfn = 0x04; /* Sensor or Event. */	msg.cmd = 2; /* Platform event command. */	msg.data = data;	msg.data_len = 8;	data[0] = 0x21; /* Kernel generator ID, IPMI table 5-4 */	data[1] = 0x03; /* This is for IPMI 1.0. */	data[2] = 0x20; /* OS Critical Stop, IPMI table 36-3 */	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */	/* These used to have the first three bytes of the panic string,	   but not only is that not terribly useful, it's not available	   any more. */	data[3] = 0;	data[6] = 0;	data[7] = 0;	smi_msg.done = dummy_smi_done_handler;	recv_msg.done = dummy_recv_done_handler;	/* For every registered interface, send the event. */	for (i=0; i<MAX_IPMI_INTERFACES; i++) {		intf = ipmi_interfaces[i];		if (intf == NULL)			continue;		intf->handlers->set_run_to_completion(intf->send_info, 1);		i_ipmi_request(NULL,			       intf,			       (struct ipmi_addr *) &addr,			       0,			       &msg,			       &smi_msg,			       &recv_msg,			       0,			       intf->my_address,			       intf->my_lun);	}}#endif /* CONFIG_IPMI_PANIC_EVENT */static int has_paniced = 0;static int panic_event(struct notifier_block *this,		       unsigned long         event,                       void                  *ptr){	int        i;	ipmi_smi_t intf;	if (has_paniced)		return NOTIFY_DONE;	has_paniced = 1;	/* For every registered interface, set it to run to completion. */	for (i=0; i<MAX_IPMI_INTERFACES; i++) {		intf = ipmi_interfaces[i];		if (intf == NULL)			continue;		intf->handlers->set_run_to_completion(intf->send_info, 1);	}#ifdef CONFIG_IPMI_PANIC_EVENT	send_panic_events();#endif	return NOTIFY_DONE;}static struct notifier_block panic_block = {	panic_event,	NULL,	200   /* priority: INT_MAX >= x >= 0 */};static __init int ipmi_init_msghandler(void){	int i;	if (initialized)		return 0;	for (i=0; i<MAX_IPMI_INTERFACES; i++) {		ipmi_interfaces[i] = NULL;	}	init_timer(&ipmi_timer);	ipmi_timer.data = 0;	ipmi_timer.function = ipmi_timeout;	ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;	add_timer(&ipmi_timer);	notifier_chain_register(&panic_notifier_list, &panic_block);	initialized = 1;	printk(KERN_INFO "ipmi: message handler initialized\n");	return 0;}static __exit void cleanup_ipmi(void){	int count;	if (!initialized)		return;	notifier_chain_unregister(&panic_notifier_list, &panic_block);	/* This can't be called if any interfaces exist, so no worry about	   shutting down the interfaces. */	/* Tell the timer to stop, then wait for it to stop.  This avoids	   problems with race conditions removing the timer here. */	stop_operation = 1;	while (!timer_stopped) {		schedule_timeout(1);	}	initialized = 0;	/* Check for buffer leaks. */	count = atomic_read(&smi_msg_inuse_count);	if (count != 0)		printk("ipmi_msghandler: SMI message count %d at exit\n",		       count);	count = atomic_read(&recv_msg_inuse_count);	if (count != 0)		printk("ipmi_msghandler: recv message count %d at exit\n",		       count);}module_exit(cleanup_ipmi);module_init(ipmi_init_msghandler);MODULE_LICENSE("GPL");EXPORT_SYMBOL(ipmi_alloc_recv_msg);EXPORT_SYMBOL(ipmi_create_user);EXPORT_SYMBOL(ipmi_destroy_user);EXPORT_SYMBOL(ipmi_get_version);EXPORT_SYMBOL(ipmi_request);EXPORT_SYMBOL(ipmi_request_supply_msgs);EXPORT_SYMBOL(ipmi_request_with_source);EXPORT_SYMBOL(ipmi_register_smi);EXPORT_SYMBOL(ipmi_unregister_smi);EXPORT_SYMBOL(ipmi_register_for_cmd);EXPORT_SYMBOL(ipmi_unregister_for_cmd);EXPORT_SYMBOL(ipmi_smi_msg_received);EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);EXPORT_SYMBOL(ipmi_alloc_smi_msg);EXPORT_SYMBOL(ipmi_register_all_cmd_rcvr);EXPORT_SYMBOL(ipmi_unregister_all_cmd_rcvr);EXPORT_SYMBOL(ipmi_addr_length);EXPORT_SYMBOL(ipmi_validate_addr);EXPORT_SYMBOL(ipmi_set_gets_events);EXPORT_SYMBOL(ipmi_addr_equal);EXPORT_SYMBOL(ipmi_smi_watcher_register);EXPORT_SYMBOL(ipmi_smi_watcher_unregister);EXPORT_SYMBOL(ipmi_set_my_address);EXPORT_SYMBOL(ipmi_get_my_address);EXPORT_SYMBOL(ipmi_set_my_LUN);EXPORT_SYMBOL(ipmi_get_my_LUN);

⌨️ 快捷键说明

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