/*
* I2O Configuration Interface Driver
*
* (C) Copyright 1999-2002 Red Hat
*
* Written by Alan Cox, Building Number Three Ltd
*
* Fixes/additions:
* Deepak Saxena (04/20/1999):
* Added basic ioctl() support
* Deepak Saxena (06/07/1999):
* Added software download ioctl (still testing)
* Auvo H�kkinen (09/10/1999):
* Changes to i2o_cfg_reply(), ioctl_parms()
* Added ioct_validate()
* Taneli V�h�kangas (09/30/1999):
* Fixed ioctl_swdl()
* Taneli V�h�kangas (10/04/1999):
* Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
* Deepak Saxena (11/18/1999):
* Added event managmenet support
* Alan Cox <alan@redhat.com>:
* 2.4 rewrite ported to 2.5
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Added pass-thru support for Adaptec's raidutils
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <asm/uaccess.h>
#include "core.h"
#define SG_TABLESIZE 30
static int i2o_cfg_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static spinlock_t i2o_config_lock;
#define MODINC(x,y) ((x) = ((x) + 1) % (y))
struct sg_simple_element {
u32 flag_count;
u32 addr_bus;
};
struct i2o_cfg_info {
struct file *fp;
struct fasync_struct *fasync;
struct i2o_evt_info event_q[I2O_EVT_Q_LEN];
u16 q_in; // Queue head index
u16 q_out; // Queue tail index
u16 q_len; // Queue length
u16 q_lost; // Number of lost events
ulong q_id; // Event queue ID...used as tx_context
struct i2o_cfg_info *next;
};
static struct i2o_cfg_info *open_files = NULL;
static ulong i2o_cfg_info_id = 0;
static int i2o_cfg_getiops(unsigned long arg)
{
struct i2o_controller *c;
u8 __user *user_iop_table = (void __user *)arg;
u8 tmp[MAX_I2O_CONTROLLERS];
int ret = 0;
memset(tmp, 0, MAX_I2O_CONTROLLERS);
list_for_each_entry(c, &i2o_controllers, list)
tmp[c->unit] = 1;
if (copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS))
ret = -EFAULT;
return ret;
};
static int i2o_cfg_gethrt(unsigned long arg)
{
struct i2o_controller *c;
struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg;
struct i2o_cmd_hrtlct kcmd;
i2o_hrt *hrt;
int len;
u32 reslen;
int ret = 0;
if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))
return -EFAULT;
if (get_user(reslen, kcmd.reslen) < 0)
return -EFAULT;
if (kcmd.resbuf == NULL)
return -EFAULT;
c = i2o_find_iop(kcmd.iop);
if (!c)
return -ENXIO;
hrt = (i2o_hrt *) c->hrt.virt;
len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);
/* We did a get user...so assuming mem is ok...is this bad? */
put_user(len, kcmd.reslen);
if (len > reslen)
ret = -ENOBUFS;
if (copy_to_user(kcmd.resbuf, (void *)hrt, len))
ret = -EFAULT;
return ret;
};
static int i2o_cfg_getlct(unsigned long arg)
{
struct i2o_controller *c;
struct i2o_cmd_hrtlct __user