Whamcloud - gitweb
Working on add_to_page_cache oops.
[fs/lustre-release.git] / lustre / obdclass / class_obd.c
1 /*
2  *              An implementation of a loadable kernel mode driver providing
3  *              multiple kernel/user space bidirectional communications links.
4  *
5  *              Author:         Alan Cox <alan@cymru.net>
6  *
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.
11  * 
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>           
15  *
16  *              Changes for Linux 2.1
17  *              Copyright (c) 1997 Carnegie-Mellon University
18  *
19  *              Redone again for Intermezzo
20  *              Copyright (c) 1998 Peter J. Braam
21  *
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.
26  *
27  * 
28  */
29
30 #define EXPORT_SYMTAB
31
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>
38 #include <linux/lp.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>
46 #include <linux/fs.h>
47 #include <linux/poll.h>
48 #include <linux/init.h>
49 #include <linux/list.h>
50 #include <asm/io.h>
51 #include <asm/segment.h>
52 #include <asm/system.h>
53 #include <asm/poll.h>
54 #include <asm/uaccess.h>
55
56 #include <linux/obd_support.h>
57 #include <linux/obd_class.h>
58
59 static int obd_init_magic;
60 int           obd_print_entry = 1;
61 int           obd_debug_level = 4095;
62 struct obd_device obd_dev[MAX_OBD_DEVICES];
63 struct list_head obd_types;
64
65 /* called when opening /dev/obdNNN */
66 static int obd_class_open(struct inode * inode, struct file * file)
67 {
68         int dev;
69         ENTRY;
70
71         if (!inode)
72                 return -EINVAL;
73         dev = MINOR(inode->i_rdev);
74         if (dev >= MAX_OBD_DEVICES)
75                 return -ENODEV;
76         obd_dev[dev].obd_refcnt++;
77         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
78                obd_dev[dev].obd_refcnt);
79
80         MOD_INC_USE_COUNT;
81         EXIT;
82         return 0;
83 }
84
85 /* called when closing /dev/obdNNN */
86 static int obd_class_release(struct inode * inode, struct file * file)
87 {
88         int dev;
89         ENTRY;
90
91         if (!inode)
92                 return -EINVAL;
93         dev = MINOR(inode->i_rdev);
94         if (dev >= MAX_OBD_DEVICES)
95                 return -ENODEV;
96         fsync_dev(inode->i_rdev);
97         if (obd_dev[dev].obd_refcnt <= 0)
98                 printk(KERN_ALERT "obd_class_release: refcount(%d) <= 0\n",
99                        obd_dev[dev].obd_refcnt);
100         obd_dev[dev].obd_refcnt--;
101
102         CDEBUG(D_PSDEV, "Dev %d refcount now %d\n", dev,
103                obd_dev[dev].obd_refcnt);
104         MOD_DEC_USE_COUNT;
105
106         EXIT;
107         return 0;
108 }
109
110 /* support function */
111 static struct obd_type *obd_nm_to_type(char *nm) 
112 {
113         struct list_head *tmp;
114         struct obd_type *type;
115         CDEBUG(D_IOCTL, "SEARCH %s\n", nm);
116         
117         tmp = &obd_types;
118         while ( (tmp = tmp->next) != &obd_types ) {
119                 type = list_entry(tmp, struct obd_type, typ_chain);
120                 CDEBUG(D_IOCTL, "TYP %s\n", type->typ_name);
121                 if (strlen(type->typ_name) == strlen(nm) &&
122                     strcmp(type->typ_name, nm) == 0 ) {
123                         return type;
124                 }
125         }
126         return NULL;
127 }
128
129
130 static int getdata(int len, void **data)
131 {
132         void *tmp = NULL;
133
134         if (!len) 
135                 return 0;
136
137         CDEBUG(D_IOCTL, "getdata: len %d, add %p\n", len, *data);
138
139         OBD_ALLOC(tmp, void *, len);
140         if ( !tmp )
141                 return -ENOMEM;
142         
143         memset(tmp, 0, len);
144         if ( copy_from_user(tmp, *data, len)) {
145                 OBD_FREE(tmp,len);
146                 return -EFAULT;
147         }
148         *data = tmp;
149
150         return 0;
151 }
152
153 /* to control /dev/obdNNN */
154 static int obd_class_ioctl (struct inode * inode, struct file * filp, 
155                             unsigned int cmd, unsigned long arg)
156 {
157         struct obd_device *obddev;
158         /* NOTE this must be larger than any of the ioctl data structs */
159         char buff[1024];
160         void *karg = buff;
161         struct obd_conn conn;
162         int err, dev;
163         long int cli_id; /* connect, disconnect */
164
165         if (!inode)
166                 return -EINVAL;
167
168         dev = MINOR(inode->i_rdev);
169         if (dev > MAX_OBD_DEVICES)
170                 return -ENODEV;
171         obddev = &obd_dev[dev];
172         conn.oc_dev = obddev;
173
174         switch (cmd) {
175         case TCGETS:
176                 return -EINVAL;
177         case OBD_IOC_ATTACH: {
178                 struct obd_type *type;
179                 struct oic_generic *input = karg;
180
181                 ENTRY;
182                 /* have we attached a type to this device */
183                 if ( obddev->obd_type || 
184                      (obddev->obd_flags & OBD_ATTACHED) ){
185                         CDEBUG(D_IOCTL,
186                                "OBD Device %d already attached to type %s.\n",
187                                dev, obddev->obd_type->typ_name);
188                         EXIT;
189                         return -EBUSY;
190                 }
191
192                 /* get data structures */
193                 err = copy_from_user(input, (void *)arg, sizeof(*input));
194                 if ( err ) {
195                         EXIT;
196                         return err;
197                 }
198
199                 err = getdata(input->att_typelen + 1, &input->att_type);
200                 if ( err ) {
201                         EXIT;
202                         return err;
203                 }
204
205                 /* find the type */
206                 type = obd_nm_to_type(input->att_type);
207                 OBD_FREE(input->att_type, input->att_typelen + 1);
208                 if ( !type ) {
209                         printk("Unknown obd type dev %d\n", dev);
210                         EXIT;
211                         return -EINVAL;
212                 }
213                 obddev->obd_type = type;
214                 
215                 /* get the attach data */
216                 err = getdata(input->att_datalen, &input->att_data);
217                 if ( err ) {
218                         EXIT;
219                         return err;
220                 }
221
222                 INIT_LIST_HEAD(&obddev->obd_gen_clients);
223                 obddev->obd_multi_count = 0;
224
225                 CDEBUG(D_IOCTL, "Attach %d, datalen %d, type %s\n", 
226                        dev, input->att_datalen, obddev->obd_type->typ_name);
227                 /* maybe we are done */
228                 if ( !OBT(obddev) || !OBP(obddev, attach) ) {
229                         obddev->obd_flags |=  OBD_ATTACHED;
230                         type->typ_refcnt++;
231                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
232                                type->typ_refcnt);
233                         MOD_INC_USE_COUNT;
234                         EXIT;
235                         return 0;
236                 }
237
238                 /* do the attach */
239                 err = OBP(obddev, attach)(obddev, input->att_datalen,
240                                           input->att_data);
241                 OBD_FREE(input->att_data, input->att_datalen);
242
243                 if ( err ) {
244                         obddev->obd_flags &= ~OBD_ATTACHED;
245                         obddev->obd_type = NULL;
246                         EXIT;
247                 } else {
248                         obddev->obd_flags |=  OBD_ATTACHED;
249                         type->typ_refcnt++;
250                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
251                                type->typ_refcnt);
252                         MOD_INC_USE_COUNT;
253                         EXIT;
254                 }
255                 return err;
256         }
257
258         case OBD_IOC_DETACH: {
259
260                 ENTRY;
261                 if (obddev->obd_flags & OBD_SET_UP) {
262                         EXIT;
263                         return -EBUSY;
264                 }
265                 if (! (obddev->obd_flags & OBD_ATTACHED) ) {
266                         CDEBUG(D_IOCTL, "Device not attached\n");
267                         EXIT;
268                         return -ENODEV;
269                 }
270                 if ( !list_empty(&obddev->obd_gen_clients) ) {
271                         CDEBUG(D_IOCTL, "Device has connected clients\n");
272                         EXIT;
273                         return -EBUSY;
274                 }
275
276                 CDEBUG(D_IOCTL, "Detach %d, type %s\n", dev,
277                        obddev->obd_type->typ_name);
278                 obddev->obd_flags &= ~OBD_ATTACHED;
279                 obddev->obd_type->typ_refcnt--;
280                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
281                        obddev->obd_type->typ_refcnt);
282                 obddev->obd_type = NULL;
283                 MOD_DEC_USE_COUNT;
284                 EXIT;
285                 return 0;
286         }
287
288         case OBD_IOC_SETUP: {
289                 struct ioc_setup {
290                         int setup_datalen;
291                         void *setup_data;
292                 } *setup;
293                 setup = karg;
294
295                 ENTRY;
296                 /* have we attached a type to this device */
297                 if (!(obddev->obd_flags & OBD_ATTACHED)) {
298                         CDEBUG(D_IOCTL, "Device not attached\n");
299                         EXIT;
300                         return -ENODEV;
301                 }
302
303                 /* has this been done already? */
304                 if ( obddev->obd_flags & OBD_SET_UP ) {
305                         CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n",
306                                dev, obddev->obd_type->typ_name);
307                         EXIT;
308                         return -EBUSY;
309                 }
310
311                 /* get main structure */
312                 err = copy_from_user(setup, (void *) arg, sizeof(*setup));
313                 if (err) {
314                         EXIT;
315                         return err;
316                 }
317
318                 err = getdata(setup->setup_datalen, &setup->setup_data);
319                 if (err) {
320                         EXIT;
321                         return err;
322                 }
323
324                 /* do the setup */
325                 CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, 
326                        obddev->obd_type->typ_name);
327                 if ( !OBT(obddev) || !OBP(obddev, setup) ) {
328                         obddev->obd_type->typ_refcnt++;
329                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
330                                dev, obddev->obd_type->typ_refcnt);
331                         obddev->obd_flags |= OBD_SET_UP;
332                         EXIT;
333                         return 0;
334                 }
335
336                 err = OBP(obddev, setup)(obddev, setup->setup_datalen,
337                                          setup->setup_data);
338
339                 if ( err )  {
340                         obddev->obd_flags &= ~OBD_SET_UP;
341                         EXIT;
342                 } else {
343                         obddev->obd_type->typ_refcnt++;
344                         CDEBUG(D_IOCTL, "Dev %d refcount now %d\n",
345                                dev, obddev->obd_type->typ_refcnt);
346                         obddev->obd_flags |= OBD_SET_UP;
347                         EXIT;
348                 }
349                 return err;
350         }
351         case OBD_IOC_CLEANUP: {
352                 ENTRY;
353                 /* has this minor been registered? */
354                 if (!obddev->obd_type) {
355                         CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev);
356                         EXIT;
357                         return -ENODEV;
358                 }
359
360                 if ( !obddev->obd_type->typ_refcnt ) {
361                         printk("OBD_CLEANUP: Dev %d has refcount (%d)!\n",
362                                dev, obddev->obd_type->typ_refcnt);
363                         EXIT;
364                         return -EBUSY;
365                 }
366
367                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
368                      (!(obddev->obd_flags & OBD_ATTACHED))) {
369                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
370                         EXIT;
371                         return -ENODEV;
372                 }
373
374                 if ( !OBT(obddev) || !OBP(obddev, cleanup) )
375                         goto cleanup_out;
376
377                 /* cleanup has no argument */
378                 err = OBP(obddev, cleanup)(obddev);
379                 if ( err ) {
380                         EXIT;
381                         return err;
382                 }
383
384         cleanup_out: 
385                 obddev->obd_flags &= ~OBD_SET_UP;
386                 obddev->obd_type->typ_refcnt--;
387                 CDEBUG(D_IOCTL, "Dev %d refcount now %d\n", dev,
388                        obddev->obd_type->typ_refcnt);
389                 EXIT;
390                 return 0;
391         }
392         case OBD_IOC_CONNECT:
393         {
394                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
395                      (!(obddev->obd_flags & OBD_ATTACHED))) {
396                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
397                         return -ENODEV;
398                 }
399
400                 if ( !OBT(obddev) || !OBP(obddev, connect) )
401                         return -EOPNOTSUPP;
402                 
403                 err = OBP(obddev, connect)(&conn);
404                 if ( err )
405                         return err;
406
407                 return copy_to_user((int *)arg, &conn.oc_id,
408                                     sizeof(uint32_t));
409         }
410         case OBD_IOC_DISCONNECT:
411                 /* frees data structures */
412                 /* has this minor been registered? */
413                 if (!obddev->obd_type)
414                         return -ENODEV;
415
416                 get_user(cli_id, (int *) arg);
417                 conn.oc_id = cli_id;
418
419                 if ( !OBT(obddev) || !OBP(obddev, disconnect))
420                         return -EOPNOTSUPP;
421                 
422                 OBP(obddev, disconnect)(&conn);
423                 return 0;
424
425         case OBD_IOC_SYNC: {
426                 struct oic_range_s *range = karg;
427
428                 if (!obddev->obd_type)
429                         return -ENODEV;
430
431                 err = copy_from_user(range, (const void *)arg,  sizeof(*range));
432
433                 if ( err ) {
434                         EXIT;
435                         return err;
436                 }
437                         
438                 if ( !OBT(obddev) || !OBP(obddev, sync) ) {
439                         err = -EOPNOTSUPP;
440                         EXIT;
441                         return err;
442                 }
443
444                 /* XXX sync needs to be tested/verified */
445                 err = OBP(obddev, sync)(&conn, &range->obdo, range->count,
446                                         range->offset);
447
448                 if ( err ) {
449                         EXIT;
450                         return err;
451                 }
452                         
453                 return put_user(err, (int *) arg);
454         }
455         case OBD_IOC_CREATE: {
456                 struct oic_attr_s *attr = karg;
457
458                 err = copy_from_user(attr, (const void *)arg,  sizeof(*attr));
459                 if (err) {
460                         EXIT;
461                         return err;
462                 }
463
464                 /* has this minor been registered? */
465                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
466                      !(obddev->obd_flags & OBD_SET_UP)) {
467                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
468                         return -ENODEV;
469                 }
470                 conn.oc_id = attr->conn_id;
471
472                 if ( !OBT(obddev) || !OBP(obddev, create) )
473                         return -EOPNOTSUPP;
474
475                 err = OBP(obddev, create)(&conn, &attr->obdo);
476                 if (err) {
477                         EXIT;
478                         return err;
479                 }
480
481                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
482                 EXIT;
483                 return err;
484         }
485
486         case OBD_IOC_DESTROY: {
487                 struct oic_attr_s *attr = karg;
488                 
489                 /* has this minor been registered? */
490                 if (!obddev->obd_type)
491                         return -ENODEV;
492
493                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
494                 if ( err ) {
495                         EXIT;
496                         return err;
497                 }
498
499                 if ( !OBT(obddev) || !OBP(obddev, destroy) )
500                         return -EOPNOTSUPP;
501
502                 conn.oc_id = attr->conn_id;
503                 err = OBP(obddev, destroy)(&conn, &attr->obdo);
504                 EXIT;
505                 return err;
506         }
507
508         case OBD_IOC_SETATTR: {
509                 struct oic_attr_s *attr = karg;
510
511                 /* has this minor been registered? */
512                 if (!obddev->obd_type)
513                         return -ENODEV;
514
515                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
516                 if (err)
517                         return err;
518
519                 if ( !OBT(obddev) || !OBP(obddev, setattr) )
520                         return -EOPNOTSUPP;
521                 
522                 conn.oc_id = attr->conn_id;
523                 err = OBP(obddev, setattr)(&conn, &attr->obdo);
524                 EXIT;
525                 return err;
526         }
527
528         case OBD_IOC_GETATTR: {
529                 struct oic_attr_s *attr = karg;
530
531                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
532                 if (err)
533                         return err;
534
535                 conn.oc_id = attr->conn_id;
536                 err = OBP(obddev, getattr)(&conn, &attr->obdo);
537                 if ( err ) {
538                         EXIT;
539                         return err;
540                 }
541
542                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
543                 EXIT;
544                 return err;
545         }
546
547         case OBD_IOC_READ: {
548                 int err;
549                 struct oic_rw_s *rw_s = karg;  /* read, write ioctl str */
550
551                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
552                 if ( err ) {
553                         EXIT;
554                         return err;
555                 }
556
557                 conn.oc_id = rw_s->conn_id;
558
559                 if ( !OBT(obddev) || !OBP(obddev, read) ) {
560                         err = -EOPNOTSUPP;
561                         EXIT;
562                         return err;
563                 }
564
565                 err = OBP(obddev, read)(&conn, &rw_s->obdo, rw_s->buf, 
566                                         &rw_s->count, rw_s->offset);
567                 if ( err ) {
568                         EXIT;
569                         return err;
570                 }
571                         
572                 err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count));
573                 EXIT;
574                 return err;
575         }
576
577         case OBD_IOC_WRITE: {
578                 struct oic_rw_s *rw_s = karg;  /* read, write ioctl str */
579
580                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
581                 if ( err ) {
582                         EXIT;
583                         return err;
584                 }
585
586                 conn.oc_id = rw_s->conn_id;
587
588                 if ( !OBT(obddev) || !OBP(obddev, write) ) {
589                         err = -EOPNOTSUPP;
590                         return err;
591                 }
592
593                 err = OBP(obddev, write)(&conn, &rw_s->obdo, rw_s->buf, 
594                                          &rw_s->count, rw_s->offset);
595                 if ( err ) {
596                         EXIT;
597                         return err;
598                 }
599
600                 err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count));
601                 EXIT;
602                 return err;
603         }
604         case OBD_IOC_PREALLOCATE: {
605                 struct oic_prealloc_s *prealloc = karg;
606
607                 /* has this minor been registered? */
608                 if (!obddev->obd_type)
609                         return -ENODEV;
610
611                 err = copy_from_user(prealloc, (int *)arg, sizeof(*prealloc));
612                 if (err) 
613                         return -EFAULT;
614
615                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
616                      !(obddev->obd_flags & OBD_SET_UP)) {
617                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
618                         return -ENODEV;
619                 }
620
621                 if ( !OBT(obddev) || !OBP(obddev, preallocate) )
622                         return -EOPNOTSUPP;
623
624                 conn.oc_id = prealloc->cli_id;
625                 err = OBP(obddev, preallocate)(&conn, &prealloc->alloc,
626                                                prealloc->ids);
627                 if ( err ) {
628                         EXIT;
629                         return err;
630                 }
631
632                 err =copy_to_user((int *)arg, prealloc, sizeof(*prealloc));
633                 EXIT;
634                 return err;
635         }
636         case OBD_IOC_STATFS: {
637                 struct statfs *tmp;
638                 unsigned int conn_id;
639                 struct statfs buf;
640
641                 /* has this minor been registered? */
642                 if (!obddev->obd_type)
643                         return -ENODEV;
644
645                 tmp = (void *)arg + sizeof(unsigned int);
646                 get_user(conn_id, (int *) arg);
647
648                 if ( !OBT(obddev) || !OBP(obddev, statfs) )
649                         return -EOPNOTSUPP;
650
651                 conn.oc_id = conn_id;
652                 err = OBP(obddev, statfs)(&conn, &buf);
653                 if ( err ) {
654                         EXIT;
655                         return err;
656                 }
657                 err = copy_to_user(tmp, &buf, sizeof(buf));
658                 EXIT;
659                 return err;
660                 
661         }
662         case OBD_IOC_COPY: {
663                 struct ioc_mv_s *mvdata = karg;
664
665                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
666                      (!(obddev->obd_flags & OBD_ATTACHED))) {
667                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
668                         return -ENODEV;
669                 }
670
671                 /* get main structure */
672                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
673                 if (err) {
674                         EXIT;
675                         return err;
676                 }
677
678                 if ( !OBT(obddev) || !OBP(obddev, copy) )
679                         return -EOPNOTSUPP;
680
681                 /* do the partition */
682                 CDEBUG(D_IOCTL, "Copy %d, type %s dst %Ld src %Ld\n", dev, 
683                        obddev->obd_type->typ_name, mvdata->dst.o_id, 
684                        mvdata->src.o_id);
685
686                 conn.oc_id = mvdata->src_conn_id;
687
688                 err = OBP(obddev, copy)(&conn, &mvdata->dst, 
689                                         &conn, &mvdata->src, 
690                                         mvdata->src.o_size, 0);
691                 return err;
692         }
693
694         case OBD_IOC_MIGR: {
695                 struct ioc_mv_s *mvdata = karg;
696
697                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
698                      (!(obddev->obd_flags & OBD_ATTACHED))) {
699                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
700                         return -ENODEV;
701                 }
702
703                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
704                 if (err) {
705                         EXIT;
706                         return err;
707                 }
708
709                 CDEBUG(D_IOCTL, "Migrate copying %d\n", sizeof(*mvdata));
710
711                 if ( !OBT(obddev) || !OBP(obddev, migrate) )
712                         return -EOPNOTSUPP;
713
714                 /* do the partition */
715                 CDEBUG(D_IOCTL, "Migrate %d, type %s conn %d src %Ld dst %Ld\n",
716                        dev, obddev->obd_type->typ_name, mvdata->src_conn_id,
717                        mvdata->src.o_id, mvdata->dst.o_id);
718
719                 conn.oc_id = mvdata->src_conn_id;
720                 err = OBP(obddev, migrate)(&conn, &mvdata->dst, &mvdata->src, 
721                                            mvdata->dst.o_size, 0);
722
723                 return err;
724         }
725
726         default: {
727                 struct obd_type *type;
728                 struct oic_generic input;
729                 void *karg;
730
731                 /* get data structures */
732                 err = copy_from_user(&input, (void *)arg, sizeof(input));
733                 if ( err ) {
734                         EXIT;
735                         return err;
736                 }
737
738                 err = getdata(input.att_typelen + 1, &input.att_type);
739                 if ( err ) {
740                         EXIT;
741                         return err;
742                 }
743
744                 /* find the type */
745                 type = obd_nm_to_type(input.att_type);
746                 OBD_FREE(input.att_type, input.att_typelen + 1);
747                 if ( !type ) {
748                         printk("Unknown obd type dev %d\n", dev);
749                         EXIT;
750                         return -EINVAL;
751                 }
752                 
753                 if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) {
754                         EXIT;
755                         return -EOPNOTSUPP;
756                 }
757                 conn.oc_id = input.att_connid;
758                 
759                 CDEBUG(D_IOCTL, "Calling ioctl %x for type %s, len %d\n",
760                        cmd, type->typ_name, input.att_datalen);
761
762                 /* get the generic data */
763                 karg = input.att_data;
764                 err = getdata(input.att_datalen, karg);
765                 if ( err ) {
766                         EXIT;
767                         return err;
768                 }
769
770                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
771                                                  karg, input.att_data);
772                 OBD_FREE(karg, input.att_datalen);
773
774                 EXIT;
775                 return err;
776         }
777         }
778 }
779
780 /* Driver interface done, utility functions follow */
781
782 int obd_register_type(struct obd_ops *ops, char *nm)
783 {
784         struct obd_type *type;
785
786
787         if (obd_init_magic != 0x11223344) {
788                 EXIT;
789                 return -EINVAL;
790         }
791
792         if  ( obd_nm_to_type(nm) ) {
793                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
794                 EXIT;
795                 return -EEXIST;
796         }
797         
798         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
799         if ( !type ) {
800                 EXIT;
801                 return -ENOMEM;
802         }
803         memset(type, 0, sizeof(*type));
804         INIT_LIST_HEAD(&type->typ_chain);
805         MOD_INC_USE_COUNT;
806         list_add(&type->typ_chain, obd_types.next);
807         type->typ_ops = ops;
808         type->typ_name = nm;
809         EXIT;
810         return 0;
811 }
812         
813 int obd_unregister_type(char *nm)
814 {
815         struct obd_type *type = obd_nm_to_type(nm);
816
817         if ( !type ) {
818                 MOD_DEC_USE_COUNT;
819                 printk("Unknown obd type\n");
820                 EXIT;
821                 return -EINVAL;
822         }
823
824         if ( type->typ_refcnt ) {
825                 MOD_DEC_USE_COUNT;
826                 printk("OBD: Type %s has refcount (%d)\n", nm,
827                        type->typ_refcnt);
828                 EXIT;
829                 return -EBUSY;
830         }
831
832         list_del(&type->typ_chain);
833         OBD_FREE(type, sizeof(*type));
834         MOD_DEC_USE_COUNT;
835         return 0;
836 }
837
838 /* declare character device */
839 static struct file_operations obd_psdev_fops = {
840         NULL,                  /* llseek */
841         NULL,                  /* read */
842         NULL,                  /* write */
843         NULL,                  /* presto_psdev_readdir */
844         NULL,                  /* poll */
845         obd_class_ioctl,       /* ioctl */
846         NULL,                  /* presto_psdev_mmap */
847         obd_class_open,        /* open */
848         NULL,
849         obd_class_release,     /* release */
850         NULL,                  /* fsync */
851         NULL,                  /* fasync */
852         NULL,                  /* check_media_change */
853         NULL,                  /* revalidate */
854         NULL                   /* lock */
855 };
856
857
858 /* modules setup */
859
860 int init_obd(void)
861 {
862         int err;
863         int i;
864
865         printk(KERN_INFO "OBD class driver  v0.01, braam@stelias.com\n");
866         
867         INIT_LIST_HEAD(&obd_types);
868         
869         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
870                             &obd_psdev_fops)) {
871                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
872                        OBD_PSDEV_MAJOR);
873                 return -EIO;
874         }
875
876         for (i = 0; i < MAX_OBD_DEVICES; i++) {
877                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
878                 obd_dev[i].obd_minor = i;
879                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
880         }
881
882         err = obd_init_obdo_cache();
883         if (err)
884                 return err;
885         obd_sysctl_init();
886         obd_init_magic = 0x11223344;
887         return 0;
888 }
889
890 EXPORT_SYMBOL(obd_register_type);
891 EXPORT_SYMBOL(obd_unregister_type);
892
893 EXPORT_SYMBOL(obd_print_entry);
894 EXPORT_SYMBOL(obd_debug_level);
895 EXPORT_SYMBOL(obd_dev);
896
897 EXPORT_SYMBOL(gen_connect);
898 EXPORT_SYMBOL(gen_client);
899 EXPORT_SYMBOL(gen_cleanup);
900 EXPORT_SYMBOL(gen_disconnect);
901 EXPORT_SYMBOL(gen_copy_data); 
902 EXPORT_SYMBOL(obdo_cachep);
903
904 /* EXPORT_SYMBOL(gen_multi_attach); */
905 EXPORT_SYMBOL(gen_multi_setup);
906 EXPORT_SYMBOL(gen_multi_cleanup);
907
908
909 #ifdef MODULE
910 int init_module(void)
911 {
912         return init_obd();
913 }
914
915 void cleanup_module(void)
916 {
917         int i;
918         ENTRY;
919
920         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
921         for (i = 0; i < MAX_OBD_DEVICES; i++) {
922                 struct obd_device *obddev = &obd_dev[i];
923                 if ( obddev->obd_type && 
924                      (obddev->obd_flags & OBD_SET_UP) &&
925                      OBT(obddev) && OBP(obddev, detach) ) {
926                         /* XXX should this call generic detach otherwise? */
927                         OBP(obddev, detach)(obddev);
928                 } 
929         }
930
931         obd_cleanup_obdo_cache();
932         obd_sysctl_clean();
933         obd_init_magic = 0;
934         EXIT;
935 }
936 #endif