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