This commit was manufactured by cvs2svn to create tag
[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
48 #define IPMI_DEVINTF_VERSION "v32"
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         unsigned char    *msgdata;
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         msgdata = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
186         if (!msgdata)
187                 return -ENOMEM;
188
189         /* From here out we cannot return, we must jump to "out" for
190            error exits to free msgdata. */
191
192         rv = ipmi_validate_addr(&addr, req->addr_len);
193         if (rv)
194                 goto out;
195
196         if (req->msg.data != NULL) {
197                 if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
198                         rv = -EMSGSIZE;
199                         goto out;
200                 }
201
202                 if (copy_from_user(msgdata,
203                                    req->msg.data,
204                                    req->msg.data_len))
205                 {
206                         rv = -EFAULT;
207                         goto out;
208                 }
209         } else {
210                 req->msg.data_len = 0;
211         }
212         req->msg.data = msgdata;
213
214         rv = ipmi_request_settime(user,
215                                   &addr,
216                                   req->msgid,
217                                   &(req->msg),
218                                   NULL,
219                                   0,
220                                   retries,
221                                   retry_time_ms);
222  out:
223         kfree(msgdata);
224         return rv;
225 }
226
227 static int ipmi_ioctl(struct inode  *inode,
228                       struct file   *file,
229                       unsigned int  cmd,
230                       unsigned long data)
231 {
232         int                      rv = -EINVAL;
233         struct ipmi_file_private *priv = file->private_data;
234         void __user *arg = (void __user *)data;
235
236         switch (cmd) 
237         {
238         case IPMICTL_SEND_COMMAND:
239         {
240                 struct ipmi_req req;
241
242                 if (copy_from_user(&req, arg, sizeof(req))) {
243                         rv = -EFAULT;
244                         break;
245                 }
246
247                 rv = handle_send_req(priv->user,
248                                      &req,
249                                      priv->default_retries,
250                                      priv->default_retry_time_ms);
251                 break;
252         }
253
254         case IPMICTL_SEND_COMMAND_SETTIME:
255         {
256                 struct ipmi_req_settime req;
257
258                 if (copy_from_user(&req, arg, sizeof(req))) {
259                         rv = -EFAULT;
260                         break;
261                 }
262
263                 rv = handle_send_req(priv->user,
264                                      &req.req,
265                                      req.retries,
266                                      req.retry_time_ms);
267                 break;
268         }
269
270         case IPMICTL_RECEIVE_MSG:
271         case IPMICTL_RECEIVE_MSG_TRUNC:
272         {
273                 struct ipmi_recv      rsp;
274                 int              addr_len;
275                 struct list_head *entry;
276                 struct ipmi_recv_msg  *msg;
277                 unsigned long    flags;
278                 
279
280                 rv = 0;
281                 if (copy_from_user(&rsp, arg, sizeof(rsp))) {
282                         rv = -EFAULT;
283                         break;
284                 }
285
286                 /* We claim a semaphore because we don't want two
287                    users getting something from the queue at a time.
288                    Since we have to release the spinlock before we can
289                    copy the data to the user, it's possible another
290                    user will grab something from the queue, too.  Then
291                    the messages might get out of order if something
292                    fails and the message gets put back onto the
293                    queue.  This semaphore prevents that problem. */
294                 down(&(priv->recv_sem));
295
296                 /* Grab the message off the list. */
297                 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
298                 if (list_empty(&(priv->recv_msgs))) {
299                         spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
300                         rv = -EAGAIN;
301                         goto recv_err;
302                 }
303                 entry = priv->recv_msgs.next;
304                 msg = list_entry(entry, struct ipmi_recv_msg, link);
305                 list_del(entry);
306                 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
307
308                 addr_len = ipmi_addr_length(msg->addr.addr_type);
309                 if (rsp.addr_len < addr_len)
310                 {
311                         rv = -EINVAL;
312                         goto recv_putback_on_err;
313                 }
314
315                 if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
316                         rv = -EFAULT;
317                         goto recv_putback_on_err;
318                 }
319                 rsp.addr_len = addr_len;
320
321                 rsp.recv_type = msg->recv_type;
322                 rsp.msgid = msg->msgid;
323                 rsp.msg.netfn = msg->msg.netfn;
324                 rsp.msg.cmd = msg->msg.cmd;
325
326                 if (msg->msg.data_len > 0) {
327                         if (rsp.msg.data_len < msg->msg.data_len) {
328                                 rv = -EMSGSIZE;
329                                 if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
330                                         msg->msg.data_len = rsp.msg.data_len;
331                                 } else {
332                                         goto recv_putback_on_err;
333                                 }
334                         }
335
336                         if (copy_to_user(rsp.msg.data,
337                                          msg->msg.data,
338                                          msg->msg.data_len))
339                         {
340                                 rv = -EFAULT;
341                                 goto recv_putback_on_err;
342                         }
343                         rsp.msg.data_len = msg->msg.data_len;
344                 } else {
345                         rsp.msg.data_len = 0;
346                 }
347
348                 if (copy_to_user(arg, &rsp, sizeof(rsp))) {
349                         rv = -EFAULT;
350                         goto recv_putback_on_err;
351                 }
352
353                 up(&(priv->recv_sem));
354                 ipmi_free_recv_msg(msg);
355                 break;
356
357         recv_putback_on_err:
358                 /* If we got an error, put the message back onto
359                    the head of the queue. */
360                 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
361                 list_add(entry, &(priv->recv_msgs));
362                 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
363                 up(&(priv->recv_sem));
364                 break;
365
366         recv_err:
367                 up(&(priv->recv_sem));
368                 break;
369         }
370
371         case IPMICTL_REGISTER_FOR_CMD:
372         {
373                 struct ipmi_cmdspec val;
374
375                 if (copy_from_user(&val, arg, sizeof(val))) {
376                         rv = -EFAULT;
377                         break;
378                 }
379
380                 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd);
381                 break;
382         }
383
384         case IPMICTL_UNREGISTER_FOR_CMD:
385         {
386                 struct ipmi_cmdspec   val;
387
388                 if (copy_from_user(&val, arg, sizeof(val))) {
389                         rv = -EFAULT;
390                         break;
391                 }
392
393                 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd);
394                 break;
395         }
396
397         case IPMICTL_SET_GETS_EVENTS_CMD:
398         {
399                 int val;
400
401                 if (copy_from_user(&val, arg, sizeof(val))) {
402                         rv = -EFAULT;
403                         break;
404                 }
405
406                 rv = ipmi_set_gets_events(priv->user, val);
407                 break;
408         }
409
410         case IPMICTL_SET_MY_ADDRESS_CMD:
411         {
412                 unsigned int val;
413
414                 if (copy_from_user(&val, arg, sizeof(val))) {
415                         rv = -EFAULT;
416                         break;
417                 }
418
419                 ipmi_set_my_address(priv->user, val);
420                 rv = 0;
421                 break;
422         }
423
424         case IPMICTL_GET_MY_ADDRESS_CMD:
425         {
426                 unsigned int val;
427
428                 val = ipmi_get_my_address(priv->user);
429
430                 if (copy_to_user(arg, &val, sizeof(val))) {
431                         rv = -EFAULT;
432                         break;
433                 }
434                 rv = 0;
435                 break;
436         }
437
438         case IPMICTL_SET_MY_LUN_CMD:
439         {
440                 unsigned int val;
441
442                 if (copy_from_user(&val, arg, sizeof(val))) {
443                         rv = -EFAULT;
444                         break;
445                 }
446
447                 ipmi_set_my_LUN(priv->user, val);
448                 rv = 0;
449                 break;
450         }
451
452         case IPMICTL_GET_MY_LUN_CMD:
453         {
454                 unsigned int val;
455
456                 val = ipmi_get_my_LUN(priv->user);
457
458                 if (copy_to_user(arg, &val, sizeof(val))) {
459                         rv = -EFAULT;
460                         break;
461                 }
462                 rv = 0;
463                 break;
464         }
465         case IPMICTL_SET_TIMING_PARMS_CMD:
466         {
467                 struct ipmi_timing_parms parms;
468
469                 if (copy_from_user(&parms, arg, sizeof(parms))) {
470                         rv = -EFAULT;
471                         break;
472                 }
473
474                 priv->default_retries = parms.retries;
475                 priv->default_retry_time_ms = parms.retry_time_ms;
476                 rv = 0;
477                 break;
478         }
479
480         case IPMICTL_GET_TIMING_PARMS_CMD:
481         {
482                 struct ipmi_timing_parms parms;
483
484                 parms.retries = priv->default_retries;
485                 parms.retry_time_ms = priv->default_retry_time_ms;
486
487                 if (copy_to_user(arg, &parms, sizeof(parms))) {
488                         rv = -EFAULT;
489                         break;
490                 }
491
492                 rv = 0;
493                 break;
494         }
495         }
496   
497         return rv;
498 }
499
500
501 static struct file_operations ipmi_fops = {
502         .owner          = THIS_MODULE,
503         .ioctl          = ipmi_ioctl,
504         .open           = ipmi_open,
505         .release        = ipmi_release,
506         .fasync         = ipmi_fasync,
507         .poll           = ipmi_poll,
508 };
509
510 #define DEVICE_NAME     "ipmidev"
511
512 static int ipmi_major = 0;
513 module_param(ipmi_major, int, 0);
514 MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
515                  " default, or if you set it to zero, it will choose the next"
516                  " available device.  Setting it to -1 will disable the"
517                  " interface.  Other values will set the major device number"
518                  " to that value.");
519
520 static void ipmi_new_smi(int if_num)
521 {
522         devfs_mk_cdev(MKDEV(ipmi_major, if_num),
523                       S_IFCHR | S_IRUSR | S_IWUSR,
524                       "ipmidev/%d", if_num);
525 }
526
527 static void ipmi_smi_gone(int if_num)
528 {
529         devfs_remove("ipmidev/%d", if_num);
530 }
531
532 static struct ipmi_smi_watcher smi_watcher =
533 {
534         .owner    = THIS_MODULE,
535         .new_smi  = ipmi_new_smi,
536         .smi_gone = ipmi_smi_gone,
537 };
538
539 static __init int init_ipmi_devintf(void)
540 {
541         int rv;
542
543         if (ipmi_major < 0)
544                 return -EINVAL;
545
546         printk(KERN_INFO "ipmi device interface version "
547                IPMI_DEVINTF_VERSION "\n");
548
549         rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
550         if (rv < 0) {
551                 printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
552                 return rv;
553         }
554
555         if (ipmi_major == 0) {
556                 ipmi_major = rv;
557         }
558
559         devfs_mk_dir(DEVICE_NAME);
560
561         rv = ipmi_smi_watcher_register(&smi_watcher);
562         if (rv) {
563                 unregister_chrdev(ipmi_major, DEVICE_NAME);
564                 printk(KERN_WARNING "ipmi: can't register smi watcher\n");
565                 return rv;
566         }
567
568         return 0;
569 }
570 module_init(init_ipmi_devintf);
571
572 static __exit void cleanup_ipmi(void)
573 {
574         ipmi_smi_watcher_unregister(&smi_watcher);
575         devfs_remove(DEVICE_NAME);
576         unregister_chrdev(ipmi_major, DEVICE_NAME);
577 }
578 module_exit(cleanup_ipmi);
579
580 MODULE_LICENSE("GPL");