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

📄 megaraid_mm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		/*		 * While attaching the dma buffer, if we didn't get the 		 * required buffer from the pool, we would have allocated 		 * it at the run time and set the free_buf flag. We must 		 * free that buffer. Otherwise, just mark that the buffer is 		 * not in use		 */		if (kioc->free_buf == 1)			pci_pool_free(pool->handle, kioc->buf_vaddr, 							kioc->buf_paddr);		else			pool->in_use = 0;		spin_unlock_irqrestore(&pool->lock, flags);	}	/* Return the kioc to the free pool */	spin_lock_irqsave(&adp->kioc_pool_lock, flags);	list_add(&kioc->list, &adp->kioc_pool);	spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);	/* increment the free kioc count */	up(&adp->kioc_semaphore);	return;}/** * lld_ioctl - Routine to issue ioctl to low level drvr * * @adp		: The adapter handle * @kioc	: The ioctl packet with kernel addresses */static intlld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc){	int			rval;	struct timer_list	timer;	struct timer_list	*tp = NULL;	kioc->status	= -ENODATA;	rval		= adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE);	if (rval) return rval;	/*	 * Start the timer	 */	if (adp->timeout > 0) {		tp		= &timer;		init_timer(tp);		tp->function	= lld_timedout;		tp->data	= (unsigned long)kioc;		tp->expires	= jiffies + adp->timeout * HZ;		add_timer(tp);	}	/*	 * Wait till the low level driver completes the ioctl. After this	 * call, the ioctl either completed successfully or timedout.	 */	wait_event(wait_q, (kioc->status != -ENODATA));	if (tp) {		del_timer_sync(tp);	}	/*	 * If the command had timedout, we mark the controller offline	 * before returning	 */	if (kioc->timedout) {		adp->quiescent = 0;	}	return kioc->status;}/** * ioctl_done - callback from the low level driver * * @kioc	: completed ioctl packet */static voidioctl_done(uioc_t *kioc){	uint32_t	adapno;	int		iterator;	mraid_mmadp_t*	adapter;	/*	 * When the kioc returns from driver, make sure it still doesn't	 * have ENODATA in status. Otherwise, driver will hang on wait_event	 * forever	 */	if (kioc->status == -ENODATA) {		con_log(CL_ANN, (KERN_WARNING			"megaraid cmm: lld didn't change status!\n"));		kioc->status = -EINVAL;	}	/*	 * Check if this kioc was timedout before. If so, nobody is waiting	 * on this kioc. We don't have to wake up anybody. Instead, we just	 * have to free the kioc	 */	if (kioc->timedout) {		iterator	= 0;		adapter		= NULL;		adapno		= kioc->adapno;		con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed "					"ioctl that was timedout before\n"));		list_for_each_entry(adapter, &adapters_list_g, list) {			if (iterator++ == adapno) break;		}		kioc->timedout = 0;		if (adapter) {			mraid_mm_dealloc_kioc( adapter, kioc );		}	}	else {		wake_up(&wait_q);	}}/* * lld_timedout	: callback from the expired timer * * @ptr		: ioctl packet that timed out */static voidlld_timedout(unsigned long ptr){	uioc_t *kioc	= (uioc_t *)ptr;	kioc->status 	= -ETIME;	kioc->timedout	= 1;	con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n"));	wake_up(&wait_q);}/** * kioc_to_mimd	: Converter from new back to old format * * @kioc	: Kernel space IOCTL packet (successfully issued) * @mimd	: User space MIMD packet */static intkioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd){	mimd_t			kmimd;	uint8_t			opcode;	uint8_t			subopcode;	mbox64_t		*mbox64;	mraid_passthru_t	__user *upthru32;	mraid_passthru_t	*kpthru32;	mcontroller_t		cinfo;	mraid_hba_info_t	*hinfo;	if (copy_from_user(&kmimd, mimd, sizeof(mimd_t)))		return (-EFAULT);	opcode		= kmimd.ui.fcs.opcode;	subopcode	= kmimd.ui.fcs.subopcode;	if (opcode == 0x82) {		switch (subopcode) {		case MEGAIOC_QADAPINFO:			hinfo = (mraid_hba_info_t *)(unsigned long)					kioc->buf_vaddr;			hinfo_to_cinfo(hinfo, &cinfo);			if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo)))				return (-EFAULT);			return 0;		default:			return (-EINVAL);		}		return 0;	}	mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;	if (kioc->user_pthru) {		upthru32 = kioc->user_pthru;		kpthru32 = kioc->pthru32;		if (copy_to_user(&upthru32->scsistatus,					&kpthru32->scsistatus,					sizeof(uint8_t))) {			return (-EFAULT);		}	}	if (kioc->user_data) {		if (copy_to_user(kioc->user_data, kioc->buf_vaddr,					kioc->user_data_len)) {			return (-EFAULT);		}	}	if (copy_to_user(&mimd->mbox[17],			&mbox64->mbox32.status, sizeof(uint8_t))) {		return (-EFAULT);	}	return 0;}/** * hinfo_to_cinfo - Convert new format hba info into old format * * @hinfo	: New format, more comprehensive adapter info * @cinfo	: Old format adapter info to support mimd_t apps */static voidhinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo){	if (!hinfo || !cinfo)		return;	cinfo->base		= hinfo->baseport;	cinfo->irq		= hinfo->irq;	cinfo->numldrv		= hinfo->num_ldrv;	cinfo->pcibus		= hinfo->pci_bus;	cinfo->pcidev		= hinfo->pci_slot;	cinfo->pcifun		= PCI_FUNC(hinfo->pci_dev_fn);	cinfo->pciid		= hinfo->pci_device_id;	cinfo->pcivendor	= hinfo->pci_vendor_id;	cinfo->pcislot		= hinfo->pci_slot;	cinfo->uid		= hinfo->unique_id;}/* * mraid_mm_register_adp - Registration routine for low level drvrs * * @adp	: Adapter objejct */intmraid_mm_register_adp(mraid_mmadp_t *lld_adp){	mraid_mmadp_t	*adapter;	mbox64_t	*mbox_list;	uioc_t		*kioc;	uint32_t	rval;	int		i;	if (lld_adp->drvr_type != DRVRTYPE_MBOX)		return (-EINVAL);	adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);	if (!adapter) {		rval = -ENOMEM;		goto memalloc_error;	}	memset(adapter, 0, sizeof(mraid_mmadp_t));	adapter->unique_id	= lld_adp->unique_id;	adapter->drvr_type	= lld_adp->drvr_type;	adapter->drvr_data	= lld_adp->drvr_data;	adapter->pdev		= lld_adp->pdev;	adapter->issue_uioc	= lld_adp->issue_uioc;	adapter->timeout	= lld_adp->timeout;	adapter->max_kioc	= lld_adp->max_kioc;	adapter->quiescent	= 1;	/*	 * Allocate single blocks of memory for all required kiocs,	 * mailboxes and passthru structures.	 */	adapter->kioc_list	= kmalloc(sizeof(uioc_t) * lld_adp->max_kioc,						GFP_KERNEL);	adapter->mbox_list	= kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc,						GFP_KERNEL);	adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool",						adapter->pdev,						sizeof(mraid_passthru_t),						16, 0);	if (!adapter->kioc_list || !adapter->mbox_list ||			!adapter->pthru_dma_pool) {		con_log(CL_ANN, (KERN_WARNING			"megaraid cmm: out of memory, %s %d\n", __FUNCTION__,			__LINE__));		rval = (-ENOMEM);		goto memalloc_error;	}	/*	 * Slice kioc_list and make a kioc_pool with the individiual kiocs	 */	INIT_LIST_HEAD(&adapter->kioc_pool);	spin_lock_init(&adapter->kioc_pool_lock);	sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc);	mbox_list	= (mbox64_t *)adapter->mbox_list;	for (i = 0; i < lld_adp->max_kioc; i++) {		kioc		= adapter->kioc_list + i;		kioc->cmdbuf	= (uint64_t)(unsigned long)(mbox_list + i);		kioc->pthru32	= pci_pool_alloc(adapter->pthru_dma_pool,						GFP_KERNEL, &kioc->pthru32_h);		if (!kioc->pthru32) {			con_log(CL_ANN, (KERN_WARNING				"megaraid cmm: out of memory, %s %d\n",					__FUNCTION__, __LINE__));			rval = (-ENOMEM);			goto pthru_dma_pool_error;		}		list_add_tail(&kioc->list, &adapter->kioc_pool);	}	// Setup the dma pools for data buffers	if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) {		goto dma_pool_error;	}	list_add_tail(&adapter->list, &adapters_list_g);	adapters_count_g++;	return 0;dma_pool_error:	/* Do nothing */pthru_dma_pool_error:	for (i = 0; i < lld_adp->max_kioc; i++) {		kioc = adapter->kioc_list + i;		if (kioc->pthru32) {			pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32,				kioc->pthru32_h);		}	}memalloc_error:	kfree(adapter->kioc_list);	kfree(adapter->mbox_list);	if (adapter->pthru_dma_pool)		pci_pool_destroy(adapter->pthru_dma_pool);	kfree(adapter);	return rval;}/** * mraid_mm_adapter_app_handle - return the application handle for this adapter * * For the given driver data, locate the adadpter in our global list and * return the corresponding handle, which is also used by applications to * uniquely identify an adapter. * * @param unique_id : adapter unique identifier * * @return adapter handle if found in the list * @return 0 if adapter could not be located, should never happen though */uint32_tmraid_mm_adapter_app_handle(uint32_t unique_id){	mraid_mmadp_t	*adapter;	mraid_mmadp_t	*tmp;	int		index = 0;	list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) {		if (adapter->unique_id == unique_id) {			return MKADAP(index);		}		index++;	}	return 0;}/** * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter * * @adp	: Adapter softstate * * We maintain a pool of dma buffers per each adapter. Each pool has one * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers. * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We * dont' want to waste too much memory by allocating more buffers per each * pool. */static intmraid_mm_setup_dma_pools(mraid_mmadp_t *adp){	mm_dmapool_t	*pool;	int		bufsize;	int		i;	/*	 * Create MAX_DMA_POOLS number of pools	 */	bufsize = MRAID_MM_INIT_BUFF_SIZE;	for (i = 0; i < MAX_DMA_POOLS; i++){		pool = &adp->dma_pool_list[i];		pool->buf_size = bufsize;		spin_lock_init(&pool->lock);		pool->handle = pci_pool_create("megaraid mm data buffer",						adp->pdev, bufsize, 16, 0);		if (!pool->handle) {			goto dma_pool_setup_error;		}		pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL,							&pool->paddr);		if (!pool->vaddr)			goto dma_pool_setup_error;		bufsize = bufsize * 2;	}	return 0;dma_pool_setup_error:	mraid_mm_teardown_dma_pools(adp);	return (-ENOMEM);}/* * mraid_mm_unregister_adp - Unregister routine for low level drivers *				  Assume no outstanding ioctls to llds. * * @unique_id	: UID of the adpater */intmraid_mm_unregister_adp(uint32_t unique_id){	mraid_mmadp_t	*adapter;	mraid_mmadp_t	*tmp;	list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) {		if (adapter->unique_id == unique_id) {			adapters_count_g--;			list_del_init(&adapter->list);			mraid_mm_free_adp_resources(adapter);			kfree(adapter);			con_log(CL_ANN, (				"megaraid cmm: Unregistered one adapter:%#x\n",				unique_id));			return 0;		}	}	return (-ENODEV);}/** * mraid_mm_free_adp_resources - Free adapter softstate * * @adp	: Adapter softstate */static voidmraid_mm_free_adp_resources(mraid_mmadp_t *adp){	uioc_t	*kioc;	int	i;	mraid_mm_teardown_dma_pools(adp);	for (i = 0; i < adp->max_kioc; i++) {		kioc = adp->kioc_list + i;		pci_pool_free(adp->pthru_dma_pool, kioc->pthru32,				kioc->pthru32_h);	}	kfree(adp->kioc_list);	kfree(adp->mbox_list);	pci_pool_destroy(adp->pthru_dma_pool);	return;}/** * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers * * @adp	: Adapter softstate */static voidmraid_mm_teardown_dma_pools(mraid_mmadp_t *adp){	int		i;	mm_dmapool_t	*pool;	for (i = 0; i < MAX_DMA_POOLS; i++) {		pool = &adp->dma_pool_list[i];		if (pool->handle) {			if (pool->vaddr)				pci_pool_free(pool->handle, pool->vaddr,							pool->paddr);			pci_pool_destroy(pool->handle);			pool->handle = NULL;		}	}	return;}/** * mraid_mm_init	: Module entry point */static int __initmraid_mm_init(void){	// Announce the driver version	con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n",		LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION));	majorno = register_chrdev(0, "megadev", &lsi_fops);	if (majorno < 0) {		con_log(CL_ANN, ("megaraid cmm: cannot get major\n"));		return majorno;	}	init_waitqueue_head(&wait_q);	INIT_LIST_HEAD(&adapters_list_g);	return 0;}/** * mraid_mm_compat_ioctl	: 32bit to 64bit ioctl conversion routine */#ifdef CONFIG_COMPATstatic longmraid_mm_compat_ioctl(struct file *filep, unsigned int cmd,		      unsigned long arg){	int err;	err = mraid_mm_ioctl(NULL, filep, cmd, arg);	return err;}#endif/** * mraid_mm_exit	: Module exit point */static void __exitmraid_mm_exit(void){	con_log(CL_DLEVEL1 , ("exiting common mod\n"));	unregister_chrdev(majorno, "megadev");}module_init(mraid_mm_init);module_exit(mraid_mm_exit);/* vi: set ts=8 sw=8 tw=78: */

⌨️ 快捷键说明

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