ipmi_devintf.c revision 780884144248cbb6945b191c9867741bb8c0ad35
1/*
2 * ipmi_devintf.c
3 *
4 * Linux device interface for the IPMI message handler.
5 *
6 * Author: MontaVista Software, Inc.
7 *         Corey Minyard <minyard@mvista.com>
8 *         source@mvista.com
9 *
10 * Copyright 2002 MontaVista Software Inc.
11 *
12 *  This program is free software; you can redistribute it and/or modify it
13 *  under the terms of the GNU General Public License as published by the
14 *  Free Software Foundation; either version 2 of the License, or (at your
15 *  option) any later version.
16 *
17 *
18 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 *  You should have received a copy of the GNU General Public License along
30 *  with this program; if not, write to the Free Software Foundation, Inc.,
31 *  675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33
34#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/errno.h>
37#include <asm/system.h>
38#include <linux/sched.h>
39#include <linux/poll.h>
40#include <linux/spinlock.h>
41#include <linux/slab.h>
42#include <linux/ipmi.h>
43#include <linux/mutex.h>
44#include <linux/init.h>
45#include <linux/device.h>
46#include <linux/compat.h>
47
48struct ipmi_file_private
49{
50	ipmi_user_t          user;
51	spinlock_t           recv_msg_lock;
52	struct list_head     recv_msgs;
53	struct file          *file;
54	struct fasync_struct *fasync_queue;
55	wait_queue_head_t    wait;
56	struct mutex	     recv_mutex;
57	int                  default_retries;
58	unsigned int         default_retry_time_ms;
59};
60
61static void file_receive_handler(struct ipmi_recv_msg *msg,
62				 void                 *handler_data)
63{
64	struct ipmi_file_private *priv = handler_data;
65	int                      was_empty;
66	unsigned long            flags;
67
68	spin_lock_irqsave(&(priv->recv_msg_lock), flags);
69
70	was_empty = list_empty(&(priv->recv_msgs));
71	list_add_tail(&(msg->link), &(priv->recv_msgs));
72
73	if (was_empty) {
74		wake_up_interruptible(&priv->wait);
75		kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
76	}
77
78	spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
79}
80
81static unsigned int ipmi_poll(struct file *file, poll_table *wait)
82{
83	struct ipmi_file_private *priv = file->private_data;
84	unsigned int             mask = 0;
85	unsigned long            flags;
86
87	poll_wait(file, &priv->wait, wait);
88
89	spin_lock_irqsave(&priv->recv_msg_lock, flags);
90
91	if (!list_empty(&(priv->recv_msgs)))
92		mask |= (POLLIN | POLLRDNORM);
93
94	spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
95
96	return mask;
97}
98
99static int ipmi_fasync(int fd, struct file *file, int on)
100{
101	struct ipmi_file_private *priv = file->private_data;
102	int                      result;
103
104	result = fasync_helper(fd, file, on, &priv->fasync_queue);
105
106	return (result);
107}
108
109static struct ipmi_user_hndl ipmi_hndlrs =
110{
111	.ipmi_recv_hndl	= file_receive_handler,
112};
113
114static int ipmi_open(struct inode *inode, struct file *file)
115{
116	int                      if_num = iminor(inode);
117	int                      rv;
118	struct ipmi_file_private *priv;
119
120
121	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
122	if (!priv)
123		return -ENOMEM;
124
125	priv->file = file;
126
127	rv = ipmi_create_user(if_num,
128			      &ipmi_hndlrs,
129			      priv,
130			      &(priv->user));
131	if (rv) {
132		kfree(priv);
133		return rv;
134	}
135
136	file->private_data = priv;
137
138	spin_lock_init(&(priv->recv_msg_lock));
139	INIT_LIST_HEAD(&(priv->recv_msgs));
140	init_waitqueue_head(&priv->wait);
141	priv->fasync_queue = NULL;
142	mutex_init(&priv->recv_mutex);
143
144	/* Use the low-level defaults. */
145	priv->default_retries = -1;
146	priv->default_retry_time_ms = 0;
147
148	return 0;
149}
150
151static int ipmi_release(struct inode *inode, struct file *file)
152{
153	struct ipmi_file_private *priv = file->private_data;
154	int                      rv;
155
156	rv = ipmi_destroy_user(priv->user);
157	if (rv)
158		return rv;
159
160	ipmi_fasync (-1, file, 0);
161
162	/* FIXME - free the messages in the list. */
163	kfree(priv);
164
165	return 0;
166}
167
168static int handle_send_req(ipmi_user_t     user,
169			   struct ipmi_req *req,
170			   int             retries,
171			   unsigned int    retry_time_ms)
172{
173	int              rv;
174	struct ipmi_addr addr;
175	struct kernel_ipmi_msg msg;
176
177	if (req->addr_len > sizeof(struct ipmi_addr))
178		return -EINVAL;
179
180	if (copy_from_user(&addr, req->addr, req->addr_len))
181		return -EFAULT;
182
183	msg.netfn = req->msg.netfn;
184	msg.cmd = req->msg.cmd;
185	msg.data_len = req->msg.data_len;
186	msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
187	if (!msg.data)
188		return -ENOMEM;
189
190	/* From here out we cannot return, we must jump to "out" for
191	   error exits to free msgdata. */
192
193	rv = ipmi_validate_addr(&addr, req->addr_len);
194	if (rv)
195		goto out;
196
197	if (req->msg.data != NULL) {
198		if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
199			rv = -EMSGSIZE;
200			goto out;
201		}
202
203		if (copy_from_user(msg.data,
204				   req->msg.data,
205				   req->msg.data_len))
206		{
207			rv = -EFAULT;
208			goto out;
209		}
210	} else {
211		msg.data_len = 0;
212	}
213
214	rv = ipmi_request_settime(user,
215				  &addr,
216				  req->msgid,
217				  &msg,
218				  NULL,
219				  0,
220				  retries,
221				  retry_time_ms);
222 out:
223	kfree(msg.data);
224	return rv;
225}
226
227static int ipmi_ioctl(struct inode  *inode,
228		      struct file   *file,
229		      unsigned int  cmd,
230		      unsigned long data)
231{
232	int                      rv = -EINVAL;
233	struct ipmi_file_private *priv = file->private_data;
234	void __user *arg = (void __user *)data;
235
236	switch (cmd)
237	{
238	case IPMICTL_SEND_COMMAND:
239	{
240		struct ipmi_req req;
241
242		if (copy_from_user(&req, arg, sizeof(req))) {
243			rv = -EFAULT;
244			break;
245		}
246
247		rv = handle_send_req(priv->user,
248				     &req,
249				     priv->default_retries,
250				     priv->default_retry_time_ms);
251		break;
252	}
253
254	case IPMICTL_SEND_COMMAND_SETTIME:
255	{
256		struct ipmi_req_settime req;
257
258		if (copy_from_user(&req, arg, sizeof(req))) {
259			rv = -EFAULT;
260			break;
261		}
262
263		rv = handle_send_req(priv->user,
264				     &req.req,
265				     req.retries,
266				     req.retry_time_ms);
267		break;
268	}
269
270	case IPMICTL_RECEIVE_MSG:
271	case IPMICTL_RECEIVE_MSG_TRUNC:
272	{
273		struct ipmi_recv      rsp;
274		int              addr_len;
275		struct list_head *entry;
276		struct ipmi_recv_msg  *msg;
277		unsigned long    flags;
278
279
280		rv = 0;
281		if (copy_from_user(&rsp, arg, sizeof(rsp))) {
282			rv = -EFAULT;
283			break;
284		}
285
286		/* We claim a mutex because we don't want two
287                   users getting something from the queue at a time.
288                   Since we have to release the spinlock before we can
289                   copy the data to the user, it's possible another
290                   user will grab something from the queue, too.  Then
291                   the messages might get out of order if something
292                   fails and the message gets put back onto the
293                   queue.  This mutex prevents that problem. */
294		mutex_lock(&priv->recv_mutex);
295
296		/* Grab the message off the list. */
297		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
298		if (list_empty(&(priv->recv_msgs))) {
299			spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
300			rv = -EAGAIN;
301			goto recv_err;
302		}
303		entry = priv->recv_msgs.next;
304		msg = list_entry(entry, struct ipmi_recv_msg, link);
305		list_del(entry);
306		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
307
308		addr_len = ipmi_addr_length(msg->addr.addr_type);
309		if (rsp.addr_len < addr_len)
310		{
311			rv = -EINVAL;
312			goto recv_putback_on_err;
313		}
314
315		if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
316			rv = -EFAULT;
317			goto recv_putback_on_err;
318		}
319		rsp.addr_len = addr_len;
320
321		rsp.recv_type = msg->recv_type;
322		rsp.msgid = msg->msgid;
323		rsp.msg.netfn = msg->msg.netfn;
324		rsp.msg.cmd = msg->msg.cmd;
325
326		if (msg->msg.data_len > 0) {
327			if (rsp.msg.data_len < msg->msg.data_len) {
328				rv = -EMSGSIZE;
329				if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
330					msg->msg.data_len = rsp.msg.data_len;
331				} else {
332					goto recv_putback_on_err;
333				}
334			}
335
336			if (copy_to_user(rsp.msg.data,
337					 msg->msg.data,
338					 msg->msg.data_len))
339			{
340				rv = -EFAULT;
341				goto recv_putback_on_err;
342			}
343			rsp.msg.data_len = msg->msg.data_len;
344		} else {
345			rsp.msg.data_len = 0;
346		}
347
348		if (copy_to_user(arg, &rsp, sizeof(rsp))) {
349			rv = -EFAULT;
350			goto recv_putback_on_err;
351		}
352
353		mutex_unlock(&priv->recv_mutex);
354		ipmi_free_recv_msg(msg);
355		break;
356
357	recv_putback_on_err:
358		/* If we got an error, put the message back onto
359		   the head of the queue. */
360		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
361		list_add(entry, &(priv->recv_msgs));
362		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
363		mutex_unlock(&priv->recv_mutex);
364		break;
365
366	recv_err:
367		mutex_unlock(&priv->recv_mutex);
368		break;
369	}
370
371	case IPMICTL_REGISTER_FOR_CMD:
372	{
373		struct ipmi_cmdspec val;
374
375		if (copy_from_user(&val, arg, sizeof(val))) {
376			rv = -EFAULT;
377			break;
378		}
379
380		rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
381					   IPMI_CHAN_ALL);
382		break;
383	}
384
385	case IPMICTL_UNREGISTER_FOR_CMD:
386	{
387		struct ipmi_cmdspec   val;
388
389		if (copy_from_user(&val, arg, sizeof(val))) {
390			rv = -EFAULT;
391			break;
392		}
393
394		rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
395					     IPMI_CHAN_ALL);
396		break;
397	}
398
399	case IPMICTL_REGISTER_FOR_CMD_CHANS:
400	{
401		struct ipmi_cmdspec_chans val;
402
403		if (copy_from_user(&val, arg, sizeof(val))) {
404			rv = -EFAULT;
405			break;
406		}
407
408		rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
409					   val.chans);
410		break;
411	}
412
413	case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
414	{
415		struct ipmi_cmdspec_chans val;
416
417		if (copy_from_user(&val, arg, sizeof(val))) {
418			rv = -EFAULT;
419			break;
420		}
421
422		rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
423					     val.chans);
424		break;
425	}
426
427	case IPMICTL_SET_GETS_EVENTS_CMD:
428	{
429		int val;
430
431		if (copy_from_user(&val, arg, sizeof(val))) {
432			rv = -EFAULT;
433			break;
434		}
435
436		rv = ipmi_set_gets_events(priv->user, val);
437		break;
438	}
439
440	/* The next four are legacy, not per-channel. */
441	case IPMICTL_SET_MY_ADDRESS_CMD:
442	{
443		unsigned int val;
444
445		if (copy_from_user(&val, arg, sizeof(val))) {
446			rv = -EFAULT;
447			break;
448		}
449
450		rv = ipmi_set_my_address(priv->user, 0, val);
451		break;
452	}
453
454	case IPMICTL_GET_MY_ADDRESS_CMD:
455	{
456		unsigned int  val;
457		unsigned char rval;
458
459		rv = ipmi_get_my_address(priv->user, 0, &rval);
460		if (rv)
461			break;
462
463		val = rval;
464
465		if (copy_to_user(arg, &val, sizeof(val))) {
466			rv = -EFAULT;
467			break;
468		}
469		break;
470	}
471
472	case IPMICTL_SET_MY_LUN_CMD:
473	{
474		unsigned int val;
475
476		if (copy_from_user(&val, arg, sizeof(val))) {
477			rv = -EFAULT;
478			break;
479		}
480
481		rv = ipmi_set_my_LUN(priv->user, 0, val);
482		break;
483	}
484
485	case IPMICTL_GET_MY_LUN_CMD:
486	{
487		unsigned int  val;
488		unsigned char rval;
489
490		rv = ipmi_get_my_LUN(priv->user, 0, &rval);
491		if (rv)
492			break;
493
494		val = rval;
495
496		if (copy_to_user(arg, &val, sizeof(val))) {
497			rv = -EFAULT;
498			break;
499		}
500		break;
501	}
502
503	case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
504	{
505		struct ipmi_channel_lun_address_set val;
506
507		if (copy_from_user(&val, arg, sizeof(val))) {
508			rv = -EFAULT;
509			break;
510		}
511
512		return ipmi_set_my_address(priv->user, val.channel, val.value);
513		break;
514	}
515
516	case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
517	{
518		struct ipmi_channel_lun_address_set val;
519
520		if (copy_from_user(&val, arg, sizeof(val))) {
521			rv = -EFAULT;
522			break;
523		}
524
525		rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
526		if (rv)
527			break;
528
529		if (copy_to_user(arg, &val, sizeof(val))) {
530			rv = -EFAULT;
531			break;
532		}
533		break;
534	}
535
536	case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
537	{
538		struct ipmi_channel_lun_address_set val;
539
540		if (copy_from_user(&val, arg, sizeof(val))) {
541			rv = -EFAULT;
542			break;
543		}
544
545		rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
546		break;
547	}
548
549	case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
550	{
551		struct ipmi_channel_lun_address_set val;
552
553		if (copy_from_user(&val, arg, sizeof(val))) {
554			rv = -EFAULT;
555			break;
556		}
557
558		rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
559		if (rv)
560			break;
561
562		if (copy_to_user(arg, &val, sizeof(val))) {
563			rv = -EFAULT;
564			break;
565		}
566		break;
567	}
568
569	case IPMICTL_SET_TIMING_PARMS_CMD:
570	{
571		struct ipmi_timing_parms parms;
572
573		if (copy_from_user(&parms, arg, sizeof(parms))) {
574			rv = -EFAULT;
575			break;
576		}
577
578		priv->default_retries = parms.retries;
579		priv->default_retry_time_ms = parms.retry_time_ms;
580		rv = 0;
581		break;
582	}
583
584	case IPMICTL_GET_TIMING_PARMS_CMD:
585	{
586		struct ipmi_timing_parms parms;
587
588		parms.retries = priv->default_retries;
589		parms.retry_time_ms = priv->default_retry_time_ms;
590
591		if (copy_to_user(arg, &parms, sizeof(parms))) {
592			rv = -EFAULT;
593			break;
594		}
595
596		rv = 0;
597		break;
598	}
599
600	case IPMICTL_GET_MAINTENANCE_MODE_CMD:
601	{
602		int mode;
603
604		mode = ipmi_get_maintenance_mode(priv->user);
605		if (copy_to_user(arg, &mode, sizeof(mode))) {
606			rv = -EFAULT;
607			break;
608		}
609		rv = 0;
610		break;
611	}
612
613	case IPMICTL_SET_MAINTENANCE_MODE_CMD:
614	{
615		int mode;
616
617		if (copy_from_user(&mode, arg, sizeof(mode))) {
618			rv = -EFAULT;
619			break;
620		}
621		rv = ipmi_set_maintenance_mode(priv->user, mode);
622		break;
623	}
624	}
625
626	return rv;
627}
628
629#ifdef CONFIG_COMPAT
630
631/*
632 * The following code contains code for supporting 32-bit compatible
633 * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
634 * 64-bit kernel
635 */
636#define COMPAT_IPMICTL_SEND_COMMAND	\
637	_IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
638#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME	\
639	_IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
640#define COMPAT_IPMICTL_RECEIVE_MSG	\
641	_IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
642#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC	\
643	_IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
644
645struct compat_ipmi_msg {
646	u8		netfn;
647	u8		cmd;
648	u16		data_len;
649	compat_uptr_t	data;
650};
651
652struct compat_ipmi_req {
653	compat_uptr_t		addr;
654	compat_uint_t		addr_len;
655	compat_long_t		msgid;
656	struct compat_ipmi_msg	msg;
657};
658
659struct compat_ipmi_recv {
660	compat_int_t		recv_type;
661	compat_uptr_t		addr;
662	compat_uint_t		addr_len;
663	compat_long_t		msgid;
664	struct compat_ipmi_msg	msg;
665};
666
667struct compat_ipmi_req_settime {
668	struct compat_ipmi_req	req;
669	compat_int_t		retries;
670	compat_uint_t		retry_time_ms;
671};
672
673/*
674 * Define some helper functions for copying IPMI data
675 */
676static long get_compat_ipmi_msg(struct ipmi_msg *p64,
677				struct compat_ipmi_msg __user *p32)
678{
679	compat_uptr_t tmp;
680
681	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
682			__get_user(p64->netfn, &p32->netfn) ||
683			__get_user(p64->cmd, &p32->cmd) ||
684			__get_user(p64->data_len, &p32->data_len) ||
685			__get_user(tmp, &p32->data))
686		return -EFAULT;
687	p64->data = compat_ptr(tmp);
688	return 0;
689}
690
691static long put_compat_ipmi_msg(struct ipmi_msg *p64,
692				struct compat_ipmi_msg __user *p32)
693{
694	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
695			__put_user(p64->netfn, &p32->netfn) ||
696			__put_user(p64->cmd, &p32->cmd) ||
697			__put_user(p64->data_len, &p32->data_len))
698		return -EFAULT;
699	return 0;
700}
701
702static long get_compat_ipmi_req(struct ipmi_req *p64,
703				struct compat_ipmi_req __user *p32)
704{
705
706	compat_uptr_t	tmp;
707
708	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
709			__get_user(tmp, &p32->addr) ||
710			__get_user(p64->addr_len, &p32->addr_len) ||
711			__get_user(p64->msgid, &p32->msgid) ||
712			get_compat_ipmi_msg(&p64->msg, &p32->msg))
713		return -EFAULT;
714	p64->addr = compat_ptr(tmp);
715	return 0;
716}
717
718static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
719		struct compat_ipmi_req_settime __user *p32)
720{
721	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
722			get_compat_ipmi_req(&p64->req, &p32->req) ||
723			__get_user(p64->retries, &p32->retries) ||
724			__get_user(p64->retry_time_ms, &p32->retry_time_ms))
725		return -EFAULT;
726	return 0;
727}
728
729static long get_compat_ipmi_recv(struct ipmi_recv *p64,
730				 struct compat_ipmi_recv __user *p32)
731{
732	compat_uptr_t tmp;
733
734	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
735			__get_user(p64->recv_type, &p32->recv_type) ||
736			__get_user(tmp, &p32->addr) ||
737			__get_user(p64->addr_len, &p32->addr_len) ||
738			__get_user(p64->msgid, &p32->msgid) ||
739			get_compat_ipmi_msg(&p64->msg, &p32->msg))
740		return -EFAULT;
741	p64->addr = compat_ptr(tmp);
742	return 0;
743}
744
745static long put_compat_ipmi_recv(struct ipmi_recv *p64,
746				 struct compat_ipmi_recv __user *p32)
747{
748	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
749			__put_user(p64->recv_type, &p32->recv_type) ||
750			__put_user(p64->addr_len, &p32->addr_len) ||
751			__put_user(p64->msgid, &p32->msgid) ||
752			put_compat_ipmi_msg(&p64->msg, &p32->msg))
753		return -EFAULT;
754	return 0;
755}
756
757/*
758 * Handle compatibility ioctls
759 */
760static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
761			      unsigned long arg)
762{
763	int rc;
764	struct ipmi_file_private *priv = filep->private_data;
765
766	switch(cmd) {
767	case COMPAT_IPMICTL_SEND_COMMAND:
768	{
769		struct ipmi_req	rp;
770
771		if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
772			return -EFAULT;
773
774		return handle_send_req(priv->user, &rp,
775				priv->default_retries,
776				priv->default_retry_time_ms);
777	}
778	case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
779	{
780		struct ipmi_req_settime	sp;
781
782		if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
783			return -EFAULT;
784
785		return handle_send_req(priv->user, &sp.req,
786				sp.retries, sp.retry_time_ms);
787	}
788	case COMPAT_IPMICTL_RECEIVE_MSG:
789	case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
790	{
791		struct ipmi_recv   __user *precv64;
792		struct ipmi_recv   recv64;
793
794		if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
795			return -EFAULT;
796
797		precv64 = compat_alloc_user_space(sizeof(recv64));
798		if (copy_to_user(precv64, &recv64, sizeof(recv64)))
799			return -EFAULT;
800
801		rc = ipmi_ioctl(filep->f_path.dentry->d_inode, filep,
802				((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
803				 ? IPMICTL_RECEIVE_MSG
804				 : IPMICTL_RECEIVE_MSG_TRUNC),
805				(unsigned long) precv64);
806		if (rc != 0)
807			return rc;
808
809		if (copy_from_user(&recv64, precv64, sizeof(recv64)))
810			return -EFAULT;
811
812		if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
813			return -EFAULT;
814
815		return rc;
816	}
817	default:
818		return ipmi_ioctl(filep->f_path.dentry->d_inode, filep, cmd, arg);
819	}
820}
821#endif
822
823static const struct file_operations ipmi_fops = {
824	.owner		= THIS_MODULE,
825	.ioctl		= ipmi_ioctl,
826#ifdef CONFIG_COMPAT
827	.compat_ioctl   = compat_ipmi_ioctl,
828#endif
829	.open		= ipmi_open,
830	.release	= ipmi_release,
831	.fasync		= ipmi_fasync,
832	.poll		= ipmi_poll,
833};
834
835#define DEVICE_NAME     "ipmidev"
836
837static int ipmi_major = 0;
838module_param(ipmi_major, int, 0);
839MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
840		 " default, or if you set it to zero, it will choose the next"
841		 " available device.  Setting it to -1 will disable the"
842		 " interface.  Other values will set the major device number"
843		 " to that value.");
844
845/* Keep track of the devices that are registered. */
846struct ipmi_reg_list {
847	dev_t            dev;
848	struct list_head link;
849};
850static LIST_HEAD(reg_list);
851static DEFINE_MUTEX(reg_list_mutex);
852
853static struct class *ipmi_class;
854
855static void ipmi_new_smi(int if_num, struct device *device)
856{
857	dev_t dev = MKDEV(ipmi_major, if_num);
858	struct ipmi_reg_list *entry;
859
860	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
861	if (!entry) {
862		printk(KERN_ERR "ipmi_devintf: Unable to create the"
863		       " ipmi class device link\n");
864		return;
865	}
866	entry->dev = dev;
867
868	mutex_lock(&reg_list_mutex);
869	class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
870	list_add(&entry->link, &reg_list);
871	mutex_unlock(&reg_list_mutex);
872}
873
874static void ipmi_smi_gone(int if_num)
875{
876	dev_t dev = MKDEV(ipmi_major, if_num);
877	struct ipmi_reg_list *entry;
878
879	mutex_lock(&reg_list_mutex);
880	list_for_each_entry(entry, &reg_list, link) {
881		if (entry->dev == dev) {
882			list_del(&entry->link);
883			kfree(entry);
884			break;
885		}
886	}
887	class_device_destroy(ipmi_class, dev);
888	mutex_unlock(&reg_list_mutex);
889}
890
891static struct ipmi_smi_watcher smi_watcher =
892{
893	.owner    = THIS_MODULE,
894	.new_smi  = ipmi_new_smi,
895	.smi_gone = ipmi_smi_gone,
896};
897
898static __init int init_ipmi_devintf(void)
899{
900	int rv;
901
902	if (ipmi_major < 0)
903		return -EINVAL;
904
905	printk(KERN_INFO "ipmi device interface\n");
906
907	ipmi_class = class_create(THIS_MODULE, "ipmi");
908	if (IS_ERR(ipmi_class)) {
909		printk(KERN_ERR "ipmi: can't register device class\n");
910		return PTR_ERR(ipmi_class);
911	}
912
913	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
914	if (rv < 0) {
915		class_destroy(ipmi_class);
916		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
917		return rv;
918	}
919
920	if (ipmi_major == 0) {
921		ipmi_major = rv;
922	}
923
924	rv = ipmi_smi_watcher_register(&smi_watcher);
925	if (rv) {
926		unregister_chrdev(ipmi_major, DEVICE_NAME);
927		class_destroy(ipmi_class);
928		printk(KERN_WARNING "ipmi: can't register smi watcher\n");
929		return rv;
930	}
931
932	return 0;
933}
934module_init(init_ipmi_devintf);
935
936static __exit void cleanup_ipmi(void)
937{
938	struct ipmi_reg_list *entry, *entry2;
939	mutex_lock(&reg_list_mutex);
940	list_for_each_entry_safe(entry, entry2, &reg_list, link) {
941		list_del(&entry->link);
942		class_device_destroy(ipmi_class, entry->dev);
943		kfree(entry);
944	}
945	mutex_unlock(&reg_list_mutex);
946	class_destroy(ipmi_class);
947	ipmi_smi_watcher_unregister(&smi_watcher);
948	unregister_chrdev(ipmi_major, DEVICE_NAME);
949}
950module_exit(cleanup_ipmi);
951
952MODULE_LICENSE("GPL");
953MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
954MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
955