]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/s390/block/dasd_devmap.c
0c67258fb9ec07cb6351edb1a4ee307848f4db67
[linux-2.6-omap-h63xx.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  */
15
16 #include <linux/ctype.h>
17 #include <linux/init.h>
18 #include <linux/module.h>
19
20 #include <asm/debug.h>
21 #include <asm/uaccess.h>
22 #include <asm/ipl.h>
23
24 /* This is ugly... */
25 #define PRINTK_HEADER "dasd_devmap:"
26
27 #include "dasd_int.h"
28
29 struct kmem_cache *dasd_page_cache;
30 EXPORT_SYMBOL_GPL(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         struct dasd_uid uid;
49 };
50
51 /*
52  * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
53  * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
54  * the DASD device driver.
55  */
56 struct dasd_server_ssid_map {
57         struct list_head list;
58         struct system_id {
59                 char vendor[4];
60                 char serial[15];
61                 __u16 ssid;
62         } sid;
63 };
64
65 static struct list_head dasd_server_ssid_list;
66
67 /*
68  * Parameter parsing functions for dasd= parameter. The syntax is:
69  *   <devno>            : (0x)?[0-9a-fA-F]+
70  *   <busid>            : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
71  *   <feature>          : ro
72  *   <feature_list>     : \(<feature>(:<feature>)*\)
73  *   <devno-range>      : <devno>(-<devno>)?<feature_list>?
74  *   <busid-range>      : <busid>(-<busid>)?<feature_list>?
75  *   <devices>          : <devno-range>|<busid-range>
76  *   <dasd_module>      : dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod
77  *
78  *   <dasd>             : autodetect|probeonly|<devices>(,<devices>)*
79  */
80
81 int dasd_probeonly =  0;        /* is true, when probeonly mode is active */
82 int dasd_autodetect = 0;        /* is true, when autodetection is active */
83 int dasd_nopav = 0;             /* is true, when PAV is disabled */
84 EXPORT_SYMBOL_GPL(dasd_nopav);
85
86 /*
87  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
88  * it is named 'dasd' to directly be filled by insmod with the comma separated
89  * strings when running as a module.
90  */
91 static char *dasd[256];
92 module_param_array(dasd, charp, NULL, 0);
93
94 /*
95  * Single spinlock to protect devmap and servermap structures and lists.
96  */
97 static DEFINE_SPINLOCK(dasd_devmap_lock);
98
99 /*
100  * Hash lists for devmap structures.
101  */
102 static struct list_head dasd_hashlists[256];
103 int dasd_max_devindex;
104
105 static struct dasd_devmap *dasd_add_busid(char *, int);
106
107 static inline int
108 dasd_hash_busid(char *bus_id)
109 {
110         int hash, i;
111
112         hash = 0;
113         for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++)
114                 hash += *bus_id;
115         return hash & 0xff;
116 }
117
118 #ifndef MODULE
119 /*
120  * The parameter parsing functions for builtin-drivers are called
121  * before kmalloc works. Store the pointers to the parameters strings
122  * into dasd[] for later processing.
123  */
124 static int __init
125 dasd_call_setup(char *str)
126 {
127         static int count = 0;
128
129         if (count < 256)
130                 dasd[count++] = str;
131         return 1;
132 }
133
134 __setup ("dasd=", dasd_call_setup);
135 #endif  /* #ifndef MODULE */
136
137 #define DASD_IPLDEV     "ipldev"
138
139 /*
140  * Read a device busid/devno from a string.
141  */
142 static int
143 dasd_busid(char **str, int *id0, int *id1, int *devno)
144 {
145         int val, old_style;
146
147         /* Interpret ipldev busid */
148         if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) {
149                 if (ipl_info.type != IPL_TYPE_CCW) {
150                         MESSAGE(KERN_ERR, "%s", "ipl device is not a ccw "
151                                 "device");
152                         return -EINVAL;
153                 }
154                 *id0 = 0;
155                 *id1 = ipl_info.data.ccw.dev_id.ssid;
156                 *devno = ipl_info.data.ccw.dev_id.devno;
157                 *str += strlen(DASD_IPLDEV);
158
159                 return 0;
160         }
161         /* check for leading '0x' */
162         old_style = 0;
163         if ((*str)[0] == '0' && (*str)[1] == 'x') {
164                 *str += 2;
165                 old_style = 1;
166         }
167         if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
168                 return -EINVAL;
169         val = simple_strtoul(*str, str, 16);
170         if (old_style || (*str)[0] != '.') {
171                 *id0 = *id1 = 0;
172                 if (val < 0 || val > 0xffff)
173                         return -EINVAL;
174                 *devno = val;
175                 return 0;
176         }
177         /* New style x.y.z busid */
178         if (val < 0 || val > 0xff)
179                 return -EINVAL;
180         *id0 = val;
181         (*str)++;
182         if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
183                 return -EINVAL;
184         val = simple_strtoul(*str, str, 16);
185         if (val < 0 || val > 0xff || (*str)++[0] != '.')
186                 return -EINVAL;
187         *id1 = val;
188         if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
189                 return -EINVAL;
190         val = simple_strtoul(*str, str, 16);
191         if (val < 0 || val > 0xffff)
192                 return -EINVAL;
193         *devno = val;
194         return 0;
195 }
196
197 /*
198  * Read colon separated list of dasd features. Currently there is
199  * only one: "ro" for read-only devices. The default feature set
200  * is empty (value 0).
201  */
202 static int
203 dasd_feature_list(char *str, char **endp)
204 {
205         int features, len, rc;
206
207         rc = 0;
208         if (*str != '(') {
209                 *endp = str;
210                 return DASD_FEATURE_DEFAULT;
211         }
212         str++;
213         features = 0;
214
215         while (1) {
216                 for (len = 0;
217                      str[len] && str[len] != ':' && str[len] != ')'; len++);
218                 if (len == 2 && !strncmp(str, "ro", 2))
219                         features |= DASD_FEATURE_READONLY;
220                 else if (len == 4 && !strncmp(str, "diag", 4))
221                         features |= DASD_FEATURE_USEDIAG;
222                 else if (len == 6 && !strncmp(str, "erplog", 6))
223                         features |= DASD_FEATURE_ERPLOG;
224                 else {
225                         MESSAGE(KERN_WARNING,
226                                 "unsupported feature: %*s, "
227                                 "ignoring setting", len, str);
228                         rc = -EINVAL;
229                 }
230                 str += len;
231                 if (*str != ':')
232                         break;
233                 str++;
234         }
235         if (*str != ')') {
236                 MESSAGE(KERN_WARNING, "%s",
237                         "missing ')' in dasd parameter string\n");
238                 rc = -EINVAL;
239         } else
240                 str++;
241         *endp = str;
242         if (rc != 0)
243                 return rc;
244         return features;
245 }
246
247 /*
248  * Try to match the first element on the comma separated parse string
249  * with one of the known keywords. If a keyword is found, take the approprate
250  * action and return a pointer to the residual string. If the first element
251  * could not be matched to any keyword then return an error code.
252  */
253 static char *
254 dasd_parse_keyword( char *parsestring ) {
255
256         char *nextcomma, *residual_str;
257         int length;
258
259         nextcomma = strchr(parsestring,',');
260         if (nextcomma) {
261                 length = nextcomma - parsestring;
262                 residual_str = nextcomma + 1;
263         } else {
264                 length = strlen(parsestring);
265                 residual_str = parsestring + length;
266         }
267         if (strncmp("autodetect", parsestring, length) == 0) {
268                 dasd_autodetect = 1;
269                 MESSAGE (KERN_INFO, "%s",
270                          "turning to autodetection mode");
271                 return residual_str;
272         }
273         if (strncmp("probeonly", parsestring, length) == 0) {
274                 dasd_probeonly = 1;
275                 MESSAGE(KERN_INFO, "%s",
276                         "turning to probeonly mode");
277                 return residual_str;
278         }
279         if (strncmp("nopav", parsestring, length) == 0) {
280                 if (MACHINE_IS_VM)
281                         MESSAGE(KERN_INFO, "%s", "'nopav' not supported on VM");
282                 else {
283                         dasd_nopav = 1;
284                         MESSAGE(KERN_INFO, "%s", "disable PAV mode");
285                 }
286                 return residual_str;
287         }
288         if (strncmp("fixedbuffers", parsestring, length) == 0) {
289                 if (dasd_page_cache)
290                         return residual_str;
291                 dasd_page_cache =
292                         kmem_cache_create("dasd_page_cache", PAGE_SIZE,
293                                           PAGE_SIZE, SLAB_CACHE_DMA,
294                                           NULL);
295                 if (!dasd_page_cache)
296                         MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
297                                 "fixed buffer mode disabled.");
298                 else
299                         MESSAGE (KERN_INFO, "%s",
300                                  "turning on fixed buffer mode");
301                 return residual_str;
302         }
303         return ERR_PTR(-EINVAL);
304 }
305
306 /*
307  * Try to interprete the first element on the comma separated parse string
308  * as a device number or a range of devices. If the interpretation is
309  * successfull, create the matching dasd_devmap entries and return a pointer
310  * to the residual string.
311  * If interpretation fails or in case of an error, return an error code.
312  */
313 static char *
314 dasd_parse_range( char *parsestring ) {
315
316         struct dasd_devmap *devmap;
317         int from, from_id0, from_id1;
318         int to, to_id0, to_id1;
319         int features, rc;
320         char bus_id[BUS_ID_SIZE+1], *str;
321
322         str = parsestring;
323         rc = dasd_busid(&str, &from_id0, &from_id1, &from);
324         if (rc == 0) {
325                 to = from;
326                 to_id0 = from_id0;
327                 to_id1 = from_id1;
328                 if (*str == '-') {
329                         str++;
330                         rc = dasd_busid(&str, &to_id0, &to_id1, &to);
331                 }
332         }
333         if (rc == 0 &&
334             (from_id0 != to_id0 || from_id1 != to_id1 || from > to))
335                 rc = -EINVAL;
336         if (rc) {
337                 MESSAGE(KERN_ERR, "Invalid device range %s", parsestring);
338                 return ERR_PTR(rc);
339         }
340         features = dasd_feature_list(str, &str);
341         if (features < 0)
342                 return ERR_PTR(-EINVAL);
343         /* each device in dasd= parameter should be set initially online */
344         features |= DASD_FEATURE_INITIAL_ONLINE;
345         while (from <= to) {
346                 sprintf(bus_id, "%01x.%01x.%04x",
347                         from_id0, from_id1, from++);
348                 devmap = dasd_add_busid(bus_id, features);
349                 if (IS_ERR(devmap))
350                         return (char *)devmap;
351         }
352         if (*str == ',')
353                 return str + 1;
354         if (*str == '\0')
355                 return str;
356         MESSAGE(KERN_WARNING,
357                 "junk at end of dasd parameter string: %s\n", str);
358         return ERR_PTR(-EINVAL);
359 }
360
361 static char *
362 dasd_parse_next_element( char *parsestring ) {
363         char * residual_str;
364         residual_str = dasd_parse_keyword(parsestring);
365         if (!IS_ERR(residual_str))
366                 return residual_str;
367         residual_str = dasd_parse_range(parsestring);
368         return residual_str;
369 }
370
371 /*
372  * Parse parameters stored in dasd[]
373  * The 'dasd=...' parameter allows to specify a comma separated list of
374  * keywords and device ranges. When the dasd driver is build into the kernel,
375  * the complete list will be stored as one element of the dasd[] array.
376  * When the dasd driver is build as a module, then the list is broken into
377  * it's elements and each dasd[] entry contains one element.
378  */
379 int
380 dasd_parse(void)
381 {
382         int rc, i;
383         char *parsestring;
384
385         rc = 0;
386         for (i = 0; i < 256; i++) {
387                 if (dasd[i] == NULL)
388                         break;
389                 parsestring = dasd[i];
390                 /* loop over the comma separated list in the parsestring */
391                 while (*parsestring) {
392                         parsestring = dasd_parse_next_element(parsestring);
393                         if(IS_ERR(parsestring)) {
394                                 rc = PTR_ERR(parsestring);
395                                 break;
396                         }
397                 }
398                 if (rc) {
399                         DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
400                         break;
401                 }
402         }
403         return rc;
404 }
405
406 /*
407  * Add a devmap for the device specified by busid. It is possible that
408  * the devmap already exists (dasd= parameter). The order of the devices
409  * added through this function will define the kdevs for the individual
410  * devices.
411  */
412 static struct dasd_devmap *
413 dasd_add_busid(char *bus_id, int features)
414 {
415         struct dasd_devmap *devmap, *new, *tmp;
416         int hash;
417
418         new = (struct dasd_devmap *)
419                 kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
420         if (!new)
421                 return ERR_PTR(-ENOMEM);
422         spin_lock(&dasd_devmap_lock);
423         devmap = NULL;
424         hash = dasd_hash_busid(bus_id);
425         list_for_each_entry(tmp, &dasd_hashlists[hash], list)
426                 if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
427                         devmap = tmp;
428                         break;
429                 }
430         if (!devmap) {
431                 /* This bus_id is new. */
432                 new->devindex = dasd_max_devindex++;
433                 strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
434                 new->features = features;
435                 new->device = NULL;
436                 list_add(&new->list, &dasd_hashlists[hash]);
437                 devmap = new;
438                 new = NULL;
439         }
440         spin_unlock(&dasd_devmap_lock);
441         kfree(new);
442         return devmap;
443 }
444
445 /*
446  * Find devmap for device with given bus_id.
447  */
448 static struct dasd_devmap *
449 dasd_find_busid(char *bus_id)
450 {
451         struct dasd_devmap *devmap, *tmp;
452         int hash;
453
454         spin_lock(&dasd_devmap_lock);
455         devmap = ERR_PTR(-ENODEV);
456         hash = dasd_hash_busid(bus_id);
457         list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
458                 if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
459                         devmap = tmp;
460                         break;
461                 }
462         }
463         spin_unlock(&dasd_devmap_lock);
464         return devmap;
465 }
466
467 /*
468  * Check if busid has been added to the list of dasd ranges.
469  */
470 int
471 dasd_busid_known(char *bus_id)
472 {
473         return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0;
474 }
475
476 /*
477  * Forget all about the device numbers added so far.
478  * This may only be called at module unload or system shutdown.
479  */
480 static void
481 dasd_forget_ranges(void)
482 {
483         struct dasd_devmap *devmap, *n;
484         int i;
485
486         spin_lock(&dasd_devmap_lock);
487         for (i = 0; i < 256; i++) {
488                 list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) {
489                         BUG_ON(devmap->device != NULL);
490                         list_del(&devmap->list);
491                         kfree(devmap);
492                 }
493         }
494         spin_unlock(&dasd_devmap_lock);
495 }
496
497 /*
498  * Find the device struct by its device index.
499  */
500 struct dasd_device *
501 dasd_device_from_devindex(int devindex)
502 {
503         struct dasd_devmap *devmap, *tmp;
504         struct dasd_device *device;
505         int i;
506
507         spin_lock(&dasd_devmap_lock);
508         devmap = NULL;
509         for (i = 0; (i < 256) && !devmap; i++)
510                 list_for_each_entry(tmp, &dasd_hashlists[i], list)
511                         if (tmp->devindex == devindex) {
512                                 /* Found the devmap for the device. */
513                                 devmap = tmp;
514                                 break;
515                         }
516         if (devmap && devmap->device) {
517                 device = devmap->device;
518                 dasd_get_device(device);
519         } else
520                 device = ERR_PTR(-ENODEV);
521         spin_unlock(&dasd_devmap_lock);
522         return device;
523 }
524
525 /*
526  * Return devmap for cdev. If no devmap exists yet, create one and
527  * connect it to the cdev.
528  */
529 static struct dasd_devmap *
530 dasd_devmap_from_cdev(struct ccw_device *cdev)
531 {
532         struct dasd_devmap *devmap;
533
534         devmap = dasd_find_busid(cdev->dev.bus_id);
535         if (IS_ERR(devmap))
536                 devmap = dasd_add_busid(cdev->dev.bus_id,
537                                         DASD_FEATURE_DEFAULT);
538         return devmap;
539 }
540
541 /*
542  * Create a dasd device structure for cdev.
543  */
544 struct dasd_device *
545 dasd_create_device(struct ccw_device *cdev)
546 {
547         struct dasd_devmap *devmap;
548         struct dasd_device *device;
549         unsigned long flags;
550         int rc;
551
552         devmap = dasd_devmap_from_cdev(cdev);
553         if (IS_ERR(devmap))
554                 return (void *) devmap;
555
556         device = dasd_alloc_device();
557         if (IS_ERR(device))
558                 return device;
559         atomic_set(&device->ref_count, 3);
560
561         spin_lock(&dasd_devmap_lock);
562         if (!devmap->device) {
563                 devmap->device = device;
564                 device->devindex = devmap->devindex;
565                 device->features = devmap->features;
566                 get_device(&cdev->dev);
567                 device->cdev = cdev;
568                 rc = 0;
569         } else
570                 /* Someone else was faster. */
571                 rc = -EBUSY;
572         spin_unlock(&dasd_devmap_lock);
573
574         if (rc) {
575                 dasd_free_device(device);
576                 return ERR_PTR(rc);
577         }
578
579         spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
580         cdev->dev.driver_data = device;
581         spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
582
583         return device;
584 }
585
586 /*
587  * Wait queue for dasd_delete_device waits.
588  */
589 static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);
590
591 /*
592  * Remove a dasd device structure. The passed referenced
593  * is destroyed.
594  */
595 void
596 dasd_delete_device(struct dasd_device *device)
597 {
598         struct ccw_device *cdev;
599         struct dasd_devmap *devmap;
600         unsigned long flags;
601
602         /* First remove device pointer from devmap. */
603         devmap = dasd_find_busid(device->cdev->dev.bus_id);
604         BUG_ON(IS_ERR(devmap));
605         spin_lock(&dasd_devmap_lock);
606         if (devmap->device != device) {
607                 spin_unlock(&dasd_devmap_lock);
608                 dasd_put_device(device);
609                 return;
610         }
611         devmap->device = NULL;
612         spin_unlock(&dasd_devmap_lock);
613
614         /* Disconnect dasd_device structure from ccw_device structure. */
615         spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
616         device->cdev->dev.driver_data = NULL;
617         spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
618
619         /*
620          * Drop ref_count by 3, one for the devmap reference, one for
621          * the cdev reference and one for the passed reference.
622          */
623         atomic_sub(3, &device->ref_count);
624
625         /* Wait for reference counter to drop to zero. */
626         wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
627
628         /* Disconnect dasd_device structure from ccw_device structure. */
629         cdev = device->cdev;
630         device->cdev = NULL;
631
632         /* Put ccw_device structure. */
633         put_device(&cdev->dev);
634
635         /* Now the device structure can be freed. */
636         dasd_free_device(device);
637 }
638
639 /*
640  * Reference counter dropped to zero. Wake up waiter
641  * in dasd_delete_device.
642  */
643 void
644 dasd_put_device_wake(struct dasd_device *device)
645 {
646         wake_up(&dasd_delete_wq);
647 }
648
649 /*
650  * Return dasd_device structure associated with cdev.
651  * This function needs to be called with the ccw device
652  * lock held. It can be used from interrupt context.
653  */
654 struct dasd_device *
655 dasd_device_from_cdev_locked(struct ccw_device *cdev)
656 {
657         struct dasd_device *device = cdev->dev.driver_data;
658
659         if (!device)
660                 return ERR_PTR(-ENODEV);
661         dasd_get_device(device);
662         return device;
663 }
664
665 /*
666  * Return dasd_device structure associated with cdev.
667  */
668 struct dasd_device *
669 dasd_device_from_cdev(struct ccw_device *cdev)
670 {
671         struct dasd_device *device;
672         unsigned long flags;
673
674         spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
675         device = dasd_device_from_cdev_locked(cdev);
676         spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
677         return device;
678 }
679
680 /*
681  * SECTION: files in sysfs
682  */
683
684 /*
685  * readonly controls the readonly status of a dasd
686  */
687 static ssize_t
688 dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
689 {
690         struct dasd_devmap *devmap;
691         int ro_flag;
692
693         devmap = dasd_find_busid(dev->bus_id);
694         if (!IS_ERR(devmap))
695                 ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
696         else
697                 ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;
698         return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n");
699 }
700
701 static ssize_t
702 dasd_ro_store(struct device *dev, struct device_attribute *attr,
703               const char *buf, size_t count)
704 {
705         struct dasd_devmap *devmap;
706         int val;
707         char *endp;
708
709         devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
710         if (IS_ERR(devmap))
711                 return PTR_ERR(devmap);
712
713         val = simple_strtoul(buf, &endp, 0);
714         if (((endp + 1) < (buf + count)) || (val > 1))
715                 return -EINVAL;
716
717         spin_lock(&dasd_devmap_lock);
718         if (val)
719                 devmap->features |= DASD_FEATURE_READONLY;
720         else
721                 devmap->features &= ~DASD_FEATURE_READONLY;
722         if (devmap->device)
723                 devmap->device->features = devmap->features;
724         if (devmap->device && devmap->device->gdp)
725                 set_disk_ro(devmap->device->gdp, val);
726         spin_unlock(&dasd_devmap_lock);
727         return count;
728 }
729
730 static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
731 /*
732  * erplog controls the logging of ERP related data
733  * (e.g. failing channel programs).
734  */
735 static ssize_t
736 dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf)
737 {
738         struct dasd_devmap *devmap;
739         int erplog;
740
741         devmap = dasd_find_busid(dev->bus_id);
742         if (!IS_ERR(devmap))
743                 erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0;
744         else
745                 erplog = (DASD_FEATURE_DEFAULT & DASD_FEATURE_ERPLOG) != 0;
746         return snprintf(buf, PAGE_SIZE, erplog ? "1\n" : "0\n");
747 }
748
749 static ssize_t
750 dasd_erplog_store(struct device *dev, struct device_attribute *attr,
751               const char *buf, size_t count)
752 {
753         struct dasd_devmap *devmap;
754         int val;
755         char *endp;
756
757         devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
758         if (IS_ERR(devmap))
759                 return PTR_ERR(devmap);
760
761         val = simple_strtoul(buf, &endp, 0);
762         if (((endp + 1) < (buf + count)) || (val > 1))
763                 return -EINVAL;
764
765         spin_lock(&dasd_devmap_lock);
766         if (val)
767                 devmap->features |= DASD_FEATURE_ERPLOG;
768         else
769                 devmap->features &= ~DASD_FEATURE_ERPLOG;
770         if (devmap->device)
771                 devmap->device->features = devmap->features;
772         spin_unlock(&dasd_devmap_lock);
773         return count;
774 }
775
776 static DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store);
777
778 /*
779  * use_diag controls whether the driver should use diag rather than ssch
780  * to talk to the device
781  */
782 static ssize_t
783 dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
784 {
785         struct dasd_devmap *devmap;
786         int use_diag;
787
788         devmap = dasd_find_busid(dev->bus_id);
789         if (!IS_ERR(devmap))
790                 use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
791         else
792                 use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
793         return sprintf(buf, use_diag ? "1\n" : "0\n");
794 }
795
796 static ssize_t
797 dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
798                     const char *buf, size_t count)
799 {
800         struct dasd_devmap *devmap;
801         ssize_t rc;
802         int val;
803         char *endp;
804
805         devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
806         if (IS_ERR(devmap))
807                 return PTR_ERR(devmap);
808
809         val = simple_strtoul(buf, &endp, 0);
810         if (((endp + 1) < (buf + count)) || (val > 1))
811                 return -EINVAL;
812
813         spin_lock(&dasd_devmap_lock);
814         /* Changing diag discipline flag is only allowed in offline state. */
815         rc = count;
816         if (!devmap->device) {
817                 if (val)
818                         devmap->features |= DASD_FEATURE_USEDIAG;
819                 else
820                         devmap->features &= ~DASD_FEATURE_USEDIAG;
821         } else
822                 rc = -EPERM;
823         spin_unlock(&dasd_devmap_lock);
824         return rc;
825 }
826
827 static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
828
829 static ssize_t
830 dasd_discipline_show(struct device *dev, struct device_attribute *attr,
831                      char *buf)
832 {
833         struct dasd_device *device;
834         ssize_t len;
835
836         device = dasd_device_from_cdev(to_ccwdev(dev));
837         if (!IS_ERR(device) && device->discipline) {
838                 len = snprintf(buf, PAGE_SIZE, "%s\n",
839                                device->discipline->name);
840                 dasd_put_device(device);
841         } else
842                 len = snprintf(buf, PAGE_SIZE, "none\n");
843         return len;
844 }
845
846 static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
847
848 static ssize_t
849 dasd_device_status_show(struct device *dev, struct device_attribute *attr,
850                      char *buf)
851 {
852         struct dasd_device *device;
853         ssize_t len;
854
855         device = dasd_device_from_cdev(to_ccwdev(dev));
856         if (!IS_ERR(device)) {
857                 switch (device->state) {
858                 case DASD_STATE_NEW:
859                         len = snprintf(buf, PAGE_SIZE, "new\n");
860                         break;
861                 case DASD_STATE_KNOWN:
862                         len = snprintf(buf, PAGE_SIZE, "detected\n");
863                         break;
864                 case DASD_STATE_BASIC:
865                         len = snprintf(buf, PAGE_SIZE, "basic\n");
866                         break;
867                 case DASD_STATE_UNFMT:
868                         len = snprintf(buf, PAGE_SIZE, "unformatted\n");
869                         break;
870                 case DASD_STATE_READY:
871                         len = snprintf(buf, PAGE_SIZE, "ready\n");
872                         break;
873                 case DASD_STATE_ONLINE:
874                         len = snprintf(buf, PAGE_SIZE, "online\n");
875                         break;
876                 default:
877                         len = snprintf(buf, PAGE_SIZE, "no stat\n");
878                         break;
879                 }
880                 dasd_put_device(device);
881         } else
882                 len = snprintf(buf, PAGE_SIZE, "unknown\n");
883         return len;
884 }
885
886 static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL);
887
888 static ssize_t
889 dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
890 {
891         struct dasd_devmap *devmap;
892         int alias;
893
894         devmap = dasd_find_busid(dev->bus_id);
895         spin_lock(&dasd_devmap_lock);
896         if (!IS_ERR(devmap))
897                 alias = devmap->uid.alias;
898         else
899                 alias = 0;
900         spin_unlock(&dasd_devmap_lock);
901
902         return sprintf(buf, alias ? "1\n" : "0\n");
903 }
904
905 static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL);
906
907 static ssize_t
908 dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
909 {
910         struct dasd_devmap *devmap;
911         char *vendor;
912
913         devmap = dasd_find_busid(dev->bus_id);
914         spin_lock(&dasd_devmap_lock);
915         if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
916                 vendor = devmap->uid.vendor;
917         else
918                 vendor = "";
919         spin_unlock(&dasd_devmap_lock);
920
921         return snprintf(buf, PAGE_SIZE, "%s\n", vendor);
922 }
923
924 static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
925
926 #define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial    */ 14 + 1 +\
927                      /* SSID   */ 4 + 1 + /* unit addr */ 2 + 1)
928
929 static ssize_t
930 dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
931 {
932         struct dasd_devmap *devmap;
933         char uid[UID_STRLEN];
934
935         devmap = dasd_find_busid(dev->bus_id);
936         spin_lock(&dasd_devmap_lock);
937         if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
938                 snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",
939                          devmap->uid.vendor, devmap->uid.serial,
940                          devmap->uid.ssid, devmap->uid.unit_addr);
941         else
942                 uid[0] = 0;
943         spin_unlock(&dasd_devmap_lock);
944
945         return snprintf(buf, PAGE_SIZE, "%s\n", uid);
946 }
947
948 static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
949
950 /*
951  * extended error-reporting
952  */
953 static ssize_t
954 dasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf)
955 {
956         struct dasd_devmap *devmap;
957         int eer_flag;
958
959         devmap = dasd_find_busid(dev->bus_id);
960         if (!IS_ERR(devmap) && devmap->device)
961                 eer_flag = dasd_eer_enabled(devmap->device);
962         else
963                 eer_flag = 0;
964         return snprintf(buf, PAGE_SIZE, eer_flag ? "1\n" : "0\n");
965 }
966
967 static ssize_t
968 dasd_eer_store(struct device *dev, struct device_attribute *attr,
969                const char *buf, size_t count)
970 {
971         struct dasd_devmap *devmap;
972         int val, rc;
973         char *endp;
974
975         devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
976         if (IS_ERR(devmap))
977                 return PTR_ERR(devmap);
978         if (!devmap->device)
979                 return -ENODEV;
980
981         val = simple_strtoul(buf, &endp, 0);
982         if (((endp + 1) < (buf + count)) || (val > 1))
983                 return -EINVAL;
984
985         if (val) {
986                 rc = dasd_eer_enable(devmap->device);
987                 if (rc)
988                         return rc;
989         } else
990                 dasd_eer_disable(devmap->device);
991         return count;
992 }
993
994 static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
995
996 static struct attribute * dasd_attrs[] = {
997         &dev_attr_readonly.attr,
998         &dev_attr_discipline.attr,
999         &dev_attr_status.attr,
1000         &dev_attr_alias.attr,
1001         &dev_attr_vendor.attr,
1002         &dev_attr_uid.attr,
1003         &dev_attr_use_diag.attr,
1004         &dev_attr_eer_enabled.attr,
1005         &dev_attr_erplog.attr,
1006         NULL,
1007 };
1008
1009 static struct attribute_group dasd_attr_group = {
1010         .attrs = dasd_attrs,
1011 };
1012
1013 /*
1014  * Return copy of the device unique identifier.
1015  */
1016 int
1017 dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
1018 {
1019         struct dasd_devmap *devmap;
1020
1021         devmap = dasd_find_busid(cdev->dev.bus_id);
1022         if (IS_ERR(devmap))
1023                 return PTR_ERR(devmap);
1024         spin_lock(&dasd_devmap_lock);
1025         *uid = devmap->uid;
1026         spin_unlock(&dasd_devmap_lock);
1027         return 0;
1028 }
1029
1030 /*
1031  * Register the given device unique identifier into devmap struct.
1032  * In addition check if the related storage server subsystem ID is already
1033  * contained in the dasd_server_ssid_list. If subsystem ID is not contained,
1034  * create new entry.
1035  * Return 0 if server was already in serverlist,
1036  *        1 if the server was added successful
1037  *       <0 in case of error.
1038  */
1039 int
1040 dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
1041 {
1042         struct dasd_devmap *devmap;
1043         struct dasd_server_ssid_map *srv, *tmp;
1044
1045         devmap = dasd_find_busid(cdev->dev.bus_id);
1046         if (IS_ERR(devmap))
1047                 return PTR_ERR(devmap);
1048
1049         /* generate entry for server_ssid_map */
1050         srv = (struct dasd_server_ssid_map *)
1051                 kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
1052         if (!srv)
1053                 return -ENOMEM;
1054         strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
1055         strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
1056         srv->sid.ssid = uid->ssid;
1057
1058         /* server is already contained ? */
1059         spin_lock(&dasd_devmap_lock);
1060         devmap->uid = *uid;
1061         list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
1062                 if (!memcmp(&srv->sid, &tmp->sid,
1063                             sizeof(struct system_id))) {
1064                         kfree(srv);
1065                         srv = NULL;
1066                         break;
1067                 }
1068         }
1069
1070         /* add servermap to serverlist */
1071         if (srv)
1072                 list_add(&srv->list, &dasd_server_ssid_list);
1073         spin_unlock(&dasd_devmap_lock);
1074
1075         return (srv ? 1 : 0);
1076 }
1077 EXPORT_SYMBOL_GPL(dasd_set_uid);
1078
1079 /*
1080  * Return value of the specified feature.
1081  */
1082 int
1083 dasd_get_feature(struct ccw_device *cdev, int feature)
1084 {
1085         struct dasd_devmap *devmap;
1086
1087         devmap = dasd_find_busid(cdev->dev.bus_id);
1088         if (IS_ERR(devmap))
1089                 return PTR_ERR(devmap);
1090
1091         return ((devmap->features & feature) != 0);
1092 }
1093
1094 /*
1095  * Set / reset given feature.
1096  * Flag indicates wether to set (!=0) or the reset (=0) the feature.
1097  */
1098 int
1099 dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
1100 {
1101         struct dasd_devmap *devmap;
1102
1103         devmap = dasd_find_busid(cdev->dev.bus_id);
1104         if (IS_ERR(devmap))
1105                 return PTR_ERR(devmap);
1106
1107         spin_lock(&dasd_devmap_lock);
1108         if (flag)
1109                 devmap->features |= feature;
1110         else
1111                 devmap->features &= ~feature;
1112         if (devmap->device)
1113                 devmap->device->features = devmap->features;
1114         spin_unlock(&dasd_devmap_lock);
1115         return 0;
1116 }
1117
1118
1119 int
1120 dasd_add_sysfs_files(struct ccw_device *cdev)
1121 {
1122         return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
1123 }
1124
1125 void
1126 dasd_remove_sysfs_files(struct ccw_device *cdev)
1127 {
1128         sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
1129 }
1130
1131
1132 int
1133 dasd_devmap_init(void)
1134 {
1135         int i;
1136
1137         /* Initialize devmap structures. */
1138         dasd_max_devindex = 0;
1139         for (i = 0; i < 256; i++)
1140                 INIT_LIST_HEAD(&dasd_hashlists[i]);
1141
1142         /* Initialize servermap structure. */
1143         INIT_LIST_HEAD(&dasd_server_ssid_list);
1144         return 0;
1145 }
1146
1147 void
1148 dasd_devmap_exit(void)
1149 {
1150         dasd_forget_ranges();
1151 }