📄 cciss.c
字号:
case BLKRASET: case BLKRAGET: case BLKPG: case BLKELVGET: case BLKELVSET: return( blk_ioctl(inode->i_rdev, cmd, arg)); case CCISS_GETPCIINFO: { cciss_pci_info_struct pciinfo; if (!arg) return -EINVAL; pciinfo.bus = hba[ctlr]->pdev->bus->number; pciinfo.dev_fn = hba[ctlr]->pdev->devfn; pciinfo.board_id = hba[ctlr]->board_id; if (copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct ))) return -EFAULT; return(0); } case CCISS_GETINTINFO: { cciss_coalint_struct intinfo; ctlr_info_t *c = hba[ctlr]; if (!arg) return -EINVAL; intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay); intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount); if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct ))) return -EFAULT; return(0); } case CCISS_SETINTINFO: { cciss_coalint_struct intinfo; ctlr_info_t *c = hba[ctlr]; unsigned long flags; int i; if (!arg) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&intinfo, (void *) arg, 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(&io_request_lock, flags); /* Can only safely update if no commands outstanding */ if (c->commands_outstanding > 0 ) {// printk("cciss_ioctl: cannot change coalasing "// "%d commands outstanding on controller\n", // c->commands_outstanding); spin_unlock_irqrestore(&io_request_lock, flags); return(-EINVAL); } /* Update the field, and then ring the doorbell */ writel( intinfo.delay, &(c->cfgtable->HostWrite.CoalIntDelay)); writel( intinfo.count, &(c->cfgtable->HostWrite.CoalIntCount)); writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); for(i=0;i<MAX_CONFIG_WAIT;i++) { if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) break; /* delay and try again */ udelay(1000); } spin_unlock_irqrestore(&io_request_lock, flags); if (i >= MAX_CONFIG_WAIT) return( -EFAULT); return(0); } case CCISS_GETNODENAME: { NodeName_type NodeName; ctlr_info_t *c = hba[ctlr]; int i; if (!arg) return -EINVAL; for(i=0;i<16;i++) NodeName[i] = readb(&c->cfgtable->ServerName[i]); if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type))) return -EFAULT; return(0); } case CCISS_SETNODENAME: { NodeName_type NodeName; ctlr_info_t *c = hba[ctlr]; unsigned long flags; int i; if (!arg) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type))) return -EFAULT; spin_lock_irqsave(&io_request_lock, flags); /* Update the field, and then ring the doorbell */ for(i=0;i<16;i++) writeb( NodeName[i], &c->cfgtable->ServerName[i]); writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); for(i=0;i<MAX_CONFIG_WAIT;i++) { if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) break; /* delay and try again */ udelay(1000); } spin_unlock_irqrestore(&io_request_lock, flags); if (i >= MAX_CONFIG_WAIT) return( -EFAULT); return(0); } case CCISS_GETHEARTBEAT: { Heartbeat_type heartbeat; ctlr_info_t *c = hba[ctlr]; if (!arg) return -EINVAL; heartbeat = readl(&c->cfgtable->HeartBeat); if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type))) return -EFAULT; return(0); } case CCISS_GETBUSTYPES: { BusTypes_type BusTypes; ctlr_info_t *c = hba[ctlr]; if (!arg) return -EINVAL; BusTypes = readl(&c->cfgtable->BusTypes); if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) )) return -EFAULT; return(0); } case CCISS_GETFIRMVER: { FirmwareVer_type firmware; if (!arg) return -EINVAL; memcpy(firmware, hba[ctlr]->firm_ver, 4); if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type))) return -EFAULT; return(0); } case CCISS_GETDRIVVER: { DriverVer_type DriverVer = DRIVER_VERSION; if (!arg) return -EINVAL; if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) )) return -EFAULT; return(0); } case CCISS_REVALIDVOLS: return( revalidate_allvol(inode->i_rdev)); case CCISS_PASSTHRU: { IOCTL_Command_struct iocommand; ctlr_info_t *h = hba[ctlr]; CommandList_struct *c; char *buff = NULL; u64bit temp64; unsigned long flags; if (!arg) return -EINVAL; if (!capable(CAP_SYS_RAWIO)) return -EPERM; if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) )) return -EFAULT; if((iocommand.buf_size < 1) && (iocommand.Request.Type.Direction != XFER_NONE)) { return -EINVAL; } /* Check kmalloc limits */ if(iocommand.buf_size > 128000) return -EINVAL; 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; } } if ((c = cmd_alloc(h , 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( h->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 } /* Put the request on the tail of the request queue */ spin_lock_irqsave(&io_request_lock, flags); addQ(&h->reqQ, c); h->Qdepth++; start_io(h); spin_unlock_irqrestore(&io_request_lock, flags); /* Wait for completion */ while(c->cmd_type != CMD_IOCTL_DONE) schedule_timeout(1); /* unlock the buffers from DMA */ temp64.val32.lower = c->SG[0].Addr.lower; temp64.val32.upper = c->SG[0].Addr.upper; pci_unmap_single( h->pdev, (dma_addr_t) temp64.val, iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); /* Copy the error information out */ iocommand.error_info = *(c->err_info); if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) ) { kfree(buff); cmd_free(h, c, 0); return( -EFAULT); } if (iocommand.Request.Type.Direction == XFER_READ) { /* Copy the data out of the buffer we created */ if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { kfree(buff); cmd_free(h, c, 0); return -EFAULT; } } kfree(buff); cmd_free(h, c, 0); return(0); } default: return -EBADRQC; } }/* Borrowed and adapted from sd.c */static int revalidate_logvol(kdev_t dev, int maxusage){ int ctlr, target; struct gendisk *gdev; unsigned long flags; int max_p; int start; int i; target = MINOR(dev) >> NWD_SHIFT; ctlr = MAJOR(dev) - MAJOR_NR; gdev = &(hba[ctlr]->gendisk); spin_lock_irqsave(&io_request_lock, flags); if (hba[ctlr]->drv[target].usage_count > maxusage) { spin_unlock_irqrestore(&io_request_lock, flags); printk(KERN_WARNING "cciss: Device busy for " "revalidation (usage=%d)\n", hba[ctlr]->drv[target].usage_count); return -EBUSY; } hba[ctlr]->drv[target].usage_count++; spin_unlock_irqrestore(&io_request_lock, flags); max_p = gdev->max_p; start = target << gdev->minor_shift; for(i=max_p-1; i>=0; i--) { int minor = start+i; invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1); gdev->part[minor].start_sect = 0; gdev->part[minor].nr_sects = 0; /* reset the blocksize so we can read the partition table */ blksize_size[MAJOR_NR+ctlr][minor] = 1024; } /* setup partitions per disk */ grok_partitions(gdev, target, MAX_PART, hba[ctlr]->drv[target].nr_blocks); hba[ctlr]->drv[target].usage_count--; return 0;}static int frevalidate_logvol(kdev_t dev){#ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: frevalidate has been called\n");#endif /* CCISS_DEBUG */ return revalidate_logvol(dev, 0);}/* * revalidate_allvol is for online array config utilities. After a * utility reconfigures the drives in the array, it can use this function * (through an ioctl) to make the driver zap any previous disk structs for * that controller and get new ones. * * Right now I'm using the getgeometry() function to do this, but this * function should probably be finer grained and allow you to revalidate one * particualar logical volume (instead of all of them on a particular * controller). */static int revalidate_allvol(kdev_t dev){ int ctlr, i; unsigned long flags; ctlr = MAJOR(dev) - MAJOR_NR; if (MINOR(dev) != 0) return -ENXIO; spin_lock_irqsave(&io_request_lock, flags); if (hba[ctlr]->usage_count > 1) { spin_unlock_irqrestore(&io_request_lock, flags); printk(KERN_WARNING "cciss: Device busy for volume" " revalidation (usage=%d)\n", hba[ctlr]->usage_count); return -EBUSY; } spin_unlock_irqrestore(&io_request_lock, flags); hba[ctlr]->usage_count++; /* * Set the partition and block size structures for all volumes * on this controller to zero. We will reread all of this data */ memset(hba[ctlr]->hd, 0, sizeof(struct hd_struct) * 256); memset(hba[ctlr]->sizes, 0, sizeof(int) * 256); memset(hba[ctlr]->blocksizes, 0, sizeof(int) * 256); memset(hba[ctlr]->hardsizes, 0, sizeof(int) * 256); memset(hba[ctlr]->drv, 0, sizeof(drive_info_struct) * CISS_MAX_LUN); hba[ctlr]->gendisk.nr_real = 0; /* * Tell the array controller not to give us any interrupts while * we check the new geometry. Then turn interrupts back on when * we're done. */ hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_OFF); cciss_getgeometry(ctlr); hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON); cciss_geninit(ctlr); for(i=0; i<NWD; i++) if (hba[ctlr]->sizes[ i<<NWD_SHIFT ]) revalidate_logvol(dev+(i<<NWD_SHIFT), 2); hba[ctlr]->usage_count--; return 0;}/* * Wait polling for a command to complete. * The memory mapped FIFO is polled for the completion. * Used only at init time, interrupts disabled. */static unsigned long pollcomplete(int ctlr){ unsigned long done;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -