⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2o_config.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * I2O Configuration Interface Driver * * (C) Copyright 1999-2002  Red Hat * * Written by Alan Cox, Building Number Three Ltd * * Fixes/additions: *	Deepak Saxena (04/20/1999): *		Added basic ioctl() support *	Deepak Saxena (06/07/1999): *		Added software download ioctl (still testing) *	Auvo H鋕kinen (09/10/1999): *		Changes to i2o_cfg_reply(), ioctl_parms() *		Added ioct_validate() *	Taneli V鋒鋕angas (09/30/1999): *		Fixed ioctl_swdl() *	Taneli V鋒鋕angas (10/04/1999): *		Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel() *	Deepak Saxena (11/18/1999): *		Added event managmenet support *	Alan Cox <alan@redhat.com>: *		2.4 rewrite ported to 2.5 *	Markus Lidel <Markus.Lidel@shadowconnect.com>: *		Added pass-thru support for Adaptec's raidutils * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/miscdevice.h>#include <linux/smp_lock.h>#include <linux/compat.h>#include <asm/uaccess.h>#include "core.h"#define SG_TABLESIZE		30static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,			 unsigned long arg);static spinlock_t i2o_config_lock;#define MODINC(x,y) ((x) = ((x) + 1) % (y))struct sg_simple_element {	u32 flag_count;	u32 addr_bus;};struct i2o_cfg_info {	struct file *fp;	struct fasync_struct *fasync;	struct i2o_evt_info event_q[I2O_EVT_Q_LEN];	u16 q_in;		// Queue head index	u16 q_out;		// Queue tail index	u16 q_len;		// Queue length	u16 q_lost;		// Number of lost events	ulong q_id;		// Event queue ID...used as tx_context	struct i2o_cfg_info *next;};static struct i2o_cfg_info *open_files = NULL;static ulong i2o_cfg_info_id = 0;static int i2o_cfg_getiops(unsigned long arg){	struct i2o_controller *c;	u8 __user *user_iop_table = (void __user *)arg;	u8 tmp[MAX_I2O_CONTROLLERS];	int ret = 0;	memset(tmp, 0, MAX_I2O_CONTROLLERS);	list_for_each_entry(c, &i2o_controllers, list)	    tmp[c->unit] = 1;	if (copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS))		ret = -EFAULT;	return ret;};static int i2o_cfg_gethrt(unsigned long arg){	struct i2o_controller *c;	struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg;	struct i2o_cmd_hrtlct kcmd;	i2o_hrt *hrt;	int len;	u32 reslen;	int ret = 0;	if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))		return -EFAULT;	if (get_user(reslen, kcmd.reslen) < 0)		return -EFAULT;	if (kcmd.resbuf == NULL)		return -EFAULT;	c = i2o_find_iop(kcmd.iop);	if (!c)		return -ENXIO;	hrt = (i2o_hrt *) c->hrt.virt;	len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);	/* We did a get user...so assuming mem is ok...is this bad? */	put_user(len, kcmd.reslen);	if (len > reslen)		ret = -ENOBUFS;	if (copy_to_user(kcmd.resbuf, (void *)hrt, len))		ret = -EFAULT;	return ret;};static int i2o_cfg_getlct(unsigned long arg){	struct i2o_controller *c;	struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg;	struct i2o_cmd_hrtlct kcmd;	i2o_lct *lct;	int len;	int ret = 0;	u32 reslen;	if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))		return -EFAULT;	if (get_user(reslen, kcmd.reslen) < 0)		return -EFAULT;	if (kcmd.resbuf == NULL)		return -EFAULT;	c = i2o_find_iop(kcmd.iop);	if (!c)		return -ENXIO;	lct = (i2o_lct *) c->lct;	len = (unsigned int)lct->table_size << 2;	put_user(len, kcmd.reslen);	if (len > reslen)		ret = -ENOBUFS;	else if (copy_to_user(kcmd.resbuf, lct, len))		ret = -EFAULT;	return ret;};static int i2o_cfg_parms(unsigned long arg, unsigned int type){	int ret = 0;	struct i2o_controller *c;	struct i2o_device *dev;	struct i2o_cmd_psetget __user *cmd =	    (struct i2o_cmd_psetget __user *)arg;	struct i2o_cmd_psetget kcmd;	u32 reslen;	u8 *ops;	u8 *res;	int len = 0;	u32 i2o_cmd = (type == I2OPARMGET ?		       I2O_CMD_UTIL_PARAMS_GET : I2O_CMD_UTIL_PARAMS_SET);	if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget)))		return -EFAULT;	if (get_user(reslen, kcmd.reslen))		return -EFAULT;	c = i2o_find_iop(kcmd.iop);	if (!c)		return -ENXIO;	dev = i2o_iop_find_device(c, kcmd.tid);	if (!dev)		return -ENXIO;	ops = (u8 *) kmalloc(kcmd.oplen, GFP_KERNEL);	if (!ops)		return -ENOMEM;	if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) {		kfree(ops);		return -EFAULT;	}	/*	 * It's possible to have a _very_ large table	 * and that the user asks for all of it at once...	 */	res = (u8 *) kmalloc(65536, GFP_KERNEL);	if (!res) {		kfree(ops);		return -ENOMEM;	}	len = i2o_parm_issue(dev, i2o_cmd, ops, kcmd.oplen, res, 65536);	kfree(ops);	if (len < 0) {		kfree(res);		return -EAGAIN;	}	put_user(len, kcmd.reslen);	if (len > reslen)		ret = -ENOBUFS;	else if (copy_to_user(kcmd.resbuf, res, len))		ret = -EFAULT;	kfree(res);	return ret;};static int i2o_cfg_swdl(unsigned long arg){	struct i2o_sw_xfer kxfer;	struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;	unsigned char maxfrag = 0, curfrag = 1;	struct i2o_dma buffer;	struct i2o_message __iomem *msg;	u32 m;	unsigned int status = 0, swlen = 0, fragsize = 8192;	struct i2o_controller *c;	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_iop(kxfer.iop);	if (!c)		return -ENXIO;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -EBUSY;	if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {		i2o_msg_nop(c, m);		return -ENOMEM;	}	__copy_from_user(buffer.virt, kxfer.buf, fragsize);	writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);	writel(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 | ADAPTER_TID,	       &msg->u.head[1]);	writel(i2o_config_driver.context, &msg->u.head[2]);	writel(0, &msg->u.head[3]);	writel((((u32) kxfer.flags) << 24) | (((u32) kxfer.sw_type) << 16) |	       (((u32) maxfrag) << 8) | (((u32) curfrag)), &msg->body[0]);	writel(swlen, &msg->body[1]);	writel(kxfer.sw_id, &msg->body[2]);	writel(0xD0000000 | fragsize, &msg->body[3]);	writel(buffer.phys, &msg->body[4]);	osm_debug("swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);	status = i2o_msg_post_wait_mem(c, m, 60, &buffer);	if (status != -ETIMEDOUT)		i2o_dma_free(&c->pdev->dev, &buffer);	if (status != I2O_POST_WAIT_OK) {		// it fails if you try and send frags out of order		// and for some yet unknown reasons too		osm_info("swdl failed, DetailedStatus = %d\n", status);		return status;	}	return 0;};static int i2o_cfg_swul(unsigned long arg){	struct i2o_sw_xfer kxfer;	struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;	unsigned char maxfrag = 0, curfrag = 1;	struct i2o_dma buffer;	struct i2o_message __iomem *msg;	u32 m;	unsigned int status = 0, swlen = 0, fragsize = 8192;	struct i2o_controller *c;	int ret = 0;	if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))		goto return_fault;	if (get_user(swlen, kxfer.swlen) < 0)		goto return_fault;	if (get_user(maxfrag, kxfer.maxfrag) < 0)		goto return_fault;	if (get_user(curfrag, kxfer.curfrag) < 0)		goto return_fault;	if (curfrag == maxfrag)		fragsize = swlen - (maxfrag - 1) * 8192;	if (!kxfer.buf)		goto return_fault;	c = i2o_find_iop(kxfer.iop);	if (!c)		return -ENXIO;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -EBUSY;	if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {		i2o_msg_nop(c, m);		return -ENOMEM;	}	writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);	writel(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID,	       &msg->u.head[1]);	writel(i2o_config_driver.context, &msg->u.head[2]);	writel(0, &msg->u.head[3]);	writel((u32) kxfer.flags << 24 | (u32) kxfer.	       sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag,	       &msg->body[0]);	writel(swlen, &msg->body[1]);	writel(kxfer.sw_id, &msg->body[2]);	writel(0xD0000000 | fragsize, &msg->body[3]);	writel(buffer.phys, &msg->body[4]);	osm_debug("swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);	status = i2o_msg_post_wait_mem(c, m, 60, &buffer);	if (status != I2O_POST_WAIT_OK) {		if (status != -ETIMEDOUT)			i2o_dma_free(&c->pdev->dev, &buffer);		osm_info("swul failed, DetailedStatus = %d\n", status);		return status;	}	if (copy_to_user(kxfer.buf, buffer.virt, fragsize))		ret = -EFAULT;	i2o_dma_free(&c->pdev->dev, &buffer);      return_ret:	return ret;      return_fault:	ret = -EFAULT;	goto return_ret;};static int i2o_cfg_swdel(unsigned long arg){	struct i2o_controller *c;	struct i2o_sw_xfer kxfer;	struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;	struct i2o_message __iomem *msg;	u32 m;	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_iop(kxfer.iop);	if (!c)		return -ENXIO;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -EBUSY;	writel(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);	writel(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID,	       &msg->u.head[1]);	writel(i2o_config_driver.context, &msg->u.head[2]);	writel(0, &msg->u.head[3]);	writel((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16,	       &msg->body[0]);	writel(swlen, &msg->body[1]);	writel(kxfer.sw_id, &msg->body[2]);	token = i2o_msg_post_wait(c, m, 10);	if (token != I2O_POST_WAIT_OK) {		osm_info("swdel failed, DetailedStatus = %d\n", token);		return -ETIMEDOUT;	}	return 0;};static int i2o_cfg_validate(unsigned long arg){	int token;	int iop = (int)arg;	struct i2o_message __iomem *msg;	u32 m;	struct i2o_controller *c;	c = i2o_find_iop(iop);	if (!c)		return -ENXIO;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -EBUSY;	writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);	writel(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop,	       &msg->u.head[1]);	writel(i2o_config_driver.context, &msg->u.head[2]);	writel(0, &msg->u.head[3]);	token = i2o_msg_post_wait(c, m, 10);	if (token != I2O_POST_WAIT_OK) {		osm_info("Can't validate configuration, ErrorStatus = %d\n",			 token);		return -ETIMEDOUT;	}	return 0;};static int i2o_cfg_evt_reg(unsigned long arg, struct file *fp){	struct i2o_message __iomem *msg;	u32 m;	struct i2o_evt_id __user *pdesc = (struct i2o_evt_id __user *)arg;	struct i2o_evt_id kdesc;	struct i2o_controller *c;	struct i2o_device *d;	if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))		return -EFAULT;	/* IOP exists? */	c = i2o_find_iop(kdesc.iop);	if (!c)		return -ENXIO;	/* Device exists? */	d = i2o_iop_find_device(c, kdesc.tid);	if (!d)		return -ENODEV;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -EBUSY;	writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);	writel(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | kdesc.tid,	       &msg->u.head[1]);	writel(i2o_config_driver.context, &msg->u.head[2]);	writel(i2o_cntxt_list_add(c, fp->private_data), &msg->u.head[3]);	writel(kdesc.evt_mask, &msg->body[0]);	i2o_msg_post(c, m);	return 0;}static int i2o_cfg_evt_get(unsigned long arg, struct file *fp){	struct i2o_cfg_info *p = NULL;	struct i2o_evt_get __user *uget = (struct i2o_evt_get __user *)arg;	struct i2o_evt_get kget;	unsigned long flags;	for (p = open_files; p; p = p->next)		if (p->q_id == (ulong) fp->private_data)			break;	if (!p->q_len)		return -ENOENT;	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;}#ifdef CONFIG_I2O_EXT_ADAPTEC#ifdef CONFIG_COMPATstatic int i2o_cfg_passthru32(struct file *file, unsigned cmnd,			      unsigned long arg){	struct i2o_cmd_passthru32 __user *cmd;	struct i2o_controller *c;	u32 __user *user_msg;	u32 *reply = NULL;	u32 __user *user_reply = NULL;	u32 size = 0;	u32 reply_size = 0;	u32 rcode = 0;	struct i2o_dma sg_list[SG_TABLESIZE];	u32 sg_offset = 0;	u32 sg_count = 0;	u32 i = 0;	u32 sg_index = 0;	i2o_status_block *sb;	struct i2o_message *msg;	u32 m;	unsigned int iop;	cmd = (struct i2o_cmd_passthru32 __user *)arg;	if (get_user(iop, &cmd->iop) || get_user(i, &cmd->msg))		return -EFAULT;	user_msg = compat_ptr(i);	c = i2o_find_iop(iop);	if (!c) {		osm_debug("controller %d not found\n", iop);		return -ENXIO;	}	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	sb = c->status_block.virt;	if (get_user(size, &user_msg[0])) {		osm_warn("unable to get size!\n");		return -EFAULT;	}	size = size >> 16;	if (size > sb->inbound_frame_size) {		osm_warn("size of message > inbound_frame_size");		return -EFAULT;	}	user_reply = &user_msg[size];	size <<= 2;		// Convert to bytes	/* Copy in the user's I2O command */	if (copy_from_user(msg, user_msg, size)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -