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(&reg_list_mutex);
88903457cd455d042c9ee4cc47c1ed4532257980693Greg Kroah-Hartman	device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
89050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard	list_add(&entry->link, &reg_list);
89150c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard	mutex_unlock(&reg_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(&reg_list_mutex);
90050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard	list_for_each_entry(entry, &reg_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(&reg_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(&reg_list_mutex);
96050c812b2b9513e3df34eae8c30cb2c221b79b2cbCorey Minyard	list_for_each_entry_safe(entry, entry2, &reg_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(&reg_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