Whamcloud - gitweb
a64e9ef13fbf759c432b589fa8817f88be4abd80
[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                 /* XXX sync needs to be done */
426         case OBD_IOC_SYNC: {
427                 struct oic_range_s *range = karg;
428
429                 if (!obddev->obd_type)
430                         return -ENODEV;
431
432                 err = copy_from_user(range, (const void *)arg,  sizeof(*range));
433                 if (err) {
434                         EXIT;
435                         return err;
436                 }
437
438                 return put_user(err, (int *) arg);
439         }
440         case OBD_IOC_CREATE: {
441                 struct oic_attr_s *attr = karg;
442
443                 err = copy_from_user(attr, (const void *)arg,  sizeof(*attr));
444                 if (err) {
445                         EXIT;
446                         return err;
447                 }
448
449                 /* has this minor been registered? */
450                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
451                      !(obddev->obd_flags & OBD_SET_UP)) {
452                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
453                         return -ENODEV;
454                 }
455                 conn.oc_id = attr->conn_id;
456
457                 if ( !OBT(obddev) || !OBP(obddev, create) )
458                         return -EOPNOTSUPP;
459
460                 err = OBP(obddev, create)(&conn, &attr->obdo);
461                 if (err) {
462                         EXIT;
463                         return err;
464                 }
465
466                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
467                 EXIT;
468                 return err;
469         }
470
471         case OBD_IOC_DESTROY: {
472                 struct oic_attr_s *attr = karg;
473                 
474                 /* has this minor been registered? */
475                 if (!obddev->obd_type)
476                         return -ENODEV;
477
478                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
479                 if ( err ) {
480                         EXIT;
481                         return err;
482                 }
483
484                 if ( !OBT(obddev) || !OBP(obddev, destroy) )
485                         return -EOPNOTSUPP;
486
487                 conn.oc_id = attr->conn_id;
488                 err = OBP(obddev, destroy)(&conn, &attr->obdo);
489                 EXIT;
490                 return err;
491         }
492
493         case OBD_IOC_SETATTR: {
494                 struct oic_attr_s *attr = karg;
495
496                 /* has this minor been registered? */
497                 if (!obddev->obd_type)
498                         return -ENODEV;
499
500                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
501                 if (err)
502                         return err;
503
504                 if ( !OBT(obddev) || !OBP(obddev, setattr) )
505                         return -EOPNOTSUPP;
506                 
507                 conn.oc_id = attr->conn_id;
508                 err = OBP(obddev, setattr)(&conn, &attr->obdo);
509                 EXIT;
510                 return err;
511         }
512
513         case OBD_IOC_GETATTR: {
514                 struct oic_attr_s *attr = karg;
515
516                 err = copy_from_user(attr, (int *)arg, sizeof(*attr));
517                 if (err)
518                         return err;
519
520                 conn.oc_id = attr->conn_id;
521                 err = OBP(obddev, getattr)(&conn, &attr->obdo);
522                 if ( err ) {
523                         EXIT;
524                         return err;
525                 }
526
527                 err = copy_to_user((int *)arg, attr, sizeof(*attr));
528                 EXIT;
529                 return err;
530         }
531
532         case OBD_IOC_READ: {
533                 int err;
534                 struct oic_rw_s *rw_s = karg;  /* read, write ioctl str */
535
536                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
537                 if ( err ) {
538                         EXIT;
539                         return err;
540                 }
541
542                 conn.oc_id = rw_s->conn_id;
543
544                 if ( !OBT(obddev) || !OBP(obddev, read) ) {
545                         err = -EOPNOTSUPP;
546                         EXIT;
547                         return err;
548                 }
549
550                 err = OBP(obddev, read)(&conn, &rw_s->obdo, rw_s->buf, 
551                                         &rw_s->count, rw_s->offset);
552                 if ( err ) {
553                         EXIT;
554                         return err;
555                 }
556                         
557                 err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count));
558                 EXIT;
559                 return err;
560         }
561
562         case OBD_IOC_WRITE: {
563                 struct oic_rw_s *rw_s = karg;  /* read, write ioctl str */
564
565                 err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s));
566                 if ( err ) {
567                         EXIT;
568                         return err;
569                 }
570
571                 conn.oc_id = rw_s->conn_id;
572
573                 if ( !OBT(obddev) || !OBP(obddev, write) ) {
574                         err = -EOPNOTSUPP;
575                         return err;
576                 }
577
578                 err = OBP(obddev, write)(&conn, &rw_s->obdo, rw_s->buf, 
579                                          &rw_s->count, rw_s->offset);
580                 if ( err ) {
581                         EXIT;
582                         return err;
583                 }
584
585                 err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count));
586                 EXIT;
587                 return err;
588         }
589         case OBD_IOC_PREALLOCATE: {
590                 struct oic_prealloc_s *prealloc = karg;
591
592                 /* has this minor been registered? */
593                 if (!obddev->obd_type)
594                         return -ENODEV;
595
596                 err = copy_from_user(prealloc, (int *)arg, sizeof(*prealloc));
597                 if (err) 
598                         return -EFAULT;
599
600                 if ( !(obddev->obd_flags & OBD_ATTACHED) ||
601                      !(obddev->obd_flags & OBD_SET_UP)) {
602                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
603                         return -ENODEV;
604                 }
605
606                 if ( !OBT(obddev) || !OBP(obddev, preallocate) )
607                         return -EOPNOTSUPP;
608
609                 conn.oc_id = prealloc->cli_id;
610                 err = OBP(obddev, preallocate)(&conn, &prealloc->alloc,
611                                                prealloc->ids);
612                 if ( err ) {
613                         EXIT;
614                         return err;
615                 }
616
617                 err =copy_to_user((int *)arg, prealloc, sizeof(*prealloc));
618                 EXIT;
619                 return err;
620         }
621         case OBD_IOC_STATFS: {
622                 struct statfs *tmp;
623                 unsigned int conn_id;
624                 struct statfs buf;
625
626                 /* has this minor been registered? */
627                 if (!obddev->obd_type)
628                         return -ENODEV;
629
630                 tmp = (void *)arg + sizeof(unsigned int);
631                 get_user(conn_id, (int *) arg);
632
633                 if ( !OBT(obddev) || !OBP(obddev, statfs) )
634                         return -EOPNOTSUPP;
635
636                 conn.oc_id = conn_id;
637                 err = OBP(obddev, statfs)(&conn, &buf);
638                 if ( err ) {
639                         EXIT;
640                         return err;
641                 }
642                 err = copy_to_user(tmp, &buf, sizeof(buf));
643                 EXIT;
644                 return err;
645                 
646         }
647         case OBD_IOC_COPY: {
648                 struct ioc_mv_s *mvdata = karg;
649
650                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
651                      (!(obddev->obd_flags & OBD_ATTACHED))) {
652                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
653                         return -ENODEV;
654                 }
655
656                 /* get main structure */
657                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
658                 if (err) {
659                         EXIT;
660                         return err;
661                 }
662
663                 if ( !OBT(obddev) || !OBP(obddev, copy) )
664                         return -EOPNOTSUPP;
665
666                 /* do the partition */
667                 CDEBUG(D_IOCTL, "Copy %d, type %s dst %Ld src %Ld\n", dev, 
668                        obddev->obd_type->typ_name, mvdata->dst.o_id, 
669                        mvdata->src.o_id);
670
671                 conn.oc_id = mvdata->src_conn_id;
672
673                 err = OBP(obddev, copy)(&conn, &mvdata->dst, 
674                                         &conn, &mvdata->src, 
675                                         mvdata->src.o_size, 0);
676                 return err;
677         }
678
679         case OBD_IOC_MIGR: {
680                 struct ioc_mv_s *mvdata = karg;
681
682                 if ( (!(obddev->obd_flags & OBD_SET_UP)) ||
683                      (!(obddev->obd_flags & OBD_ATTACHED))) {
684                         CDEBUG(D_IOCTL, "Device not attached or set up\n");
685                         return -ENODEV;
686                 }
687
688                 err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata));
689                 if (err) {
690                         EXIT;
691                         return err;
692                 }
693
694                 CDEBUG(D_IOCTL, "Migrate copying %d\n", sizeof(*mvdata));
695
696                 if ( !OBT(obddev) || !OBP(obddev, migrate) )
697                         return -EOPNOTSUPP;
698
699                 /* do the partition */
700                 CDEBUG(D_IOCTL, "Migrate %d, type %s conn %d src %Ld dst %Ld\n",
701                        dev, obddev->obd_type->typ_name, mvdata->src_conn_id,
702                        mvdata->src.o_id, mvdata->dst.o_id);
703
704                 conn.oc_id = mvdata->src_conn_id;
705                 err = OBP(obddev, migrate)(&conn, &mvdata->dst, &mvdata->src, 
706                                            mvdata->dst.o_size, 0);
707
708                 return err;
709         }
710
711         default: {
712                 struct obd_type *type;
713                 struct oic_generic input;
714                 void *karg;
715
716                 /* get data structures */
717                 err = copy_from_user(&input, (void *)arg, sizeof(input));
718                 if ( err ) {
719                         EXIT;
720                         return err;
721                 }
722
723                 err = getdata(input.att_typelen + 1, &input.att_type);
724                 if ( err ) {
725                         EXIT;
726                         return err;
727                 }
728
729                 /* find the type */
730                 type = obd_nm_to_type(input.att_type);
731                 OBD_FREE(input.att_type, input.att_typelen + 1);
732                 if ( !type ) {
733                         printk("Unknown obd type dev %d\n", dev);
734                         EXIT;
735                         return -EINVAL;
736                 }
737                 
738                 if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) {
739                         EXIT;
740                         return -EOPNOTSUPP;
741                 }
742                 conn.oc_id = input.att_connid;
743                 
744                 CDEBUG(D_IOCTL, "Calling ioctl %x for type %s, len %d\n",
745                        cmd, type->typ_name, input.att_datalen);
746
747                 /* get the generic data */
748                 karg = input.att_data;
749                 err = getdata(input.att_datalen, karg);
750                 if ( err ) {
751                         EXIT;
752                         return err;
753                 }
754
755                 err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, 
756                                                  karg, input.att_data);
757                 OBD_FREE(karg, input.att_datalen);
758
759                 EXIT;
760                 return err;
761         }
762         }
763 }
764
765 /* Driver interface done, utility functions follow */
766
767 int obd_register_type(struct obd_ops *ops, char *nm)
768 {
769         struct obd_type *type;
770
771
772         if (obd_init_magic != 0x11223344) {
773                 EXIT;
774                 return -EINVAL;
775         }
776
777         if  ( obd_nm_to_type(nm) ) {
778                 CDEBUG(D_IOCTL, "Type %s already registered\n", nm);
779                 EXIT;
780                 return -EEXIST;
781         }
782         
783         OBD_ALLOC(type, struct obd_type * , sizeof(*type));
784         if ( !type ) {
785                 EXIT;
786                 return -ENOMEM;
787         }
788         memset(type, 0, sizeof(*type));
789         INIT_LIST_HEAD(&type->typ_chain);
790         MOD_INC_USE_COUNT;
791         list_add(&type->typ_chain, obd_types.next);
792         type->typ_ops = ops;
793         type->typ_name = nm;
794         EXIT;
795         return 0;
796 }
797         
798 int obd_unregister_type(char *nm)
799 {
800         struct obd_type *type = obd_nm_to_type(nm);
801
802         if ( !type ) {
803                 MOD_DEC_USE_COUNT;
804                 printk("Unknown obd type\n");
805                 EXIT;
806                 return -EINVAL;
807         }
808
809         if ( type->typ_refcnt ) {
810                 MOD_DEC_USE_COUNT;
811                 printk("OBD: Type %s has refcount (%d)\n", nm,
812                        type->typ_refcnt);
813                 EXIT;
814                 return -EBUSY;
815         }
816
817         list_del(&type->typ_chain);
818         OBD_FREE(type, sizeof(*type));
819         MOD_DEC_USE_COUNT;
820         return 0;
821 }
822
823 /* declare character device */
824 static struct file_operations obd_psdev_fops = {
825         NULL,                  /* llseek */
826         NULL,                  /* read */
827         NULL,                  /* write */
828         NULL,                  /* presto_psdev_readdir */
829         NULL,                  /* poll */
830         obd_class_ioctl,       /* ioctl */
831         NULL,                  /* presto_psdev_mmap */
832         obd_class_open,        /* open */
833         NULL,
834         obd_class_release,     /* release */
835         NULL,                  /* fsync */
836         NULL,                  /* fasync */
837         NULL,                  /* check_media_change */
838         NULL,                  /* revalidate */
839         NULL                   /* lock */
840 };
841
842
843 /* modules setup */
844
845 int init_obd(void)
846 {
847         int i;
848
849         printk(KERN_INFO "OBD class driver  v0.01, braam@stelias.com\n");
850         
851         INIT_LIST_HEAD(&obd_types);
852         
853         if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", 
854                             &obd_psdev_fops)) {
855                 printk(KERN_ERR "obd_psdev: unable to get major %d\n", 
856                        OBD_PSDEV_MAJOR);
857                 return -EIO;
858         }
859
860         for (i = 0; i < MAX_OBD_DEVICES; i++) {
861                 memset(&(obd_dev[i]), 0, sizeof(obd_dev[i]));
862                 obd_dev[i].obd_minor = i;
863                 INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients);
864         }
865
866         obd_init_obdo_cache();
867         obd_sysctl_init();
868         obd_init_magic = 0x11223344;
869         return 0;
870 }
871
872 EXPORT_SYMBOL(obd_register_type);
873 EXPORT_SYMBOL(obd_unregister_type);
874
875 EXPORT_SYMBOL(obd_print_entry);
876 EXPORT_SYMBOL(obd_debug_level);
877 EXPORT_SYMBOL(obd_dev);
878
879 EXPORT_SYMBOL(gen_connect);
880 EXPORT_SYMBOL(gen_client);
881 EXPORT_SYMBOL(gen_cleanup);
882 EXPORT_SYMBOL(gen_disconnect);
883 EXPORT_SYMBOL(gen_copy_data); 
884 EXPORT_SYMBOL(obdo_cachep);
885
886 /* EXPORT_SYMBOL(gen_multi_attach); */
887 EXPORT_SYMBOL(gen_multi_setup);
888 EXPORT_SYMBOL(gen_multi_cleanup);
889
890
891 #ifdef MODULE
892 int init_module(void)
893 {
894         return init_obd();
895 }
896
897 void cleanup_module(void)
898 {
899         int i;
900         ENTRY;
901
902         unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev");
903         for (i = 0; i < MAX_OBD_DEVICES; i++) {
904                 struct obd_device *obddev = &obd_dev[i];
905                 if ( obddev->obd_type && 
906                      (obddev->obd_flags & OBD_SET_UP) &&
907                      OBT(obddev) && OBP(obddev, detach) ) {
908                         /* XXX should this call generic detach otherwise? */
909                         OBP(obddev, detach)(obddev);
910                 } 
911         }
912
913
914         obd_sysctl_clean();
915         obd_init_magic = 0;
916 }
917 #endif