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