📄 cciss.c
字号:
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 + -