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