[go: nahoru, domu]

11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I2O Configuration Interface Driver
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 1999-2002  Red Hat
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written by Alan Cox, Building Number Three Ltd
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixes/additions:
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Deepak Saxena (04/20/1999):
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Added basic ioctl() support
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Deepak Saxena (06/07/1999):
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Added software download ioctl (still testing)
1396de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt *	Auvo Häkkinen (09/10/1999):
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Changes to i2o_cfg_reply(), ioctl_parms()
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Added ioct_validate()
1696de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt *	Taneli Vähäkangas (09/30/1999):
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Fixed ioctl_swdl()
1896de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt *	Taneli Vähäkangas (10/04/1999):
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Deepak Saxena (11/18/1999):
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Added event managmenet support
22f1b11e505463fd597ab7963df26dd1f446dcceaeAlan Cox *	Alan Cox <alan@lxorguk.ukuu.org.uk>:
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		2.4 rewrite ported to 2.5
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Markus Lidel <Markus.Lidel@shadowconnect.com>:
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Added pass-thru support for Adaptec's raidutils
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/miscdevice.h>
34c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann#include <linux/mutex.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/compat.h>
365a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
40e62c23c751b5136ed52ac324ecf78a814e2d2fe3Adrian Bunk#include "core.h"
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42e62c23c751b5136ed52ac324ecf78a814e2d2fe3Adrian Bunk#define SG_TABLESIZE		30
43dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel
44c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmannstatic DEFINE_MUTEX(i2o_cfg_mutex);
455d9d6e44ce15d072d22c10fe670679c77fa2b31dAlan Coxstatic long i2o_cfg_ioctl(struct file *, unsigned int, unsigned long);
46f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic spinlock_t i2o_config_lock;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MODINC(x,y) ((x) = ((x) + 1) % (y))
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sg_simple_element {
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 flag_count;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 addr_bus;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct i2o_cfg_info {
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct file *fp;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fasync_struct *fasync;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_evt_info event_q[I2O_EVT_Q_LEN];
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 q_in;		// Queue head index
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 q_out;		// Queue tail index
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 q_len;		// Queue length
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 q_lost;		// Number of lost events
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong q_id;		// Event queue ID...used as tx_context
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cfg_info *next;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2o_cfg_info *open_files = NULL;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ulong i2o_cfg_info_id = 0;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_getiops(unsigned long arg)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 __user *user_iop_table = (void __user *)arg;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 tmp[MAX_I2O_CONTROLLERS];
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(tmp, 0, MAX_I2O_CONTROLLERS);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_entry(c, &i2o_controllers, list)
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    tmp[c->unit] = 1;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS))
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EFAULT;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_gethrt(unsigned long arg)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_hrtlct kcmd;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_hrt *hrt;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 reslen;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(reslen, kcmd.reslen) < 0)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kcmd.resbuf == NULL)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(kcmd.iop);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hrt = (i2o_hrt *) c->hrt.virt;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11589596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy	if (put_user(len, kcmd.reslen))
11689596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy		ret = -EFAULT;
11789596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy	else if (len > reslen)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOBUFS;
119d929dc2bfd8a58c34f1df0680018fa8ea5caa907Kulikov Vasiliy	else if (copy_to_user(kcmd.resbuf, (void *)hrt, len))
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EFAULT;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_getlct(unsigned long arg)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_hrtlct kcmd;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_lct *lct;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 reslen;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(reslen, kcmd.reslen) < 0)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (kcmd.resbuf == NULL)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(kcmd.iop);
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lct = (i2o_lct *) c->lct;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = (unsigned int)lct->table_size << 2;
15189596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy	if (put_user(len, kcmd.reslen))
15289596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy		ret = -EFAULT;
15389596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy	else if (len > reslen)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOBUFS;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (copy_to_user(kcmd.resbuf, lct, len))
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EFAULT;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_parms(unsigned long arg, unsigned int type)
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *dev;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_psetget __user *cmd =
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (struct i2o_cmd_psetget __user *)arg;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_psetget kcmd;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 reslen;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *ops;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *res;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int len = 0;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 i2o_cmd = (type == I2OPARMGET ?
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       I2O_CMD_UTIL_PARAMS_GET : I2O_CMD_UTIL_PARAMS_SET);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget)))
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(reslen, kcmd.reslen))
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(kcmd.iop);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev = i2o_iop_find_device(c, kcmd.tid);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191261eba73353edd48b0c0cb7aad59553dfc712ebcAlan Cox	/*
1928fdbb340ef0683437e791360d63726d5725add66Masanari Iida	 * Stop users being able to try and allocate arbitrary amounts
193261eba73353edd48b0c0cb7aad59553dfc712ebcAlan Cox	 * of DMA space. 64K is way more than sufficient for this.
194261eba73353edd48b0c0cb7aad59553dfc712ebcAlan Cox	 */
195261eba73353edd48b0c0cb7aad59553dfc712ebcAlan Cox	if (kcmd.oplen > 65536)
196261eba73353edd48b0c0cb7aad59553dfc712ebcAlan Cox		return -EMSGSIZE;
197261eba73353edd48b0c0cb7aad59553dfc712ebcAlan Cox
198b81d67a50c0f3021d170466388bec3e7fc3abe75Julia Lawall	ops = memdup_user(kcmd.opbuf, kcmd.oplen);
199b81d67a50c0f3021d170466388bec3e7fc3abe75Julia Lawall	if (IS_ERR(ops))
200b81d67a50c0f3021d170466388bec3e7fc3abe75Julia Lawall		return PTR_ERR(ops);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * It's possible to have a _very_ large table
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and that the user asks for all of it at once...
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2065cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	res = kmalloc(65536, GFP_KERNEL);
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!res) {
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(ops);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = i2o_parm_issue(dev, i2o_cmd, ops, kcmd.oplen, res, 65536);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(ops);
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (len < 0) {
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(res);
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EAGAIN;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22089596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy	if (put_user(len, kcmd.reslen))
22189596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy		ret = -EFAULT;
22289596f20bb5f0f32c37abd337d995080e04519c8Kulikov Vasiliy	else if (len > reslen)
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOBUFS;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (copy_to_user(kcmd.resbuf, res, len))
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EFAULT;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(res);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_swdl(unsigned long arg)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_sw_xfer kxfer;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char maxfrag = 0, curfrag = 1;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_dma buffer;
238a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status = 0, swlen = 0, fragsize = 8192;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(swlen, kxfer.swlen) < 0)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(maxfrag, kxfer.maxfrag) < 0)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(curfrag, kxfer.curfrag) < 0)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (curfrag == maxfrag)
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fragsize = swlen - (maxfrag - 1) * 8192;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize))
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(kxfer.iop);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
264a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
265a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	if (IS_ERR(msg))
266a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		return PTR_ERR(msg);
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2689d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox	if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
269a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		i2o_msg_nop(c, msg);
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2739d69b7d3d115d0db3ddd87f09e496db7ecf72650Randy Dunlap	if (__copy_from_user(buffer.virt, kxfer.buf, fragsize)) {
2749d69b7d3d115d0db3ddd87f09e496db7ecf72650Randy Dunlap		i2o_msg_nop(c, msg);
2759d69b7d3d115d0db3ddd87f09e496db7ecf72650Randy Dunlap		i2o_dma_free(&c->pdev->dev, &buffer);
2769d69b7d3d115d0db3ddd87f09e496db7ecf72650Randy Dunlap		return -EFAULT;
2779d69b7d3d115d0db3ddd87f09e496db7ecf72650Randy Dunlap	}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
279a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_7);
280a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[1] =
281a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 |
282a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel			ADAPTER_TID);
283a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
284a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[3] = cpu_to_le32(0);
285a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[0] =
286a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32((((u32) kxfer.flags) << 24) | (((u32) kxfer.
287a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel							sw_type) << 16) |
288a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel			(((u32) maxfrag) << 8) | (((u32) curfrag)));
289a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[1] = cpu_to_le32(swlen);
290a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[2] = cpu_to_le32(kxfer.sw_id);
291a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[3] = cpu_to_le32(0xD0000000 | fragsize);
292a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[4] = cpu_to_le32(buffer.phys);
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	osm_debug("swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
295a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	status = i2o_msg_post_wait_mem(c, msg, 60, &buffer);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status != -ETIMEDOUT)
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i2o_dma_free(&c->pdev->dev, &buffer);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status != I2O_POST_WAIT_OK) {
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// it fails if you try and send frags out of order
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// and for some yet unknown reasons too
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_info("swdl failed, DetailedStatus = %d\n", status);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return status;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_swul(unsigned long arg)
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_sw_xfer kxfer;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char maxfrag = 0, curfrag = 1;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_dma buffer;
316a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status = 0, swlen = 0, fragsize = 8192;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = 0;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
322b1ffdc8f3d8c8913388ca97dfdf064c87940dd72Dan Carpenter		return -EFAULT;
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(swlen, kxfer.swlen) < 0)
325b1ffdc8f3d8c8913388ca97dfdf064c87940dd72Dan Carpenter		return -EFAULT;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(maxfrag, kxfer.maxfrag) < 0)
328b1ffdc8f3d8c8913388ca97dfdf064c87940dd72Dan Carpenter		return -EFAULT;
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(curfrag, kxfer.curfrag) < 0)
331b1ffdc8f3d8c8913388ca97dfdf064c87940dd72Dan Carpenter		return -EFAULT;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (curfrag == maxfrag)
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fragsize = swlen - (maxfrag - 1) * 8192;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!kxfer.buf)
337b1ffdc8f3d8c8913388ca97dfdf064c87940dd72Dan Carpenter		return -EFAULT;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(kxfer.iop);
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
343a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
344a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	if (IS_ERR(msg))
345a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		return PTR_ERR(msg);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3479d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox	if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
348a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		i2o_msg_nop(c, msg);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
352a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_7);
353a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[1] =
354a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID);
355a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
356a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[3] = cpu_to_le32(0);
357a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[0] =
358a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32((u32) kxfer.flags << 24 | (u32) kxfer.
359a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel			sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag);
360a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[1] = cpu_to_le32(swlen);
361a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[2] = cpu_to_le32(kxfer.sw_id);
362a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[3] = cpu_to_le32(0xD0000000 | fragsize);
363a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[4] = cpu_to_le32(buffer.phys);
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	osm_debug("swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
366a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	status = i2o_msg_post_wait_mem(c, msg, 60, &buffer);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status != I2O_POST_WAIT_OK) {
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status != -ETIMEDOUT)
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			i2o_dma_free(&c->pdev->dev, &buffer);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_info("swul failed, DetailedStatus = %d\n", status);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return status;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(kxfer.buf, buffer.virt, fragsize))
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EFAULT;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_dma_free(&c->pdev->dev, &buffer);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
382b1ffdc8f3d8c8913388ca97dfdf064c87940dd72Dan Carpenter}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_swdel(unsigned long arg)
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_sw_xfer kxfer;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;
389a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int swlen;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int token;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(swlen, kxfer.swlen) < 0)
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(kxfer.iop);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
403a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
404a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	if (IS_ERR(msg))
405a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		return PTR_ERR(msg);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
407a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[0] = cpu_to_le32(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0);
408a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[1] =
409a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID);
410a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
411a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[3] = cpu_to_le32(0);
412a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[0] =
413a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16);
414a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[1] = cpu_to_le32(swlen);
415a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[2] = cpu_to_le32(kxfer.sw_id);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
417a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	token = i2o_msg_post_wait(c, msg, 10);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (token != I2O_POST_WAIT_OK) {
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_info("swdel failed, DetailedStatus = %d\n", token);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ETIMEDOUT;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_validate(unsigned long arg)
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int token;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int iop = (int)arg;
431a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(iop);
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
438a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
439a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	if (IS_ERR(msg))
440a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		return PTR_ERR(msg);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
442a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
443a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[1] =
444a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop);
445a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
446a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[3] = cpu_to_le32(0);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
448a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	token = i2o_msg_post_wait(c, msg, 10);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (token != I2O_POST_WAIT_OK) {
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_info("Can't validate configuration, ErrorStatus = %d\n",
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 token);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ETIMEDOUT;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_evt_reg(unsigned long arg, struct file *fp)
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
461a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_evt_id __user *pdesc = (struct i2o_evt_id __user *)arg;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_evt_id kdesc;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_device *d;
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* IOP exists? */
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(kdesc.iop);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c)
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Device exists? */
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d = i2o_iop_find_device(c, kdesc.tid);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!d)
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
480a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
481a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	if (IS_ERR(msg))
482a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel		return PTR_ERR(msg);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
484a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
485a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[1] =
486a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	    cpu_to_le32(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 |
487a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel			kdesc.tid);
488a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);
489a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->u.head[3] = cpu_to_le32(i2o_cntxt_list_add(c, fp->private_data));
490a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	msg->body[0] = cpu_to_le32(kdesc.evt_mask);
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
492a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	i2o_msg_post(c, msg);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_evt_get(unsigned long arg, struct file *fp)
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cfg_info *p = NULL;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_evt_get __user *uget = (struct i2o_evt_get __user *)arg;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_evt_get kget;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = open_files; p; p = p->next)
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (p->q_id == (ulong) fp->private_data)
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!p->q_len)
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info));
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	MODINC(p->q_out, I2O_EVT_Q_LEN);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&i2o_config_lock, flags);
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	p->q_len--;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kget.pending = p->q_len;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kget.lost = p->q_lost;
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&i2o_config_lock, flags);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)))
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_COMPAT
525f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidelstatic int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
526f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel			      unsigned long arg)
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_passthru32 __user *cmd;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 __user *user_msg;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 *reply = NULL;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 __user *user_reply = NULL;
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 size = 0;
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 reply_size = 0;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rcode = 0;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_dma sg_list[SG_TABLESIZE];
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sg_offset = 0;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sg_count = 0;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 i = 0;
54061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel	u32 sg_index = 0;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_status_block *sb;
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_message *msg;
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int iop;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cmd = (struct i2o_cmd_passthru32 __user *)arg;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(iop, &cmd->iop) || get_user(i, &cmd->msg))
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	user_msg = compat_ptr(i);
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(iop);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c) {
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_debug("controller %d not found\n", iop);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sb = c->status_block.virt;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(size, &user_msg[0])) {
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("unable to get size!\n");
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = size >> 16;
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size > sb->inbound_frame_size) {
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("size of message > inbound_frame_size");
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	user_reply = &user_msg[size];
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size <<= 2;		// Convert to bytes
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5751725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
5761725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	if (IS_ERR(msg))
5771725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		return PTR_ERR(msg);
5781725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin
5791725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	rcode = -EFAULT;
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy in the user's I2O command */
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(msg, user_msg, size)) {
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("unable to copy user message\n");
5831725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		goto out;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_dump_message(msg);
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(reply_size, &user_reply[0]) < 0)
5881725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		goto out;
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reply_size >>= 16;
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reply_size <<= 2;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	rcode = -ENOMEM;
594f6ed39a6e1a88240eec629a3da17c3a47ada3b89Markus Lidel	reply = kzalloc(reply_size, GFP_KERNEL);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!reply) {
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: Could not allocate reply buffer\n",
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       c->name);
5981725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		goto out;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sg_offset = (msg->u.head[0] >> 4) & 0x0f;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_offset) {
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sg_simple_element *sg;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sg_offset * 4 >= size) {
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO 64bit fix
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sg = (struct sg_simple_element *)((&msg->u.head[0]) +
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  sg_offset);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sg_count =
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sg_count > SG_TABLESIZE) {
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       c->name, sg_count);
61961fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			rcode = -EINVAL;
62061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			goto cleanup;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < sg_count; i++) {
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int sg_size;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct i2o_dma *p;
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(sg[i].flag_count & 0x10000000
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) {
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_DEBUG
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "%s:Bad SG element %d - not simple (%x)\n",
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       c->name, i, sg[i].flag_count);
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rcode = -EINVAL;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto cleanup;
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sg_size = sg[i].flag_count & 0xffffff;
636dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel			p = &(sg_list[sg_index]);
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Allocate memory for the transfer */
6389d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox			if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_DEBUG
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       c->name, sg_size, i, sg_count);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rcode = -ENOMEM;
64361fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel				goto sg_list_cleanup;
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
645dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel			sg_index++;
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Copy in the user's SG buffer if necessary */
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (sg[i].
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// TODO 64bit fix
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (copy_from_user
651f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel				    (p->virt,
652f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel				     (void __user *)(unsigned long)sg[i].
653f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel				     addr_bus, sg_size)) {
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_DEBUG
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "%s: Could not copy SG buf %d FROM user\n",
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       c->name, i);
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rcode = -EFAULT;
65861fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel					goto sg_list_cleanup;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			//TODO 64bit fix
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sg[i].addr_bus = (u32) p->phys;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
666a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	rcode = i2o_msg_post_wait(c, msg, 60);
6671725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	msg = NULL;
668dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel	if (rcode) {
669dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel		reply[4] = ((u32) rcode) << 24;
67061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel		goto sg_list_cleanup;
671dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel	}
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_offset) {
6741725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Copy back the Scatter Gather buffers back to user space */
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 j;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO 64bit fix
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sg_simple_element *sg;
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int sg_size;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// re-acquire the original message to handle correctly the sg copy operation
6821725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// get user msg size in u32s
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (get_user(size, &user_msg[0])) {
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
68661fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			goto sg_list_cleanup;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = size >> 16;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size *= 4;
6909151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter		if (size > sizeof(rmsg)) {
6919151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter			rcode = -EINVAL;
6929151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter			goto sg_list_cleanup;
6939151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter		}
6949151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Copy in the user's I2O command */
6961725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		if (copy_from_user(rmsg, user_msg, size)) {
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
69861fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			goto sg_list_cleanup;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sg_count =
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO 64bit fix
7041725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		sg = (struct sg_simple_element *)(rmsg + sg_offset);
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < sg_count; j++) {
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Copy out the SG list to user's buffer if necessary */
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (sg[j].
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) {
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sg_size = sg[j].flag_count & 0xffffff;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// TODO 64bit fix
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (copy_to_user
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				    ((void __user *)(u64) sg[j].addr_bus,
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     sg_list[j].virt, sg_size)) {
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_WARNING
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "%s: Could not copy %p TO user %x\n",
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       c->name, sg_list[j].virt,
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       sg[j].addr_bus);
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rcode = -EFAULT;
72061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel					goto sg_list_cleanup;
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7261725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averinsg_list_cleanup:
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy back the reply to user space */
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reply_size) {
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// we wrote our own values for context - now restore the user supplied ones
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) {
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s: Could not copy message context FROM user\n",
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       c->name);
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(user_reply, reply, reply_size)) {
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s: Could not copy reply TO user\n", c->name);
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
74261fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel	for (i = 0; i < sg_index; i++)
74361fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel		i2o_dma_free(&c->pdev->dev, &sg_list[i]);
74461fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel
7451725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averincleanup:
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(reply);
7471725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averinout:
7481725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	if (msg)
7491725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		i2o_msg_nop(c, msg);
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rcode;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
753f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidelstatic long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
754f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel				 unsigned long arg)
755f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>{
756f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>	int ret;
757f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel	switch (cmd) {
758f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>	case I2OGETIOPS:
7595d9d6e44ce15d072d22c10fe670679c77fa2b31dAlan Cox		ret = i2o_cfg_ioctl(file, cmd, arg);
760f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>		break;
761f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>	case I2OPASSTHRU32:
762a3eb7fbb41eb8d6e22d491741b8c5d5aa6cb069aAlexey Khoroshilov		mutex_lock(&i2o_cfg_mutex);
763f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>		ret = i2o_cfg_passthru32(file, cmd, arg);
764a3eb7fbb41eb8d6e22d491741b8c5d5aa6cb069aAlexey Khoroshilov		mutex_unlock(&i2o_cfg_mutex);
765f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>		break;
766f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>	default:
767f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>		ret = -ENOIOCTLCMD;
768f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>		break;
769f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>	}
770f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>	return ret;
771f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>}
772f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>
773f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>#endif
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
775f13a603786819cc8f2eef6a89bc4a6c88f40ee60Randy Dunlap#ifdef CONFIG_I2O_EXT_ADAPTEC
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int i2o_cfg_passthru(unsigned long arg)
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cmd_passthru __user *cmd =
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (struct i2o_cmd_passthru __user *)arg;
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_controller *c;
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 __user *user_msg;
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 *reply = NULL;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 __user *user_reply = NULL;
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 size = 0;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 reply_size = 0;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 rcode = 0;
7879d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox	struct i2o_dma sg_list[SG_TABLESIZE];
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sg_offset = 0;
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 sg_count = 0;
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sg_index = 0;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 i = 0;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2o_status_block *sb;
793a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	struct i2o_message *msg;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int iop;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg))
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c = i2o_find_iop(iop);
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!c) {
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("controller %d not found\n", iop);
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sb = c->status_block.virt;
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(size, &user_msg[0]))
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = size >> 16;
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size > sb->inbound_frame_size) {
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_warn("size of message > inbound_frame_size");
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	user_reply = &user_msg[size];
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size <<= 2;		// Convert to bytes
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8201725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
8211725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	if (IS_ERR(msg))
8221725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		return PTR_ERR(msg);
8231725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin
8241725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	rcode = -EFAULT;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy in the user's I2O command */
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_from_user(msg, user_msg, size))
8271725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		goto out;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (get_user(reply_size, &user_reply[0]) < 0)
8301725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		goto out;
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reply_size >>= 16;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	reply_size <<= 2;
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
835f6ed39a6e1a88240eec629a3da17c3a47ada3b89Markus Lidel	reply = kzalloc(reply_size, GFP_KERNEL);
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!reply) {
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_WARNING "%s: Could not allocate reply buffer\n",
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       c->name);
8391725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		rcode = -ENOMEM;
8401725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		goto out;
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sg_offset = (msg->u.head[0] >> 4) & 0x0f;
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_offset) {
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sg_simple_element *sg;
8489d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox		struct i2o_dma *p;
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sg_offset * 4 >= size) {
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto cleanup;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO 64bit fix
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sg = (struct sg_simple_element *)((&msg->u.head[0]) +
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						  sg_offset);
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sg_count =
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sg_count > SG_TABLESIZE) {
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       c->name, sg_count);
86261fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			rcode = -EINVAL;
86361fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			goto cleanup;
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 0; i < sg_count; i++) {
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int sg_size;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(sg[i].flag_count & 0x10000000
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) {
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_DEBUG
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "%s:Bad SG element %d - not simple (%x)\n",
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       c->name, i, sg[i].flag_count);
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rcode = -EINVAL;
87561fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel				goto sg_list_cleanup;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sg_size = sg[i].flag_count & 0xffffff;
8789d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox			p = &(sg_list[sg_index]);
8799d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox			if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Allocate memory for the transfer */
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk(KERN_DEBUG
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       c->name, sg_size, i, sg_count);
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				rcode = -ENOMEM;
88561fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel				goto sg_list_cleanup;
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
8879d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox			sg_index++;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Copy in the user's SG buffer if necessary */
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (sg[i].
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// TODO 64bit fix
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (copy_from_user
8939d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox				    (p->virt, (void __user *)sg[i].addr_bus,
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     sg_size)) {
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_DEBUG
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "%s: Could not copy SG buf %d FROM user\n",
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       c->name, i);
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rcode = -EFAULT;
89961fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel					goto sg_list_cleanup;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9029d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox			sg[i].addr_bus = p->phys;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
906a1a5ea70a6e9db6332b27fe2d96666e17aa1436bMarkus Lidel	rcode = i2o_msg_post_wait(c, msg, 60);
9071725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	msg = NULL;
908dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel	if (rcode) {
909dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel		reply[4] = ((u32) rcode) << 24;
91061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel		goto sg_list_cleanup;
911dcceafe25a5f47cf69e5b46b4da6f15186ec8386Markus Lidel	}
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sg_offset) {
9149d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox		u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Copy back the Scatter Gather buffers back to user space */
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32 j;
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO 64bit fix
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sg_simple_element *sg;
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int sg_size;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// re-acquire the original message to handle correctly the sg copy operation
9221725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// get user msg size in u32s
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (get_user(size, &user_msg[0])) {
9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
92661fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			goto sg_list_cleanup;
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = size >> 16;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size *= 4;
9309151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter		if (size > sizeof(rmsg)) {
9319151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter			rcode = -EFAULT;
9329151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter			goto sg_list_cleanup;
9339151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter		}
9349151b3982dafaa87bca3834c4d20db831ca98bcbDan Carpenter
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Copy in the user's I2O command */
9361725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		if (copy_from_user(rmsg, user_msg, size)) {
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
93861fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel			goto sg_list_cleanup;
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sg_count =
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (size - sg_offset * 4) / sizeof(struct sg_simple_element);
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// TODO 64bit fix
9441725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		sg = (struct sg_simple_element *)(rmsg + sg_offset);
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < sg_count; j++) {
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Copy out the SG list to user's buffer if necessary */
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    (sg[j].
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) {
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				sg_size = sg[j].flag_count & 0xffffff;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				// TODO 64bit fix
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (copy_to_user
9539d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox				    ((void __user *)sg[j].addr_bus, sg_list[j].virt,
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     sg_size)) {
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk(KERN_WARNING
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       "%s: Could not copy %p TO user %x\n",
9579d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox					       c->name, sg_list[j].virt,
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       sg[j].addr_bus);
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					rcode = -EFAULT;
96061fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel					goto sg_list_cleanup;
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9661725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averinsg_list_cleanup:
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy back the reply to user space */
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (reply_size) {
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// we wrote our own values for context - now restore the user supplied ones
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) {
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s: Could not copy message context FROM user\n",
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       c->name);
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(user_reply, reply, reply_size)) {
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       "%s: Could not copy reply TO user\n", c->name);
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			rcode = -EFAULT;
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98361fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel	for (i = 0; i < sg_index; i++)
9849d793b0bcbbbc37d80241862dfa5257963d5415eAlan Cox		i2o_dma_free(&c->pdev->dev, &sg_list[i]);
98561fbfa8129c1771061a0e9f47747854293081c5bMarkus Lidel
9861725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averincleanup:
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(reply);
9881725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averinout:
9891725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin	if (msg)
9901725d71d992f5947bdd5b4f9a30fe8a05571fe66Vasily Averin		i2o_msg_nop(c, msg);
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return rcode;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
993b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IOCTL Handler
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
9985d9d6e44ce15d072d22c10fe670679c77fa2b31dAlan Coxstatic long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1002c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_lock(&i2o_cfg_mutex);
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (cmd) {
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OGETIOPS:
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_getiops(arg);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OHRTGET:
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_gethrt(arg);
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OLCTGET:
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_getlct(arg);
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OPARMSET:
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_parms(arg, I2OPARMSET);
10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OPARMGET:
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_parms(arg, I2OPARMGET);
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OSWDL:
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_swdl(arg);
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OSWUL:
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_swul(arg);
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OSWDEL:
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_swdel(arg);
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OVALIDATE:
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_validate(arg);
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OEVTREG:
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_evt_reg(arg, fp);
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OEVTGET:
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_evt_get(arg, fp);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1048b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#ifdef CONFIG_I2O_EXT_ADAPTEC
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2OPASSTHRU:
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = i2o_cfg_passthru(arg);
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
1052b2aaee33fbb354a2f08121aa1c1be55841102761Markus Lidel#endif
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_debug("unknown ioctl called!\n");
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -EINVAL;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1058c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_unlock(&i2o_cfg_mutex);
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cfg_open(struct inode *inode, struct file *file)
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10641dcb202f42d0483d8d24015d8ded3badc1d11e2eJesper Juhl	struct i2o_cfg_info *tmp = kmalloc(sizeof(struct i2o_cfg_info),
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   GFP_KERNEL);
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!tmp)
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_lock(&i2o_cfg_mutex);
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	file->private_data = (void *)(i2o_cfg_info_id++);
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->fp = file;
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->fasync = NULL;
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->q_id = (ulong) file->private_data;
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->q_len = 0;
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->q_in = 0;
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->q_out = 0;
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->q_lost = 0;
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp->next = open_files;
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&i2o_config_lock, flags);
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	open_files = tmp;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&i2o_config_lock, flags);
1085c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_unlock(&i2o_cfg_mutex);
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cfg_fasync(int fd, struct file *fp, int on)
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong id = (ulong) fp->private_data;
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct i2o_cfg_info *p;
1094743115ee05f09f356d86763316acf627a7f5a6b3Jonathan Corbet	int ret = -EBADF;
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1096c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_lock(&i2o_cfg_mutex);
10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (p = open_files; p; p = p->next)
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (p->q_id == id)
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101743115ee05f09f356d86763316acf627a7f5a6b3Jonathan Corbet	if (p)
1102743115ee05f09f356d86763316acf627a7f5a6b3Jonathan Corbet		ret = fasync_helper(fd, fp, on, &p->fasync);
1103c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_unlock(&i2o_cfg_mutex);
1104743115ee05f09f356d86763316acf627a7f5a6b3Jonathan Corbet	return ret;
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cfg_release(struct inode *inode, struct file *file)
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong id = (ulong) file->private_data;
1110233e70f4228e78eb2f80dc6650f65d3ae3dbf17cAl Viro	struct i2o_cfg_info *p, **q;
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1113c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_lock(&i2o_cfg_mutex);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&i2o_config_lock, flags);
1115233e70f4228e78eb2f80dc6650f65d3ae3dbf17cAl Viro	for (q = &open_files; (p = *q) != NULL; q = &p->next) {
1116233e70f4228e78eb2f80dc6650f65d3ae3dbf17cAl Viro		if (p->q_id == id) {
1117233e70f4228e78eb2f80dc6650f65d3ae3dbf17cAl Viro			*q = p->next;
1118233e70f4228e78eb2f80dc6650f65d3ae3dbf17cAl Viro			kfree(p);
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&i2o_config_lock, flags);
1123c45d15d24eb2b49bf734e1e5e7e103befb76b19bArnd Bergmann	mutex_unlock(&i2o_cfg_mutex);
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1128d54b1fdb1d9f82e375a299e22bd366aad52d4c34Arjan van de Venstatic const struct file_operations config_fops = {
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.llseek = no_llseek,
11315d9d6e44ce15d072d22c10fe670679c77fa2b31dAlan Cox	.unlocked_ioctl = i2o_cfg_ioctl,
1132f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>#ifdef CONFIG_COMPAT
1133f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>	.compat_ioctl = i2o_cfg_compat_ioctl,
1134f4c2c15b930b23edaa633b09fe3f4c01b4ecce9f<jejb@titanic.il.steeleye.com>#endif
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.open = cfg_open,
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release = cfg_release,
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fasync = cfg_fasync,
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct miscdevice i2o_miscdev = {
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	I2O_MINOR,
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"i2octl",
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	&config_fops
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1146f10378fff658f61307496e0ae00095041725cf07Markus Lidelstatic int __init i2o_config_old_init(void)
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_init(&i2o_config_lock);
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (misc_register(&i2o_miscdev) < 0) {
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		osm_err("can't register device.\n");
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EBUSY;
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1154f33213ecf49c98da4e85121b592c3bea8057c2e6Markus Lidel
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1158f10378fff658f61307496e0ae00095041725cf07Markus Lidelstatic void i2o_config_old_exit(void)
11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	misc_deregister(&i2o_miscdev);
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Red Hat Software");
1164