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