xref: /linux/drivers/misc/ibmasm/ibmasmfs.c (revision 5e8d780d745c1619aba81fe7166c5a4b5cad2b84)
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 <asm/uaccess.h>
79 #include <asm/io.h>
80 #include "ibmasm.h"
81 #include "remote.h"
82 #include "dot_command.h"
83 
84 #define IBMASMFS_MAGIC 0x66726f67
85 
86 static LIST_HEAD(service_processors);
87 
88 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
89 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
90 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
91 
92 
93 static int ibmasmfs_get_super(struct file_system_type *fst,
94 			int flags, const char *name, void *data,
95 			struct vfsmount *mnt)
96 {
97 	return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt);
98 }
99 
100 static struct super_operations ibmasmfs_s_ops = {
101 	.statfs		= simple_statfs,
102 	.drop_inode	= generic_delete_inode,
103 };
104 
105 static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
106 
107 static struct file_system_type ibmasmfs_type = {
108 	.owner          = THIS_MODULE,
109 	.name           = "ibmasmfs",
110 	.get_sb         = ibmasmfs_get_super,
111 	.kill_sb        = kill_litter_super,
112 };
113 
114 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
115 {
116 	struct inode *root;
117 	struct dentry *root_dentry;
118 
119 	sb->s_blocksize = PAGE_CACHE_SIZE;
120 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
121 	sb->s_magic = IBMASMFS_MAGIC;
122 	sb->s_op = &ibmasmfs_s_ops;
123 	sb->s_time_gran = 1;
124 
125 	root = ibmasmfs_make_inode (sb, S_IFDIR | 0500);
126 	if (!root)
127 		return -ENOMEM;
128 
129 	root->i_op = &simple_dir_inode_operations;
130 	root->i_fop = ibmasmfs_dir_ops;
131 
132 	root_dentry = d_alloc_root(root);
133 	if (!root_dentry) {
134 		iput(root);
135 		return -ENOMEM;
136 	}
137 	sb->s_root = root_dentry;
138 
139 	ibmasmfs_create_files(sb, root_dentry);
140 	return 0;
141 }
142 
143 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
144 {
145 	struct inode *ret = new_inode(sb);
146 
147 	if (ret) {
148 		ret->i_mode = mode;
149 		ret->i_uid = ret->i_gid = 0;
150 		ret->i_blksize = PAGE_CACHE_SIZE;
151 		ret->i_blocks = 0;
152 		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
153 	}
154 	return ret;
155 }
156 
157 static struct dentry *ibmasmfs_create_file (struct super_block *sb,
158 			struct dentry *parent,
159 		       	const char *name,
160 			struct file_operations *fops,
161 			void *data,
162 			int mode)
163 {
164 	struct dentry *dentry;
165 	struct inode *inode;
166 
167 	dentry = d_alloc_name(parent, name);
168 	if (!dentry)
169 		return NULL;
170 
171 	inode = ibmasmfs_make_inode(sb, S_IFREG | mode);
172 	if (!inode) {
173 		dput(dentry);
174 		return NULL;
175 	}
176 
177 	inode->i_fop = fops;
178 	inode->u.generic_ip = data;
179 
180 	d_add(dentry, inode);
181 	return dentry;
182 }
183 
184 static struct dentry *ibmasmfs_create_dir (struct super_block *sb,
185 				struct dentry *parent,
186 				const char *name)
187 {
188 	struct dentry *dentry;
189 	struct inode *inode;
190 
191 	dentry = d_alloc_name(parent, name);
192 	if (!dentry)
193 		return NULL;
194 
195 	inode = ibmasmfs_make_inode(sb, S_IFDIR | 0500);
196 	if (!inode) {
197 		dput(dentry);
198 		return NULL;
199 	}
200 
201 	inode->i_op = &simple_dir_inode_operations;
202 	inode->i_fop = ibmasmfs_dir_ops;
203 
204 	d_add(dentry, inode);
205 	return dentry;
206 }
207 
208 int ibmasmfs_register(void)
209 {
210 	return register_filesystem(&ibmasmfs_type);
211 }
212 
213 void ibmasmfs_unregister(void)
214 {
215 	unregister_filesystem(&ibmasmfs_type);
216 }
217 
218 void ibmasmfs_add_sp(struct service_processor *sp)
219 {
220 	list_add(&sp->node, &service_processors);
221 }
222 
223 /* struct to save state between command file operations */
224 struct ibmasmfs_command_data {
225 	struct service_processor	*sp;
226 	struct command			*command;
227 };
228 
229 /* struct to save state between event file operations */
230 struct ibmasmfs_event_data {
231 	struct service_processor	*sp;
232 	struct event_reader		reader;
233 	int				active;
234 };
235 
236 /* struct to save state between reverse heartbeat file operations */
237 struct ibmasmfs_heartbeat_data {
238 	struct service_processor	*sp;
239 	struct reverse_heartbeat	heartbeat;
240 	int				active;
241 };
242 
243 static int command_file_open(struct inode *inode, struct file *file)
244 {
245 	struct ibmasmfs_command_data *command_data;
246 
247 	if (!inode->u.generic_ip)
248 		return -ENODEV;
249 
250 	command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
251 	if (!command_data)
252 		return -ENOMEM;
253 
254 	command_data->command = NULL;
255 	command_data->sp = inode->u.generic_ip;
256 	file->private_data = command_data;
257 	return 0;
258 }
259 
260 static int command_file_close(struct inode *inode, struct file *file)
261 {
262 	struct ibmasmfs_command_data *command_data = file->private_data;
263 
264 	if (command_data->command)
265 		command_put(command_data->command);
266 
267 	kfree(command_data);
268 	return 0;
269 }
270 
271 static ssize_t command_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
272 {
273 	struct ibmasmfs_command_data *command_data = file->private_data;
274 	struct command *cmd;
275 	int len;
276 	unsigned long flags;
277 
278 	if (*offset < 0)
279 		return -EINVAL;
280 	if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
281 		return 0;
282 	if (*offset != 0)
283 		return 0;
284 
285 	spin_lock_irqsave(&command_data->sp->lock, flags);
286 	cmd = command_data->command;
287 	if (cmd == NULL) {
288 		spin_unlock_irqrestore(&command_data->sp->lock, flags);
289 		return 0;
290 	}
291 	command_data->command = NULL;
292 	spin_unlock_irqrestore(&command_data->sp->lock, flags);
293 
294 	if (cmd->status != IBMASM_CMD_COMPLETE) {
295 		command_put(cmd);
296 		return -EIO;
297 	}
298 	len = min(count, cmd->buffer_size);
299 	if (copy_to_user(buf, cmd->buffer, len)) {
300 		command_put(cmd);
301 		return -EFAULT;
302 	}
303 	command_put(cmd);
304 
305 	return len;
306 }
307 
308 static ssize_t command_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
309 {
310 	struct ibmasmfs_command_data *command_data = file->private_data;
311 	struct command *cmd;
312 	unsigned long flags;
313 
314 	if (*offset < 0)
315 		return -EINVAL;
316 	if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
317 		return 0;
318 	if (*offset != 0)
319 		return 0;
320 
321 	/* commands are executed sequentially, only one command at a time */
322 	if (command_data->command)
323 		return -EAGAIN;
324 
325 	cmd = ibmasm_new_command(command_data->sp, count);
326 	if (!cmd)
327 		return -ENOMEM;
328 
329 	if (copy_from_user(cmd->buffer, ubuff, count)) {
330 		command_put(cmd);
331 		return -EFAULT;
332 	}
333 
334 	spin_lock_irqsave(&command_data->sp->lock, flags);
335 	if (command_data->command) {
336 		spin_unlock_irqrestore(&command_data->sp->lock, flags);
337 		command_put(cmd);
338 		return -EAGAIN;
339 	}
340 	command_data->command = cmd;
341 	spin_unlock_irqrestore(&command_data->sp->lock, flags);
342 
343 	ibmasm_exec_command(command_data->sp, cmd);
344 	ibmasm_wait_for_response(cmd, get_dot_command_timeout(cmd->buffer));
345 
346 	return count;
347 }
348 
349 static int event_file_open(struct inode *inode, struct file *file)
350 {
351 	struct ibmasmfs_event_data *event_data;
352 	struct service_processor *sp;
353 
354 	if (!inode->u.generic_ip)
355 		return -ENODEV;
356 
357 	sp = inode->u.generic_ip;
358 
359 	event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
360 	if (!event_data)
361 		return -ENOMEM;
362 
363 	ibmasm_event_reader_register(sp, &event_data->reader);
364 
365 	event_data->sp = sp;
366 	event_data->active = 0;
367 	file->private_data = event_data;
368 	return 0;
369 }
370 
371 static int event_file_close(struct inode *inode, struct file *file)
372 {
373 	struct ibmasmfs_event_data *event_data = file->private_data;
374 
375 	ibmasm_event_reader_unregister(event_data->sp, &event_data->reader);
376 	kfree(event_data);
377 	return 0;
378 }
379 
380 static ssize_t event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
381 {
382 	struct ibmasmfs_event_data *event_data = file->private_data;
383 	struct event_reader *reader = &event_data->reader;
384 	struct service_processor *sp = event_data->sp;
385 	int ret;
386 	unsigned long flags;
387 
388 	if (*offset < 0)
389 		return -EINVAL;
390 	if (count == 0 || count > IBMASM_EVENT_MAX_SIZE)
391 		return 0;
392 	if (*offset != 0)
393 		return 0;
394 
395 	spin_lock_irqsave(&sp->lock, flags);
396 	if (event_data->active) {
397 		spin_unlock_irqrestore(&sp->lock, flags);
398 		return -EBUSY;
399 	}
400 	event_data->active = 1;
401 	spin_unlock_irqrestore(&sp->lock, flags);
402 
403 	ret = ibmasm_get_next_event(sp, reader);
404 	if (ret <= 0)
405 		goto out;
406 
407 	if (count < reader->data_size) {
408 		ret = -EINVAL;
409 		goto out;
410 	}
411 
412         if (copy_to_user(buf, reader->data, reader->data_size)) {
413 		ret = -EFAULT;
414 		goto out;
415 	}
416 	ret = reader->data_size;
417 
418 out:
419 	event_data->active = 0;
420 	return ret;
421 }
422 
423 static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
424 {
425 	struct ibmasmfs_event_data *event_data = file->private_data;
426 
427 	if (*offset < 0)
428 		return -EINVAL;
429 	if (count != 1)
430 		return 0;
431 	if (*offset != 0)
432 		return 0;
433 
434 	ibmasm_cancel_next_event(&event_data->reader);
435 	return 0;
436 }
437 
438 static int r_heartbeat_file_open(struct inode *inode, struct file *file)
439 {
440 	struct ibmasmfs_heartbeat_data *rhbeat;
441 
442 	if (!inode->u.generic_ip)
443 		return -ENODEV;
444 
445 	rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
446 	if (!rhbeat)
447 		return -ENOMEM;
448 
449 	rhbeat->sp = (struct service_processor *)inode->u.generic_ip;
450 	rhbeat->active = 0;
451 	ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
452 	file->private_data = rhbeat;
453 	return 0;
454 }
455 
456 static int r_heartbeat_file_close(struct inode *inode, struct file *file)
457 {
458 	struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
459 
460 	kfree(rhbeat);
461 	return 0;
462 }
463 
464 static ssize_t r_heartbeat_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
465 {
466 	struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
467 	unsigned long flags;
468 	int result;
469 
470 	if (*offset < 0)
471 		return -EINVAL;
472 	if (count == 0 || count > 1024)
473 		return 0;
474 	if (*offset != 0)
475 		return 0;
476 
477 	/* allow only one reverse heartbeat per process */
478 	spin_lock_irqsave(&rhbeat->sp->lock, flags);
479 	if (rhbeat->active) {
480 		spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
481 		return -EBUSY;
482 	}
483 	rhbeat->active = 1;
484 	spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
485 
486 	result = ibmasm_start_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
487 	rhbeat->active = 0;
488 
489 	return result;
490 }
491 
492 static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
493 {
494 	struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
495 
496 	if (*offset < 0)
497 		return -EINVAL;
498 	if (count != 1)
499 		return 0;
500 	if (*offset != 0)
501 		return 0;
502 
503 	if (rhbeat->active)
504 		ibmasm_stop_reverse_heartbeat(&rhbeat->heartbeat);
505 
506 	return 1;
507 }
508 
509 static int remote_settings_file_open(struct inode *inode, struct file *file)
510 {
511 	file->private_data = inode->u.generic_ip;
512 	return 0;
513 }
514 
515 static int remote_settings_file_close(struct inode *inode, struct file *file)
516 {
517 	return 0;
518 }
519 
520 static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
521 {
522 	void __iomem *address = (void __iomem *)file->private_data;
523 	unsigned char *page;
524 	int retval;
525 	int len = 0;
526 	unsigned int value;
527 
528 	if (*offset < 0)
529 		return -EINVAL;
530 	if (count == 0 || count > 1024)
531 		return 0;
532 	if (*offset != 0)
533 		return 0;
534 
535 	page = (unsigned char *)__get_free_page(GFP_KERNEL);
536 	if (!page)
537 		return -ENOMEM;
538 
539 	value = readl(address);
540 	len = sprintf(page, "%d\n", value);
541 
542 	if (copy_to_user(buf, page, len)) {
543 		retval = -EFAULT;
544 		goto exit;
545 	}
546 	*offset += len;
547 	retval = len;
548 
549 exit:
550 	free_page((unsigned long)page);
551 	return retval;
552 }
553 
554 static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
555 {
556 	void __iomem *address = (void __iomem *)file->private_data;
557 	char *buff;
558 	unsigned int value;
559 
560 	if (*offset < 0)
561 		return -EINVAL;
562 	if (count == 0 || count > 1024)
563 		return 0;
564 	if (*offset != 0)
565 		return 0;
566 
567 	buff = kmalloc (count + 1, GFP_KERNEL);
568 	if (!buff)
569 		return -ENOMEM;
570 
571 	memset(buff, 0x0, count + 1);
572 
573 	if (copy_from_user(buff, ubuff, count)) {
574 		kfree(buff);
575 		return -EFAULT;
576 	}
577 
578 	value = simple_strtoul(buff, NULL, 10);
579 	writel(value, address);
580 	kfree(buff);
581 
582 	return count;
583 }
584 
585 static struct file_operations command_fops = {
586 	.open =		command_file_open,
587 	.release =	command_file_close,
588 	.read =		command_file_read,
589 	.write =	command_file_write,
590 };
591 
592 static struct file_operations event_fops = {
593 	.open =		event_file_open,
594 	.release =	event_file_close,
595 	.read =		event_file_read,
596 	.write =	event_file_write,
597 };
598 
599 static struct file_operations r_heartbeat_fops = {
600 	.open =		r_heartbeat_file_open,
601 	.release =	r_heartbeat_file_close,
602 	.read =		r_heartbeat_file_read,
603 	.write =	r_heartbeat_file_write,
604 };
605 
606 static 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 };
612 
613 
614 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
615 {
616 	struct list_head *entry;
617 	struct service_processor *sp;
618 
619 	list_for_each(entry, &service_processors) {
620 		struct dentry *dir;
621 		struct dentry *remote_dir;
622 		sp = list_entry(entry, struct service_processor, node);
623 		dir = ibmasmfs_create_dir(sb, root, sp->dirname);
624 		if (!dir)
625 			continue;
626 
627 		ibmasmfs_create_file(sb, dir, "command", &command_fops, sp, S_IRUSR|S_IWUSR);
628 		ibmasmfs_create_file(sb, dir, "event", &event_fops, sp, S_IRUSR|S_IWUSR);
629 		ibmasmfs_create_file(sb, dir, "reverse_heartbeat", &r_heartbeat_fops, sp, S_IRUSR|S_IWUSR);
630 
631 		remote_dir = ibmasmfs_create_dir(sb, dir, "remote_video");
632 		if (!remote_dir)
633 			continue;
634 
635 		ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR);
636 		ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR);
637 		ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR);
638 	}
639 }
640