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