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

📄 exec-osm.c

📁 h内核
💻 C
字号:
/* *	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>#define OSM_NAME "exec-osm"struct i2o_driver i2o_exec_driver;static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);/* Module internal functions from other sources */extern int i2o_device_parse_lct(struct i2o_controller *);/* 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 __iomem *msg;	/* pointer to the reply message */	struct list_head list;	/* node in global wait list */};/* 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 = kmalloc(sizeof(*wait), GFP_KERNEL);	if (!wait)		return ERR_PTR(-ENOMEM);	memset(wait, 0, sizeof(*wait));	INIT_LIST_HEAD(&wait->list);	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 or negative error code on failure. */int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long			  timeout, struct i2o_dma *dma){	DECLARE_WAIT_QUEUE_HEAD(wq);	struct i2o_exec_wait *wait;	static u32 tcntxt = 0x80000000;	struct i2o_message __iomem *msg = c->in_queue.virt + m;	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.	 */	writel(i2o_exec_driver.context, &msg->u.s.icntxt);	wait->tcntxt = tcntxt++;	writel(wait->tcntxt, &msg->u.s.tcntxt);	/*	 * 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, m);	if (!wait->complete) {		wait->wq = &wq;		/*		 * we add elements add 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);		wait_event_interruptible_timeout(wq, wait->complete,			timeout * HZ);		wait->wq = NULL;	}	barrier();	if (wait->complete) {		if (readl(&wait->msg->body[0]) >> 24)			rc = readl(&wait->msg->body[0]) & 0xff;		i2o_flush_reply(c, wait->m);		i2o_exec_wait_free(wait);	} 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;	}	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 * *	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 __iomem *msg){	struct i2o_exec_wait *wait, *tmp;	static spinlock_t lock;	int rc = 1;	u32 context;	spin_lock_init(&lock);	context = readl(&msg->u.s.tcntxt);	/*	 * 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.	 */	spin_lock(&lock);	list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {		if (wait->tcntxt == context) {			list_del(&wait->list);			wait->m = m;			wait->msg = msg;			wait->complete = 1;			barrier();			if (wait->wq) {				wake_up_interruptible(wait->wq);				rc = 0;			} else {				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);				rc = -1;			}			spin_unlock(&lock);			return rc;		}	}	spin_unlock(&lock);	pr_debug("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,		 context);	return -1;};/** *	i2o_exec_probe - Called if a new I2O device (executive class) appears *	@dev: I2O device which should be probed * *	Registers event notification for every event from Executive device. The *	return is always 0, because we want all devices of class Executive. * *	Returns 0 on success. */static int i2o_exec_probe(struct device *dev){	struct i2o_device *i2o_dev = to_i2o_device(dev);	i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);	i2o_dev->iop->exec = i2o_dev;	return 0;};/** *	i2o_exec_remove - Called on I2O device removal *	@dev: I2O device which was removed * *	Unregisters event notification from Executive I2O device. * *	Returns 0 on success. */static int i2o_exec_remove(struct device *dev){	i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);	return 0;};/** *	i2o_exec_lct_modified - Called on LCT NOTIFY reply *	@c: I2O controller on which the LCT has modified * *	This function handles asynchronus LCT NOTIFY replies. It parses the *	new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY *	again. */static void i2o_exec_lct_modified(struct i2o_controller *c){	if (i2o_device_parse_lct(c) == -EAGAIN)		i2o_exec_lct_notify(c, 0);};/** *	i2o_exec_reply -  I2O Executive reply handler *	@c: I2O controller from which the reply comes *	@m: message id *	@msg: pointer to the I2O reply message * *	This function is always called from interrupt context. If a POST WAIT *	reply was received, pass it to the complete function. If a LCT NOTIFY *	reply was received, a new event is created to handle the update. * *	Returns 0 on success and if the reply should not be flushed or > 0 *	on success and if the reply should be flushed. Returns negative error *	code on failure and if the reply should be flushed. */static int i2o_exec_reply(struct i2o_controller *c, u32 m,			  struct i2o_message *msg){	if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {	// Fail bit is set		struct i2o_message __iomem *pmsg;	/* preserved message */		u32 pm;		pm = le32_to_cpu(msg->body[3]);		pmsg = i2o_msg_in_to_virt(c, pm);		i2o_report_status(KERN_INFO, "i2o_core", msg);		/* Release the preserved msg by resubmitting it as a NOP */		i2o_msg_nop(c, pm);		/* If reply to i2o_post_wait failed, return causes a timeout */		return -1;	}	if (le32_to_cpu(msg->u.s.tcntxt) & 0x80000000)		return i2o_msg_post_wait_complete(c, m, msg);	if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {		struct work_struct *work;		pr_debug("%s: LCT notify received\n", c->name);		work = kmalloc(sizeof(*work), GFP_ATOMIC);		if (!work)			return -ENOMEM;		INIT_WORK(work, (void (*)(void *))i2o_exec_lct_modified, c);		queue_work(i2o_exec_driver.event_queue, work);		return 1;	}	/*	 * If this happens, we want to dump the message to the syslog so	 * it can be sent back to the card manufacturer by the end user	 * to aid in debugging.	 *	 */	printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"	       "Message dumped to syslog\n", c->name);	i2o_dump_message(msg);	return -EFAULT;}/** *	i2o_exec_event - Event handling function *	@evt: Event which occurs * *	Handles events send by the Executive device. At the moment does not do *	anything useful. */static void i2o_exec_event(struct i2o_event *evt){	osm_info("Event received from device: %d\n",		 evt->i2o_dev->lct_data.tid);	kfree(evt);};/** *	i2o_exec_lct_get - Get the IOP's Logical Configuration Table *	@c: I2O controller from which the LCT should be fetched * *	Send a LCT NOTIFY request to the controller, and wait *	I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is *	to large, retry it. * *	Returns 0 on success or negative error code on failure. */int i2o_exec_lct_get(struct i2o_controller *c){	struct i2o_message __iomem *msg;	u32 m;	int i = 0;	int rc = -EAGAIN;	for (i = 1; i <= I2O_LCT_GET_TRIES; i++) {		m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);		if (m == I2O_QUEUE_EMPTY)			return -ETIMEDOUT;		writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]);		writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID,		       &msg->u.head[1]);		writel(0xffffffff, &msg->body[0]);		writel(0x00000000, &msg->body[1]);		writel(0xd0000000 | c->dlct.len, &msg->body[2]);		writel(c->dlct.phys, &msg->body[3]);		rc = i2o_msg_post_wait(c, m, I2O_TIMEOUT_LCT_GET);		if (rc < 0)			break;		rc = i2o_device_parse_lct(c);		if (rc != -EAGAIN)			break;	}	return rc;}/** *	i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request *	@c: I2O controller to which the request should be send *	@change_ind: change indicator * *	This function sends a LCT NOTIFY request to the I2O controller with *	the change indicator change_ind. If the change_ind == 0 the controller *	replies immediately after the request. If change_ind > 0 the reply is *	send after change indicator of the LCT is > change_ind. */static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind){	i2o_status_block *sb = c->status_block.virt;	struct device *dev;	struct i2o_message __iomem *msg;	u32 m;	dev = &c->pdev->dev;	if (i2o_dma_realloc(dev, &c->dlct, sb->expected_lct_size, GFP_KERNEL))		return -ENOMEM;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -ETIMEDOUT;	writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]);	writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID,	       &msg->u.head[1]);	writel(i2o_exec_driver.context, &msg->u.s.icntxt);	writel(0, &msg->u.s.tcntxt);	/* FIXME */	writel(0xffffffff, &msg->body[0]);	writel(change_ind, &msg->body[1]);	writel(0xd0000000 | c->dlct.len, &msg->body[2]);	writel(c->dlct.phys, &msg->body[3]);	i2o_msg_post(c, m);	return 0;};/* Exec OSM driver struct */struct i2o_driver i2o_exec_driver = {	.name = OSM_NAME,	.reply = i2o_exec_reply,	.event = i2o_exec_event,	.classes = i2o_exec_class_id,	.driver = {		   .probe = i2o_exec_probe,		   .remove = i2o_exec_remove,		   },};/** *	i2o_exec_init - Registers the Exec OSM * *	Registers the Exec OSM in the I2O core. * *	Returns 0 on success or negative error code on failure. */int __init i2o_exec_init(void){	return i2o_driver_register(&i2o_exec_driver);};/** *	i2o_exec_exit - Removes the Exec OSM * *	Unregisters the Exec OSM from the I2O core. */void __exit i2o_exec_exit(void){	i2o_driver_unregister(&i2o_exec_driver);};EXPORT_SYMBOL(i2o_msg_post_wait_mem);EXPORT_SYMBOL(i2o_exec_lct_get);

⌨️ 快捷键说明

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