Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/cpufreq
[linux-2.6] / drivers / char / ipmi / ipmi_devintf.c
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
48 struct 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
61 static 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
81 static 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
99 static 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
109 static struct ipmi_user_hndl ipmi_hndlrs =
110 {
111         .ipmi_recv_hndl = file_receive_handler,
112 };
113
114 static 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
151 static 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
168 static 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
227 static 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   
601         return rv;
602 }
603
604 #ifdef CONFIG_COMPAT
605
606 /*
607  * The following code contains code for supporting 32-bit compatible
608  * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
609  * 64-bit kernel
610  */
611 #define COMPAT_IPMICTL_SEND_COMMAND     \
612         _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
613 #define COMPAT_IPMICTL_SEND_COMMAND_SETTIME     \
614         _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
615 #define COMPAT_IPMICTL_RECEIVE_MSG      \
616         _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
617 #define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC        \
618         _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
619
620 struct compat_ipmi_msg {
621         u8              netfn;
622         u8              cmd;
623         u16             data_len;
624         compat_uptr_t   data;
625 };
626
627 struct compat_ipmi_req {
628         compat_uptr_t           addr;
629         compat_uint_t           addr_len;
630         compat_long_t           msgid;
631         struct compat_ipmi_msg  msg;
632 };
633
634 struct compat_ipmi_recv {
635         compat_int_t            recv_type;
636         compat_uptr_t           addr;
637         compat_uint_t           addr_len;
638         compat_long_t           msgid;
639         struct compat_ipmi_msg  msg;
640 };
641
642 struct compat_ipmi_req_settime {
643         struct compat_ipmi_req  req;
644         compat_int_t            retries;
645         compat_uint_t           retry_time_ms;
646 };
647
648 /*
649  * Define some helper functions for copying IPMI data
650  */
651 static long get_compat_ipmi_msg(struct ipmi_msg *p64,
652                                 struct compat_ipmi_msg __user *p32)
653 {
654         compat_uptr_t tmp;
655
656         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
657                         __get_user(p64->netfn, &p32->netfn) ||
658                         __get_user(p64->cmd, &p32->cmd) ||
659                         __get_user(p64->data_len, &p32->data_len) ||
660                         __get_user(tmp, &p32->data))
661                 return -EFAULT;
662         p64->data = compat_ptr(tmp);
663         return 0;
664 }
665
666 static long put_compat_ipmi_msg(struct ipmi_msg *p64,
667                                 struct compat_ipmi_msg __user *p32)
668 {
669         if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
670                         __put_user(p64->netfn, &p32->netfn) ||
671                         __put_user(p64->cmd, &p32->cmd) ||
672                         __put_user(p64->data_len, &p32->data_len))
673                 return -EFAULT;
674         return 0;
675 }
676
677 static long get_compat_ipmi_req(struct ipmi_req *p64,
678                                 struct compat_ipmi_req __user *p32)
679 {
680
681         compat_uptr_t   tmp;
682
683         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
684                         __get_user(tmp, &p32->addr) ||
685                         __get_user(p64->addr_len, &p32->addr_len) ||
686                         __get_user(p64->msgid, &p32->msgid) ||
687                         get_compat_ipmi_msg(&p64->msg, &p32->msg))
688                 return -EFAULT;
689         p64->addr = compat_ptr(tmp);
690         return 0;
691 }
692
693 static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
694                 struct compat_ipmi_req_settime __user *p32)
695 {
696         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
697                         get_compat_ipmi_req(&p64->req, &p32->req) ||
698                         __get_user(p64->retries, &p32->retries) ||
699                         __get_user(p64->retry_time_ms, &p32->retry_time_ms))
700                 return -EFAULT;
701         return 0;
702 }
703
704 static long get_compat_ipmi_recv(struct ipmi_recv *p64,
705                                  struct compat_ipmi_recv __user *p32)
706 {
707         compat_uptr_t tmp;
708
709         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
710                         __get_user(p64->recv_type, &p32->recv_type) ||
711                         __get_user(tmp, &p32->addr) ||
712                         __get_user(p64->addr_len, &p32->addr_len) ||
713                         __get_user(p64->msgid, &p32->msgid) ||
714                         get_compat_ipmi_msg(&p64->msg, &p32->msg))
715                 return -EFAULT;
716         p64->addr = compat_ptr(tmp);
717         return 0;
718 }
719
720 static long put_compat_ipmi_recv(struct ipmi_recv *p64,
721                                  struct compat_ipmi_recv __user *p32)
722 {
723         if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
724                         __put_user(p64->recv_type, &p32->recv_type) ||
725                         __put_user(p64->addr_len, &p32->addr_len) ||
726                         __put_user(p64->msgid, &p32->msgid) ||
727                         put_compat_ipmi_msg(&p64->msg, &p32->msg))
728                 return -EFAULT;
729         return 0;
730 }
731
732 /*
733  * Handle compatibility ioctls
734  */
735 static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
736                               unsigned long arg)
737 {
738         int rc;
739         struct ipmi_file_private *priv = filep->private_data;
740
741         switch(cmd) {
742         case COMPAT_IPMICTL_SEND_COMMAND:
743         {
744                 struct ipmi_req rp;
745
746                 if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
747                         return -EFAULT;
748
749                 return handle_send_req(priv->user, &rp,
750                                 priv->default_retries,
751                                 priv->default_retry_time_ms);
752         }
753         case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
754         {
755                 struct ipmi_req_settime sp;
756
757                 if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
758                         return -EFAULT;
759
760                 return handle_send_req(priv->user, &sp.req,
761                                 sp.retries, sp.retry_time_ms);
762         }
763         case COMPAT_IPMICTL_RECEIVE_MSG:
764         case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
765         {
766                 struct ipmi_recv   __user *precv64;
767                 struct ipmi_recv   recv64;
768
769                 if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
770                         return -EFAULT;
771
772                 precv64 = compat_alloc_user_space(sizeof(recv64));
773                 if (copy_to_user(precv64, &recv64, sizeof(recv64)))
774                         return -EFAULT;
775
776                 rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
777                                 ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
778                                  ? IPMICTL_RECEIVE_MSG
779                                  : IPMICTL_RECEIVE_MSG_TRUNC),
780                                 (unsigned long) precv64);
781                 if (rc != 0)
782                         return rc;
783
784                 if (copy_from_user(&recv64, precv64, sizeof(recv64)))
785                         return -EFAULT;
786
787                 if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
788                         return -EFAULT;
789
790                 return rc;
791         }
792         default:
793                 return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
794         }
795 }
796 #endif
797
798 static const struct file_operations ipmi_fops = {
799         .owner          = THIS_MODULE,
800         .ioctl          = ipmi_ioctl,
801 #ifdef CONFIG_COMPAT
802         .compat_ioctl   = compat_ipmi_ioctl,
803 #endif
804         .open           = ipmi_open,
805         .release        = ipmi_release,
806         .fasync         = ipmi_fasync,
807         .poll           = ipmi_poll,
808 };
809
810 #define DEVICE_NAME     "ipmidev"
811
812 static int ipmi_major = 0;
813 module_param(ipmi_major, int, 0);
814 MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
815                  " default, or if you set it to zero, it will choose the next"
816                  " available device.  Setting it to -1 will disable the"
817                  " interface.  Other values will set the major device number"
818                  " to that value.");
819
820 /* Keep track of the devices that are registered. */
821 struct ipmi_reg_list {
822         dev_t            dev;
823         struct list_head link;
824 };
825 static LIST_HEAD(reg_list);
826 static DEFINE_MUTEX(reg_list_mutex);
827
828 static struct class *ipmi_class;
829
830 static void ipmi_new_smi(int if_num, struct device *device)
831 {
832         dev_t dev = MKDEV(ipmi_major, if_num);
833         struct ipmi_reg_list *entry;
834
835         entry = kmalloc(sizeof(*entry), GFP_KERNEL);
836         if (!entry) {
837                 printk(KERN_ERR "ipmi_devintf: Unable to create the"
838                        " ipmi class device link\n");
839                 return;
840         }
841         entry->dev = dev;
842
843         mutex_lock(&reg_list_mutex);
844         class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
845         list_add(&entry->link, &reg_list);
846         mutex_unlock(&reg_list_mutex);
847 }
848
849 static void ipmi_smi_gone(int if_num)
850 {
851         dev_t dev = MKDEV(ipmi_major, if_num);
852         struct ipmi_reg_list *entry;
853
854         mutex_lock(&reg_list_mutex);
855         list_for_each_entry(entry, &reg_list, link) {
856                 if (entry->dev == dev) {
857                         list_del(&entry->link);
858                         kfree(entry);
859                         break;
860                 }
861         }
862         class_device_destroy(ipmi_class, dev);
863         mutex_unlock(&reg_list_mutex);
864 }
865
866 static struct ipmi_smi_watcher smi_watcher =
867 {
868         .owner    = THIS_MODULE,
869         .new_smi  = ipmi_new_smi,
870         .smi_gone = ipmi_smi_gone,
871 };
872
873 static __init int init_ipmi_devintf(void)
874 {
875         int rv;
876
877         if (ipmi_major < 0)
878                 return -EINVAL;
879
880         printk(KERN_INFO "ipmi device interface\n");
881
882         ipmi_class = class_create(THIS_MODULE, "ipmi");
883         if (IS_ERR(ipmi_class)) {
884                 printk(KERN_ERR "ipmi: can't register device class\n");
885                 return PTR_ERR(ipmi_class);
886         }
887
888         rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
889         if (rv < 0) {
890                 class_destroy(ipmi_class);
891                 printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
892                 return rv;
893         }
894
895         if (ipmi_major == 0) {
896                 ipmi_major = rv;
897         }
898
899         rv = ipmi_smi_watcher_register(&smi_watcher);
900         if (rv) {
901                 unregister_chrdev(ipmi_major, DEVICE_NAME);
902                 class_destroy(ipmi_class);
903                 printk(KERN_WARNING "ipmi: can't register smi watcher\n");
904                 return rv;
905         }
906
907         return 0;
908 }
909 module_init(init_ipmi_devintf);
910
911 static __exit void cleanup_ipmi(void)
912 {
913         struct ipmi_reg_list *entry, *entry2;
914         mutex_lock(&reg_list_mutex);
915         list_for_each_entry_safe(entry, entry2, &reg_list, link) {
916                 list_del(&entry->link);
917                 class_device_destroy(ipmi_class, entry->dev);
918                 kfree(entry);
919         }
920         mutex_unlock(&reg_list_mutex);
921         class_destroy(ipmi_class);
922         ipmi_smi_watcher_unregister(&smi_watcher);
923         unregister_chrdev(ipmi_major, DEVICE_NAME);
924 }
925 module_exit(cleanup_ipmi);
926
927 MODULE_LICENSE("GPL");
928 MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
929 MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");