exec-osm.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 589 行 · 第 1/2 页

C
589
字号
/* *	Executive OSM * * 	Copyright (C) 1999-2002	Red Hat Software * *	Written by Alan Cox, Building Number Three Ltd * *	This program is free software; you can redistribute it and/or modify it *	under the terms of the GNU General Public License as published by the *	Free Software Foundation; either version 2 of the License, or (at your *	option) any later version. * *	A lot of the I2O message side code from this is taken from the Red *	Creek RCPCI45 adapter driver by Red Creek Communications * *	Fixes/additions: *		Philipp Rumpf *		Juha Siev鋘en <Juha.Sievanen@cs.Helsinki.FI> *		Auvo H鋕kinen <Auvo.Hakkinen@cs.Helsinki.FI> *		Deepak Saxena <deepak@plexity.net> *		Boji T Kannanthanam <boji.t.kannanthanam@intel.com> *		Alan Cox <alan@redhat.com>: *			Ported to Linux 2.5. *		Markus Lidel <Markus.Lidel@shadowconnect.com>: *			Minor fixes for 2.6. *		Markus Lidel <Markus.Lidel@shadowconnect.com>: *			Support for sysfs included. */#include <linux/module.h>#include <linux/i2o.h>#include <linux/delay.h>#include <linux/workqueue.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/sched.h>	/* wait_event_interruptible_timeout() needs this */#include <asm/param.h>		/* HZ */#include "core.h"#define OSM_NAME "exec-osm"struct i2o_driver i2o_exec_driver;static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);/* global wait list for POST WAIT */static LIST_HEAD(i2o_exec_wait_list);/* Wait struct needed for POST WAIT */struct i2o_exec_wait {	wait_queue_head_t *wq;	/* Pointer to Wait queue */	struct i2o_dma dma;	/* DMA buffers to free on failure */	u32 tcntxt;		/* transaction context from reply */	int complete;		/* 1 if reply received otherwise 0 */	u32 m;			/* message id */	struct i2o_message *msg;	/* pointer to the reply message */	struct list_head list;	/* node in global wait list */	spinlock_t lock;	/* lock before modifying */};/* Work struct needed to handle LCT NOTIFY replies */struct i2o_exec_lct_notify_work {	struct work_struct work;	/* work struct */	struct i2o_controller *c;	/* controller on which the LCT NOTIFY					   was received */};/* Exec OSM class handling definition */static struct i2o_class_id i2o_exec_class_id[] = {	{I2O_CLASS_EXECUTIVE},	{I2O_CLASS_END}};/** *	i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it * *	Allocate the i2o_exec_wait struct and initialize the wait. * *	Returns i2o_exec_wait pointer on success or negative error code on *	failure. */static struct i2o_exec_wait *i2o_exec_wait_alloc(void){	struct i2o_exec_wait *wait;	wait = kzalloc(sizeof(*wait), GFP_KERNEL);	if (!wait)		return NULL;	INIT_LIST_HEAD(&wait->list);	spin_lock_init(&wait->lock);	return wait;};/** *	i2o_exec_wait_free - Free a i2o_exec_wait struct *	@i2o_exec_wait: I2O wait data which should be cleaned up */static void i2o_exec_wait_free(struct i2o_exec_wait *wait){	kfree(wait);};/** * 	i2o_msg_post_wait_mem - Post and wait a message with DMA buffers *	@c: controller *	@m: message to post *	@timeout: time in seconds to wait *	@dma: i2o_dma struct of the DMA buffer to free on failure * * 	This API allows an OSM to post a message and then be told whether or *	not the system received a successful reply. If the message times out *	then the value '-ETIMEDOUT' is returned. This is a special case. In *	this situation the message may (should) complete at an indefinite time *	in the future. When it completes it will use the memory buffer *	attached to the request. If -ETIMEDOUT is returned then the memory *	buffer must not be freed. Instead the event completion will free them *	for you. In all other cases the buffer are your problem. * *	Returns 0 on success, negative error code on timeout or positive error *	code from reply. */int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,			  unsigned long timeout, struct i2o_dma *dma){	DECLARE_WAIT_QUEUE_HEAD(wq);	struct i2o_exec_wait *wait;	static u32 tcntxt = 0x80000000;	long flags;	int rc = 0;	wait = i2o_exec_wait_alloc();	if (!wait)		return -ENOMEM;	if (tcntxt == 0xffffffff)		tcntxt = 0x80000000;	if (dma)		wait->dma = *dma;	/*	 * Fill in the message initiator context and transaction context.	 * We will only use transaction contexts >= 0x80000000 for POST WAIT,	 * so we could find a POST WAIT reply easier in the reply handler.	 */	msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);	wait->tcntxt = tcntxt++;	msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt);	wait->wq = &wq;	/*	 * we add elements to the head, because if a entry in the list will	 * never be removed, we have to iterate over it every time	 */	list_add(&wait->list, &i2o_exec_wait_list);	/*	 * Post the message to the controller. At some point later it will	 * return. If we time out before it returns then complete will be zero.	 */	i2o_msg_post(c, msg);	wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ);	spin_lock_irqsave(&wait->lock, flags);	wait->wq = NULL;	if (wait->complete)		rc = le32_to_cpu(wait->msg->body[0]) >> 24;	else {		/*		 * We cannot remove it now. This is important. When it does		 * terminate (which it must do if the controller has not		 * died...) then it will otherwise scribble on stuff.		 *		 * FIXME: try abort message		 */		if (dma)			dma->virt = NULL;		rc = -ETIMEDOUT;	}	spin_unlock_irqrestore(&wait->lock, flags);	if (rc != -ETIMEDOUT) {		i2o_flush_reply(c, wait->m);		i2o_exec_wait_free(wait);	}	return rc;};/** *	i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP *	@c: I2O controller which answers *	@m: message id *	@msg: pointer to the I2O reply message *	@context: transaction context of request * *	This function is called in interrupt context only. If the reply reached *	before the timeout, the i2o_exec_wait struct is filled with the message *	and the task will be waked up. The task is now responsible for returning *	the message m back to the controller! If the message reaches us after *	the timeout clean up the i2o_exec_wait struct (including allocated *	DMA buffer). * *	Return 0 on success and if the message m should not be given back to the *	I2O controller, or >0 on success and if the message should be given back *	afterwords. Returns negative error code on failure. In this case the *	message must also be given back to the controller. */static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,				      struct i2o_message *msg, u32 context){	struct i2o_exec_wait *wait, *tmp;	unsigned long flags;	int rc = 1;	/*	 * We need to search through the i2o_exec_wait_list to see if the given	 * message is still outstanding. If not, it means that the IOP took	 * longer to respond to the message than we had allowed and timer has	 * already expired. Not much we can do about that except log it for	 * debug purposes, increase timeout, and recompile.	 */	list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {		if (wait->tcntxt == context) {			spin_lock_irqsave(&wait->lock, flags);			list_del(&wait->list);			wait->m = m;			wait->msg = msg;			wait->complete = 1;			if (wait->wq)				rc = 0;			else				rc = -1;			spin_unlock_irqrestore(&wait->lock, flags);			if (rc) {				struct device *dev;				dev = &c->pdev->dev;				pr_debug("%s: timedout reply received!\n",					 c->name);				i2o_dma_free(dev, &wait->dma);				i2o_exec_wait_free(wait);			} else				wake_up_interruptible(wait->wq);			return rc;		}	}	osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,		 context);	return -1;};/** *	i2o_exec_show_vendor_id - Displays Vendor ID of controller *	@d: device of which the Vendor ID should be displayed *	@buf: buffer into which the Vendor ID should be printed * *	Returns number of bytes printed into buffer. */static ssize_t i2o_exec_show_vendor_id(struct device *d,				       struct device_attribute *attr, char *buf){	struct i2o_device *dev = to_i2o_device(d);	u16 id;	if (!i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) {		sprintf(buf, "0x%04x", le16_to_cpu(id));		return strlen(buf) + 1;	}	return 0;};/** *	i2o_exec_show_product_id - Displays Product ID of controller *	@d: device of which the Product ID should be displayed *	@buf: buffer into which the Product ID should be printed * *	Returns number of bytes printed into buffer.

⌨️ 快捷键说明

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