Merge branch 'kvm-updates/2.6.37' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[pandora-kernel.git] / drivers / misc / ibmasm / ibmasmfs.c
1 /*
2  * IBM ASM Service Processor Device Driver
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * Copyright (C) IBM Corporation, 2004
19  *
20  * Author: Max Asböck <amax@us.ibm.com>
21  *
22  */
23
24 /*
25  * Parts of this code are based on an article by Jonathan Corbet
26  * that appeared in Linux Weekly News.
27  */
28
29
30 /*
31  * The IBMASM file virtual filesystem. It creates the following hierarchy
32  * dymamically when mounted from user space:
33  *
34  *    /ibmasm
35  *    |-- 0
36  *    |   |-- command
37  *    |   |-- event
38  *    |   |-- reverse_heartbeat
39  *    |   `-- remote_video
40  *    |       |-- depth
41  *    |       |-- height
42  *    |       `-- width
43  *    .
44  *    .
45  *    .
46  *    `-- n
47  *        |-- command
48  *        |-- event
49  *        |-- reverse_heartbeat
50  *        `-- remote_video
51  *            |-- depth
52  *            |-- height
53  *            `-- width
54  *
55  * For each service processor the following files are created:
56  *
57  * command: execute dot commands
58  *      write: execute a dot command on the service processor
59  *      read: return the result of a previously executed dot command
60  *
61  * events: listen for service processor events
62  *      read: sleep (interruptible) until an event occurs
63  *      write: wakeup sleeping event listener
64  *
65  * reverse_heartbeat: send a heartbeat to the service processor
66  *      read: sleep (interruptible) until the reverse heartbeat fails
67  *      write: wakeup sleeping heartbeat listener
68  *
69  * remote_video/width
70  * remote_video/height
71  * remote_video/width: control remote display settings
72  *      write: set value
73  *      read: read value
74  */
75
76 #include <linux/fs.h>
77 #include <linux/pagemap.h>
78 #include <linux/slab.h>
79 #include <asm/uaccess.h>
80 #include <asm/io.h>
81 #include "ibmasm.h"
82 #include "remote.h"
83 #include "dot_command.h"
84
85 #define IBMASMFS_MAGIC 0x66726f67
86
87 static LIST_HEAD(service_processors);
88
89 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
90 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
91 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
92
93
94 static int ibmasmfs_get_super(struct file_system_type *fst,
95                         int flags, const char *name, void *data,
96                         struct vfsmount *mnt)
97 {
98         return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt);
99 }
100
101 static const struct super_operations ibmasmfs_s_ops = {
102         .statfs         = simple_statfs,
103         .drop_inode     = generic_delete_inode,
104 };
105
106 static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
107
108 static struct file_system_type ibmasmfs_type = {
109         .owner          = THIS_MODULE,
110         .name           = "ibmasmfs",
111         .get_sb         = ibmasmfs_get_super,
112         .kill_sb        = kill_litter_super,
113 };
114
115 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
116 {
117         struct inode *root;
118         struct dentry *root_dentry;
119
120         sb->s_blocksize = PAGE_CACHE_SIZE;
121         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
122         sb->s_magic = IBMASMFS_MAGIC;
123         sb->s_op = &ibmasmfs_s_ops;
124         sb->s_time_gran = 1;
125
126         root = ibmasmfs_make_inode (sb, S_IFDIR | 0500);
127         if (!root)
128                 return -ENOMEM;
129
130         root->i_op = &simple_dir_inode_operations;
131         root->i_fop = ibmasmfs_dir_ops;
132
133         root_dentry = d_alloc_root(root);
134         if (!root_dentry) {
135                 iput(root);
136                 return -ENOMEM;
137         }
138         sb->s_root = root_dentry;
139
140         ibmasmfs_create_files(sb, root_dentry);
141         return 0;
142 }
143
144 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
145 {
146         struct inode *ret = new_inode(sb);
147
148         if (ret) {
149                 ret->i_mode = mode;
150                 ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
151         }
152         return ret;
153 }
154
155 static struct dentry *ibmasmfs_create_file (struct super_block *sb,
156                         struct dentry *parent,
157                         const char *name,
158                         const struct file_operations *fops,
159                         void *data,
160                         int mode)
161 {
162         struct dentry *dentry;
163         struct inode *inode;
164
165         dentry = d_alloc_name(parent, name);
166         if (!dentry)
167                 return NULL;
168
169         inode = ibmasmfs_make_inode(sb, S_IFREG | mode);
170         if (!inode) {
171                 dput(dentry);
172                 return NULL;
173         }
174
175         inode->i_fop = fops;
176         inode->i_private = data;
177
178         d_add(dentry, inode);
179         return dentry;
180 }
181
182 static struct dentry *ibmasmfs_create_dir (struct super_block *sb,
183                                 struct dentry *parent,
184                                 const char *name)
185 {
186         struct dentry *dentry;
187         struct inode *inode;
188
189         dentry = d_alloc_name(parent, name);
190         if (!dentry)
191                 return NULL;
192
193         inode = ibmasmfs_make_inode(sb, S_IFDIR | 0500);
194         if (!inode) {
195                 dput(dentry);
196                 return NULL;
197         }
198
199         inode->i_op = &simple_dir_inode_operations;
200         inode->i_fop = ibmasmfs_dir_ops;
201
202         d_add(dentry, inode);
203         return dentry;
204 }
205
206 int ibmasmfs_register(void)
207 {
208         return register_filesystem(&ibmasmfs_type);
209 }
210
211 void ibmasmfs_unregister(void)
212 {
213         unregister_filesystem(&ibmasmfs_type);
214 }
215
216 void ibmasmfs_add_sp(struct service_processor *sp)
217 {
218         list_add(&sp->node, &service_processors);
219 }
220
221 /* struct to save state between command file operations */
222 struct ibmasmfs_command_data {
223         struct service_processor        *sp;
224         struct command                  *command;
225 };
226
227 /* struct to save state between event file operations */
228 struct ibmasmfs_event_data {
229         struct service_processor        *sp;
230         struct event_reader             reader;
231         int                             active;
232 };
233
234 /* struct to save state between reverse heartbeat file operations */
235 struct ibmasmfs_heartbeat_data {
236         struct service_processor        *sp;
237         struct reverse_heartbeat        heartbeat;
238         int                             active;
239 };
240
241 static int command_file_open(struct inode *inode, struct file *file)
242 {
243         struct ibmasmfs_command_data *command_data;
244
245         if (!inode->i_private)
246                 return -ENODEV;
247
248         command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
249         if (!command_data)
250                 return -ENOMEM;
251
252         command_data->command = NULL;
253         command_data->sp = inode->i_private;
254         file->private_data = command_data;
255         return 0;
256 }
257
258 static int command_file_close(struct inode *inode, struct file *file)
259 {
260         struct ibmasmfs_command_data *command_data = file->private_data;
261
262         if (command_data->command)
263                 command_put(command_data->command);
264
265         kfree(command_data);
266         return 0;
267 }
268
269 static ssize_t command_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
270 {
271         struct ibmasmfs_command_data *command_data = file->private_data;
272         struct command *cmd;
273         int len;
274         unsigned long flags;
275
276         if (*offset < 0)
277                 return -EINVAL;
278         if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
279                 return 0;
280         if (*offset != 0)
281                 return 0;
282
283         spin_lock_irqsave(&command_data->sp->lock, flags);
284         cmd = command_data->command;
285         if (cmd == NULL) {
286                 spin_unlock_irqrestore(&command_data->sp->lock, flags);
287                 return 0;
288         }
289         command_data->command = NULL;
290         spin_unlock_irqrestore(&command_data->sp->lock, flags);
291
292         if (cmd->status != IBMASM_CMD_COMPLETE) {
293                 command_put(cmd);
294                 return -EIO;
295         }
296         len = min(count, cmd->buffer_size);
297         if (copy_to_user(buf, cmd->buffer, len)) {
298                 command_put(cmd);
299                 return -EFAULT;
300         }
301         command_put(cmd);
302
303         return len;
304 }
305
306 static ssize_t command_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
307 {
308         struct ibmasmfs_command_data *command_data = file->private_data;
309         struct command *cmd;
310         unsigned long flags;
311
312         if (*offset < 0)
313                 return -EINVAL;
314         if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
315                 return 0;
316         if (*offset != 0)
317                 return 0;
318
319         /* commands are executed sequentially, only one command at a time */
320         if (command_data->command)
321                 return -EAGAIN;
322
323         cmd = ibmasm_new_command(command_data->sp, count);
324         if (!cmd)
325                 return -ENOMEM;
326
327         if (copy_from_user(cmd->buffer, ubuff, count)) {
328                 command_put(cmd);
329                 return -EFAULT;
330         }
331
332         spin_lock_irqsave(&command_data->sp->lock, flags);
333         if (command_data->command) {
334                 spin_unlock_irqrestore(&command_data->sp->lock, flags);
335                 command_put(cmd);
336                 return -EAGAIN;
337         }
338         command_data->command = cmd;
339         spin_unlock_irqrestore(&command_data->sp->lock, flags);
340
341         ibmasm_exec_command(command_data->sp, cmd);
342         ibmasm_wait_for_response(cmd, get_dot_command_timeout(cmd->buffer));
343
344         return count;
345 }
346
347 static int event_file_open(struct inode *inode, struct file *file)
348 {
349         struct ibmasmfs_event_data *event_data;
350         struct service_processor *sp;
351
352         if (!inode->i_private)
353                 return -ENODEV;
354
355         sp = inode->i_private;
356
357         event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
358         if (!event_data)
359                 return -ENOMEM;
360
361         ibmasm_event_reader_register(sp, &event_data->reader);
362
363         event_data->sp = sp;
364         event_data->active = 0;
365         file->private_data = event_data;
366         return 0;
367 }
368
369 static int event_file_close(struct inode *inode, struct file *file)
370 {
371         struct ibmasmfs_event_data *event_data = file->private_data;
372
373         ibmasm_event_reader_unregister(event_data->sp, &event_data->reader);
374         kfree(event_data);
375         return 0;
376 }
377
378 static ssize_t event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
379 {
380         struct ibmasmfs_event_data *event_data = file->private_data;
381         struct event_reader *reader = &event_data->reader;
382         struct service_processor *sp = event_data->sp;
383         int ret;
384         unsigned long flags;
385
386         if (*offset < 0)
387                 return -EINVAL;
388         if (count == 0 || count > IBMASM_EVENT_MAX_SIZE)
389                 return 0;
390         if (*offset != 0)
391                 return 0;
392
393         spin_lock_irqsave(&sp->lock, flags);
394         if (event_data->active) {
395                 spin_unlock_irqrestore(&sp->lock, flags);
396                 return -EBUSY;
397         }
398         event_data->active = 1;
399         spin_unlock_irqrestore(&sp->lock, flags);
400
401         ret = ibmasm_get_next_event(sp, reader);
402         if (ret <= 0)
403                 goto out;
404
405         if (count < reader->data_size) {
406                 ret = -EINVAL;
407                 goto out;
408         }
409
410         if (copy_to_user(buf, reader->data, reader->data_size)) {
411                 ret = -EFAULT;
412                 goto out;
413         }
414         ret = reader->data_size;
415
416 out:
417         event_data->active = 0;
418         return ret;
419 }
420
421 static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
422 {
423         struct ibmasmfs_event_data *event_data = file->private_data;
424
425         if (*offset < 0)
426                 return -EINVAL;
427         if (count != 1)
428                 return 0;
429         if (*offset != 0)
430                 return 0;
431
432         ibmasm_cancel_next_event(&event_data->reader);
433         return 0;
434 }
435
436 static int r_heartbeat_file_open(struct inode *inode, struct file *file)
437 {
438         struct ibmasmfs_heartbeat_data *rhbeat;
439
440         if (!inode->i_private)
441                 return -ENODEV;
442
443         rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
444         if (!rhbeat)
445                 return -ENOMEM;
446
447         rhbeat->sp = inode->i_private;
448         rhbeat->active = 0;
449         ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
450         file->private_data = rhbeat;
451         return 0;
452 }
453
454 static int r_heartbeat_file_close(struct inode *inode, struct file *file)
455 {
456         struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
457
458         kfree(rhbeat);
459         return 0;
460 }
461
462 static ssize_t r_heartbeat_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
463 {
464         struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
465         unsigned long flags;
466         int result;
467
468         if (*offset < 0)
469                 return -EINVAL;
470         if (count == 0 || count > 1024)
471                 return 0;
472         if (*offset != 0)
473                 return 0;
474
475         /* allow only one reverse heartbeat per process */
476         spin_lock_irqsave(&rhbeat->sp->lock, flags);
477         if (rhbeat->active) {
478                 spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
479                 return -EBUSY;
480         }
481         rhbeat->active = 1;
482         spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
483
484         result = ibmasm_start_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
485         rhbeat->active = 0;
486
487         return result;
488 }
489
490 static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
491 {
492         struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
493
494         if (*offset < 0)
495                 return -EINVAL;
496         if (count != 1)
497                 return 0;
498         if (*offset != 0)
499                 return 0;
500
501         if (rhbeat->active)
502                 ibmasm_stop_reverse_heartbeat(&rhbeat->heartbeat);
503
504         return 1;
505 }
506
507 static int remote_settings_file_open(struct inode *inode, struct file *file)
508 {
509         file->private_data = inode->i_private;
510         return 0;
511 }
512
513 static int remote_settings_file_close(struct inode *inode, struct file *file)
514 {
515         return 0;
516 }
517
518 static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
519 {
520         void __iomem *address = (void __iomem *)file->private_data;
521         unsigned char *page;
522         int retval;
523         int len = 0;
524         unsigned int value;
525
526         if (*offset < 0)
527                 return -EINVAL;
528         if (count == 0 || count > 1024)
529                 return 0;
530         if (*offset != 0)
531                 return 0;
532
533         page = (unsigned char *)__get_free_page(GFP_KERNEL);
534         if (!page)
535                 return -ENOMEM;
536
537         value = readl(address);
538         len = sprintf(page, "%d\n", value);
539
540         if (copy_to_user(buf, page, len)) {
541                 retval = -EFAULT;
542                 goto exit;
543         }
544         *offset += len;
545         retval = len;
546
547 exit:
548         free_page((unsigned long)page);
549         return retval;
550 }
551
552 static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
553 {
554         void __iomem *address = (void __iomem *)file->private_data;
555         char *buff;
556         unsigned int value;
557
558         if (*offset < 0)
559                 return -EINVAL;
560         if (count == 0 || count > 1024)
561                 return 0;
562         if (*offset != 0)
563                 return 0;
564
565         buff = kzalloc (count + 1, GFP_KERNEL);
566         if (!buff)
567                 return -ENOMEM;
568
569
570         if (copy_from_user(buff, ubuff, count)) {
571                 kfree(buff);
572                 return -EFAULT;
573         }
574
575         value = simple_strtoul(buff, NULL, 10);
576         writel(value, address);
577         kfree(buff);
578
579         return count;
580 }
581
582 static const struct file_operations command_fops = {
583         .open =         command_file_open,
584         .release =      command_file_close,
585         .read =         command_file_read,
586         .write =        command_file_write,
587         .llseek =       generic_file_llseek,
588 };
589
590 static const struct file_operations event_fops = {
591         .open =         event_file_open,
592         .release =      event_file_close,
593         .read =         event_file_read,
594         .write =        event_file_write,
595         .llseek =       generic_file_llseek,
596 };
597
598 static const struct file_operations r_heartbeat_fops = {
599         .open =         r_heartbeat_file_open,
600         .release =      r_heartbeat_file_close,
601         .read =         r_heartbeat_file_read,
602         .write =        r_heartbeat_file_write,
603         .llseek =       generic_file_llseek,
604 };
605
606 static const struct file_operations remote_settings_fops = {
607         .open =         remote_settings_file_open,
608         .release =      remote_settings_file_close,
609         .read =         remote_settings_file_read,
610         .write =        remote_settings_file_write,
611         .llseek =       generic_file_llseek,
612 };
613
614
615 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
616 {
617         struct list_head *entry;
618         struct service_processor *sp;
619
620         list_for_each(entry, &service_processors) {
621                 struct dentry *dir;
622                 struct dentry *remote_dir;
623                 sp = list_entry(entry, struct service_processor, node);
624                 dir = ibmasmfs_create_dir(sb, root, sp->dirname);
625                 if (!dir)
626                         continue;
627
628                 ibmasmfs_create_file(sb, dir, "command", &command_fops, sp, S_IRUSR|S_IWUSR);
629                 ibmasmfs_create_file(sb, dir, "event", &event_fops, sp, S_IRUSR|S_IWUSR);
630                 ibmasmfs_create_file(sb, dir, "reverse_heartbeat", &r_heartbeat_fops, sp, S_IRUSR|S_IWUSR);
631
632                 remote_dir = ibmasmfs_create_dir(sb, dir, "remote_video");
633                 if (!remote_dir)
634                         continue;
635
636                 ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR);
637                 ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR);
638                 ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR);
639         }
640 }