cciss.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,278 行 · 第 1/5 页

C
2,278
字号
 */static int cciss_release(struct inode *inode, struct file *filep){	ctlr_info_t *host = get_host(inode->i_bdev->bd_disk);	drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);#ifdef CCISS_DEBUG	printk(KERN_DEBUG "cciss_release %s\n", inode->i_bdev->bd_disk->disk_name);#endif /* CCISS_DEBUG */	drv->usage_count--;	host->usage_count--;	return 0;}#ifdef CONFIG_COMPAT/* for AMD 64 bit kernel compatibility with 32-bit userland ioctls */extern long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);extern intregister_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int,      unsigned int, unsigned long, struct file *));extern int unregister_ioctl32_conversion(unsigned int cmd);static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file);static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,	struct file *file);typedef int (*handler_type) (unsigned int, unsigned int, unsigned long, struct file *);static struct ioctl32_map {	unsigned int cmd;	handler_type handler;	int registered;} cciss_ioctl32_map[] = {	{ CCISS_GETPCIINFO,	(handler_type) sys_ioctl, 0 },	{ CCISS_GETINTINFO,	(handler_type) sys_ioctl, 0 },	{ CCISS_SETINTINFO,	(handler_type) sys_ioctl, 0 },	{ CCISS_GETNODENAME,	(handler_type) sys_ioctl, 0 },	{ CCISS_SETNODENAME,	(handler_type) sys_ioctl, 0 },	{ CCISS_GETHEARTBEAT,	(handler_type) sys_ioctl, 0 },	{ CCISS_GETBUSTYPES,	(handler_type) sys_ioctl, 0 },	{ CCISS_GETFIRMVER,	(handler_type) sys_ioctl, 0 },	{ CCISS_GETDRIVVER,	(handler_type) sys_ioctl, 0 },	{ CCISS_REVALIDVOLS,	(handler_type) sys_ioctl, 0 },	{ CCISS_PASSTHRU32,	cciss_ioctl32_passthru, 0 },	{ CCISS_DEREGDISK,	(handler_type) sys_ioctl, 0 },	{ CCISS_REGNEWDISK,	(handler_type) sys_ioctl, 0 },	{ CCISS_REGNEWD,	(handler_type) sys_ioctl, 0 },	{ CCISS_RESCANDISK,	(handler_type) sys_ioctl, 0 },	{ CCISS_GETLUNINFO,	(handler_type) sys_ioctl, 0 },	{ CCISS_BIG_PASSTHRU32,	cciss_ioctl32_big_passthru, 0 },};#define NCCISS_IOCTL32_ENTRIES (sizeof(cciss_ioctl32_map) / sizeof(cciss_ioctl32_map[0]))static void register_cciss_ioctl32(void){	int i, rc;	for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {		rc = register_ioctl32_conversion(			cciss_ioctl32_map[i].cmd,			cciss_ioctl32_map[i].handler);		if (rc != 0) {			printk(KERN_WARNING "cciss: failed to register "				"32 bit compatible ioctl 0x%08x\n",				cciss_ioctl32_map[i].cmd);			cciss_ioctl32_map[i].registered = 0;		} else			cciss_ioctl32_map[i].registered = 1;	}}static void unregister_cciss_ioctl32(void){	int i, rc;	for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {		if (!cciss_ioctl32_map[i].registered)			continue;		rc = unregister_ioctl32_conversion(			cciss_ioctl32_map[i].cmd);		if (rc == 0) {			cciss_ioctl32_map[i].registered = 0;			continue;		}		printk(KERN_WARNING "cciss: failed to unregister "			"32 bit compatible ioctl 0x%08x\n",			cciss_ioctl32_map[i].cmd);	}}int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg,	struct file *file){	IOCTL32_Command_struct __user *arg32 =		(IOCTL32_Command_struct __user *) arg;	IOCTL_Command_struct arg64;	IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));	int err;	u32 cp;	err = 0;	err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));	err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));	err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));	err |= get_user(arg64.buf_size, &arg32->buf_size);	err |= get_user(cp, &arg32->buf);	arg64.buf = compat_ptr(cp);	err |= copy_to_user(p, &arg64, sizeof(arg64));	if (err)		return -EFAULT;	err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) p);	if (err)		return err;	err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));	if (err)		return -EFAULT;	return err;}int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,	struct file *file){	BIG_IOCTL32_Command_struct __user *arg32 =		(BIG_IOCTL32_Command_struct __user *) arg;	BIG_IOCTL_Command_struct arg64;	BIG_IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));	int err;	u32 cp;	err = 0;	err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));	err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));	err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));	err |= get_user(arg64.buf_size, &arg32->buf_size);	err |= get_user(arg64.malloc_size, &arg32->malloc_size);	err |= get_user(cp, &arg32->buf);	arg64.buf = compat_ptr(cp);	err |= copy_to_user(p, &arg64, sizeof(arg64));	if (err)		 return -EFAULT;	err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) p);	if (err)		return err;	err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));	if (err)		return -EFAULT;	return err;}#elsestatic inline void register_cciss_ioctl32(void) {}static inline void unregister_cciss_ioctl32(void) {}#endif/* * ioctl  */static int cciss_ioctl(struct inode *inode, struct file *filep, 		unsigned int cmd, unsigned long arg){	struct block_device *bdev = inode->i_bdev;	struct gendisk *disk = bdev->bd_disk;	ctlr_info_t *host = get_host(disk);	drive_info_struct *drv = get_drv(disk);	int ctlr = host->ctlr;	void __user *argp = (void __user *)arg;#ifdef CCISS_DEBUG	printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);#endif /* CCISS_DEBUG */ 		switch(cmd) {	case HDIO_GETGEO:	{                struct hd_geometry driver_geo;                if (drv->cylinders) {                        driver_geo.heads = drv->heads;                        driver_geo.sectors = drv->sectors;                        driver_geo.cylinders = drv->cylinders;                } else			return -ENXIO;                driver_geo.start= get_start_sect(inode->i_bdev);                if (copy_to_user(argp, &driver_geo, sizeof(struct hd_geometry)))                        return  -EFAULT;                return(0);	}	case CCISS_GETPCIINFO:	{		cciss_pci_info_struct pciinfo;		if (!arg) return -EINVAL;		pciinfo.bus = host->pdev->bus->number;		pciinfo.dev_fn = host->pdev->devfn;		pciinfo.board_id = host->board_id;		if (copy_to_user(argp, &pciinfo,  sizeof( cciss_pci_info_struct )))			return  -EFAULT;		return(0);	}		case CCISS_GETINTINFO:	{		cciss_coalint_struct intinfo;		if (!arg) return -EINVAL;		intinfo.delay = readl(&host->cfgtable->HostWrite.CoalIntDelay);		intinfo.count = readl(&host->cfgtable->HostWrite.CoalIntCount);		if (copy_to_user(argp, &intinfo, sizeof( cciss_coalint_struct )))			return -EFAULT;                return(0);        }	case CCISS_SETINTINFO:        {                cciss_coalint_struct intinfo;		unsigned long flags;		int i;		if (!arg) return -EINVAL;			if (!capable(CAP_SYS_ADMIN)) return -EPERM;		if (copy_from_user(&intinfo, argp, sizeof( cciss_coalint_struct)))			return -EFAULT;		if ( (intinfo.delay == 0 ) && (intinfo.count == 0))		{//			printk("cciss_ioctl: delay and count cannot be 0\n");			return( -EINVAL);		}		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);		/* Update the field, and then ring the doorbell */ 		writel( intinfo.delay, 			&(host->cfgtable->HostWrite.CoalIntDelay));		writel( intinfo.count,                         &(host->cfgtable->HostWrite.CoalIntCount));		writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);		for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {			if (!(readl(host->vaddr + SA5_DOORBELL) 					& CFGTBL_ChangeReq))				break;			/* delay and try again */			udelay(1000);		}			spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);		if (i >= MAX_IOCTL_CONFIG_WAIT)			return -EAGAIN;                return(0);        }	case CCISS_GETNODENAME:        {                NodeName_type NodeName;		int i; 		if (!arg) return -EINVAL;		for(i=0;i<16;i++)			NodeName[i] = readb(&host->cfgtable->ServerName[i]);                if (copy_to_user(argp, NodeName, sizeof( NodeName_type)))                	return  -EFAULT;                return(0);        }	case CCISS_SETNODENAME:	{		NodeName_type NodeName;		unsigned long flags;		int i;		if (!arg) return -EINVAL;		if (!capable(CAP_SYS_ADMIN)) return -EPERM;				if (copy_from_user(NodeName, argp, sizeof( NodeName_type)))			return -EFAULT;		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);			/* Update the field, and then ring the doorbell */ 		for(i=0;i<16;i++)			writeb( NodeName[i], &host->cfgtable->ServerName[i]);					writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);		for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {			if (!(readl(host->vaddr + SA5_DOORBELL) 					& CFGTBL_ChangeReq))				break;			/* delay and try again */			udelay(1000);		}			spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);		if (i >= MAX_IOCTL_CONFIG_WAIT)			return -EAGAIN;                return(0);        }	case CCISS_GETHEARTBEAT:        {                Heartbeat_type heartbeat;		if (!arg) return -EINVAL;                heartbeat = readl(&host->cfgtable->HeartBeat);                if (copy_to_user(argp, &heartbeat, sizeof( Heartbeat_type)))                	return -EFAULT;                return(0);        }	case CCISS_GETBUSTYPES:        {                BusTypes_type BusTypes;		if (!arg) return -EINVAL;                BusTypes = readl(&host->cfgtable->BusTypes);                if (copy_to_user(argp, &BusTypes, sizeof( BusTypes_type) ))                	return  -EFAULT;                return(0);        }	case CCISS_GETFIRMVER:        {		FirmwareVer_type firmware;		if (!arg) return -EINVAL;		memcpy(firmware, host->firm_ver, 4);                if (copy_to_user(argp, firmware, sizeof( FirmwareVer_type)))                	return -EFAULT;                return(0);        }        case CCISS_GETDRIVVER:        {		DriverVer_type DriverVer = DRIVER_VERSION;                if (!arg) return -EINVAL;                if (copy_to_user(argp, &DriverVer, sizeof( DriverVer_type) ))                	return -EFAULT;                return(0);        }	case CCISS_REVALIDVOLS:		if (bdev != bdev->bd_contains || drv != host->drv)			return -ENXIO;                return revalidate_allvol(host); 	case CCISS_GETLUNINFO: { 		LogvolInfo_struct luninfo; 		int i; 		 		luninfo.LunID = drv->LunID; 		luninfo.num_opens = drv->usage_count; 		luninfo.num_parts = 0; 		/* count partitions 1 to 15 with sizes > 0 */ 		for(i=1; i <MAX_PART; i++) {			if (!disk->part[i])				continue;			if (disk->part[i]->nr_sects != 0)				luninfo.num_parts++;		} 		if (copy_to_user(argp, &luninfo, 				sizeof(LogvolInfo_struct))) 			return -EFAULT; 		return(0); 	}	case CCISS_DEREGDISK:		return deregister_disk(disk);	case CCISS_REGNEWD:		return register_new_disk(host);	case CCISS_PASSTHRU:	{		IOCTL_Command_struct iocommand;		CommandList_struct *c;		char 	*buff = NULL;		u64bit	temp64;		unsigned long flags;		DECLARE_COMPLETION(wait);		if (!arg) return -EINVAL;			if (!capable(CAP_SYS_RAWIO)) return -EPERM;		if (copy_from_user(&iocommand, argp, sizeof( IOCTL_Command_struct) ))			return -EFAULT;		if((iocommand.buf_size < 1) && 				(iocommand.Request.Type.Direction != XFER_NONE))		{				return -EINVAL;		} #if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */		/* Check kmalloc limits */		if(iocommand.buf_size > 128000)			return -EINVAL;#endif		if(iocommand.buf_size > 0)		{			buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);			if( buff == NULL) 				return -EFAULT;		}		if (iocommand.Request.Type.Direction == XFER_WRITE)		{			/* Copy the data into the buffer we created */ 			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))			{				kfree(buff);				return -EFAULT;			}		} else {			memset(buff, 0, iocommand.buf_size);		}		if ((c = cmd_alloc(host , 0)) == NULL)		{			kfree(buff);			return -ENOMEM;		}			// Fill in the command type 		c->cmd_type = CMD_IOCTL_PEND;			// Fill in Command Header 		c->Header.ReplyQueue = 0;  // unused in simple mode		if( iocommand.buf_size > 0) 	// buffer to fill 		{			c->Header.SGList = 1;			c->Header.SGTotal= 1;		} else	// no buffers to fill  		{			c->Header.SGList = 0;                	c->Header.SGTotal= 0;		}		c->Header.LUN = iocommand.LUN_info;		c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag				// Fill in Request block 		c->Request = iocommand.Request; 			// Fill in the scatter gather information		if (iocommand.buf_size > 0 ) 		{			temp64.val = pci_map_single( host->pdev, buff,                                        iocommand.buf_size,                                 PCI_DMA_BIDIRECTIONAL);				c->SG[0].Addr.lower = temp64.val32.lower;			c->SG[0].Addr.upper = temp64.val32.upper;			c->SG[0].Len = iocommand.buf_size;			c->SG[0].Ext = 0;  // we are not chaining		}		c->waiting = &wait;		/* Put the request on the tail of the request queue */		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);		addQ(&host->reqQ, c);		host->Qdepth++;		start_io(host);		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);		wait_for_completion(&wait);		/* unlock the buffers from DMA */		temp64.val32.lower = c->SG[0].Addr.lower;                temp64.val32.upper = c->SG[0].Addr.upper;                pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,                	iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);

⌨️ 快捷键说明

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