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