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 + -
显示快捷键?