2 * An implementation of a loadable kernel mode driver providing
3 * multiple kernel/user space bidirectional communications links.
5 * Author: Alan Cox <alan@cymru.net>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
12 * Adapted to become the Linux 2.0 Coda pseudo device
13 * Peter Braam <braam@maths.ox.ac.uk>
14 * Michael Callahan <mjc@emmy.smith.edu>
16 * Changes for Linux 2.1
17 * Copyright (c) 1997 Carnegie-Mellon University
19 * Redone again for Intermezzo
20 * Copyright (c) 1998 Peter J. Braam
22 * Hacked up again for simulated OBD
23 * Copyright (c) 1999 Stelias Computing, Inc.
24 * (authors {pschwan,braam}@stelias.com)
25 * Copyright (C) 1999 Seagate Technology, Inc.
32 #include <linux/config.h> /* for CONFIG_PROC_FS */
33 #include <linux/module.h>
34 #include <linux/errno.h>
35 #include <linux/kernel.h>
36 #include <linux/major.h>
37 #include <linux/sched.h>
39 #include <linux/malloc.h>
40 #include <linux/ioport.h>
41 #include <linux/fcntl.h>
42 #include <linux/delay.h>
43 #include <linux/skbuff.h>
44 #include <linux/proc_fs.h>
45 #include <linux/vmalloc.h>
47 #include <linux/poll.h>
48 #include <linux/init.h>
49 #include <linux/list.h>
51 #include <asm/segment.h>
52 #include <asm/system.h>
54 #include <asm/uaccess.h>
56 #include <linux/obd_support.h>
57 #include <linux/obd_class.h>
59 int obd_print_entry = 1;
60 int obd_debug_level = 4095;
61 struct obd_device obd_dev[MAX_OBD_DEVICES];
62 struct list_head obd_types;
64 /* called when opening /dev/obdNNN */
65 static int obd_class_open(struct inode * inode, struct file * file)
72 dev = MINOR(inode->i_rdev);
73 if (dev >= MAX_OBD_DEVICES)
75 obd_dev[dev].obd_refcnt++;
76 CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++);
83 /* called when closing /dev/obdNNN */
84 static int obd_class_release(struct inode * inode, struct file * file)
91 dev = MINOR(inode->i_rdev);
92 if (dev >= MAX_OBD_DEVICES)
94 fsync_dev(inode->i_rdev);
95 if (obd_dev[dev].obd_refcnt <= 0)
96 printk(KERN_ALERT "presto_psdev_release: refcount(%d) <= 0\n",
97 obd_dev[dev].obd_refcnt);
98 obd_dev[dev].obd_refcnt--;
100 CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++);
108 /* support function */
109 static struct obd_type *obd_nm_to_type(char *nm)
111 struct list_head *tmp;
112 struct obd_type *type;
115 while ( (tmp = tmp->next) != &obd_types ) {
116 type = list_entry(tmp, struct obd_type, typ_chain);
117 if (strlen(type->typ_name) == strlen(nm) &&
118 strcmp(type->typ_name, nm) == 0 ) {
125 /* to control /dev/obdNNN */
126 static int obd_class_ioctl (struct inode * inode, struct file * filp,
127 unsigned int cmd, unsigned long arg)
130 struct obd_device *obddev;
131 struct oic_rw_s rw_s; /* read, write */
132 long int cli_id; /* connect, disconnect */
134 struct oic_prealloc_s prealloc; /* preallocate */
137 dev = MINOR(inode->i_rdev);
138 if (dev > MAX_OBD_DEVICES)
141 obddev = &obd_dev[dev];
143 /* has this minor been registered? */
144 if (cmd != OBD_IOC_SETUP_OBDDEV && !obd_dev[dev].obd_type)
148 case OBD_IOC_SETUP_OBDDEV: {
149 struct obd_type *type;
156 if ( obddev->obd_type ) {
157 CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
158 dev, obddev->obd_type->typ_name);
162 /* get data structures */
163 err= copy_from_user(&input, (void *) arg, sizeof(input));
167 type = obd_nm_to_type(input.setup_type);
169 printk("Trying to register non existent type %s\n",
173 obddev->obd_type = type;
175 CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, input.setup_type);
176 if ( obddev->obd_type->typ_ops->o_setup(obddev,
178 obddev->obd_type = NULL;
186 case OBD_IOC_CLEANUP_OBDDEV: {
189 if ( !obddev->obd_type->typ_refcnt )
190 printk("OBD_CLEANUP: refcount wrap!\n");
192 if ( !obddev->obd_type->typ_ops->o_cleanup )
195 /* cleanup has no argument */
196 rc = obddev->obd_type->typ_ops->o_cleanup(obddev);
201 obddev->obd_type->typ_refcnt--;
202 obddev->obd_type = NULL;
206 case OBD_IOC_CONNECT:
208 struct obd_conn_info conninfo;
210 if (obddev->obd_type->typ_ops->o_connect(dev, &conninfo))
213 return copy_to_user((int *)arg, &conninfo,
214 sizeof(struct obd_conn_info));
216 case OBD_IOC_DISCONNECT:
217 /* frees data structures */
218 get_user(cli_id, (int *) arg);
220 obddev->obd_type->typ_ops->o_disconnect(cli_id);
224 /* sync doesn't need a connection ID, because it knows
225 * what device it was called on, and can thus get the
226 * superblock that it needs. */
227 if (!obddev->u.sim.sim_sb || !obddev->u.sim.sim_sb->s_dev) {
228 CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
231 if ((err = fsync_dev(obddev->u.sim.sim_sb->s_dev)))
232 CDEBUG(D_IOCTL, "sync: fsync_dev failure\n");
234 CDEBUG(D_IOCTL, "sync: success\n");
237 return put_user(err, (int *) arg);
239 /* similarly, create doesn't need a connection ID for
240 * the same reasons. */
241 if (!obddev->u.sim.sim_sb) {
242 CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
243 return put_user(-EINVAL, (int *) arg);
246 i_ino = obddev->obd_type->typ_ops->o_create(obddev, 0, &err);
248 CDEBUG(D_IOCTL, "create: obd_inode_new failure\n");
249 /* 0 is the only error value */
250 return put_user(0, (int *) arg);
253 return put_user(i_ino, (int *) arg);
254 case OBD_IOC_DESTROY:
257 unsigned int conn_id;
260 copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s));
261 if ( !obddev->obd_type ||
262 !obddev->obd_type->typ_ops->o_destroy)
265 return obddev->obd_type->typ_ops->o_destroy(destroy.conn_id, destroy.ino);
267 case OBD_IOC_SETATTR:
271 unsigned int conn_id;
276 err= copy_from_user(&foo, (int *)arg, sizeof(struct tmp));
280 if ( !obddev->obd_type ||
281 !obddev->obd_type->typ_ops->o_setattr)
284 return obddev->obd_type->typ_ops->o_setattr(foo.conn_id, foo.ino, &foo.iattr);
287 case OBD_IOC_GETATTR:
291 unsigned int conn_id;
295 copy_from_user(&foo, (int *)arg, sizeof(struct tmp));
297 if ( !obddev->obd_type ||
298 !obddev->obd_type->typ_ops->o_getattr)
301 if (obddev->obd_type->typ_ops->o_getattr(foo.conn_id,
305 err = copy_to_user((int *)arg, &iattr, sizeof(iattr));
313 err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
317 if ( !obddev->obd_type->typ_ops ||
318 !obddev->obd_type->typ_ops->o_read )
321 rw_s.count = obddev->obd_type->typ_ops->o_read2(rw_s.conn_id,
330 err = copy_to_user((int*)arg, &rw_s.count,
331 sizeof(unsigned long));
340 err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
344 if ( !obddev->obd_type->typ_ops ||
345 !obddev->obd_type->typ_ops->o_read )
348 rw_s.count = obddev->obd_type->typ_ops->o_read(rw_s.conn_id,
357 err = copy_to_user((int*)arg, &rw_s.count,
358 sizeof(unsigned long));
366 copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s));
367 CDEBUG(D_IOCTL, "\n");
368 if ( !obddev->obd_type->typ_ops->o_write )
371 obddev->obd_type->typ_ops->o_write(rw_s.conn_id,
378 printk("Result rw_s.count %ld\n", rw_s.count);
379 return (int)rw_s.count;
380 copy_to_user((int *)arg, &rw_s.count,
381 sizeof(unsigned long));
384 case OBD_IOC_PREALLOCATE:
385 copy_from_user(&prealloc, (int *)arg,
386 sizeof(struct oic_prealloc_s));
388 if (!obddev->u.sim.sim_sb || !obddev->u.sim.sim_sb->s_dev) {
389 CDEBUG(D_IOCTL, "fatal: device not initialized.\n");
393 if (!obddev->obd_type ||
394 !obddev->obd_type->typ_ops->o_preallocate)
398 obddev->obd_type->typ_ops->o_preallocate(prealloc.cli_id, prealloc.alloc,
399 prealloc.inodes, &err);
402 return copy_to_user((int *)arg, &prealloc,
403 sizeof(struct oic_prealloc_s));
407 unsigned int conn_id;
411 tmp = (void *)arg + sizeof(unsigned int);
412 get_user(conn_id, (int *) arg);
413 if ( !obddev->obd_type ||
414 !obddev->obd_type->typ_ops->o_statfs)
417 rc = obddev->obd_type->typ_ops->o_statfs(conn_id, &buf);
420 rc = copy_to_user(tmp, &buf, sizeof(buf));
425 printk("invalid ioctl: cmd = %u, arg = %lu\n", cmd, arg);
430 /* Driver interface done, utility functions follow */
432 int obd_register_type(struct obd_ops *ops, char *nm)
434 struct obd_type *type;
436 if ( obd_nm_to_type(nm) ) {
437 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
441 OBD_ALLOC(type, struct obd_type * , sizeof(*type));
444 memset(type, 0, sizeof(*type));
445 INIT_LIST_HEAD(&type->typ_chain);
447 list_add(&type->typ_chain, obd_types.next);
453 int obd_unregister_type(char *nm)
455 struct obd_type *type = obd_nm_to_type(nm);
460 if ( type->typ_refcnt )
463 list_del(&type->typ_chain);
464 OBD_FREE(type, sizeof(*type));
468 /* declare character device */
469 static struct file_operations obd_psdev_fops = {
473 NULL, /* presto_psdev_readdir */
475 obd_class_ioctl, /* ioctl */
476 NULL, /* presto_psdev_mmap */
477 obd_class_open, /* open */
479 obd_class_release, /* release */
482 NULL, /* check_media_change */
483 NULL, /* revalidate */
494 printk(KERN_INFO "OBD class driver v0.002, braam@stelias.com\n");
496 INIT_LIST_HEAD(&obd_types);
498 if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev",
500 printk(KERN_ERR "obd_psdev: unable to get major %d\n",
505 for (i = 0; i < MAX_OBD_DEVICES; i++) {
506 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
507 INIT_LIST_HEAD(&obd_dev[i].u.sim.sim_clients);
515 EXPORT_SYMBOL(obd_register_type);
516 EXPORT_SYMBOL(obd_unregister_type);
518 EXPORT_SYMBOL(obd_print_entry);
519 EXPORT_SYMBOL(obd_debug_level);
520 EXPORT_SYMBOL(obd_dev);
523 int init_module(void)
528 void cleanup_module(void)
533 unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
534 for (i = 0; i < MAX_OBD_DEVICES; i++) {
535 struct obd_device *obddev = &obd_dev[i];
536 if ( obddev->obd_type &&
537 obddev->obd_type->typ_ops->o_cleanup_device )
538 return obddev->obd_type->typ_ops->o_cleanup_device(i);