i2o_config.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,150 行 · 第 1/2 页
C
1,150 行
struct i2o_sw_xfer __user *pxfer = (void __user *)arg; unsigned char maxfrag = 0, curfrag = 1; unsigned char *buffer; u32 msg[9]; unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; dma_addr_t buffer_phys; if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; if(get_user(swlen, kxfer.swlen) < 0) return -EFAULT; if(get_user(maxfrag, kxfer.maxfrag) < 0) return -EFAULT; if(get_user(curfrag, kxfer.curfrag) < 0) return -EFAULT; if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; if(!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize)) return -EFAULT; c = i2o_find_controller(kxfer.iop); if(!c) return -ENXIO; buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); if (buffer==NULL) { i2o_unlock_controller(c); return -ENOMEM; } __copy_from_user(buffer, kxfer.buf, fragsize); msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; msg[1]= I2O_CMD_SW_DOWNLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; msg[2]= (u32)cfg_handler.context; msg[3]= 0; msg[4]= (((u32)kxfer.flags)<<24) | (((u32)kxfer.sw_type)<<16) | (((u32)maxfrag)<<8) | (((u32)curfrag)); msg[5]= swlen; msg[6]= kxfer.sw_id; msg[7]= (0xD0000000 | fragsize); msg[8]= buffer_phys;// printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); i2o_unlock_controller(c); if(status != -ETIMEDOUT) pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); if (status != I2O_POST_WAIT_OK) { // it fails if you try and send frags out of order // and for some yet unknown reasons too printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status); return status; } return 0;}int ioctl_swul(unsigned long arg){ struct i2o_sw_xfer kxfer; struct i2o_sw_xfer __user *pxfer = (void __user *)arg; unsigned char maxfrag = 0, curfrag = 1; unsigned char *buffer; u32 msg[9]; unsigned int status = 0, swlen = 0, fragsize = 8192; struct i2o_controller *c; dma_addr_t buffer_phys; if(copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; if(get_user(swlen, kxfer.swlen) < 0) return -EFAULT; if(get_user(maxfrag, kxfer.maxfrag) < 0) return -EFAULT; if(get_user(curfrag, kxfer.curfrag) < 0) return -EFAULT; if(curfrag==maxfrag) fragsize = swlen-(maxfrag-1)*8192; if(!kxfer.buf || !access_ok(VERIFY_WRITE, kxfer.buf, fragsize)) return -EFAULT; c = i2o_find_controller(kxfer.iop); if(!c) return -ENXIO; buffer=pci_alloc_consistent(c->pdev, fragsize, &buffer_phys); if (buffer==NULL) { i2o_unlock_controller(c); return -ENOMEM; } msg[0]= NINE_WORD_MSG_SIZE | SGL_OFFSET_7; msg[1]= I2O_CMD_SW_UPLOAD<<24 | HOST_TID<<12 | ADAPTER_TID; msg[2]= (u32)cfg_handler.context; msg[3]= 0; msg[4]= (u32)kxfer.flags<<24|(u32)kxfer.sw_type<<16|(u32)maxfrag<<8|(u32)curfrag; msg[5]= swlen; msg[6]= kxfer.sw_id; msg[7]= (0xD0000000 | fragsize); msg[8]= buffer_phys; // printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize); status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL, buffer_phys, 0, fragsize, 0); i2o_unlock_controller(c); if (status != I2O_POST_WAIT_OK) { if(status != -ETIMEDOUT) pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status); return status; } __copy_to_user(kxfer.buf, buffer, fragsize); pci_free_consistent(c->pdev, fragsize, buffer, buffer_phys); return 0;}int ioctl_swdel(unsigned long arg){ struct i2o_controller *c; struct i2o_sw_xfer kxfer; struct i2o_sw_xfer __user *pxfer = (void __user *)arg; u32 msg[7]; unsigned int swlen; int token; if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer))) return -EFAULT; if (get_user(swlen, kxfer.swlen) < 0) return -EFAULT; c = i2o_find_controller(kxfer.iop); if (!c) return -ENXIO; msg[0] = SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0; msg[1] = I2O_CMD_SW_REMOVE<<24 | HOST_TID<<12 | ADAPTER_TID; msg[2] = (u32)i2o_cfg_context; msg[3] = 0; msg[4] = (u32)kxfer.flags<<24 | (u32)kxfer.sw_type<<16; msg[5] = swlen; msg[6] = kxfer.sw_id; token = i2o_post_wait(c, msg, sizeof(msg), 10); i2o_unlock_controller(c); if (token != I2O_POST_WAIT_OK) { printk(KERN_INFO "i2o_config: swdel failed, DetailedStatus = %d\n", token); return -ETIMEDOUT; } return 0;}int ioctl_validate(unsigned long arg){ int token; int iop = (int)arg; u32 msg[4]; struct i2o_controller *c; c=i2o_find_controller(iop); if (!c) return -ENXIO; msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_CONFIG_VALIDATE<<24 | HOST_TID<<12 | iop; msg[2] = (u32)i2o_cfg_context; msg[3] = 0; token = i2o_post_wait(c, msg, sizeof(msg), 10); i2o_unlock_controller(c); if (token != I2O_POST_WAIT_OK) { printk(KERN_INFO "Can't validate configuration, ErrorStatus = %d\n", token); return -ETIMEDOUT; } return 0;} static int ioctl_evt_reg(unsigned long arg, struct file *fp){ u32 msg[5]; struct i2o_evt_id __user *pdesc = (void __user *)arg; struct i2o_evt_id kdesc; struct i2o_controller *iop; struct i2o_device *d; if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id))) return -EFAULT; /* IOP exists? */ iop = i2o_find_controller(kdesc.iop); if(!iop) return -ENXIO; i2o_unlock_controller(iop); /* Device exists? */ for(d = iop->devices; d; d = d->next) if(d->lct_data.tid == kdesc.tid) break; if(!d) return -ENODEV; msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | kdesc.tid; msg[2] = (u32)i2o_cfg_context; msg[3] = (u32)fp->private_data; msg[4] = kdesc.evt_mask; i2o_post_this(iop, msg, 20); return 0;} static int ioctl_evt_get(unsigned long arg, struct file *fp){ u32 id = (u32)fp->private_data; struct i2o_cfg_info *p = NULL; struct i2o_evt_get __user *uget = (void __user *)arg; struct i2o_evt_get kget; unsigned long flags; for(p = open_files; p; p = p->next) if(p->q_id == id) break; if(!p->q_len) { return -ENOENT; return 0; } memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info)); MODINC(p->q_out, I2O_EVT_Q_LEN); spin_lock_irqsave(&i2o_config_lock, flags); p->q_len--; kget.pending = p->q_len; kget.lost = p->q_lost; spin_unlock_irqrestore(&i2o_config_lock, flags); if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get))) return -EFAULT; return 0;}static int ioctl_passthru(unsigned long arg){ struct i2o_cmd_passthru __user *cmd = (void __user *) arg; struct i2o_controller *c; u32 msg[MSG_FRAME_SIZE]; u32 __user *user_msg; u32 *reply = NULL; u32 __user *user_reply = NULL; u32 size = 0; u32 reply_size = 0; u32 rcode = 0; void *sg_list[SG_TABLESIZE]; u32 sg_offset = 0; u32 sg_count = 0; int sg_index = 0; u32 i = 0; void *p = NULL; unsigned int iop; if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg)) return -EFAULT; c = i2o_find_controller(iop); if (!c) return -ENXIO; memset(&msg, 0, MSG_FRAME_SIZE*4); if(get_user(size, &user_msg[0])) return -EFAULT; size = size>>16; user_reply = &user_msg[size]; if(size > MSG_FRAME_SIZE) return -EFAULT; size *= 4; // Convert to bytes /* Copy in the user's I2O command */ if(copy_from_user(msg, user_msg, size)) return -EFAULT; if(get_user(reply_size, &user_reply[0]) < 0) return -EFAULT; reply_size = reply_size>>16; reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); if(!reply) { printk(KERN_WARNING"%s: Could not allocate reply buffer\n",c->name); return -ENOMEM; } memset(reply, 0, REPLY_FRAME_SIZE*4); sg_offset = (msg[0]>>4)&0x0f; msg[2] = (u32)i2o_cfg_context; msg[3] = (u32)reply; memset(sg_list,0, sizeof(sg_list[0])*SG_TABLESIZE); if(sg_offset) { struct sg_simple_element *sg; if(sg_offset * 4 >= size) { rcode = -EFAULT; goto cleanup; } // TODO 64bit fix sg = (struct sg_simple_element*) (msg+sg_offset); sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); if (sg_count > SG_TABLESIZE) { printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", c->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",c->name,i, sg[i].flag_count); rcode = -EINVAL; goto cleanup; } sg_size = sg[i].flag_count & 0xffffff; /* Allocate memory for the transfer */ p = kmalloc(sg_size, GFP_KERNEL); if (!p) { printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", c->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(p,(void __user *)sg[i].addr_bus, sg_size)) { printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",c->name,i); rcode = -EFAULT; goto cleanup; } } //TODO 64bit fix sg[i].addr_bus = (u32)virt_to_bus(p); } } rcode = i2o_post_wait(c, msg, size, 60); 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, MSG_FRAME_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 (msg, 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 __user *)sg[j].addr_bus,sg_list[j], sg_size)) { printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",c->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",c->name); rcode = -EFAULT; } if(copy_to_user(user_reply, reply, reply_size)) { printk(KERN_WARNING"%s: Could not copy reply TO user\n",c->name); rcode = -EFAULT; } }cleanup: kfree(reply); i2o_unlock_controller(c); return rcode;}static int cfg_open(struct inode *inode, struct file *file){ struct i2o_cfg_info *tmp = (struct i2o_cfg_info *)kmalloc(sizeof(struct i2o_cfg_info), GFP_KERNEL); unsigned long flags; if(!tmp) return -ENOMEM; file->private_data = (void*)(i2o_cfg_info_id++); tmp->fp = file; tmp->fasync = NULL; tmp->q_id = (u32)file->private_data; tmp->q_len = 0; tmp->q_in = 0; tmp->q_out = 0; tmp->q_lost = 0; tmp->next = open_files; spin_lock_irqsave(&i2o_config_lock, flags); open_files = tmp; spin_unlock_irqrestore(&i2o_config_lock, flags); return 0;}static int cfg_release(struct inode *inode, struct file *file){ u32 id = (u32)file->private_data; struct i2o_cfg_info *p1, *p2; unsigned long flags; lock_kernel(); p1 = p2 = NULL; spin_lock_irqsave(&i2o_config_lock, flags); for(p1 = open_files; p1; ) { if(p1->q_id == id) { if(p1->fasync) cfg_fasync(-1, file, 0); if(p2) p2->next = p1->next; else open_files = p1->next; kfree(p1); break; } p2 = p1; p1 = p1->next; } spin_unlock_irqrestore(&i2o_config_lock, flags); unlock_kernel(); return 0;}static int cfg_fasync(int fd, struct file *fp, int on){ u32 id = (u32)fp->private_data; struct i2o_cfg_info *p; for(p = open_files; p; p = p->next) if(p->q_id == id) break; if(!p) return -EBADF; return fasync_helper(fd, fp, on, &p->fasync);}static struct file_operations config_fops ={ .owner = THIS_MODULE, .llseek = no_llseek, .read = cfg_read, .write = cfg_write, .ioctl = cfg_ioctl, .open = cfg_open, .release = cfg_release, .fasync = cfg_fasync,};static struct miscdevice i2o_miscdev = { I2O_MINOR, "i2octl", &config_fops}; static int __init i2o_config_init(void){ printk(KERN_INFO "I2O configuration manager v 0.04.\n"); printk(KERN_INFO " (C) Copyright 1999 Red Hat Software\n"); if((page_buf = kmalloc(4096, GFP_KERNEL))==NULL) { printk(KERN_ERR "i2o_config: no memory for page buffer.\n"); return -ENOBUFS; } if(misc_register(&i2o_miscdev) < 0) { printk(KERN_ERR "i2o_config: can't register device.\n"); kfree(page_buf); return -EBUSY; } /* * Install our handler */ if(i2o_install_handler(&cfg_handler)<0) { kfree(page_buf); printk(KERN_ERR "i2o_config: handler register failed.\n"); misc_deregister(&i2o_miscdev); return -EBUSY; } /* * The low 16bits of the transaction context must match this * for everything we post. Otherwise someone else gets our mail */ i2o_cfg_context = cfg_handler.context; return 0;}static void i2o_config_exit(void){ misc_deregister(&i2o_miscdev); if(page_buf) kfree(page_buf); if(i2o_cfg_context != -1) i2o_remove_handler(&cfg_handler);} MODULE_AUTHOR("Red Hat Software");MODULE_DESCRIPTION("I2O Configuration");MODULE_LICENSE("GPL");module_init(i2o_config_init);module_exit(i2o_config_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?