📄 dpt_i2o.c
字号:
return -ENOMEM; } pHba->channel[bus_no].device[scsi_id] = pDev; memset(pDev,0,sizeof(struct adpt_device)); } else { for( pDev = pHba->channel[bus_no].device[scsi_id]; pDev->next_lun; pDev = pDev->next_lun){ } pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL); if(pDev == NULL) { return -ENOMEM; } memset(pDev->next_lun,0,sizeof(struct adpt_device)); pDev = pDev->next_lun; } pDev->tid = tid; pDev->scsi_channel = bus_no; pDev->scsi_id = scsi_id; pDev->scsi_lun = scsi_lun; pDev->pI2o_dev = d; d->owner = pDev; pDev->type = (buf[0])&0xff; pDev->flags = (buf[0]>>8)&0xff; if(scsi_id > pHba->top_scsi_id){ pHba->top_scsi_id = scsi_id; } if(scsi_lun > pHba->top_scsi_lun){ pHba->top_scsi_lun = scsi_lun; } } if(scsi_id == -1){ printk(KERN_WARNING"Could not find SCSI ID for %s\n", d->lct_data.identity_tag); } } } return 0;}/* * Each I2O controller has a chain of devices on it - these match * the useful parts of the LCT of the board. */ static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d){ down(&adpt_configuration_lock); d->controller=pHba; d->owner=NULL; d->next=pHba->devices; d->prev=NULL; if (pHba->devices != NULL){ pHba->devices->prev=d; } pHba->devices=d; *d->dev_name = 0; up(&adpt_configuration_lock); return 0;}static int adpt_open(struct inode *inode, struct file *file){ int minor; adpt_hba* pHba; //TODO check for root access // minor = MINOR(inode->i_rdev); if (minor >= hba_count) { return -ENXIO; } down(&adpt_configuration_lock); for (pHba = hba_chain; pHba; pHba = pHba->next) { if (pHba->unit == minor) { break; /* found adapter */ } } if (pHba == NULL) { up(&adpt_configuration_lock); return -ENXIO; }// if(pHba->in_use){ // up(&adpt_configuration_lock);// return -EBUSY;// } pHba->in_use = 1; up(&adpt_configuration_lock); return 0;}static int adpt_close(struct inode *inode, struct file *file){ int minor; adpt_hba* pHba; minor = MINOR(inode->i_rdev); if (minor >= hba_count) { return -ENXIO; } down(&adpt_configuration_lock); for (pHba = hba_chain; pHba; pHba = pHba->next) { if (pHba->unit == minor) { break; /* found adapter */ } } up(&adpt_configuration_lock); if (pHba == NULL) { return -ENXIO; } pHba->in_use = 0; return 0;}static int adpt_i2o_passthru(adpt_hba* pHba, u32* arg){ u32 msg[MAX_MESSAGE_SIZE]; u32* reply = NULL; u32 size = 0; u32 reply_size = 0; u32* user_msg = (u32*)arg; u32* user_reply = NULL; ulong sg_list[pHba->sg_tablesize]; u32 sg_offset = 0; u32 sg_count = 0; int sg_index = 0; u32 i = 0; u32 rcode = 0; ulong p = 0; ulong flags = 0; memset(&msg, 0, MAX_MESSAGE_SIZE*4); // get user msg size in u32s if(get_user(size, &user_msg[0])){ return -EFAULT; } size = size>>16; user_reply = &user_msg[size]; if(size > MAX_MESSAGE_SIZE){ return -EFAULT; } size *= 4; // Convert to bytes /* Copy in the user's I2O command */ if(copy_from_user((void*)msg, (void*)user_msg, size)) { return -EFAULT; } get_user(reply_size, &user_reply[0]); reply_size = reply_size>>16; if(reply_size > REPLY_FRAME_SIZE){ reply_size = REPLY_FRAME_SIZE; } reply_size *= 4; reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); if(reply == NULL) { printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name); return -ENOMEM; } memset(reply,0,REPLY_FRAME_SIZE*4); sg_offset = (msg[0]>>4)&0xf; msg[2] = 0x40000000; // IOCTL context msg[3] = (u32)reply; memset(sg_list,0, sizeof(sg_list[0])*pHba->sg_tablesize); if(sg_offset) { // TODO 64bit fix struct sg_simple_element *sg = (struct sg_simple_element*) (msg+sg_offset); sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); if (sg_count > pHba->sg_tablesize){ printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", pHba->name,sg_count); kfree (reply); return -EINVAL; } for(i = 0; i < sg_count; i++) { int sg_size; if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) { printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",pHba->name,i, sg[i].flag_count); rcode = -EINVAL; goto cleanup; } sg_size = sg[i].flag_count & 0xffffff; /* Allocate memory for the transfer */ p = (ulong)kmalloc(sg_size, GFP_KERNEL|ADDR32); if(p == 0) { printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", pHba->name,sg_size,i,sg_count); rcode = -ENOMEM; goto cleanup; } sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. /* Copy in the user's SG buffer if necessary */ if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) { // TODO 64bit fix if (copy_from_user((void*)p,(void*)sg[i].addr_bus, sg_size)) { printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i); rcode = -EFAULT; goto cleanup; } } //TODO 64bit fix sg[i].addr_bus = (u32)virt_to_bus((void*)p); } } do { spin_lock_irqsave(&io_request_lock, flags); // This state stops any new commands from enterring the // controller while processing the ioctl// pHba->state |= DPTI_STATE_IOCTL;// We can't set this now - The scsi subsystem sets host_blocked and// the queue empties and stops. We need a way to restart the queue rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER);// pHba->state &= ~DPTI_STATE_IOCTL; spin_unlock_irqrestore(&io_request_lock, flags); } while(rcode == -ETIMEDOUT); if(rcode){ goto cleanup; } if(sg_offset) { /* Copy back the Scatter Gather buffers back to user space */ u32 j; // TODO 64bit fix struct sg_simple_element* sg; int sg_size; // re-acquire the original message to handle correctly the sg copy operation memset(&msg, 0, MAX_MESSAGE_SIZE*4); // get user msg size in u32s if(get_user(size, &user_msg[0])){ rcode = -EFAULT; goto cleanup; } size = size>>16; size *= 4; /* Copy in the user's I2O command */ if (copy_from_user ((void*)msg, (void*)user_msg, size)) { rcode = -EFAULT; goto cleanup; } sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); // TODO 64bit fix sg = (struct sg_simple_element*)(msg + sg_offset); for (j = 0; j < sg_count; j++) { /* Copy out the SG list to user's buffer if necessary */ if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) { sg_size = sg[j].flag_count & 0xffffff; // TODO 64bit fix if (copy_to_user((void*)sg[j].addr_bus,(void*)sg_list[j], sg_size)) { printk(KERN_WARNING"%s: Could not copy %lx TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus); rcode = -EFAULT; goto cleanup; } } } } /* Copy back the reply to user space */ if (reply_size) { // we wrote our own values for context - now restore the user supplied ones if(copy_from_user(reply+2, user_msg+2, sizeof(u32)*2)) { printk(KERN_WARNING"%s: Could not copy message context FROM user\n",pHba->name); rcode = -EFAULT; } if(copy_to_user(user_reply, reply, reply_size)) { printk(KERN_WARNING"%s: Could not copy reply TO user\n",pHba->name); rcode = -EFAULT; } }cleanup: kfree (reply); while(sg_index) { if(sg_list[--sg_index]) { kfree((void*)(sg_list[sg_index])); } } return rcode;}/* * This routine returns information about the system. This does not effect * any logic and if the info is wrong - it doesn't matter. *//* Get all the info we can not get from kernel services */static int adpt_system_info(void *buffer){ sysInfo_S si; memset(&si, 0, sizeof(si)); si.osType = OS_LINUX; si.osMajorVersion = (u8) (LINUX_VERSION_CODE >> 16); si.osMinorVersion = (u8) (LINUX_VERSION_CODE >> 8 & 0x0ff); si.osRevision = (u8) (LINUX_VERSION_CODE & 0x0ff); si.busType = SI_PCI_BUS; si.processorFamily = DPTI_sig.dsProcessorFamily;#if defined __i386__ adpt_i386_info(&si);#elif defined (__ia64__) adpt_ia64_info(&si);#elif defined(__sparc__) adpt_sparc_info(&si);#elif defined (__alpha__) adpt_alpha_info(&si);#else si.processorType = 0xff ;#endif if(copy_to_user(buffer, &si, sizeof(si))){ printk(KERN_WARNING"dpti: Could not copy buffer TO user\n"); return -EFAULT; } return 0;}#if defined __ia64__ static void adpt_ia64_info(sysInfo_S* si){ // This is all the info we need for now // We will add more info as our new // managmenent utility requires it si->processorType = PROC_IA64;}#endif#if defined __sparc__ static void adpt_sparc_info(sysInfo_S* si){ // This is all the info we need for now // We will add more info as our new // managmenent utility requires it si->processorType = PROC_ULTRASPARC;}#endif#if defined __alpha__ static void adpt_alpha_info(sysInfo_S* si){ // This is all the info we need for now // We will add more info as our new // managmenent utility requires it si->processorType = PROC_ALPHA;}#endif#if defined __i386__static void adpt_i386_info(sysInfo_S* si){ // This is all the info we need for now // We will add more info as our new // managmenent utility requires it switch (boot_cpu_data.x86) { case CPU_386: si->processorType = PROC_386; break; case CPU_486: si->processorType = PROC_486; break; case CPU_586: si->processorType = PROC_PENTIUM; break; default: // Just in case si->processorType = PROC_PENTIUM; break; }}#endifstatic int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg){ int minor; int error = 0; adpt_hba* pHba; ulong flags; minor = MINOR(inode->i_rdev); if (minor >= DPTI_MAX_HBA){ return -ENXIO; } down(&adpt_configuration_lock); for (pHba = hba_chain; pHba; pHba = pHba->next) { if (pHba->unit == minor) { break; /* found adapter */ } } up(&adpt_configuration_lock); if(pHba == NULL){ return -ENXIO; } while((volatile u32) pHba->state & DPTI_STATE_RESET ) { set_task_state(current,TASK_UNINTERRUPTIBLE); schedule_timeout(2); } switch (cmd) { // TODO: handle 3 cases case DPT_SIGNATURE: if (copy_to_user((char*)arg, &DPTI_sig, sizeof(DPTI_sig))) { return -EFAULT; } break; case I2OUSRCMD: return adpt_i2o_passthru(pHba,(u32*)arg); break; case DPT_CTRLINFO:{ drvrHBAinfo_S HbaInfo;#define FLG_OSD_PCI_VALID 0x0001#define FLG_OSD_DMA 0x0002#define FLG_OSD_I2O 0x0004 memset(&HbaInfo, 0, sizeof(HbaInfo)); HbaInfo.drvrHBAnum = pHba->unit; HbaInfo.baseAddr = (ulong) pHba->base_addr_phys; HbaInfo.blinkState = adpt_read_blink_led(pHba); HbaInfo.pciBusNum = pHba->pDev->bus->number; HbaInfo.pciDeviceNum=PCI_SLOT(pHba->pDev->devfn); HbaInfo.Interrupt = pHba->pDev->irq; HbaInfo.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O; if(copy_to_user((void *) arg, &HbaInfo, sizeof(HbaInfo))){ printk(KERN_WARNING"%s: Could not copy HbaInfo TO user\n",pHba->name); return -EFAULT; } break; } case DPT_SYSINFO: return adpt_system_info((void*)arg); break; case DPT_BLINKLED:{ u32 value; value = (u32)adpt_read_blink_led(pHba); if (copy_to_user((char*)arg, &value, sizeof(value))) { return -EFAULT; } break; } case I2ORESETCMD: spin_lock_irqsave(&io_request_lock, flags); adpt_hba_reset(pHba); spin_unlock_irqrestore(&io_request_lock, flags); break; case I2ORESCANCMD: adpt_rescan(pHba); break; case DPT_TARGET_BUSY & 0xFFFF: case DPT_TARGET_BUSY: { TARGET_BUSY_T busy; struct adpt_device* d; if (copy_from_user((void*)&busy, (void*)arg, sizeof(TARGET_BUSY_T))) { return -EFAULT; } d = adpt_find_device(pHba, busy.channel, busy.id, busy.lun); if(d == NULL){ return -ENODEV; } busy.isBusy = ((d->pScsi_dev) && (0 != d->pScsi_dev->access_count)) ? 1 : 0; if (copy_to_user ((char*)arg, &busy, sizeof(busy))) { return -EFAULT; } break; } default: return -EINVAL; } return error;}static void adpt_isr(int irq, void *dev_id, struct pt_regs *regs){ Scsi_Cmnd* cmd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -