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