i2o_core.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,683 行 · 第 1/5 页

C
2,683
字号
/* * Core I2O structure management  *  * (C) Copyright 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. *  */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/i2o.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/bitops.h>#include <linux/wait.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <asm/semaphore.h>#include <linux/completion.h>#include <linux/workqueue.h>#include <asm/io.h>#include <linux/reboot.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif // CONFIG_MTRR#include "i2o_lan.h"//#define DRIVERDEBUG#ifdef DRIVERDEBUG#define dprintk(s, args...) printk(s, ## args)#else#define dprintk(s, args...)#endif/* OSM table */static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];/* Controller list */static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];struct i2o_controller *i2o_controller_chain;int i2o_num_controllers;/* Initiator Context for Core message */static int core_context;/* Initialization && shutdown functions */void i2o_sys_init(void);static void i2o_sys_shutdown(void);static int i2o_reset_controller(struct i2o_controller *);static int i2o_reboot_event(struct notifier_block *, unsigned long , void *);static int i2o_online_controller(struct i2o_controller *);static int i2o_init_outbound_q(struct i2o_controller *);static int i2o_post_outbound_messages(struct i2o_controller *);/* Reply handler */static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *,			   struct i2o_message *);/* Various helper functions */static int i2o_lct_get(struct i2o_controller *);static int i2o_lct_notify(struct i2o_controller *);static int i2o_hrt_get(struct i2o_controller *);static int i2o_build_sys_table(void);static int i2o_systab_send(struct i2o_controller *c);/* I2O core event handler */static int i2o_core_evt(void *);static int evt_pid;static int evt_running;/* Dynamic LCT update handler */static int i2o_dyn_lct(void *);void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *);static void i2o_pci_dispose(struct i2o_controller *c);/* * I2O System Table.  Contains information about * all the IOPs in the system.  Used to inform IOPs * about each other's existence. * * sys_tbl_ver is the CurrentChangeIndicator that is * used by IOPs to track changes. */static struct i2o_sys_tbl *sys_tbl;static int sys_tbl_ind;static int sys_tbl_len;/* * This spin lock is used to keep a device from being * added and deleted concurrently across CPUs or interrupts. * This can occur when a user creates a device and immediatelly * deletes it before the new_dev_notify() handler is called. */static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;/* * Structures and definitions for synchronous message posting. * See i2o_post_wait() for description. */ struct i2o_post_wait_data{	int *status;		/* Pointer to status block on caller stack */	int *complete;		/* Pointer to completion flag on caller stack */	u32 id;			/* Unique identifier */	wait_queue_head_t *wq;	/* Wake up for caller (NULL for dead) */	struct i2o_post_wait_data *next;	/* Chain */	void *mem[2];		/* Memory blocks to recover on failure path */	dma_addr_t phys[2];	/* Physical address of blocks to recover */	u32 size[2];		/* Size of blocks to recover */};static struct i2o_post_wait_data *post_wait_queue;static u32 post_wait_id;	// Unique ID for each post_waitstatic spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;static void i2o_post_wait_complete(struct i2o_controller *, u32, int);/* OSM descriptor handler */ static struct i2o_handler i2o_core_handler ={	(void *)i2o_core_reply,	NULL,	NULL,	NULL,	"I2O core layer",	0,	I2O_CLASS_EXECUTIVE};/* * Used when queueing a reply to be handled later */ struct reply_info{	struct i2o_controller *iop;	u32 msg[MSG_FRAME_SIZE];};static struct reply_info evt_reply;static struct reply_info events[I2O_EVT_Q_LEN];static int evt_in;static int evt_out;static int evt_q_len;#define MODINC(x,y) ((x) = ((x) + 1) % (y))/* * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */static DECLARE_MUTEX(i2o_configuration_lock);/*  * Event spinlock.  Used to keep event queue sane and from * handling multiple events simultaneously. */static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;/* * Semaphore used to synchronize event handling thread with  * interrupt handler. */ static DECLARE_MUTEX(evt_sem);static DECLARE_COMPLETION(evt_dead);static DECLARE_WAIT_QUEUE_HEAD(evt_wait);static struct notifier_block i2o_reboot_notifier ={        i2o_reboot_event,        NULL,        0};/* *	Config options */static int verbose;#if BITS_PER_LONG == 64/** *      i2o_context_list_add -	append an ptr to the context list and return a *				matching context id. *	@ptr: pointer to add to the context list *	@c: controller to which the context list belong *	returns context id, which could be used in the transaction context *	field. * *	Because the context field in I2O is only 32-bit large, on 64-bit the *	pointer is to large to fit in the context field. The i2o_context_list *	functiones map pointers to context fields. */u32 i2o_context_list_add(void *ptr, struct i2o_controller *c) {	u32 context = 1;	struct i2o_context_list_element **entry = &c->context_list;	struct i2o_context_list_element *element;	unsigned long flags;	spin_lock_irqsave(&c->context_list_lock, flags);	while(*entry && ((*entry)->flags & I2O_CONTEXT_LIST_USED)) {		if((*entry)->context >= context)			context = (*entry)->context + 1;		entry = &((*entry)->next);	}	if(!*entry) {		if(unlikely(!context)) {			spin_unlock_irqrestore(&c->context_list_lock, flags);			printk(KERN_EMERG "i2o_core: context list overflow\n");			return 0;		}		element = kmalloc(sizeof(struct i2o_context_list_element), GFP_KERNEL);		if(!element) {			printk(KERN_EMERG "i2o_core: could not allocate memory for context list element\n");			return 0;		}		element->context = context;		element->next = NULL;		*entry = element;	} else		element = *entry;	element->ptr = ptr;	element->flags = I2O_CONTEXT_LIST_USED;	spin_unlock_irqrestore(&c->context_list_lock, flags);	dprintk(KERN_DEBUG "i2o_core: add context to list %p -> %d\n", ptr, context);	return context;}/** *      i2o_context_list_remove - remove a ptr from the context list and return *				  the matching context id. *	@ptr: pointer to be removed from the context list *	@c: controller to which the context list belong *	returns context id, which could be used in the transaction context *	field. */u32 i2o_context_list_remove(void *ptr, struct i2o_controller *c) {	struct i2o_context_list_element **entry = &c->context_list;	struct i2o_context_list_element *element;	u32 context;	unsigned long flags;	spin_lock_irqsave(&c->context_list_lock, flags);	while(*entry && ((*entry)->ptr != ptr))		entry = &((*entry)->next);	if(unlikely(!*entry)) {		spin_unlock_irqrestore(&c->context_list_lock, flags);		printk(KERN_WARNING "i2o_core: could not remove nonexistent ptr %p\n", ptr);		return 0;	}	element = *entry;	context = element->context;	element->ptr = NULL;	element->flags |= I2O_CONTEXT_LIST_DELETED;	spin_unlock_irqrestore(&c->context_list_lock, flags);	dprintk(KERN_DEBUG "i2o_core: markt as deleted in context list %p -> %d\n", ptr, context);	return context;}/** *      i2o_context_list_get -	get a ptr from the context list and remove it *				from the list. *	@context: context id to which the pointer belong *	@c: controller to which the context list belong *	returns pointer to the matching context id */void *i2o_context_list_get(u32 context, struct i2o_controller *c) {	struct i2o_context_list_element **entry = &c->context_list;	struct i2o_context_list_element *element;	void *ptr;	int count = 0;	unsigned long flags;	spin_lock_irqsave(&c->context_list_lock, flags);	while(*entry && ((*entry)->context != context)) {		entry = &((*entry)->next);		count ++;	}	if(unlikely(!*entry)) {		spin_unlock_irqrestore(&c->context_list_lock, flags);		printk(KERN_WARNING "i2o_core: context id %d not found\n", context);		return NULL;	}	element = *entry;	ptr = element->ptr;	if(count >= I2O_CONTEXT_LIST_MIN_LENGTH) {		*entry = (*entry)->next;		kfree(element);	} else {		element->ptr = NULL;		element->flags &= !I2O_CONTEXT_LIST_USED;	}	spin_unlock_irqrestore(&c->context_list_lock, flags);	dprintk(KERN_DEBUG "i2o_core: get ptr from context list %d -> %p\n", context, ptr);	return ptr;}#endif/* * I2O Core reply handler */static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c,		    struct i2o_message *m){	u32 *msg=(u32 *)m;	u32 status;	u32 context = msg[2];	if (msg[0] & MSG_FAIL) // Fail bit is set	{		u32 *preserved_msg = (u32*)(c->msg_virt + msg[7]);		i2o_report_status(KERN_INFO, "i2o_core", msg);		i2o_dump_message(preserved_msg);		/* If the failed request needs special treatment,		 * it should be done here. */                /* Release the preserved msg by resubmitting it as a NOP */		preserved_msg[0] = cpu_to_le32(THREE_WORD_MSG_SIZE | SGL_OFFSET_0);		preserved_msg[1] = cpu_to_le32(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0);		preserved_msg[2] = 0;		i2o_post_message(c, msg[7]);		/* If reply to i2o_post_wait failed, return causes a timeout */		return;	}       #ifdef DRIVERDEBUG	i2o_report_status(KERN_INFO, "i2o_core", msg);#endif	if(msg[2]&0x80000000)	// Post wait message	{		if (msg[4] >> 24)			status = (msg[4] & 0xFFFF);		else			status = I2O_POST_WAIT_OK;			i2o_post_wait_complete(c, context, status);		return;	}	if(m->function == I2O_CMD_UTIL_EVT_REGISTER)	{		memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2);		events[evt_in].iop = c;		spin_lock(&i2o_evt_lock);		MODINC(evt_in, I2O_EVT_Q_LEN);		if(evt_q_len == I2O_EVT_Q_LEN)			MODINC(evt_out, I2O_EVT_Q_LEN);		else			evt_q_len++;		spin_unlock(&i2o_evt_lock);		up(&evt_sem);		wake_up_interruptible(&evt_wait);		return;	}	if(m->function == I2O_CMD_LCT_NOTIFY)	{		up(&c->lct_sem);		return;	}	/*	 * 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;}/** *	i2o_install_handler - install a message handler *	@h: Handler structure * *	Install an I2O handler - these handle the asynchronous messaging *	from the card once it has initialised. If the table of handlers is *	full then -ENOSPC is returned. On a success 0 is returned and the *	context field is set by the function. The structure is part of the *	system from this time onwards. It must not be freed until it has *	been uninstalled */ int i2o_install_handler(struct i2o_handler *h){	int i;	down(&i2o_configuration_lock);	for(i=0;i<MAX_I2O_MODULES;i++)	{		if(i2o_handlers[i]==NULL)		{			h->context = i;			i2o_handlers[i]=h;			up(&i2o_configuration_lock);			return 0;		}	}	up(&i2o_configuration_lock);	return -ENOSPC;}/** *	i2o_remove_handler - remove an i2o message handler *	@h: handler * *	Remove a message handler previously installed with i2o_install_handler. *	After this function returns the handler object can be freed or re-used */ int i2o_remove_handler(struct i2o_handler *h){	i2o_handlers[h->context]=NULL;	return 0;}	/* *	Each I2O controller has a chain of devices on it. * Each device has a pointer to its LCT entry to be used * for fun purposes. *//** *	i2o_install_device	-	attach a device to a controller *	@c: controller *	@d: device * 	 *	Add a new device to an i2o controller. This can be called from *	non interrupt contexts only. It adds the device and marks it as *	unclaimed. The device memory becomes part of the kernel and must *	be uninstalled before being freed or reused. Zero is returned *	on success. */ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d){	int i;	down(&i2o_configuration_lock);	d->controller=c;	d->owner=NULL;	d->next=c->devices;	d->prev=NULL;	if (c->devices != NULL)		c->devices->prev=d;	c->devices=d;	*d->dev_name = 0;	for(i = 0; i < I2O_MAX_MANAGERS; i++)		d->managers[i] = NULL;	up(&i2o_configuration_lock);	return 0;}/* we need this version to call out of i2o_delete_controller */int __i2o_delete_device(struct i2o_device *d){	struct i2o_device **p;	int i;	p=&(d->controller->devices);	/*	 *	Hey we have a driver!	 * Check to see if the driver wants us to notify it of 	 * device deletion. If it doesn't we assume that it	 * is unsafe to delete a device with an owner and 	 * fail.	 */	if(d->owner)	{		if(d->owner->dev_del_notify)		{			dprintk(KERN_INFO "Device has owner, notifying\n");			d->owner->dev_del_notify(d->controller, d);			if(d->owner)			{

⌨️ 快捷键说明

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