Path: blob/master/drivers/message/i2o/i2o_config.c
15111 views
/*1* I2O Configuration Interface Driver2*3* (C) Copyright 1999-2002 Red Hat4*5* Written by Alan Cox, Building Number Three Ltd6*7* Fixes/additions:8* Deepak Saxena (04/20/1999):9* Added basic ioctl() support10* Deepak Saxena (06/07/1999):11* Added software download ioctl (still testing)12* Auvo Häkkinen (09/10/1999):13* Changes to i2o_cfg_reply(), ioctl_parms()14* Added ioct_validate()15* Taneli Vähäkangas (09/30/1999):16* Fixed ioctl_swdl()17* Taneli Vähäkangas (10/04/1999):18* Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()19* Deepak Saxena (11/18/1999):20* Added event managmenet support21* Alan Cox <[email protected]>:22* 2.4 rewrite ported to 2.523* Markus Lidel <[email protected]>:24* Added pass-thru support for Adaptec's raidutils25*26* This program is free software; you can redistribute it and/or27* modify it under the terms of the GNU General Public License28* as published by the Free Software Foundation; either version29* 2 of the License, or (at your option) any later version.30*/3132#include <linux/miscdevice.h>33#include <linux/mutex.h>34#include <linux/compat.h>35#include <linux/slab.h>3637#include <asm/uaccess.h>3839#include "core.h"4041#define SG_TABLESIZE 304243static DEFINE_MUTEX(i2o_cfg_mutex);44static long i2o_cfg_ioctl(struct file *, unsigned int, unsigned long);4546static spinlock_t i2o_config_lock;4748#define MODINC(x,y) ((x) = ((x) + 1) % (y))4950struct sg_simple_element {51u32 flag_count;52u32 addr_bus;53};5455struct i2o_cfg_info {56struct file *fp;57struct fasync_struct *fasync;58struct i2o_evt_info event_q[I2O_EVT_Q_LEN];59u16 q_in; // Queue head index60u16 q_out; // Queue tail index61u16 q_len; // Queue length62u16 q_lost; // Number of lost events63ulong q_id; // Event queue ID...used as tx_context64struct i2o_cfg_info *next;65};66static struct i2o_cfg_info *open_files = NULL;67static ulong i2o_cfg_info_id = 0;6869static int i2o_cfg_getiops(unsigned long arg)70{71struct i2o_controller *c;72u8 __user *user_iop_table = (void __user *)arg;73u8 tmp[MAX_I2O_CONTROLLERS];74int ret = 0;7576memset(tmp, 0, MAX_I2O_CONTROLLERS);7778list_for_each_entry(c, &i2o_controllers, list)79tmp[c->unit] = 1;8081if (copy_to_user(user_iop_table, tmp, MAX_I2O_CONTROLLERS))82ret = -EFAULT;8384return ret;85};8687static int i2o_cfg_gethrt(unsigned long arg)88{89struct i2o_controller *c;90struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg;91struct i2o_cmd_hrtlct kcmd;92i2o_hrt *hrt;93int len;94u32 reslen;95int ret = 0;9697if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))98return -EFAULT;99100if (get_user(reslen, kcmd.reslen) < 0)101return -EFAULT;102103if (kcmd.resbuf == NULL)104return -EFAULT;105106c = i2o_find_iop(kcmd.iop);107if (!c)108return -ENXIO;109110hrt = (i2o_hrt *) c->hrt.virt;111112len = 8 + ((hrt->entry_len * hrt->num_entries) << 2);113114if (put_user(len, kcmd.reslen))115ret = -EFAULT;116else if (len > reslen)117ret = -ENOBUFS;118else if (copy_to_user(kcmd.resbuf, (void *)hrt, len))119ret = -EFAULT;120121return ret;122};123124static int i2o_cfg_getlct(unsigned long arg)125{126struct i2o_controller *c;127struct i2o_cmd_hrtlct __user *cmd = (struct i2o_cmd_hrtlct __user *)arg;128struct i2o_cmd_hrtlct kcmd;129i2o_lct *lct;130int len;131int ret = 0;132u32 reslen;133134if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_hrtlct)))135return -EFAULT;136137if (get_user(reslen, kcmd.reslen) < 0)138return -EFAULT;139140if (kcmd.resbuf == NULL)141return -EFAULT;142143c = i2o_find_iop(kcmd.iop);144if (!c)145return -ENXIO;146147lct = (i2o_lct *) c->lct;148149len = (unsigned int)lct->table_size << 2;150if (put_user(len, kcmd.reslen))151ret = -EFAULT;152else if (len > reslen)153ret = -ENOBUFS;154else if (copy_to_user(kcmd.resbuf, lct, len))155ret = -EFAULT;156157return ret;158};159160static int i2o_cfg_parms(unsigned long arg, unsigned int type)161{162int ret = 0;163struct i2o_controller *c;164struct i2o_device *dev;165struct i2o_cmd_psetget __user *cmd =166(struct i2o_cmd_psetget __user *)arg;167struct i2o_cmd_psetget kcmd;168u32 reslen;169u8 *ops;170u8 *res;171int len = 0;172173u32 i2o_cmd = (type == I2OPARMGET ?174I2O_CMD_UTIL_PARAMS_GET : I2O_CMD_UTIL_PARAMS_SET);175176if (copy_from_user(&kcmd, cmd, sizeof(struct i2o_cmd_psetget)))177return -EFAULT;178179if (get_user(reslen, kcmd.reslen))180return -EFAULT;181182c = i2o_find_iop(kcmd.iop);183if (!c)184return -ENXIO;185186dev = i2o_iop_find_device(c, kcmd.tid);187if (!dev)188return -ENXIO;189190ops = memdup_user(kcmd.opbuf, kcmd.oplen);191if (IS_ERR(ops))192return PTR_ERR(ops);193194/*195* It's possible to have a _very_ large table196* and that the user asks for all of it at once...197*/198res = kmalloc(65536, GFP_KERNEL);199if (!res) {200kfree(ops);201return -ENOMEM;202}203204len = i2o_parm_issue(dev, i2o_cmd, ops, kcmd.oplen, res, 65536);205kfree(ops);206207if (len < 0) {208kfree(res);209return -EAGAIN;210}211212if (put_user(len, kcmd.reslen))213ret = -EFAULT;214else if (len > reslen)215ret = -ENOBUFS;216else if (copy_to_user(kcmd.resbuf, res, len))217ret = -EFAULT;218219kfree(res);220221return ret;222};223224static int i2o_cfg_swdl(unsigned long arg)225{226struct i2o_sw_xfer kxfer;227struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;228unsigned char maxfrag = 0, curfrag = 1;229struct i2o_dma buffer;230struct i2o_message *msg;231unsigned int status = 0, swlen = 0, fragsize = 8192;232struct i2o_controller *c;233234if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))235return -EFAULT;236237if (get_user(swlen, kxfer.swlen) < 0)238return -EFAULT;239240if (get_user(maxfrag, kxfer.maxfrag) < 0)241return -EFAULT;242243if (get_user(curfrag, kxfer.curfrag) < 0)244return -EFAULT;245246if (curfrag == maxfrag)247fragsize = swlen - (maxfrag - 1) * 8192;248249if (!kxfer.buf || !access_ok(VERIFY_READ, kxfer.buf, fragsize))250return -EFAULT;251252c = i2o_find_iop(kxfer.iop);253if (!c)254return -ENXIO;255256msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);257if (IS_ERR(msg))258return PTR_ERR(msg);259260if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {261i2o_msg_nop(c, msg);262return -ENOMEM;263}264265if (__copy_from_user(buffer.virt, kxfer.buf, fragsize)) {266i2o_msg_nop(c, msg);267i2o_dma_free(&c->pdev->dev, &buffer);268return -EFAULT;269}270271msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_7);272msg->u.head[1] =273cpu_to_le32(I2O_CMD_SW_DOWNLOAD << 24 | HOST_TID << 12 |274ADAPTER_TID);275msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);276msg->u.head[3] = cpu_to_le32(0);277msg->body[0] =278cpu_to_le32((((u32) kxfer.flags) << 24) | (((u32) kxfer.279sw_type) << 16) |280(((u32) maxfrag) << 8) | (((u32) curfrag)));281msg->body[1] = cpu_to_le32(swlen);282msg->body[2] = cpu_to_le32(kxfer.sw_id);283msg->body[3] = cpu_to_le32(0xD0000000 | fragsize);284msg->body[4] = cpu_to_le32(buffer.phys);285286osm_debug("swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);287status = i2o_msg_post_wait_mem(c, msg, 60, &buffer);288289if (status != -ETIMEDOUT)290i2o_dma_free(&c->pdev->dev, &buffer);291292if (status != I2O_POST_WAIT_OK) {293// it fails if you try and send frags out of order294// and for some yet unknown reasons too295osm_info("swdl failed, DetailedStatus = %d\n", status);296return status;297}298299return 0;300};301302static int i2o_cfg_swul(unsigned long arg)303{304struct i2o_sw_xfer kxfer;305struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;306unsigned char maxfrag = 0, curfrag = 1;307struct i2o_dma buffer;308struct i2o_message *msg;309unsigned int status = 0, swlen = 0, fragsize = 8192;310struct i2o_controller *c;311int ret = 0;312313if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))314return -EFAULT;315316if (get_user(swlen, kxfer.swlen) < 0)317return -EFAULT;318319if (get_user(maxfrag, kxfer.maxfrag) < 0)320return -EFAULT;321322if (get_user(curfrag, kxfer.curfrag) < 0)323return -EFAULT;324325if (curfrag == maxfrag)326fragsize = swlen - (maxfrag - 1) * 8192;327328if (!kxfer.buf)329return -EFAULT;330331c = i2o_find_iop(kxfer.iop);332if (!c)333return -ENXIO;334335msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);336if (IS_ERR(msg))337return PTR_ERR(msg);338339if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {340i2o_msg_nop(c, msg);341return -ENOMEM;342}343344msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_7);345msg->u.head[1] =346cpu_to_le32(I2O_CMD_SW_UPLOAD << 24 | HOST_TID << 12 | ADAPTER_TID);347msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);348msg->u.head[3] = cpu_to_le32(0);349msg->body[0] =350cpu_to_le32((u32) kxfer.flags << 24 | (u32) kxfer.351sw_type << 16 | (u32) maxfrag << 8 | (u32) curfrag);352msg->body[1] = cpu_to_le32(swlen);353msg->body[2] = cpu_to_le32(kxfer.sw_id);354msg->body[3] = cpu_to_le32(0xD0000000 | fragsize);355msg->body[4] = cpu_to_le32(buffer.phys);356357osm_debug("swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);358status = i2o_msg_post_wait_mem(c, msg, 60, &buffer);359360if (status != I2O_POST_WAIT_OK) {361if (status != -ETIMEDOUT)362i2o_dma_free(&c->pdev->dev, &buffer);363364osm_info("swul failed, DetailedStatus = %d\n", status);365return status;366}367368if (copy_to_user(kxfer.buf, buffer.virt, fragsize))369ret = -EFAULT;370371i2o_dma_free(&c->pdev->dev, &buffer);372373return ret;374}375376static int i2o_cfg_swdel(unsigned long arg)377{378struct i2o_controller *c;379struct i2o_sw_xfer kxfer;380struct i2o_sw_xfer __user *pxfer = (struct i2o_sw_xfer __user *)arg;381struct i2o_message *msg;382unsigned int swlen;383int token;384385if (copy_from_user(&kxfer, pxfer, sizeof(struct i2o_sw_xfer)))386return -EFAULT;387388if (get_user(swlen, kxfer.swlen) < 0)389return -EFAULT;390391c = i2o_find_iop(kxfer.iop);392if (!c)393return -ENXIO;394395msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);396if (IS_ERR(msg))397return PTR_ERR(msg);398399msg->u.head[0] = cpu_to_le32(SEVEN_WORD_MSG_SIZE | SGL_OFFSET_0);400msg->u.head[1] =401cpu_to_le32(I2O_CMD_SW_REMOVE << 24 | HOST_TID << 12 | ADAPTER_TID);402msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);403msg->u.head[3] = cpu_to_le32(0);404msg->body[0] =405cpu_to_le32((u32) kxfer.flags << 24 | (u32) kxfer.sw_type << 16);406msg->body[1] = cpu_to_le32(swlen);407msg->body[2] = cpu_to_le32(kxfer.sw_id);408409token = i2o_msg_post_wait(c, msg, 10);410411if (token != I2O_POST_WAIT_OK) {412osm_info("swdel failed, DetailedStatus = %d\n", token);413return -ETIMEDOUT;414}415416return 0;417};418419static int i2o_cfg_validate(unsigned long arg)420{421int token;422int iop = (int)arg;423struct i2o_message *msg;424struct i2o_controller *c;425426c = i2o_find_iop(iop);427if (!c)428return -ENXIO;429430msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);431if (IS_ERR(msg))432return PTR_ERR(msg);433434msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);435msg->u.head[1] =436cpu_to_le32(I2O_CMD_CONFIG_VALIDATE << 24 | HOST_TID << 12 | iop);437msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);438msg->u.head[3] = cpu_to_le32(0);439440token = i2o_msg_post_wait(c, msg, 10);441442if (token != I2O_POST_WAIT_OK) {443osm_info("Can't validate configuration, ErrorStatus = %d\n",444token);445return -ETIMEDOUT;446}447448return 0;449};450451static int i2o_cfg_evt_reg(unsigned long arg, struct file *fp)452{453struct i2o_message *msg;454struct i2o_evt_id __user *pdesc = (struct i2o_evt_id __user *)arg;455struct i2o_evt_id kdesc;456struct i2o_controller *c;457struct i2o_device *d;458459if (copy_from_user(&kdesc, pdesc, sizeof(struct i2o_evt_id)))460return -EFAULT;461462/* IOP exists? */463c = i2o_find_iop(kdesc.iop);464if (!c)465return -ENXIO;466467/* Device exists? */468d = i2o_iop_find_device(c, kdesc.tid);469if (!d)470return -ENODEV;471472msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);473if (IS_ERR(msg))474return PTR_ERR(msg);475476msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);477msg->u.head[1] =478cpu_to_le32(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 |479kdesc.tid);480msg->u.head[2] = cpu_to_le32(i2o_config_driver.context);481msg->u.head[3] = cpu_to_le32(i2o_cntxt_list_add(c, fp->private_data));482msg->body[0] = cpu_to_le32(kdesc.evt_mask);483484i2o_msg_post(c, msg);485486return 0;487}488489static int i2o_cfg_evt_get(unsigned long arg, struct file *fp)490{491struct i2o_cfg_info *p = NULL;492struct i2o_evt_get __user *uget = (struct i2o_evt_get __user *)arg;493struct i2o_evt_get kget;494unsigned long flags;495496for (p = open_files; p; p = p->next)497if (p->q_id == (ulong) fp->private_data)498break;499500if (!p->q_len)501return -ENOENT;502503memcpy(&kget.info, &p->event_q[p->q_out], sizeof(struct i2o_evt_info));504MODINC(p->q_out, I2O_EVT_Q_LEN);505spin_lock_irqsave(&i2o_config_lock, flags);506p->q_len--;507kget.pending = p->q_len;508kget.lost = p->q_lost;509spin_unlock_irqrestore(&i2o_config_lock, flags);510511if (copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)))512return -EFAULT;513return 0;514}515516#ifdef CONFIG_COMPAT517static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,518unsigned long arg)519{520struct i2o_cmd_passthru32 __user *cmd;521struct i2o_controller *c;522u32 __user *user_msg;523u32 *reply = NULL;524u32 __user *user_reply = NULL;525u32 size = 0;526u32 reply_size = 0;527u32 rcode = 0;528struct i2o_dma sg_list[SG_TABLESIZE];529u32 sg_offset = 0;530u32 sg_count = 0;531u32 i = 0;532u32 sg_index = 0;533i2o_status_block *sb;534struct i2o_message *msg;535unsigned int iop;536537cmd = (struct i2o_cmd_passthru32 __user *)arg;538539if (get_user(iop, &cmd->iop) || get_user(i, &cmd->msg))540return -EFAULT;541542user_msg = compat_ptr(i);543544c = i2o_find_iop(iop);545if (!c) {546osm_debug("controller %d not found\n", iop);547return -ENXIO;548}549550sb = c->status_block.virt;551552if (get_user(size, &user_msg[0])) {553osm_warn("unable to get size!\n");554return -EFAULT;555}556size = size >> 16;557558if (size > sb->inbound_frame_size) {559osm_warn("size of message > inbound_frame_size");560return -EFAULT;561}562563user_reply = &user_msg[size];564565size <<= 2; // Convert to bytes566567msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);568if (IS_ERR(msg))569return PTR_ERR(msg);570571rcode = -EFAULT;572/* Copy in the user's I2O command */573if (copy_from_user(msg, user_msg, size)) {574osm_warn("unable to copy user message\n");575goto out;576}577i2o_dump_message(msg);578579if (get_user(reply_size, &user_reply[0]) < 0)580goto out;581582reply_size >>= 16;583reply_size <<= 2;584585rcode = -ENOMEM;586reply = kzalloc(reply_size, GFP_KERNEL);587if (!reply) {588printk(KERN_WARNING "%s: Could not allocate reply buffer\n",589c->name);590goto out;591}592593sg_offset = (msg->u.head[0] >> 4) & 0x0f;594595memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);596if (sg_offset) {597struct sg_simple_element *sg;598599if (sg_offset * 4 >= size) {600rcode = -EFAULT;601goto cleanup;602}603// TODO 64bit fix604sg = (struct sg_simple_element *)((&msg->u.head[0]) +605sg_offset);606sg_count =607(size - sg_offset * 4) / sizeof(struct sg_simple_element);608if (sg_count > SG_TABLESIZE) {609printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",610c->name, sg_count);611rcode = -EINVAL;612goto cleanup;613}614615for (i = 0; i < sg_count; i++) {616int sg_size;617struct i2o_dma *p;618619if (!(sg[i].flag_count & 0x10000000620/*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) {621printk(KERN_DEBUG622"%s:Bad SG element %d - not simple (%x)\n",623c->name, i, sg[i].flag_count);624rcode = -EINVAL;625goto cleanup;626}627sg_size = sg[i].flag_count & 0xffffff;628p = &(sg_list[sg_index]);629/* Allocate memory for the transfer */630if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {631printk(KERN_DEBUG632"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",633c->name, sg_size, i, sg_count);634rcode = -ENOMEM;635goto sg_list_cleanup;636}637sg_index++;638/* Copy in the user's SG buffer if necessary */639if (sg[i].640flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {641// TODO 64bit fix642if (copy_from_user643(p->virt,644(void __user *)(unsigned long)sg[i].645addr_bus, sg_size)) {646printk(KERN_DEBUG647"%s: Could not copy SG buf %d FROM user\n",648c->name, i);649rcode = -EFAULT;650goto sg_list_cleanup;651}652}653//TODO 64bit fix654sg[i].addr_bus = (u32) p->phys;655}656}657658rcode = i2o_msg_post_wait(c, msg, 60);659msg = NULL;660if (rcode) {661reply[4] = ((u32) rcode) << 24;662goto sg_list_cleanup;663}664665if (sg_offset) {666u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];667/* Copy back the Scatter Gather buffers back to user space */668u32 j;669// TODO 64bit fix670struct sg_simple_element *sg;671int sg_size;672673// re-acquire the original message to handle correctly the sg copy operation674memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);675// get user msg size in u32s676if (get_user(size, &user_msg[0])) {677rcode = -EFAULT;678goto sg_list_cleanup;679}680size = size >> 16;681size *= 4;682/* Copy in the user's I2O command */683if (copy_from_user(rmsg, user_msg, size)) {684rcode = -EFAULT;685goto sg_list_cleanup;686}687sg_count =688(size - sg_offset * 4) / sizeof(struct sg_simple_element);689690// TODO 64bit fix691sg = (struct sg_simple_element *)(rmsg + sg_offset);692for (j = 0; j < sg_count; j++) {693/* Copy out the SG list to user's buffer if necessary */694if (!695(sg[j].696flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) {697sg_size = sg[j].flag_count & 0xffffff;698// TODO 64bit fix699if (copy_to_user700((void __user *)(u64) sg[j].addr_bus,701sg_list[j].virt, sg_size)) {702printk(KERN_WARNING703"%s: Could not copy %p TO user %x\n",704c->name, sg_list[j].virt,705sg[j].addr_bus);706rcode = -EFAULT;707goto sg_list_cleanup;708}709}710}711}712713sg_list_cleanup:714/* Copy back the reply to user space */715if (reply_size) {716// we wrote our own values for context - now restore the user supplied ones717if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) {718printk(KERN_WARNING719"%s: Could not copy message context FROM user\n",720c->name);721rcode = -EFAULT;722}723if (copy_to_user(user_reply, reply, reply_size)) {724printk(KERN_WARNING725"%s: Could not copy reply TO user\n", c->name);726rcode = -EFAULT;727}728}729for (i = 0; i < sg_index; i++)730i2o_dma_free(&c->pdev->dev, &sg_list[i]);731732cleanup:733kfree(reply);734out:735if (msg)736i2o_msg_nop(c, msg);737return rcode;738}739740static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,741unsigned long arg)742{743int ret;744mutex_lock(&i2o_cfg_mutex);745switch (cmd) {746case I2OGETIOPS:747ret = i2o_cfg_ioctl(file, cmd, arg);748break;749case I2OPASSTHRU32:750ret = i2o_cfg_passthru32(file, cmd, arg);751break;752default:753ret = -ENOIOCTLCMD;754break;755}756mutex_unlock(&i2o_cfg_mutex);757return ret;758}759760#endif761762#ifdef CONFIG_I2O_EXT_ADAPTEC763static int i2o_cfg_passthru(unsigned long arg)764{765struct i2o_cmd_passthru __user *cmd =766(struct i2o_cmd_passthru __user *)arg;767struct i2o_controller *c;768u32 __user *user_msg;769u32 *reply = NULL;770u32 __user *user_reply = NULL;771u32 size = 0;772u32 reply_size = 0;773u32 rcode = 0;774struct i2o_dma sg_list[SG_TABLESIZE];775u32 sg_offset = 0;776u32 sg_count = 0;777int sg_index = 0;778u32 i = 0;779i2o_status_block *sb;780struct i2o_message *msg;781unsigned int iop;782783if (get_user(iop, &cmd->iop) || get_user(user_msg, &cmd->msg))784return -EFAULT;785786c = i2o_find_iop(iop);787if (!c) {788osm_warn("controller %d not found\n", iop);789return -ENXIO;790}791792sb = c->status_block.virt;793794if (get_user(size, &user_msg[0]))795return -EFAULT;796size = size >> 16;797798if (size > sb->inbound_frame_size) {799osm_warn("size of message > inbound_frame_size");800return -EFAULT;801}802803user_reply = &user_msg[size];804805size <<= 2; // Convert to bytes806807msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);808if (IS_ERR(msg))809return PTR_ERR(msg);810811rcode = -EFAULT;812/* Copy in the user's I2O command */813if (copy_from_user(msg, user_msg, size))814goto out;815816if (get_user(reply_size, &user_reply[0]) < 0)817goto out;818819reply_size >>= 16;820reply_size <<= 2;821822reply = kzalloc(reply_size, GFP_KERNEL);823if (!reply) {824printk(KERN_WARNING "%s: Could not allocate reply buffer\n",825c->name);826rcode = -ENOMEM;827goto out;828}829830sg_offset = (msg->u.head[0] >> 4) & 0x0f;831832memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);833if (sg_offset) {834struct sg_simple_element *sg;835struct i2o_dma *p;836837if (sg_offset * 4 >= size) {838rcode = -EFAULT;839goto cleanup;840}841// TODO 64bit fix842sg = (struct sg_simple_element *)((&msg->u.head[0]) +843sg_offset);844sg_count =845(size - sg_offset * 4) / sizeof(struct sg_simple_element);846if (sg_count > SG_TABLESIZE) {847printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",848c->name, sg_count);849rcode = -EINVAL;850goto cleanup;851}852853for (i = 0; i < sg_count; i++) {854int sg_size;855856if (!(sg[i].flag_count & 0x10000000857/*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT */ )) {858printk(KERN_DEBUG859"%s:Bad SG element %d - not simple (%x)\n",860c->name, i, sg[i].flag_count);861rcode = -EINVAL;862goto sg_list_cleanup;863}864sg_size = sg[i].flag_count & 0xffffff;865p = &(sg_list[sg_index]);866if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {867/* Allocate memory for the transfer */868printk(KERN_DEBUG869"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",870c->name, sg_size, i, sg_count);871rcode = -ENOMEM;872goto sg_list_cleanup;873}874sg_index++;875/* Copy in the user's SG buffer if necessary */876if (sg[i].877flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {878// TODO 64bit fix879if (copy_from_user880(p->virt, (void __user *)sg[i].addr_bus,881sg_size)) {882printk(KERN_DEBUG883"%s: Could not copy SG buf %d FROM user\n",884c->name, i);885rcode = -EFAULT;886goto sg_list_cleanup;887}888}889sg[i].addr_bus = p->phys;890}891}892893rcode = i2o_msg_post_wait(c, msg, 60);894msg = NULL;895if (rcode) {896reply[4] = ((u32) rcode) << 24;897goto sg_list_cleanup;898}899900if (sg_offset) {901u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];902/* Copy back the Scatter Gather buffers back to user space */903u32 j;904// TODO 64bit fix905struct sg_simple_element *sg;906int sg_size;907908// re-acquire the original message to handle correctly the sg copy operation909memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);910// get user msg size in u32s911if (get_user(size, &user_msg[0])) {912rcode = -EFAULT;913goto sg_list_cleanup;914}915size = size >> 16;916size *= 4;917/* Copy in the user's I2O command */918if (copy_from_user(rmsg, user_msg, size)) {919rcode = -EFAULT;920goto sg_list_cleanup;921}922sg_count =923(size - sg_offset * 4) / sizeof(struct sg_simple_element);924925// TODO 64bit fix926sg = (struct sg_simple_element *)(rmsg + sg_offset);927for (j = 0; j < sg_count; j++) {928/* Copy out the SG list to user's buffer if necessary */929if (!930(sg[j].931flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR */ )) {932sg_size = sg[j].flag_count & 0xffffff;933// TODO 64bit fix934if (copy_to_user935((void __user *)sg[j].addr_bus, sg_list[j].virt,936sg_size)) {937printk(KERN_WARNING938"%s: Could not copy %p TO user %x\n",939c->name, sg_list[j].virt,940sg[j].addr_bus);941rcode = -EFAULT;942goto sg_list_cleanup;943}944}945}946}947948sg_list_cleanup:949/* Copy back the reply to user space */950if (reply_size) {951// we wrote our own values for context - now restore the user supplied ones952if (copy_from_user(reply + 2, user_msg + 2, sizeof(u32) * 2)) {953printk(KERN_WARNING954"%s: Could not copy message context FROM user\n",955c->name);956rcode = -EFAULT;957}958if (copy_to_user(user_reply, reply, reply_size)) {959printk(KERN_WARNING960"%s: Could not copy reply TO user\n", c->name);961rcode = -EFAULT;962}963}964965for (i = 0; i < sg_index; i++)966i2o_dma_free(&c->pdev->dev, &sg_list[i]);967968cleanup:969kfree(reply);970out:971if (msg)972i2o_msg_nop(c, msg);973return rcode;974}975#endif976977/*978* IOCTL Handler979*/980static long i2o_cfg_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)981{982int ret;983984mutex_lock(&i2o_cfg_mutex);985switch (cmd) {986case I2OGETIOPS:987ret = i2o_cfg_getiops(arg);988break;989990case I2OHRTGET:991ret = i2o_cfg_gethrt(arg);992break;993994case I2OLCTGET:995ret = i2o_cfg_getlct(arg);996break;997998case I2OPARMSET:999ret = i2o_cfg_parms(arg, I2OPARMSET);1000break;10011002case I2OPARMGET:1003ret = i2o_cfg_parms(arg, I2OPARMGET);1004break;10051006case I2OSWDL:1007ret = i2o_cfg_swdl(arg);1008break;10091010case I2OSWUL:1011ret = i2o_cfg_swul(arg);1012break;10131014case I2OSWDEL:1015ret = i2o_cfg_swdel(arg);1016break;10171018case I2OVALIDATE:1019ret = i2o_cfg_validate(arg);1020break;10211022case I2OEVTREG:1023ret = i2o_cfg_evt_reg(arg, fp);1024break;10251026case I2OEVTGET:1027ret = i2o_cfg_evt_get(arg, fp);1028break;10291030#ifdef CONFIG_I2O_EXT_ADAPTEC1031case I2OPASSTHRU:1032ret = i2o_cfg_passthru(arg);1033break;1034#endif10351036default:1037osm_debug("unknown ioctl called!\n");1038ret = -EINVAL;1039}1040mutex_unlock(&i2o_cfg_mutex);1041return ret;1042}10431044static int cfg_open(struct inode *inode, struct file *file)1045{1046struct i2o_cfg_info *tmp = kmalloc(sizeof(struct i2o_cfg_info),1047GFP_KERNEL);1048unsigned long flags;10491050if (!tmp)1051return -ENOMEM;10521053mutex_lock(&i2o_cfg_mutex);1054file->private_data = (void *)(i2o_cfg_info_id++);1055tmp->fp = file;1056tmp->fasync = NULL;1057tmp->q_id = (ulong) file->private_data;1058tmp->q_len = 0;1059tmp->q_in = 0;1060tmp->q_out = 0;1061tmp->q_lost = 0;1062tmp->next = open_files;10631064spin_lock_irqsave(&i2o_config_lock, flags);1065open_files = tmp;1066spin_unlock_irqrestore(&i2o_config_lock, flags);1067mutex_unlock(&i2o_cfg_mutex);10681069return 0;1070}10711072static int cfg_fasync(int fd, struct file *fp, int on)1073{1074ulong id = (ulong) fp->private_data;1075struct i2o_cfg_info *p;1076int ret = -EBADF;10771078mutex_lock(&i2o_cfg_mutex);1079for (p = open_files; p; p = p->next)1080if (p->q_id == id)1081break;10821083if (p)1084ret = fasync_helper(fd, fp, on, &p->fasync);1085mutex_unlock(&i2o_cfg_mutex);1086return ret;1087}10881089static int cfg_release(struct inode *inode, struct file *file)1090{1091ulong id = (ulong) file->private_data;1092struct i2o_cfg_info *p, **q;1093unsigned long flags;10941095mutex_lock(&i2o_cfg_mutex);1096spin_lock_irqsave(&i2o_config_lock, flags);1097for (q = &open_files; (p = *q) != NULL; q = &p->next) {1098if (p->q_id == id) {1099*q = p->next;1100kfree(p);1101break;1102}1103}1104spin_unlock_irqrestore(&i2o_config_lock, flags);1105mutex_unlock(&i2o_cfg_mutex);11061107return 0;1108}11091110static const struct file_operations config_fops = {1111.owner = THIS_MODULE,1112.llseek = no_llseek,1113.unlocked_ioctl = i2o_cfg_ioctl,1114#ifdef CONFIG_COMPAT1115.compat_ioctl = i2o_cfg_compat_ioctl,1116#endif1117.open = cfg_open,1118.release = cfg_release,1119.fasync = cfg_fasync,1120};11211122static struct miscdevice i2o_miscdev = {1123I2O_MINOR,1124"i2octl",1125&config_fops1126};11271128static int __init i2o_config_old_init(void)1129{1130spin_lock_init(&i2o_config_lock);11311132if (misc_register(&i2o_miscdev) < 0) {1133osm_err("can't register device.\n");1134return -EBUSY;1135}11361137return 0;1138}11391140static void i2o_config_old_exit(void)1141{1142misc_deregister(&i2o_miscdev);1143}11441145MODULE_AUTHOR("Red Hat Software");114611471148