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