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

📄 commctrl.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Adaptec AAC series RAID controller driver *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com> * * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING.  If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * Module Name: *  commctrl.c * * Abstract: Contains all routines for control of the AFA comm layer * */#include <linux/kernel.h>#include <linux/init.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/completion.h>#include <linux/dma-mapping.h>#include <linux/blkdev.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include "aacraid.h"/** *	ioctl_send_fib	-	send a FIB from userspace *	@dev:	adapter is being processed *	@arg:	arguments to the ioctl call *	 *	This routine sends a fib to the adapter on behalf of a user level *	program. */# define AAC_DEBUG_PREAMBLE	KERN_INFO# define AAC_DEBUG_POSTAMBLE static int ioctl_send_fib(struct aac_dev * dev, void __user *arg){	struct hw_fib * kfib;	struct fib *fibptr;	struct hw_fib * hw_fib = (struct hw_fib *)0;	dma_addr_t hw_fib_pa = (dma_addr_t)0LL;	unsigned size;	int retval;	fibptr = fib_alloc(dev);	if(fibptr == NULL) {		return -ENOMEM;	}			kfib = fibptr->hw_fib;	/*	 *	First copy in the header so that we can check the size field.	 */	if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {		fib_free(fibptr);		return -EFAULT;	}	/*	 *	Since we copy based on the fib header size, make sure that we	 *	will not overrun the buffer when we copy the memory. Return	 *	an error if we would.	 */	size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr);	if (size < le16_to_cpu(kfib->header.SenderSize))		size = le16_to_cpu(kfib->header.SenderSize);	if (size > dev->max_fib_size) {		/* Highjack the hw_fib */		hw_fib = fibptr->hw_fib;		hw_fib_pa = fibptr->hw_fib_pa;		fibptr->hw_fib = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);		memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size);		memcpy(kfib, hw_fib, dev->max_fib_size);	}	if (copy_from_user(kfib, arg, size)) {		retval = -EFAULT;		goto cleanup;	}	if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) {		aac_adapter_interrupt(dev);		/*		 * Since we didn't really send a fib, zero out the state to allow 		 * cleanup code not to assert.		 */		kfib->header.XferState = 0;	} else {		retval = fib_send(le16_to_cpu(kfib->header.Command), fibptr,				le16_to_cpu(kfib->header.Size) , FsaNormal,				1, 1, NULL, NULL);		if (retval) {			goto cleanup;		}		if (fib_complete(fibptr) != 0) {			retval = -EINVAL;			goto cleanup;		}	}	/*	 *	Make sure that the size returned by the adapter (which includes	 *	the header) is less than or equal to the size of a fib, so we	 *	don't corrupt application data. Then copy that size to the user	 *	buffer. (Don't try to add the header information again, since it	 *	was already included by the adapter.)	 */	retval = 0;	if (copy_to_user(arg, (void *)kfib, size))		retval = -EFAULT;cleanup:	if (hw_fib) {		pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa);		fibptr->hw_fib_pa = hw_fib_pa;		fibptr->hw_fib = hw_fib;	}	fib_free(fibptr);	return retval;}/** *	open_getadapter_fib	-	Get the next fib * *	This routine will get the next Fib, if available, from the AdapterFibContext *	passed in from the user. */static int open_getadapter_fib(struct aac_dev * dev, void __user *arg){	struct aac_fib_context * fibctx;	int status;	fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);	if (fibctx == NULL) {		status = -ENOMEM;	} else {		unsigned long flags;		struct list_head * entry;		struct aac_fib_context * context;		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;		fibctx->size = sizeof(struct aac_fib_context); 		/*		 *	Yes yes, I know this could be an index, but we have a		 * better guarantee of uniqueness for the locked loop below.		 * Without the aid of a persistent history, this also helps		 * reduce the chance that the opaque context would be reused.		 */		fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF);		/*		 *	Initialize the mutex used to wait for the next AIF.		 */		init_MUTEX_LOCKED(&fibctx->wait_sem);		fibctx->wait = 0;		/*		 *	Initialize the fibs and set the count of fibs on		 *	the list to 0.		 */		fibctx->count = 0;		INIT_LIST_HEAD(&fibctx->fib_list);		fibctx->jiffies = jiffies/HZ;		/*		 *	Now add this context onto the adapter's 		 *	AdapterFibContext list.		 */		spin_lock_irqsave(&dev->fib_lock, flags);		/* Ensure that we have a unique identifier */		entry = dev->fib_list.next;		while (entry != &dev->fib_list) {			context = list_entry(entry, struct aac_fib_context, next);			if (context->unique == fibctx->unique) {				/* Not unique (32 bits) */				fibctx->unique++;				entry = dev->fib_list.next;			} else {				entry = entry->next;			}		}		list_add_tail(&fibctx->next, &dev->fib_list);		spin_unlock_irqrestore(&dev->fib_lock, flags);		if (copy_to_user(arg,  &fibctx->unique, 						sizeof(fibctx->unique))) {			status = -EFAULT;		} else {			status = 0;		}		}	return status;}/** *	next_getadapter_fib	-	get the next fib *	@dev: adapter to use *	@arg: ioctl argument *	 * 	This routine will get the next Fib, if available, from the AdapterFibContext *	passed in from the user. */static int next_getadapter_fib(struct aac_dev * dev, void __user *arg){	struct fib_ioctl f;	struct fib *fib;	struct aac_fib_context *fibctx;	int status;	struct list_head * entry;	unsigned long flags;		if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))		return -EFAULT;	/*	 *	Verify that the HANDLE passed in was a valid AdapterFibContext	 *	 *	Search the list of AdapterFibContext addresses on the adapter	 *	to be sure this is a valid address	 */	entry = dev->fib_list.next;	fibctx = NULL;	while (entry != &dev->fib_list) {		fibctx = list_entry(entry, struct aac_fib_context, next);		/*		 *	Extract the AdapterFibContext from the Input parameters.		 */		if (fibctx->unique == f.fibctx) {   /* We found a winner */			break;		}		entry = entry->next;		fibctx = NULL;	}	if (!fibctx) {		dprintk ((KERN_INFO "Fib Context not found\n"));		return -EINVAL;	}	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||		 (fibctx->size != sizeof(struct aac_fib_context))) {		dprintk ((KERN_INFO "Fib Context corrupt?\n"));		return -EINVAL;	}	status = 0;	spin_lock_irqsave(&dev->fib_lock, flags);	/*	 *	If there are no fibs to send back, then either wait or return	 *	-EAGAIN	 */return_fib:	if (!list_empty(&fibctx->fib_list)) {		struct list_head * entry;		/*		 *	Pull the next fib from the fibs		 */		entry = fibctx->fib_list.next;		list_del(entry);				fib = list_entry(entry, struct fib, fiblink);		fibctx->count--;		spin_unlock_irqrestore(&dev->fib_lock, flags);		if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {			kfree(fib->hw_fib);			kfree(fib);			return -EFAULT;		}			/*		 *	Free the space occupied by this copy of the fib.		 */		kfree(fib->hw_fib);		kfree(fib);		status = 0;	} else {		spin_unlock_irqrestore(&dev->fib_lock, flags);		if (f.wait) {			if(down_interruptible(&fibctx->wait_sem) < 0) {				status = -EINTR;			} else {				/* Lock again and retry */				spin_lock_irqsave(&dev->fib_lock, flags);				goto return_fib;			}		} else {			status = -EAGAIN;		}		}	fibctx->jiffies = jiffies/HZ;	return status;}int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx){	struct fib *fib;	/*	 *	First free any FIBs that have not been consumed.	 */	while (!list_empty(&fibctx->fib_list)) {		struct list_head * entry;		/*		 *	Pull the next fib from the fibs		 */		entry = fibctx->fib_list.next;		list_del(entry);		fib = list_entry(entry, struct fib, fiblink);		fibctx->count--;		/*		 *	Free the space occupied by this copy of the fib.		 */		kfree(fib->hw_fib);		kfree(fib);	}	/*	 *	Remove the Context from the AdapterFibContext List	 */	list_del(&fibctx->next);	/*	 *	Invalidate context	 */	fibctx->type = 0;	/*	 *	Free the space occupied by the Context	 */	kfree(fibctx);	return 0;}/** *	close_getadapter_fib	-	close down user fib context *	@dev: adapter *	@arg: ioctl arguments * *	This routine will close down the fibctx passed in from the user. */ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg){	struct aac_fib_context *fibctx;	int status;	unsigned long flags;	struct list_head * entry;	/*	 *	Verify that the HANDLE passed in was a valid AdapterFibContext	 *	 *	Search the list of AdapterFibContext addresses on the adapter	 *	to be sure this is a valid address	 */	entry = dev->fib_list.next;	fibctx = NULL;	while(entry != &dev->fib_list) {		fibctx = list_entry(entry, struct aac_fib_context, next);		/*		 *	Extract the fibctx from the input parameters		 */		if (fibctx->unique == (u32)(unsigned long)arg) {   			/* We found a winner */

⌨️ 快捷键说明

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