11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ipmi_devintf.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Linux device interface for the IPMI message handler. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: MontaVista Software, Inc. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Corey Minyard <minyard@mvista.com> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * source@mvista.com 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2002 MontaVista Software Inc. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2 of the License, or (at your 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * option) any later version. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 675 Mass Ave, Cambridge, MA 02139, USA. 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h> 38a99bbaf5ee6bad1aca0c88ea65ec6e5373e86184Alexey Dobriyan#include <linux/sched.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ipmi.h> 42d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard#include <linux/mutex.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 4437e0915b701281182cea9fc90e894d10addf134aCorey Minyard#include <linux/device.h> 456a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#include <linux/compat.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ipmi_file_private 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipmi_user_t user; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t recv_msg_lock; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head recv_msgs; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file *file; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fasync_struct *fasync_queue; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t wait; 55d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard struct mutex recv_mutex; 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int default_retries; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int default_retry_time_ms; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60609146fdb319cebce93be550938ab852f7bade90Arnd Bergmannstatic DEFINE_MUTEX(ipmi_mutex); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void file_receive_handler(struct ipmi_recv_msg *msg, 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *handler_data) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_file_private *priv = handler_data; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int was_empty; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&(priv->recv_msg_lock), flags); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds was_empty = list_empty(&(priv->recv_msgs)); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(&(msg->link), &(priv->recv_msgs)); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (was_empty) { 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible(&priv->wait); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int ipmi_poll(struct file *file, poll_table *wait) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_file_private *priv = file->private_data; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mask = 0; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds poll_wait(file, &priv->wait, wait); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&priv->recv_msg_lock, flags); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9150c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard if (!list_empty(&(priv->recv_msgs))) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mask |= (POLLIN | POLLRDNORM); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&priv->recv_msg_lock, flags); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mask; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipmi_fasync(int fd, struct file *file, int on) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_file_private *priv = file->private_data; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 104609146fdb319cebce93be550938ab852f7bade90Arnd Bergmann mutex_lock(&ipmi_mutex); /* could race against open() otherwise */ 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = fasync_helper(fd, file, on, &priv->fasync_queue); 106609146fdb319cebce93be550938ab852f7bade90Arnd Bergmann mutex_unlock(&ipmi_mutex); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (result); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ipmi_user_hndl ipmi_hndlrs = 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ipmi_recv_hndl = file_receive_handler, 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipmi_open(struct inode *inode, struct file *file) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int if_num = iminor(inode); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rv; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_file_private *priv; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv = kmalloc(sizeof(*priv), GFP_KERNEL); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!priv) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127609146fdb319cebce93be550938ab852f7bade90Arnd Bergmann mutex_lock(&ipmi_mutex); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->file = file; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = ipmi_create_user(if_num, 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &ipmi_hndlrs, 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv, 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &(priv->user)); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rv) { 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 136ecc38983f6c83f371fefb5a69a72e358fc7b1218Jonathan Corbet goto out; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file->private_data = priv; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&(priv->recv_msg_lock)); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&(priv->recv_msgs)); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&priv->wait); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->fasync_queue = NULL; 145d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard mutex_init(&priv->recv_mutex); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Use the low-level defaults. */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->default_retries = -1; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->default_retry_time_ms = 0; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151ecc38983f6c83f371fefb5a69a72e358fc7b1218Jonathan Corbetout: 152609146fdb319cebce93be550938ab852f7bade90Arnd Bergmann mutex_unlock(&ipmi_mutex); 153ecc38983f6c83f371fefb5a69a72e358fc7b1218Jonathan Corbet return rv; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ipmi_release(struct inode *inode, struct file *file) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_file_private *priv = file->private_data; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rv; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = ipmi_destroy_user(priv->user); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rv) 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rv; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME - free the messages in the list. */ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(priv); 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int handle_send_req(ipmi_user_t user, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_req *req, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retries, 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int retry_time_ms) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rv; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_addr addr; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kernel_ipmi_msg msg; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->addr_len > sizeof(struct ipmi_addr)) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&addr, req->addr, req->addr_len)) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.netfn = req->msg.netfn; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.cmd = req->msg.cmd; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.data_len = req->msg.data_len; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!msg.data) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* From here out we cannot return, we must jump to "out" for 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error exits to free msgdata. */ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = ipmi_validate_addr(&addr, req->addr_len); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rv) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->msg.data != NULL) { 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) { 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EMSGSIZE; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(msg.data, 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->msg.data, 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->msg.data_len)) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg.data_len = 0; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = ipmi_request_settime(user, 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &addr, 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->msgid, 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &msg, 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL, 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retries, 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retry_time_ms); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(msg.data); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rv; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic int ipmi_ioctl(struct file *file, 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long data) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rv = -EINVAL; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_file_private *priv = file->private_data; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *arg = (void __user *)data; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_SEND_COMMAND: 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_req req; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&req, arg, sizeof(req))) { 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = handle_send_req(priv->user, 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &req, 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->default_retries, 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->default_retry_time_ms); 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_SEND_COMMAND_SETTIME: 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_req_settime req; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&req, arg, sizeof(req))) { 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = handle_send_req(priv->user, 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &req.req, 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.retries, 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req.retry_time_ms); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_RECEIVE_MSG: 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_RECEIVE_MSG_TRUNC: 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_recv rsp; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int addr_len; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *entry; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_recv_msg *msg; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = 0; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&rsp, arg, sizeof(rsp))) { 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 288d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard /* We claim a mutex because we don't want two 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds users getting something from the queue at a time. 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Since we have to release the spinlock before we can 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copy the data to the user, it's possible another 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds user will grab something from the queue, too. Then 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the messages might get out of order if something 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fails and the message gets put back onto the 295d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard queue. This mutex prevents that problem. */ 296d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard mutex_lock(&priv->recv_mutex); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Grab the message off the list. */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&(priv->recv_msg_lock), flags); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (list_empty(&(priv->recv_msgs))) { 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EAGAIN; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto recv_err; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = priv->recv_msgs.next; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg = list_entry(entry, struct ipmi_recv_msg, link); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(entry); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr_len = ipmi_addr_length(msg->addr.addr_type); 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rsp.addr_len < addr_len) 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EINVAL; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto recv_putback_on_err; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) { 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto recv_putback_on_err; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rsp.addr_len = addr_len; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rsp.recv_type = msg->recv_type; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rsp.msgid = msg->msgid; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rsp.msg.netfn = msg->msg.netfn; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rsp.msg.cmd = msg->msg.cmd; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msg->msg.data_len > 0) { 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rsp.msg.data_len < msg->msg.data_len) { 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EMSGSIZE; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) { 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg.data_len = rsp.msg.data_len; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto recv_putback_on_err; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(rsp.msg.data, 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg.data, 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msg->msg.data_len)) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto recv_putback_on_err; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rsp.msg.data_len = msg->msg.data_len; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rsp.msg.data_len = 0; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(arg, &rsp, sizeof(rsp))) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto recv_putback_on_err; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 355d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard mutex_unlock(&priv->recv_mutex); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipmi_free_recv_msg(msg); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds recv_putback_on_err: 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we got an error, put the message back onto 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the head of the queue. */ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&(priv->recv_msg_lock), flags); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(entry, &(priv->recv_msgs)); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); 365d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard mutex_unlock(&priv->recv_mutex); 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds recv_err: 369d6dfd1310d3562698fd7c3c086f6c239f96394acCorey Minyard mutex_unlock(&priv->recv_mutex); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_REGISTER_FOR_CMD: 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_cmdspec val; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&val, arg, sizeof(val))) { 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 382c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd, 383c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard IPMI_CHAN_ALL); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_UNREGISTER_FOR_CMD: 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_cmdspec val; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&val, arg, sizeof(val))) { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 396c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd, 397c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard IPMI_CHAN_ALL); 398c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard break; 399c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard } 400c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard 401c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard case IPMICTL_REGISTER_FOR_CMD_CHANS: 402c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard { 403c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard struct ipmi_cmdspec_chans val; 404c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard 405c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard if (copy_from_user(&val, arg, sizeof(val))) { 406c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard rv = -EFAULT; 407c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard break; 408c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard } 409c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard 410c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd, 411c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard val.chans); 412c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard break; 413c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard } 414c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard 415c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard case IPMICTL_UNREGISTER_FOR_CMD_CHANS: 416c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard { 417c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard struct ipmi_cmdspec_chans val; 418c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard 419c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard if (copy_from_user(&val, arg, sizeof(val))) { 420c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard rv = -EFAULT; 421c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard break; 422c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard } 423c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard 424c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd, 425c69c31270c35a6b8421a8e4ba81de1247ac6df95Corey Minyard val.chans); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_SET_GETS_EVENTS_CMD: 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int val; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&val, arg, sizeof(val))) { 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = ipmi_set_gets_events(priv->user, val); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 442c14979b993021377228958498937bcdd9539cbceCorey Minyard /* The next four are legacy, not per-channel. */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_SET_MY_ADDRESS_CMD: 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int val; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&val, arg, sizeof(val))) { 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 452c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = ipmi_set_my_address(priv->user, 0, val); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_GET_MY_ADDRESS_CMD: 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 458c14979b993021377228958498937bcdd9539cbceCorey Minyard unsigned int val; 459c14979b993021377228958498937bcdd9539cbceCorey Minyard unsigned char rval; 460c14979b993021377228958498937bcdd9539cbceCorey Minyard 461c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = ipmi_get_my_address(priv->user, 0, &rval); 462c14979b993021377228958498937bcdd9539cbceCorey Minyard if (rv) 463c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 465c14979b993021377228958498937bcdd9539cbceCorey Minyard val = rval; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(arg, &val, sizeof(val))) { 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_SET_MY_LUN_CMD: 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int val; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&val, arg, sizeof(val))) { 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 483c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = ipmi_set_my_LUN(priv->user, 0, val); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_GET_MY_LUN_CMD: 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 489c14979b993021377228958498937bcdd9539cbceCorey Minyard unsigned int val; 490c14979b993021377228958498937bcdd9539cbceCorey Minyard unsigned char rval; 491c14979b993021377228958498937bcdd9539cbceCorey Minyard 492c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = ipmi_get_my_LUN(priv->user, 0, &rval); 493c14979b993021377228958498937bcdd9539cbceCorey Minyard if (rv) 494c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 496c14979b993021377228958498937bcdd9539cbceCorey Minyard val = rval; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(arg, &val, sizeof(val))) { 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 504c14979b993021377228958498937bcdd9539cbceCorey Minyard 505c14979b993021377228958498937bcdd9539cbceCorey Minyard case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD: 506c14979b993021377228958498937bcdd9539cbceCorey Minyard { 507c14979b993021377228958498937bcdd9539cbceCorey Minyard struct ipmi_channel_lun_address_set val; 508c14979b993021377228958498937bcdd9539cbceCorey Minyard 509c14979b993021377228958498937bcdd9539cbceCorey Minyard if (copy_from_user(&val, arg, sizeof(val))) { 510c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = -EFAULT; 511c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 512c14979b993021377228958498937bcdd9539cbceCorey Minyard } 513c14979b993021377228958498937bcdd9539cbceCorey Minyard 514c14979b993021377228958498937bcdd9539cbceCorey Minyard return ipmi_set_my_address(priv->user, val.channel, val.value); 515c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 516c14979b993021377228958498937bcdd9539cbceCorey Minyard } 517c14979b993021377228958498937bcdd9539cbceCorey Minyard 518c14979b993021377228958498937bcdd9539cbceCorey Minyard case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD: 519c14979b993021377228958498937bcdd9539cbceCorey Minyard { 520c14979b993021377228958498937bcdd9539cbceCorey Minyard struct ipmi_channel_lun_address_set val; 521c14979b993021377228958498937bcdd9539cbceCorey Minyard 522c14979b993021377228958498937bcdd9539cbceCorey Minyard if (copy_from_user(&val, arg, sizeof(val))) { 523c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = -EFAULT; 524c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 525c14979b993021377228958498937bcdd9539cbceCorey Minyard } 526c14979b993021377228958498937bcdd9539cbceCorey Minyard 527c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = ipmi_get_my_address(priv->user, val.channel, &val.value); 528c14979b993021377228958498937bcdd9539cbceCorey Minyard if (rv) 529c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 530c14979b993021377228958498937bcdd9539cbceCorey Minyard 531c14979b993021377228958498937bcdd9539cbceCorey Minyard if (copy_to_user(arg, &val, sizeof(val))) { 532c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = -EFAULT; 533c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 534c14979b993021377228958498937bcdd9539cbceCorey Minyard } 535c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 536c14979b993021377228958498937bcdd9539cbceCorey Minyard } 537c14979b993021377228958498937bcdd9539cbceCorey Minyard 538c14979b993021377228958498937bcdd9539cbceCorey Minyard case IPMICTL_SET_MY_CHANNEL_LUN_CMD: 539c14979b993021377228958498937bcdd9539cbceCorey Minyard { 540c14979b993021377228958498937bcdd9539cbceCorey Minyard struct ipmi_channel_lun_address_set val; 541c14979b993021377228958498937bcdd9539cbceCorey Minyard 542c14979b993021377228958498937bcdd9539cbceCorey Minyard if (copy_from_user(&val, arg, sizeof(val))) { 543c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = -EFAULT; 544c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 545c14979b993021377228958498937bcdd9539cbceCorey Minyard } 546c14979b993021377228958498937bcdd9539cbceCorey Minyard 547c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = ipmi_set_my_LUN(priv->user, val.channel, val.value); 548c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 549c14979b993021377228958498937bcdd9539cbceCorey Minyard } 550c14979b993021377228958498937bcdd9539cbceCorey Minyard 551c14979b993021377228958498937bcdd9539cbceCorey Minyard case IPMICTL_GET_MY_CHANNEL_LUN_CMD: 552c14979b993021377228958498937bcdd9539cbceCorey Minyard { 553c14979b993021377228958498937bcdd9539cbceCorey Minyard struct ipmi_channel_lun_address_set val; 554c14979b993021377228958498937bcdd9539cbceCorey Minyard 555c14979b993021377228958498937bcdd9539cbceCorey Minyard if (copy_from_user(&val, arg, sizeof(val))) { 556c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = -EFAULT; 557c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 558c14979b993021377228958498937bcdd9539cbceCorey Minyard } 559c14979b993021377228958498937bcdd9539cbceCorey Minyard 560c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value); 561c14979b993021377228958498937bcdd9539cbceCorey Minyard if (rv) 562c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 563c14979b993021377228958498937bcdd9539cbceCorey Minyard 564c14979b993021377228958498937bcdd9539cbceCorey Minyard if (copy_to_user(arg, &val, sizeof(val))) { 565c14979b993021377228958498937bcdd9539cbceCorey Minyard rv = -EFAULT; 566c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 567c14979b993021377228958498937bcdd9539cbceCorey Minyard } 568c14979b993021377228958498937bcdd9539cbceCorey Minyard break; 569c14979b993021377228958498937bcdd9539cbceCorey Minyard } 570c14979b993021377228958498937bcdd9539cbceCorey Minyard 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_SET_TIMING_PARMS_CMD: 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_timing_parms parms; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&parms, arg, sizeof(parms))) { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->default_retries = parms.retries; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds priv->default_retry_time_ms = parms.retry_time_ms; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = 0; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case IPMICTL_GET_TIMING_PARMS_CMD: 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ipmi_timing_parms parms; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parms.retries = priv->default_retries; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parms.retry_time_ms = priv->default_retry_time_ms; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(arg, &parms, sizeof(parms))) { 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = -EFAULT; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = 0; 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 601b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard 602b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard case IPMICTL_GET_MAINTENANCE_MODE_CMD: 603b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard { 604b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard int mode; 605b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard 606b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard mode = ipmi_get_maintenance_mode(priv->user); 607b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard if (copy_to_user(arg, &mode, sizeof(mode))) { 608b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard rv = -EFAULT; 609b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard break; 610b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard } 611b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard rv = 0; 612b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard break; 613b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard } 614b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard 615b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard case IPMICTL_SET_MAINTENANCE_MODE_CMD: 616b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard { 617b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard int mode; 618b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard 619b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard if (copy_from_user(&mode, arg, sizeof(mode))) { 620b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard rv = -EFAULT; 621b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard break; 622b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard } 623b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard rv = ipmi_set_maintenance_mode(priv->user, mode); 624b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard break; 625b9675136e2ad95156fb93be6155f17590bb26fd7Corey Minyard } 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rv; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63155929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann/* 63255929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann * Note: it doesn't make sense to take the BKL here but 63355929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann * not in compat_ipmi_ioctl. -arnd 63455929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann */ 63555929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmannstatic long ipmi_unlocked_ioctl(struct file *file, 63655929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann unsigned int cmd, 63755929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann unsigned long data) 63855929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann{ 63955929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann int ret; 64055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann 641609146fdb319cebce93be550938ab852f7bade90Arnd Bergmann mutex_lock(&ipmi_mutex); 64255929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann ret = ipmi_ioctl(file, cmd, data); 643609146fdb319cebce93be550938ab852f7bade90Arnd Bergmann mutex_unlock(&ipmi_mutex); 64455929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann 64555929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann return ret; 64655929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann} 64755929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann 6486a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#ifdef CONFIG_COMPAT 6496a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 6506a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton/* 6516a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton * The following code contains code for supporting 32-bit compatible 6526a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton * ioctls on 64-bit kernels. This allows running 32-bit apps on the 6536a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton * 64-bit kernel 6546a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton */ 6556a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#define COMPAT_IPMICTL_SEND_COMMAND \ 6566a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req) 6576a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \ 6586a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime) 6596a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#define COMPAT_IPMICTL_RECEIVE_MSG \ 6606a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv) 6616a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \ 6626a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv) 6636a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 6646a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstruct compat_ipmi_msg { 6656a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton u8 netfn; 6666a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton u8 cmd; 6676a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton u16 data_len; 6686a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uptr_t data; 6696a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton}; 6706a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 6716a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstruct compat_ipmi_req { 6726a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uptr_t addr; 6736a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uint_t addr_len; 6746a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_long_t msgid; 6756a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_msg msg; 6766a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton}; 6776a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 6786a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstruct compat_ipmi_recv { 6796a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_int_t recv_type; 6806a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uptr_t addr; 6816a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uint_t addr_len; 6826a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_long_t msgid; 6836a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_msg msg; 6846a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton}; 6856a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 6866a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstruct compat_ipmi_req_settime { 6876a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_req req; 6886a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_int_t retries; 6896a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uint_t retry_time_ms; 6906a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton}; 6916a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 6926a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton/* 6936a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton * Define some helper functions for copying IPMI data 6946a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton */ 6956a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstatic long get_compat_ipmi_msg(struct ipmi_msg *p64, 6966a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_msg __user *p32) 6976a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton{ 6986a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uptr_t tmp; 6996a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7006a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || 7016a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->netfn, &p32->netfn) || 7026a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->cmd, &p32->cmd) || 7036a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->data_len, &p32->data_len) || 7046a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(tmp, &p32->data)) 7056a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 7066a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton p64->data = compat_ptr(tmp); 7076a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return 0; 7086a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton} 7096a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7106a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstatic long put_compat_ipmi_msg(struct ipmi_msg *p64, 7116a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_msg __user *p32) 7126a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton{ 7136a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || 7146a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __put_user(p64->netfn, &p32->netfn) || 7156a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __put_user(p64->cmd, &p32->cmd) || 7166a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __put_user(p64->data_len, &p32->data_len)) 7176a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 7186a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return 0; 7196a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton} 7206a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7216a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstatic long get_compat_ipmi_req(struct ipmi_req *p64, 7226a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_req __user *p32) 7236a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton{ 7246a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7256a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uptr_t tmp; 7266a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7276a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || 7286a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(tmp, &p32->addr) || 7296a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->addr_len, &p32->addr_len) || 7306a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->msgid, &p32->msgid) || 7316a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton get_compat_ipmi_msg(&p64->msg, &p32->msg)) 7326a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 7336a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton p64->addr = compat_ptr(tmp); 7346a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return 0; 7356a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton} 7366a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7376a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstatic long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64, 7386a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_req_settime __user *p32) 7396a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton{ 7406a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || 7416a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton get_compat_ipmi_req(&p64->req, &p32->req) || 7426a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->retries, &p32->retries) || 7436a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->retry_time_ms, &p32->retry_time_ms)) 7446a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 7456a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return 0; 7466a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton} 7476a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7486a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstatic long get_compat_ipmi_recv(struct ipmi_recv *p64, 7496a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_recv __user *p32) 7506a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton{ 7516a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton compat_uptr_t tmp; 7526a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7536a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || 7546a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->recv_type, &p32->recv_type) || 7556a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(tmp, &p32->addr) || 7566a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->addr_len, &p32->addr_len) || 7576a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __get_user(p64->msgid, &p32->msgid) || 7586a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton get_compat_ipmi_msg(&p64->msg, &p32->msg)) 7596a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 7606a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton p64->addr = compat_ptr(tmp); 7616a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return 0; 7626a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton} 7636a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7646a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstatic long put_compat_ipmi_recv(struct ipmi_recv *p64, 7656a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct compat_ipmi_recv __user *p32) 7666a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton{ 7676a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || 7686a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __put_user(p64->recv_type, &p32->recv_type) || 7696a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __put_user(p64->addr_len, &p32->addr_len) || 7706a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton __put_user(p64->msgid, &p32->msgid) || 7716a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton put_compat_ipmi_msg(&p64->msg, &p32->msg)) 7726a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 7736a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return 0; 7746a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton} 7756a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7766a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton/* 7776a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton * Handle compatibility ioctls 7786a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton */ 7796a94f9209762a6eb286f668e1346ad87985cc765Andrew Mortonstatic long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, 7806a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton unsigned long arg) 7816a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton{ 7826a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton int rc; 7836a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct ipmi_file_private *priv = filep->private_data; 7846a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7856a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton switch(cmd) { 7866a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton case COMPAT_IPMICTL_SEND_COMMAND: 7876a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton { 7886a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct ipmi_req rp; 7896a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7906a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (get_compat_ipmi_req(&rp, compat_ptr(arg))) 7916a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 7926a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 7936a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return handle_send_req(priv->user, &rp, 7946a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton priv->default_retries, 7956a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton priv->default_retry_time_ms); 7966a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton } 7976a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton case COMPAT_IPMICTL_SEND_COMMAND_SETTIME: 7986a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton { 7996a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton struct ipmi_req_settime sp; 8006a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 8016a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg))) 8026a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 8036a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 8046a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return handle_send_req(priv->user, &sp.req, 8056a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton sp.retries, sp.retry_time_ms); 8066a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton } 8076a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton case COMPAT_IPMICTL_RECEIVE_MSG: 8086a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC: 8096a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton { 81018fb9442576c79fc2f4bca1fd90c3aa4d1115e97Al Viro struct ipmi_recv __user *precv64; 81118fb9442576c79fc2f4bca1fd90c3aa4d1115e97Al Viro struct ipmi_recv recv64; 8126a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 8136a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (get_compat_ipmi_recv(&recv64, compat_ptr(arg))) 8146a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 8156a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 8166a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton precv64 = compat_alloc_user_space(sizeof(recv64)); 8176a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (copy_to_user(precv64, &recv64, sizeof(recv64))) 8186a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 8196a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 82055929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann rc = ipmi_ioctl(filep, 8216a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton ((cmd == COMPAT_IPMICTL_RECEIVE_MSG) 8226a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton ? IPMICTL_RECEIVE_MSG 8236a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton : IPMICTL_RECEIVE_MSG_TRUNC), 82418fb9442576c79fc2f4bca1fd90c3aa4d1115e97Al Viro (unsigned long) precv64); 8256a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (rc != 0) 8266a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return rc; 8276a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 8286a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (copy_from_user(&recv64, precv64, sizeof(recv64))) 8296a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 8306a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 8316a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton if (put_compat_ipmi_recv(&recv64, compat_ptr(arg))) 8326a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return -EFAULT; 8336a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton 8346a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton return rc; 8356a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton } 8366a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton default: 83755929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann return ipmi_ioctl(filep, cmd, arg); 8386a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton } 8396a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton} 8406a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#endif 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84262322d2554d2f9680c8ace7bbf1f97d8fa84ad1aArjan van de Venstatic const struct file_operations ipmi_fops = { 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 84455929332c92e5d34d65a8f784604c92677ea3e15Arnd Bergmann .unlocked_ioctl = ipmi_unlocked_ioctl, 8456a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#ifdef CONFIG_COMPAT 8466a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton .compat_ioctl = compat_ipmi_ioctl, 8476a94f9209762a6eb286f668e1346ad87985cc765Andrew Morton#endif 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = ipmi_open, 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = ipmi_release, 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fasync = ipmi_fasync, 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .poll = ipmi_poll, 8526038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = noop_llseek, 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEVICE_NAME "ipmidev" 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8570c8204b380f92a6a8533d228c50f0b681daf6121Randy Dunlapstatic int ipmi_major; 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(ipmi_major, int, 0); 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By" 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " default, or if you set it to zero, it will choose the next" 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " available device. Setting it to -1 will disable the" 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " interface. Other values will set the major device number" 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " to that value."); 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 86550c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard/* Keep track of the devices that are registered. */ 86650c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyardstruct ipmi_reg_list { 86750c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard dev_t dev; 86850c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard struct list_head link; 86950c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard}; 87050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyardstatic LIST_HEAD(reg_list); 87150c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyardstatic DEFINE_MUTEX(reg_list_mutex); 87250c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard 873eb51b65005737b777e0709683b061d5f82aefd97Andrew Mortonstatic struct class *ipmi_class; 87437e0915b701281182cea9fc90e894d10addf134aCorey Minyard 87550c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyardstatic void ipmi_new_smi(int if_num, struct device *device) 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 87737e0915b701281182cea9fc90e894d10addf134aCorey Minyard dev_t dev = MKDEV(ipmi_major, if_num); 87850c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard struct ipmi_reg_list *entry; 87937e0915b701281182cea9fc90e894d10addf134aCorey Minyard 88050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard entry = kmalloc(sizeof(*entry), GFP_KERNEL); 88150c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard if (!entry) { 88250c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard printk(KERN_ERR "ipmi_devintf: Unable to create the" 88350c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard " ipmi class device link\n"); 88450c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard return; 88550c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard } 88650c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard entry->dev = dev; 88750c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard 88850c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard mutex_lock(®_list_mutex); 88903457cd455d042c9ee4cc47c1ed4532257980693Greg Kroah-Hartman device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num); 89050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard list_add(&entry->link, ®_list); 89150c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard mutex_unlock(®_list_mutex); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ipmi_smi_gone(int if_num) 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 89650c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard dev_t dev = MKDEV(ipmi_major, if_num); 89750c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard struct ipmi_reg_list *entry; 89850c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard 89950c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard mutex_lock(®_list_mutex); 90050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard list_for_each_entry(entry, ®_list, link) { 90150c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard if (entry->dev == dev) { 90250c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard list_del(&entry->link); 90350c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard kfree(entry); 90450c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard break; 90550c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard } 90650c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard } 90707c015e7654821f2dda00dcf152c65b2afd46ac3tonyj@suse.de device_destroy(ipmi_class, dev); 90850c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard mutex_unlock(®_list_mutex); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ipmi_smi_watcher smi_watcher = 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .new_smi = ipmi_new_smi, 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .smi_gone = ipmi_smi_gone, 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91860ee6d5faf5f7920ba88b82c072864596f5b88afCorey Minyardstatic int __init init_ipmi_devintf(void) 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rv; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipmi_major < 0) 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9251fdd75bd6cfa60a54b6db91d9256a711ab52fef3Corey Minyard printk(KERN_INFO "ipmi device interface\n"); 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 927eb51b65005737b777e0709683b061d5f82aefd97Andrew Morton ipmi_class = class_create(THIS_MODULE, "ipmi"); 92837e0915b701281182cea9fc90e894d10addf134aCorey Minyard if (IS_ERR(ipmi_class)) { 92937e0915b701281182cea9fc90e894d10addf134aCorey Minyard printk(KERN_ERR "ipmi: can't register device class\n"); 93037e0915b701281182cea9fc90e894d10addf134aCorey Minyard return PTR_ERR(ipmi_class); 93137e0915b701281182cea9fc90e894d10addf134aCorey Minyard } 93237e0915b701281182cea9fc90e894d10addf134aCorey Minyard 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rv < 0) { 935eb51b65005737b777e0709683b061d5f82aefd97Andrew Morton class_destroy(ipmi_class); 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major); 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rv; 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ipmi_major == 0) { 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipmi_major = rv; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rv = ipmi_smi_watcher_register(&smi_watcher); 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rv) { 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev(ipmi_major, DEVICE_NAME); 947eb51b65005737b777e0709683b061d5f82aefd97Andrew Morton class_destroy(ipmi_class); 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "ipmi: can't register smi watcher\n"); 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rv; 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(init_ipmi_devintf); 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 95660ee6d5faf5f7920ba88b82c072864596f5b88afCorey Minyardstatic void __exit cleanup_ipmi(void) 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 95850c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard struct ipmi_reg_list *entry, *entry2; 95950c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard mutex_lock(®_list_mutex); 96050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard list_for_each_entry_safe(entry, entry2, ®_list, link) { 96150c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard list_del(&entry->link); 96207c015e7654821f2dda00dcf152c65b2afd46ac3tonyj@suse.de device_destroy(ipmi_class, entry->dev); 96350c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard kfree(entry); 96450c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard } 96550c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard mutex_unlock(®_list_mutex); 966eb51b65005737b777e0709683b061d5f82aefd97Andrew Morton class_destroy(ipmi_class); 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ipmi_smi_watcher_unregister(&smi_watcher); 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev(ipmi_major, DEVICE_NAME); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(cleanup_ipmi); 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 9731fdd75bd6cfa60a54b6db91d9256a711ab52fef3Corey MinyardMODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); 9741fdd75bd6cfa60a54b6db91d9256a711ab52fef3Corey MinyardMODULE_DESCRIPTION("Linux device interface for the IPMI message handler."); 9756c89161b10f5771ee0b51ada0fce0e8835e72adeScott James RemnantMODULE_ALIAS("platform:ipmi_si"); 976