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