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

📄 cciss.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		temp64.val32.upper = c->ErrDesc.Addr.upper;		pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), 			c->err_info, (dma_addr_t) temp64.val);		pci_free_consistent(h->pdev, sizeof(CommandList_struct), 			c, (dma_addr_t) c->busaddr);	} else 	{		i = c - h->cmd_pool;		clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));                h->nr_frees++;        }}static inline ctlr_info_t *get_host(struct gendisk *disk){	return disk->queue->queuedata; }static inline drive_info_struct *get_drv(struct gendisk *disk){	return disk->private_data;}/* * Open.  Make sure the device is really there. */static int cciss_open(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_open %s\n", inode->i_bdev->bd_disk->disk_name);#endif /* CCISS_DEBUG */ 	if (host->busy_initializing || drv->busy_configuring)		return -EBUSY;	/*	 * Root is allowed to open raw volume zero even if it's not configured	 * so array config can still work. Root is also allowed to open any	 * volume that has a LUN ID, so it can issue IOCTL to reread the	 * disk information.  I don't think I really like this	 * but I'm already using way to many device nodes to claim another one	 * for "raw controller".	 */	if (drv->nr_blocks == 0) {		if (iminor(inode) != 0)	{ 	/* not node 0? */			/* if not node 0 make sure it is a partition = 0 */			if (iminor(inode) & 0x0f) {			return -ENXIO;				/* if it is, make sure we have a LUN ID */			} else if (drv->LunID == 0) {				return -ENXIO;			}		}		if (!capable(CAP_SYS_ADMIN))			return -EPERM;	}	drv->usage_count++;	host->usage_count++;	return 0;}/* * Close.  Sync first. */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_COMPATstatic int do_ioctl(struct file *f, unsigned cmd, unsigned long arg){	int ret;	lock_kernel();	ret = cciss_ioctl(f->f_dentry->d_inode, f, cmd, arg);	unlock_kernel();	return ret;}static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg);static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd, unsigned long arg);static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg){	switch (cmd) {	case CCISS_GETPCIINFO:	case CCISS_GETINTINFO:	case CCISS_SETINTINFO:	case CCISS_GETNODENAME:	case CCISS_SETNODENAME:	case CCISS_GETHEARTBEAT:	case CCISS_GETBUSTYPES:	case CCISS_GETFIRMVER:	case CCISS_GETDRIVVER:	case CCISS_REVALIDVOLS:	case CCISS_DEREGDISK:	case CCISS_REGNEWDISK:	case CCISS_REGNEWD:	case CCISS_RESCANDISK:	case CCISS_GETLUNINFO:		return do_ioctl(f, cmd, arg);	case CCISS_PASSTHRU32:		return cciss_ioctl32_passthru(f, cmd, arg);	case CCISS_BIG_PASSTHRU32:		return cciss_ioctl32_big_passthru(f, cmd, arg);	default:		return -ENOIOCTLCMD;	}}static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg){	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 = do_ioctl(f, 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;}static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned long arg){	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 = do_ioctl(file, 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;}#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.domain = pci_domain_nr(host->pdev->bus);		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; 		 		luninfo.LunID = drv->LunID; 		luninfo.num_opens = drv->usage_count; 		luninfo.num_parts = 0; 		if (copy_to_user(argp, &luninfo, 				sizeof(LogvolInfo_struct))) 			return -EFAULT; 		return(0); 	}	case CCISS_DEREGDISK:		return rebuild_lun_table(host, disk);	case CCISS_REGNEWD:		return rebuild_lun_table(host, NULL);	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; 

⌨️ 快捷键说明

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