📄 cciss.c
字号:
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)) return -EFAULT; } if ((c = cmd_alloc(NULL)) == NULL) { if(buff!=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 = (__u64) virt_to_bus(buff); 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); /* Copy the error information out */ iocommand.error_info = *(c->err_info); if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) ) { cmd_free(NULL, c); if (buff != NULL) kfree(buff); 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)) { cmd_free(NULL, c); kfree(buff); } } cmd_free(NULL, c); if (buff != NULL) kfree(buff); 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 "cpqarray: 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; i>=0; i--) { int minor = start+i; kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); struct super_block *sb = get_super(devi); sync_dev(devi); if (sb) invalidate_inodes(sb); invalidate_buffers(devi); 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 interupts 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; int i; /* Wait (up to 2 seconds) for a command to complete */ for (i = 200000; i > 0; i--) { done = hba[ctlr]->access.command_completed(hba[ctlr]); if (done == FIFO_EMPTY) { udelay(10); /* a short fixed delay */ } else return (done); } /* Invalid address to tell caller we ran out of time */ return 1;}/* * Send a command to the controller, and wait for it to complete. * Only used at init time. */static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, unsigned int log_unit, __u8 page_code ){ CommandList_struct *c; int i; unsigned long complete; ctlr_info_t *info_p= hba[ctlr]; u64bit temp64; c = cmd_alloc(info_p); if (c == NULL) { printk(KERN_WARNING "cciss: unable to get memory"); return(IO_ERROR); } // Fill in Command Header c->Header.ReplyQueue = 0; // unused in simple mode if( buff != NULL) // 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.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag // Fill in Request block switch(cmd) { case CISS_INQUIRY: /* If the logical unit number is 0 then, this is going to controller so It's a physical command mode = 0 target = 0. So we have nothing to write. Otherwise mode = 1 target = LUNID */ if(use_unit_num != 0) { c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; } /* are we trying to read a vital product page */ if(page_code != 0) { c->Request.CDB[1] = 0x01; c->Request.CDB[2] = page_code; } c->Request.CDBLen = 6; c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; // Read c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CISS_INQUIRY; c->Request.CDB[4] = size & 0xFF; break; case CISS_REPORT_LOG: /* Talking to controller so It's a physical command mode = 00 target = 0. So we have nothing to write. */ c->Request.CDBLen = 12; c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; // Read c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CISS_REPORT_LOG; c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0xFF; c->Request.CDB[9] = size & 0xFF; break; case CCISS_READ_CAPACITY: c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; c->Request.Type.Type = TYPE_CMD; // It is a command. c->Request.Type.Attribute = ATTR_SIMPLE; c->Request.Type.Direction = XFER_READ; // Read c->Request.Timeout = 0; // Don't time out c->Request.CDB[0] = CCISS_READ_CAPACITY; break; default: printk(KERN_WARNING "cciss: Unknown Command 0x%c sent attempted\n", cmd); cmd_free(info_p, c); return(IO_ERROR); }; // Fill in the scatter gather information if (size > 0 ) { temp64.val = (__u64) virt_to_bus(buff); c->SG[0].Addr.lower = temp64.val32.lower; c->SG[0].Addr.upper = temp64.val32.upper; c->SG[0].Len = size; c->SG[0].Ext = 0; // we are not chaining } /* * Disable interrupt */#ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: turning intr off\n");#endif /* CCISS_DEBUG */ info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); /* Make sure there is room in the command FIFO */ /* Actually it should be completely empty at this time. */ for (i = 200000; i > 0; i--) { /* if fifo isn't full go */ if (!(info_p->access.fifo_full(info_p))) { break; } udelay(10); printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," " waiting!\n", ctlr); } /* * Send the cmd */ info_p->access.submit_command(info_p, c); complete = pollcomplete(ctlr);#ifdef CCISS_DEBUG printk(KERN_DEBUG "cciss: command completed\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -