upgrade to linux 2.6.10-1.12_FC2
[linux-2.6.git] / drivers / s390 / block / dasd_devmap.c
1 /*
2  * File...........: linux/drivers/s390/block/dasd_devmap.c
3  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4  *                  Horst Hummel <Horst.Hummel@de.ibm.com>
5  *                  Carsten Otte <Cotte@de.ibm.com>
6  *                  Martin Schwidefsky <schwidefsky@de.ibm.com>
7  * Bugreports.to..: <Linux390@de.ibm.com>
8  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
9  *
10  * Device mapping and dasd= parameter parsing functions. All devmap
11  * functions may not be called from interrupt context. In particular
12  * dasd_get_device is a no-no from interrupt context.
13  *
14  * $Revision: 1.34 $
15  */
16
17 #include <linux/config.h>
18 #include <linux/ctype.h>
19 #include <linux/init.h>
20
21 #include <asm/debug.h>
22 #include <asm/uaccess.h>
23
24 /* This is ugly... */
25 #define PRINTK_HEADER "dasd_devmap:"
26
27 #include "dasd_int.h"
28
29 kmem_cache_t *dasd_page_cache;
30 EXPORT_SYMBOL(dasd_page_cache);
31
32 /*
33  * dasd_devmap_t is used to store the features and the relation
34  * between device number and device index. To find a dasd_devmap_t
35  * that corresponds to a device number of a device index each
36  * dasd_devmap_t is added to two linked lists, one to search by
37  * the device number and one to search by the device index. As
38  * soon as big minor numbers are available the device index list
39  * can be removed since the device number will then be identical
40  * to the device index.
41  */
42 struct dasd_devmap {
43         struct list_head list;
44         char bus_id[BUS_ID_SIZE];
45         unsigned int devindex;
46         unsigned short features;
47         struct dasd_device *device;
48 };
49
50 /*
51  * Parameter parsing functions for dasd= parameter. The syntax is:
52  *   <devno>            : (0x)?[0-9a-fA-F]+
53  *   <busid>            : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
54  *   <feature>          : ro
55  *   <feature_list>     : \(<feature>(:<feature>)*\)
56  *   <devno-range>      : <devno>(-<devno>)?<feature_list>?
57  *   <busid-range>      : <busid>(-<busid>)?<feature_list>?
58  *   <devices>          : <devno-range>|<busid-range>
59  *   <dasd_module>      : dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod
60  *
61  *   <dasd>             : autodetect|probeonly|<devices>(,<devices>)*
62  */
63
64 int dasd_probeonly =  0;        /* is true, when probeonly mode is active */
65 int dasd_autodetect = 0;        /* is true, when autodetection is active */
66
67 /*
68  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
69  * it is named 'dasd' to directly be filled by insmod with the comma separated
70  * strings when running as a module.
71  */
72 static char *dasd[256];
73
74 /*
75  * Single spinlock to protect devmap structures and lists.
76  */
77 static spinlock_t dasd_devmap_lock = SPIN_LOCK_UNLOCKED;
78
79 /*
80  * Hash lists for devmap structures.
81  */
82 static struct list_head dasd_hashlists[256];
83 int dasd_max_devindex;
84
85 static struct dasd_devmap *dasd_add_busid(char *, int);
86
87 static inline int
88 dasd_hash_busid(char *bus_id)
89 {
90         int hash, i;
91
92         hash = 0;
93         for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++)
94                 hash += *bus_id;
95         return hash & 0xff;
96 }
97
98 #ifndef MODULE
99 /*
100  * The parameter parsing functions for builtin-drivers are called
101  * before kmalloc works. Store the pointers to the parameters strings
102  * into dasd[] for later processing.
103  */
104 static int __init
105 dasd_call_setup(char *str)
106 {
107         static int count = 0;
108
109         if (count < 256)
110                 dasd[count++] = str;
111         return 1;
112 }
113
114 __setup ("dasd=", dasd_call_setup);
115 #endif  /* #ifndef MODULE */
116
117 /*
118  * Read a device busid/devno from a string.
119  */
120 static inline int
121 dasd_busid(char **str, int *id0, int *id1, int *devno)
122 {
123         int val, old_style;
124  
125         /* check for leading '0x' */
126         old_style = 0;
127         if ((*str)[0] == '0' && (*str)[1] == 'x') {
128                 *str += 2;
129                 old_style = 1;
130         }
131         if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
132                 return -EINVAL;
133         val = simple_strtoul(*str, str, 16);
134         if (old_style || (*str)[0] != '.') {
135                 *id0 = *id1 = 0;
136                 if (val < 0 || val > 0xffff)
137                         return -EINVAL;
138                 *devno = val;
139                 return 0;
140         }
141         /* New style x.y.z busid */
142         if (val < 0 || val > 0xff)
143                 return -EINVAL;
144         *id0 = val;
145         (*str)++;
146         if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
147                 return -EINVAL;
148         val = simple_strtoul(*str, str, 16);
149         if (val < 0 || val > 0xff || (*str)++[0] != '.')
150                 return -EINVAL;
151         *id1 = val;
152         if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
153                 return -EINVAL;
154         val = simple_strtoul(*str, str, 16);
155         if (val < 0 || val > 0xffff)
156                 return -EINVAL;
157         *devno = val;
158         return 0;
159 }
160
161 /*
162  * Read colon separated list of dasd features. Currently there is
163  * only one: "ro" for read-only devices. The default feature set
164  * is empty (value 0).
165  */
166 static inline int
167 dasd_feature_list(char *str, char **endp)
168 {
169         int features, len, rc;
170
171         rc = 0;
172         if (*str != '(') {
173                 *endp = str;
174                 return DASD_FEATURE_DEFAULT;
175         }
176         str++;
177         features = 0;
178
179         while (1) {
180                 for (len = 0; 
181                      str[len] && str[len] != ':' && str[len] != ')'; len++);
182                 if (len == 2 && !strncmp(str, "ro", 2))
183                         features |= DASD_FEATURE_READONLY;
184                 else if (len == 4 && !strncmp(str, "diag", 4))
185                         features |= DASD_FEATURE_USEDIAG;
186                 else {
187                         MESSAGE(KERN_WARNING,
188                                 "unsupported feature: %*s, "
189                                 "ignoring setting", len, str);
190                         rc = -EINVAL;
191                 }
192                 str += len;
193                 if (*str != ':')
194                         break;
195                 str++;
196         }
197         if (*str != ')') {
198                 MESSAGE(KERN_WARNING, "%s",
199                         "missing ')' in dasd parameter string\n");
200                 rc = -EINVAL;
201         } else
202                 str++;
203         *endp = str;
204         if (rc != 0)
205                 return rc;
206         return features;
207 }
208
209 /*
210  * Try to match the first element on the comma separated parse string
211  * with one of the known keywords. If a keyword is found, take the approprate
212  * action and return a pointer to the residual string. If the first element
213  * could not be matched to any keyword then return an error code.
214  */
215 static char *
216 dasd_parse_keyword( char *parsestring ) {
217
218         char *nextcomma, *residual_str;
219         int length;
220
221         nextcomma = strchr(parsestring,',');
222         if (nextcomma) {
223                 length = nextcomma - parsestring;
224                 residual_str = nextcomma + 1;
225         } else {
226                 length = strlen(parsestring);
227                 residual_str = parsestring + length;
228         }
229         if (strncmp ("autodetect", parsestring, length) == 0) {
230                 dasd_autodetect = 1;
231                 MESSAGE (KERN_INFO, "%s",
232                          "turning to autodetection mode");
233                 return residual_str;
234         }
235         if (strncmp ("probeonly", parsestring, length) == 0) {
236                 dasd_probeonly = 1;
237                 MESSAGE(KERN_INFO, "%s",
238                         "turning to probeonly mode");
239                 return residual_str;
240         }
241         if (strncmp ("fixedbuffers", parsestring, length) == 0) {
242                 if (dasd_page_cache)
243                         return residual_str;
244                 dasd_page_cache =
245                         kmem_cache_create("dasd_page_cache", PAGE_SIZE, 0,
246                                           SLAB_CACHE_DMA, NULL, NULL );
247                 if (!dasd_page_cache)
248                         MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
249                                 "fixed buffer mode disabled.");
250                 else
251                         MESSAGE (KERN_INFO, "%s",
252                                  "turning on fixed buffer mode");
253                 return residual_str;
254         }
255         return ERR_PTR(-EINVAL);
256 }
257
258 /*
259  * Try to interprete the first element on the comma separated parse string
260  * as a device number or a range of devices. If the interpretation is
261  * successfull, create the matching dasd_devmap entries and return a pointer
262  * to the residual string.
263  * If interpretation fails or in case of an error, return an error code.
264  */
265 static char *
266 dasd_parse_range( char *parsestring ) {
267
268         struct dasd_devmap *devmap;
269         int from, from_id0, from_id1;
270         int to, to_id0, to_id1;
271         int features, rc;
272         char bus_id[BUS_ID_SIZE+1], *str;
273
274         str = parsestring;
275         rc = dasd_busid(&str, &from_id0, &from_id1, &from);
276         if (rc == 0) {
277                 to = from;
278                 to_id0 = from_id0;
279                 to_id1 = from_id1;
280                 if (*str == '-') {
281                         str++;
282                         rc = dasd_busid(&str, &to_id0, &to_id1, &to);
283                 }
284         }
285         if (rc == 0 &&
286             (from_id0 != to_id0 || from_id1 != to_id1 || from > to))
287                 rc = -EINVAL;
288         if (rc) {
289                 MESSAGE(KERN_ERR, "Invalid device range %s", parsestring);
290                 return ERR_PTR(rc);
291         }
292         features = dasd_feature_list(str, &str);
293         if (features < 0)
294                 return ERR_PTR(-EINVAL);
295         while (from <= to) {
296                 sprintf(bus_id, "%01x.%01x.%04x",
297                         from_id0, from_id1, from++);
298                 devmap = dasd_add_busid(bus_id, features);
299                 if (IS_ERR(devmap))
300                         return (char *)devmap;
301         }
302         if (*str == ',')
303                 return str + 1;
304         if (*str == '\0')
305                 return str;
306         MESSAGE(KERN_WARNING,
307                 "junk at end of dasd parameter string: %s\n", str);
308         return ERR_PTR(-EINVAL);
309 }
310
311 static inline char *
312 dasd_parse_next_element( char *parsestring ) {
313         char * residual_str;
314         residual_str = dasd_parse_keyword(parsestring);
315         if (!IS_ERR(residual_str))
316                 return residual_str;
317         residual_str = dasd_parse_range(parsestring);
318         return residual_str;
319 }
320
321 /*
322  * Parse parameters stored in dasd[]
323  * The 'dasd=...' parameter allows to specify a comma separated list of
324  * keywords and device ranges. When the dasd driver is build into the kernel,
325  * the complete list will be stored as one element of the dasd[] array.
326  * When the dasd driver is build as a module, then the list is broken into
327  * it's elements and each dasd[] entry contains one element.
328  */
329 int
330 dasd_parse(void)
331 {
332         int rc, i;
333         char *parsestring;
334
335         rc = 0;
336         for (i = 0; i < 256; i++) {
337                 if (dasd[i] == NULL)
338                         break;
339                 parsestring = dasd[i];
340                 /* loop over the comma separated list in the parsestring */
341                 while (*parsestring) {
342                         parsestring = dasd_parse_next_element(parsestring);
343                         if(IS_ERR(parsestring)) {
344                                 rc = PTR_ERR(parsestring);
345                                 break;
346                         }
347                 }
348                 if (rc) {
349                         DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
350                         break;
351                 }
352         }
353         return rc;
354 }
355
356 /*
357  * Add a devmap for the device specified by busid. It is possible that
358  * the devmap already exists (dasd= parameter). The order of the devices
359  * added through this function will define the kdevs for the individual
360  * devices. 
361  */
362 static struct dasd_devmap *
363 dasd_add_busid(char *bus_id, int features)
364 {
365         struct dasd_devmap *devmap, *new, *tmp;
366         int hash;
367
368         new = (struct dasd_devmap *)
369                 kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
370         if (!new)
371                 return ERR_PTR(-ENOMEM);
372         spin_lock(&dasd_devmap_lock);
373         devmap = 0;
374         hash = dasd_hash_busid(bus_id);
375         list_for_each_entry(tmp, &dasd_hashlists[hash], list)
376                 if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
377                         devmap = tmp;
378                         break;
379                 }
380         if (!devmap) {
381                 /* This bus_id is new. */
382                 new->devindex = dasd_max_devindex++;
383                 strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
384                 new->features = features;
385                 new->device = 0;
386                 list_add(&new->list, &dasd_hashlists[hash]);
387                 devmap = new;
388                 new = 0;
389         }
390         spin_unlock(&dasd_devmap_lock);
391         if (new)
392                 kfree(new);
393         return devmap;
394 }
395
396 /*
397  * Find devmap for device with given bus_id.
398  */
399 static struct dasd_devmap *
400 dasd_find_busid(char *bus_id)
401 {
402         struct dasd_devmap *devmap, *tmp;
403         int hash;
404
405         spin_lock(&dasd_devmap_lock);
406         devmap = ERR_PTR(-ENODEV);
407         hash = dasd_hash_busid(bus_id);
408         list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
409                 if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
410                         devmap = tmp;
411                         break;
412                 }
413         }
414         spin_unlock(&dasd_devmap_lock);
415         return devmap;
416 }
417
418 /*
419  * Check if busid has been added to the list of dasd ranges.
420  */
421 int
422 dasd_busid_known(char *bus_id)
423 {
424         return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0;
425 }
426
427 /*
428  * Forget all about the device numbers added so far.
429  * This may only be called at module unload or system shutdown.
430  */
431 static void
432 dasd_forget_ranges(void)
433 {
434         struct dasd_devmap *devmap, *n;
435         int i;
436
437         spin_lock(&dasd_devmap_lock);
438         for (i = 0; i < 256; i++) {
439                 list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) {
440                         if (devmap->device != NULL)
441                                 BUG();
442                         list_del(&devmap->list);
443                         kfree(devmap);
444                 }
445         }
446         spin_unlock(&dasd_devmap_lock);
447 }
448
449 /*
450  * Find the device struct by its device index.
451  */
452 struct dasd_device *
453 dasd_device_from_devindex(int devindex)
454 {
455         struct dasd_devmap *devmap, *tmp;
456         struct dasd_device *device;
457         int i;
458
459         spin_lock(&dasd_devmap_lock);
460         devmap = 0;
461         for (i = 0; (i < 256) && !devmap; i++)
462                 list_for_each_entry(tmp, &dasd_hashlists[i], list)
463                         if (tmp->devindex == devindex) {
464                                 /* Found the devmap for the device. */
465                                 devmap = tmp;
466                                 break;
467                         }
468         if (devmap && devmap->device) {
469                 device = devmap->device;
470                 dasd_get_device(device);
471         } else
472                 device = ERR_PTR(-ENODEV);
473         spin_unlock(&dasd_devmap_lock);
474         return device;
475 }
476
477 /*
478  * Return devmap for cdev. If no devmap exists yet, create one and
479  * connect it to the cdev.
480  */
481 static struct dasd_devmap *
482 dasd_devmap_from_cdev(struct ccw_device *cdev)
483 {
484         struct dasd_devmap *devmap;
485
486         devmap = dasd_find_busid(cdev->dev.bus_id);
487         if (IS_ERR(devmap))
488                 devmap = dasd_add_busid(cdev->dev.bus_id, DASD_FEATURE_DEFAULT);
489         return devmap;
490 }
491
492 /*
493  * Create a dasd device structure for cdev.
494  */
495 struct dasd_device *
496 dasd_create_device(struct ccw_device *cdev)
497 {
498         struct dasd_devmap *devmap;
499         struct dasd_device *device;
500         int rc;
501
502         devmap = dasd_devmap_from_cdev(cdev);
503         if (IS_ERR(devmap))
504                 return (void *) devmap;
505         cdev->dev.driver_data = devmap;
506
507         device = dasd_alloc_device();
508         if (IS_ERR(device))
509                 return device;
510         atomic_set(&device->ref_count, 2);
511
512         spin_lock(&dasd_devmap_lock);
513         if (!devmap->device) {
514                 devmap->device = device;
515                 device->devindex = devmap->devindex;
516                 if (devmap->features & DASD_FEATURE_READONLY)
517                         set_bit(DASD_FLAG_RO, &device->flags);
518                 else
519                         clear_bit(DASD_FLAG_RO, &device->flags);
520                 if (devmap->features & DASD_FEATURE_USEDIAG)
521                         set_bit(DASD_FLAG_USE_DIAG, &device->flags);
522                 else
523                         clear_bit(DASD_FLAG_USE_DIAG, &device->flags);
524                 get_device(&cdev->dev);
525                 device->cdev = cdev;
526                 rc = 0;
527         } else
528                 /* Someone else was faster. */
529                 rc = -EBUSY;
530         spin_unlock(&dasd_devmap_lock);
531
532         if (rc) {
533                 dasd_free_device(device);
534                 return ERR_PTR(rc);
535         }
536         return device;
537 }
538
539 /*
540  * Wait queue for dasd_delete_device waits.
541  */
542 static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);
543
544 /*
545  * Remove a dasd device structure. The passed referenced
546  * is destroyed.
547  */
548 void
549 dasd_delete_device(struct dasd_device *device)
550 {
551         struct ccw_device *cdev;
552         struct dasd_devmap *devmap;
553
554         /* First remove device pointer from devmap. */
555         devmap = dasd_find_busid(device->cdev->dev.bus_id);
556         spin_lock(&dasd_devmap_lock);
557         if (devmap->device != device) {
558                 spin_unlock(&dasd_devmap_lock);
559                 dasd_put_device(device);
560                 return;
561         }
562         devmap->device = NULL;
563         spin_unlock(&dasd_devmap_lock);
564
565         /* Drop ref_count by 2, one for the devmap reference and
566          * one for the passed reference. */
567         atomic_sub(2, &device->ref_count);
568
569         /* Wait for reference counter to drop to zero. */
570         wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
571
572         /* Disconnect dasd_device structure from ccw_device structure. */
573         cdev = device->cdev;
574         device->cdev = NULL;
575
576         /* Disconnect dasd_devmap structure from ccw_device structure. */
577         cdev->dev.driver_data = NULL;
578
579         /* Put ccw_device structure. */
580         put_device(&cdev->dev);
581
582         /* Now the device structure can be freed. */
583         dasd_free_device(device);
584 }
585
586 /*
587  * Reference counter dropped to zero. Wake up waiter
588  * in dasd_delete_device.
589  */
590 void
591 dasd_put_device_wake(struct dasd_device *device)
592 {
593         wake_up(&dasd_delete_wq);
594 }
595
596 /*
597  * Return dasd_device structure associated with cdev.
598  */
599 struct dasd_device *
600 dasd_device_from_cdev(struct ccw_device *cdev)
601 {
602         struct dasd_devmap *devmap;
603         struct dasd_device *device;
604
605         device = ERR_PTR(-ENODEV);
606         spin_lock(&dasd_devmap_lock);
607         devmap = cdev->dev.driver_data;
608         if (devmap && devmap->device) {
609                 device = devmap->device;
610                 dasd_get_device(device);
611         }
612         spin_unlock(&dasd_devmap_lock);
613         return device;
614 }
615
616 /*
617  * SECTION: files in sysfs
618  */
619
620 /*
621  * readonly controls the readonly status of a dasd
622  */
623 static ssize_t
624 dasd_ro_show(struct device *dev, char *buf)
625 {
626         struct dasd_devmap *devmap;
627         int ro_flag;
628
629         devmap = dev->driver_data;
630         if (devmap)
631                 ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
632         else
633                 ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;
634         return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n");
635 }
636
637 static ssize_t
638 dasd_ro_store(struct device *dev, const char *buf, size_t count)
639 {
640         struct dasd_devmap *devmap;
641         int ro_flag;
642
643         devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
644         ro_flag = buf[0] == '1';
645         spin_lock(&dasd_devmap_lock);
646         if (ro_flag)
647                 devmap->features |= DASD_FEATURE_READONLY;
648         else
649                 devmap->features &= ~DASD_FEATURE_READONLY;
650         if (devmap->device) {
651                 if (devmap->device->gdp)
652                         set_disk_ro(devmap->device->gdp, ro_flag);
653                 if (ro_flag)
654                         set_bit(DASD_FLAG_RO, &devmap->device->flags);
655                 else
656                         clear_bit(DASD_FLAG_RO, &devmap->device->flags);
657         }
658         spin_unlock(&dasd_devmap_lock);
659         return count;
660 }
661
662 static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
663
664 /*
665  * use_diag controls whether the driver should use diag rather than ssch
666  * to talk to the device
667  */
668 /* TODO: Implement */
669 static ssize_t 
670 dasd_use_diag_show(struct device *dev, char *buf)
671 {
672         struct dasd_devmap *devmap;
673         int use_diag;
674
675         devmap = dev->driver_data;
676         if (devmap)
677                 use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
678         else
679                 use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
680         return sprintf(buf, use_diag ? "1\n" : "0\n");
681 }
682
683 static ssize_t
684 dasd_use_diag_store(struct device *dev, const char *buf, size_t count)
685 {
686         struct dasd_devmap *devmap;
687         int use_diag;
688
689         devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
690         use_diag = buf[0] == '1';
691         spin_lock(&dasd_devmap_lock);
692         /* Changing diag discipline flag is only allowed in offline state. */
693         if (!devmap->device) {
694                 if (use_diag)
695                         devmap->features |= DASD_FEATURE_USEDIAG;
696                 else
697                         devmap->features &= ~DASD_FEATURE_USEDIAG;
698         } else
699                 count = -EPERM;
700         spin_unlock(&dasd_devmap_lock);
701         return count;
702 }
703
704 static
705 DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
706
707 static ssize_t
708 dasd_discipline_show(struct device *dev, char *buf)
709 {
710         struct dasd_devmap *devmap;
711         char *dname;
712
713         spin_lock(&dasd_devmap_lock);
714         dname = "none";
715         devmap = dev->driver_data;
716         if (devmap && devmap->device && devmap->device->discipline)
717                 dname = devmap->device->discipline->name;
718         spin_unlock(&dasd_devmap_lock);
719         return snprintf(buf, PAGE_SIZE, "%s\n", dname);
720 }
721
722 static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
723
724 static struct attribute * dasd_attrs[] = {
725         &dev_attr_readonly.attr,
726         &dev_attr_discipline.attr,
727         &dev_attr_use_diag.attr,
728         NULL,
729 };
730
731 static struct attribute_group dasd_attr_group = {
732         .attrs = dasd_attrs,
733 };
734
735 int
736 dasd_add_sysfs_files(struct ccw_device *cdev)
737 {
738         return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
739 }
740
741 void
742 dasd_remove_sysfs_files(struct ccw_device *cdev)
743 {
744         sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
745 }
746
747
748 int
749 dasd_devmap_init(void)
750 {
751         int i;
752
753         /* Initialize devmap structures. */
754         dasd_max_devindex = 0;
755         for (i = 0; i < 256; i++)
756                 INIT_LIST_HEAD(&dasd_hashlists[i]);
757         return 0;
758
759 }
760
761 void
762 dasd_devmap_exit(void)
763 {
764         dasd_forget_ranges();
765 }