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