linux/drivers/s390/block/dasd_devmap.c
<<
>>
Prefs
   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#define KMSG_COMPONENT "dasd"
  17
  18#include <linux/ctype.h>
  19#include <linux/init.h>
  20#include <linux/module.h>
  21#include <linux/slab.h>
  22
  23#include <asm/debug.h>
  24#include <asm/uaccess.h>
  25#include <asm/ipl.h>
  26
  27/* This is ugly... */
  28#define PRINTK_HEADER "dasd_devmap:"
  29#define DASD_BUS_ID_SIZE 20
  30
  31#include "dasd_int.h"
  32
  33struct kmem_cache *dasd_page_cache;
  34EXPORT_SYMBOL_GPL(dasd_page_cache);
  35
  36/*
  37 * dasd_devmap_t is used to store the features and the relation
  38 * between device number and device index. To find a dasd_devmap_t
  39 * that corresponds to a device number of a device index each
  40 * dasd_devmap_t is added to two linked lists, one to search by
  41 * the device number and one to search by the device index. As
  42 * soon as big minor numbers are available the device index list
  43 * can be removed since the device number will then be identical
  44 * to the device index.
  45 */
  46struct dasd_devmap {
  47        struct list_head list;
  48        char bus_id[DASD_BUS_ID_SIZE];
  49        unsigned int devindex;
  50        unsigned short features;
  51        struct dasd_device *device;
  52};
  53
  54/*
  55 * Parameter parsing functions for dasd= parameter. The syntax is:
  56 *   <devno>            : (0x)?[0-9a-fA-F]+
  57 *   <busid>            : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
  58 *   <feature>          : ro
  59 *   <feature_list>     : \(<feature>(:<feature>)*\)
  60 *   <devno-range>      : <devno>(-<devno>)?<feature_list>?
  61 *   <busid-range>      : <busid>(-<busid>)?<feature_list>?
  62 *   <devices>          : <devno-range>|<busid-range>
  63 *   <dasd_module>      : dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod
  64 *
  65 *   <dasd>             : autodetect|probeonly|<devices>(,<devices>)*
  66 */
  67
  68int dasd_probeonly =  0;        /* is true, when probeonly mode is active */
  69int dasd_autodetect = 0;        /* is true, when autodetection is active */
  70int dasd_nopav = 0;             /* is true, when PAV is disabled */
  71EXPORT_SYMBOL_GPL(dasd_nopav);
  72int dasd_nofcx;                 /* disable High Performance Ficon */
  73EXPORT_SYMBOL_GPL(dasd_nofcx);
  74
  75/*
  76 * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
  77 * it is named 'dasd' to directly be filled by insmod with the comma separated
  78 * strings when running as a module.
  79 */
  80static char *dasd[256];
  81module_param_array(dasd, charp, NULL, 0);
  82
  83/*
  84 * Single spinlock to protect devmap and servermap structures and lists.
  85 */
  86static DEFINE_SPINLOCK(dasd_devmap_lock);
  87
  88/*
  89 * Hash lists for devmap structures.
  90 */
  91static struct list_head dasd_hashlists[256];
  92int dasd_max_devindex;
  93
  94static struct dasd_devmap *dasd_add_busid(const char *, int);
  95
  96static inline int
  97dasd_hash_busid(const char *bus_id)
  98{
  99        int hash, i;
 100
 101        hash = 0;
 102        for (i = 0; (i < DASD_BUS_ID_SIZE) && *bus_id; i++, bus_id++)
 103                hash += *bus_id;
 104        return hash & 0xff;
 105}
 106
 107#ifndef MODULE
 108/*
 109 * The parameter parsing functions for builtin-drivers are called
 110 * before kmalloc works. Store the pointers to the parameters strings
 111 * into dasd[] for later processing.
 112 */
 113static int __init
 114dasd_call_setup(char *str)
 115{
 116        static int count = 0;
 117
 118        if (count < 256)
 119                dasd[count++] = str;
 120        return 1;
 121}
 122
 123__setup ("dasd=", dasd_call_setup);
 124#endif  /* #ifndef MODULE */
 125
 126#define DASD_IPLDEV     "ipldev"
 127
 128/*
 129 * Read a device busid/devno from a string.
 130 */
 131static int
 132
 133dasd_busid(char **str, int *id0, int *id1, int *devno)
 134{
 135        int val, old_style;
 136
 137        /* Interpret ipldev busid */
 138        if (strncmp(DASD_IPLDEV, *str, strlen(DASD_IPLDEV)) == 0) {
 139                if (ipl_info.type != IPL_TYPE_CCW) {
 140                        pr_err("The IPL device is not a CCW device\n");
 141                        return -EINVAL;
 142                }
 143                *id0 = 0;
 144                *id1 = ipl_info.data.ccw.dev_id.ssid;
 145                *devno = ipl_info.data.ccw.dev_id.devno;
 146                *str += strlen(DASD_IPLDEV);
 147
 148                return 0;
 149        }
 150        /* check for leading '0x' */
 151        old_style = 0;
 152        if ((*str)[0] == '0' && (*str)[1] == 'x') {
 153                *str += 2;
 154                old_style = 1;
 155        }
 156        if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
 157                return -EINVAL;
 158        val = simple_strtoul(*str, str, 16);
 159        if (old_style || (*str)[0] != '.') {
 160                *id0 = *id1 = 0;
 161                if (val < 0 || val > 0xffff)
 162                        return -EINVAL;
 163                *devno = val;
 164                return 0;
 165        }
 166        /* New style x.y.z busid */
 167        if (val < 0 || val > 0xff)
 168                return -EINVAL;
 169        *id0 = val;
 170        (*str)++;
 171        if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
 172                return -EINVAL;
 173        val = simple_strtoul(*str, str, 16);
 174        if (val < 0 || val > 0xff || (*str)++[0] != '.')
 175                return -EINVAL;
 176        *id1 = val;
 177        if (!isxdigit((*str)[0]))       /* We require at least one hex digit */
 178                return -EINVAL;
 179        val = simple_strtoul(*str, str, 16);
 180        if (val < 0 || val > 0xffff)
 181                return -EINVAL;
 182        *devno = val;
 183        return 0;
 184}
 185
 186/*
 187 * Read colon separated list of dasd features. Currently there is
 188 * only one: "ro" for read-only devices. The default feature set
 189 * is empty (value 0).
 190 */
 191static int
 192dasd_feature_list(char *str, char **endp)
 193{
 194        int features, len, rc;
 195
 196        rc = 0;
 197        if (*str != '(') {
 198                *endp = str;
 199                return DASD_FEATURE_DEFAULT;
 200        }
 201        str++;
 202        features = 0;
 203
 204        while (1) {
 205                for (len = 0;
 206                     str[len] && str[len] != ':' && str[len] != ')'; len++);
 207                if (len == 2 && !strncmp(str, "ro", 2))
 208                        features |= DASD_FEATURE_READONLY;
 209                else if (len == 4 && !strncmp(str, "diag", 4))
 210                        features |= DASD_FEATURE_USEDIAG;
 211                else if (len == 3 && !strncmp(str, "raw", 3))
 212                        features |= DASD_FEATURE_USERAW;
 213                else if (len == 6 && !strncmp(str, "erplog", 6))
 214                        features |= DASD_FEATURE_ERPLOG;
 215                else if (len == 8 && !strncmp(str, "failfast", 8))
 216                        features |= DASD_FEATURE_FAILFAST;
 217                else {
 218                        pr_warning("%*s is not a supported device option\n",
 219                                   len, str);
 220                        rc = -EINVAL;
 221                }
 222                str += len;
 223                if (*str != ':')
 224                        break;
 225                str++;
 226        }
 227        if (*str != ')') {
 228                pr_warning("A closing parenthesis ')' is missing in the "
 229                           "dasd= parameter\n");
 230                rc = -EINVAL;
 231        } else
 232                str++;
 233        *endp = str;
 234        if (rc != 0)
 235                return rc;
 236        return features;
 237}
 238
 239/*
 240 * Try to match the first element on the comma separated parse string
 241 * with one of the known keywords. If a keyword is found, take the approprate
 242 * action and return a pointer to the residual string. If the first element
 243 * could not be matched to any keyword then return an error code.
 244 */
 245static char *
 246dasd_parse_keyword( char *parsestring ) {
 247
 248        char *nextcomma, *residual_str;
 249        int length;
 250
 251        nextcomma = strchr(parsestring,',');
 252        if (nextcomma) {
 253                length = nextcomma - parsestring;
 254                residual_str = nextcomma + 1;
 255        } else {
 256                length = strlen(parsestring);
 257                residual_str = parsestring + length;
 258        }
 259        if (strncmp("autodetect", parsestring, length) == 0) {
 260                dasd_autodetect = 1;
 261                pr_info("The autodetection mode has been activated\n");
 262                return residual_str;
 263        }
 264        if (strncmp("probeonly", parsestring, length) == 0) {
 265                dasd_probeonly = 1;
 266                pr_info("The probeonly mode has been activated\n");
 267                return residual_str;
 268        }
 269        if (strncmp("nopav", parsestring, length) == 0) {
 270                if (MACHINE_IS_VM)
 271                        pr_info("'nopav' is not supported on z/VM\n");
 272                else {
 273                        dasd_nopav = 1;
 274                        pr_info("PAV support has be deactivated\n");
 275                }
 276                return residual_str;
 277        }
 278        if (strncmp("nofcx", parsestring, length) == 0) {
 279                dasd_nofcx = 1;
 280                pr_info("High Performance FICON support has been "
 281                        "deactivated\n");
 282                return residual_str;
 283        }
 284        if (strncmp("fixedbuffers", parsestring, length) == 0) {
 285                if (dasd_page_cache)
 286                        return residual_str;
 287                dasd_page_cache =
 288                        kmem_cache_create("dasd_page_cache", PAGE_SIZE,
 289                                          PAGE_SIZE, SLAB_CACHE_DMA,
 290                                          NULL);
 291                if (!dasd_page_cache)
 292                        DBF_EVENT(DBF_WARNING, "%s", "Failed to create slab, "
 293                                "fixed buffer mode disabled.");
 294                else
 295                        DBF_EVENT(DBF_INFO, "%s",
 296                                 "turning on fixed buffer mode");
 297                return residual_str;
 298        }
 299        return ERR_PTR(-EINVAL);
 300}
 301
 302/*
 303 * Try to interprete the first element on the comma separated parse string
 304 * as a device number or a range of devices. If the interpretation is
 305 * successful, create the matching dasd_devmap entries and return a pointer
 306 * to the residual string.
 307 * If interpretation fails or in case of an error, return an error code.
 308 */
 309static char *
 310dasd_parse_range( char *parsestring ) {
 311
 312        struct dasd_devmap *devmap;
 313        int from, from_id0, from_id1;
 314        int to, to_id0, to_id1;
 315        int features, rc;
 316        char bus_id[DASD_BUS_ID_SIZE+1], *str;
 317
 318        str = parsestring;
 319        rc = dasd_busid(&str, &from_id0, &from_id1, &from);
 320        if (rc == 0) {
 321                to = from;
 322                to_id0 = from_id0;
 323                to_id1 = from_id1;
 324                if (*str == '-') {
 325                        str++;
 326                        rc = dasd_busid(&str, &to_id0, &to_id1, &to);
 327                }
 328        }
 329        if (rc == 0 &&
 330            (from_id0 != to_id0 || from_id1 != to_id1 || from > to))
 331                rc = -EINVAL;
 332        if (rc) {
 333                pr_err("%s is not a valid device range\n", parsestring);
 334                return ERR_PTR(rc);
 335        }
 336        features = dasd_feature_list(str, &str);
 337        if (features < 0)
 338                return ERR_PTR(-EINVAL);
 339        /* each device in dasd= parameter should be set initially online */
 340        features |= DASD_FEATURE_INITIAL_ONLINE;
 341        while (from <= to) {
 342                sprintf(bus_id, "%01x.%01x.%04x",
 343                        from_id0, from_id1, from++);
 344                devmap = dasd_add_busid(bus_id, features);
 345                if (IS_ERR(devmap))
 346                        return (char *)devmap;
 347        }
 348        if (*str == ',')
 349                return str + 1;
 350        if (*str == '\0')
 351                return str;
 352        pr_warning("The dasd= parameter value %s has an invalid ending\n",
 353                   str);
 354        return ERR_PTR(-EINVAL);
 355}
 356
 357static char *
 358dasd_parse_next_element( char *parsestring ) {
 359        char * residual_str;
 360        residual_str = dasd_parse_keyword(parsestring);
 361        if (!IS_ERR(residual_str))
 362                return residual_str;
 363        residual_str = dasd_parse_range(parsestring);
 364        return residual_str;
 365}
 366
 367/*
 368 * Parse parameters stored in dasd[]
 369 * The 'dasd=...' parameter allows to specify a comma separated list of
 370 * keywords and device ranges. When the dasd driver is build into the kernel,
 371 * the complete list will be stored as one element of the dasd[] array.
 372 * When the dasd driver is build as a module, then the list is broken into
 373 * it's elements and each dasd[] entry contains one element.
 374 */
 375int
 376dasd_parse(void)
 377{
 378        int rc, i;
 379        char *parsestring;
 380
 381        rc = 0;
 382        for (i = 0; i < 256; i++) {
 383                if (dasd[i] == NULL)
 384                        break;
 385                parsestring = dasd[i];
 386                /* loop over the comma separated list in the parsestring */
 387                while (*parsestring) {
 388                        parsestring = dasd_parse_next_element(parsestring);
 389                        if(IS_ERR(parsestring)) {
 390                                rc = PTR_ERR(parsestring);
 391                                break;
 392                        }
 393                }
 394                if (rc) {
 395                        DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
 396                        break;
 397                }
 398        }
 399        return rc;
 400}
 401
 402/*
 403 * Add a devmap for the device specified by busid. It is possible that
 404 * the devmap already exists (dasd= parameter). The order of the devices
 405 * added through this function will define the kdevs for the individual
 406 * devices.
 407 */
 408static struct dasd_devmap *
 409dasd_add_busid(const char *bus_id, int features)
 410{
 411        struct dasd_devmap *devmap, *new, *tmp;
 412        int hash;
 413
 414        new = (struct dasd_devmap *)
 415                kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
 416        if (!new)
 417                return ERR_PTR(-ENOMEM);
 418        spin_lock(&dasd_devmap_lock);
 419        devmap = NULL;
 420        hash = dasd_hash_busid(bus_id);
 421        list_for_each_entry(tmp, &dasd_hashlists[hash], list)
 422                if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) {
 423                        devmap = tmp;
 424                        break;
 425                }
 426        if (!devmap) {
 427                /* This bus_id is new. */
 428                new->devindex = dasd_max_devindex++;
 429                strncpy(new->bus_id, bus_id, DASD_BUS_ID_SIZE);
 430                new->features = features;
 431                new->device = NULL;
 432                list_add(&new->list, &dasd_hashlists[hash]);
 433                devmap = new;
 434                new = NULL;
 435        }
 436        spin_unlock(&dasd_devmap_lock);
 437        kfree(new);
 438        return devmap;
 439}
 440
 441/*
 442 * Find devmap for device with given bus_id.
 443 */
 444static struct dasd_devmap *
 445dasd_find_busid(const char *bus_id)
 446{
 447        struct dasd_devmap *devmap, *tmp;
 448        int hash;
 449
 450        spin_lock(&dasd_devmap_lock);
 451        devmap = ERR_PTR(-ENODEV);
 452        hash = dasd_hash_busid(bus_id);
 453        list_for_each_entry(tmp, &dasd_hashlists[hash], list) {
 454                if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) {
 455                        devmap = tmp;
 456                        break;
 457                }
 458        }
 459        spin_unlock(&dasd_devmap_lock);
 460        return devmap;
 461}
 462
 463/*
 464 * Check if busid has been added to the list of dasd ranges.
 465 */
 466int
 467dasd_busid_known(const char *bus_id)
 468{
 469        return IS_ERR(dasd_find_busid(bus_id)) ? -ENOENT : 0;
 470}
 471
 472/*
 473 * Forget all about the device numbers added so far.
 474 * This may only be called at module unload or system shutdown.
 475 */
 476static void
 477dasd_forget_ranges(void)
 478{
 479        struct dasd_devmap *devmap, *n;
 480        int i;
 481
 482        spin_lock(&dasd_devmap_lock);
 483        for (i = 0; i < 256; i++) {
 484                list_for_each_entry_safe(devmap, n, &dasd_hashlists[i], list) {
 485                        BUG_ON(devmap->device != NULL);
 486                        list_del(&devmap->list);
 487                        kfree(devmap);
 488                }
 489        }
 490        spin_unlock(&dasd_devmap_lock);
 491}
 492
 493/*
 494 * Find the device struct by its device index.
 495 */
 496struct dasd_device *
 497dasd_device_from_devindex(int devindex)
 498{
 499        struct dasd_devmap *devmap, *tmp;
 500        struct dasd_device *device;
 501        int i;
 502
 503        spin_lock(&dasd_devmap_lock);
 504        devmap = NULL;
 505        for (i = 0; (i < 256) && !devmap; i++)
 506                list_for_each_entry(tmp, &dasd_hashlists[i], list)
 507                        if (tmp->devindex == devindex) {
 508                                /* Found the devmap for the device. */
 509                                devmap = tmp;
 510                                break;
 511                        }
 512        if (devmap && devmap->device) {
 513                device = devmap->device;
 514                dasd_get_device(device);
 515        } else
 516                device = ERR_PTR(-ENODEV);
 517        spin_unlock(&dasd_devmap_lock);
 518        return device;
 519}
 520
 521/*
 522 * Return devmap for cdev. If no devmap exists yet, create one and
 523 * connect it to the cdev.
 524 */
 525static struct dasd_devmap *
 526dasd_devmap_from_cdev(struct ccw_device *cdev)
 527{
 528        struct dasd_devmap *devmap;
 529
 530        devmap = dasd_find_busid(dev_name(&cdev->dev));
 531        if (IS_ERR(devmap))
 532                devmap = dasd_add_busid(dev_name(&cdev->dev),
 533                                        DASD_FEATURE_DEFAULT);
 534        return devmap;
 535}
 536
 537/*
 538 * Create a dasd device structure for cdev.
 539 */
 540struct dasd_device *
 541dasd_create_device(struct ccw_device *cdev)
 542{
 543        struct dasd_devmap *devmap;
 544        struct dasd_device *device;
 545        unsigned long flags;
 546        int rc;
 547
 548        devmap = dasd_devmap_from_cdev(cdev);
 549        if (IS_ERR(devmap))
 550                return (void *) devmap;
 551
 552        device = dasd_alloc_device();
 553        if (IS_ERR(device))
 554                return device;
 555        atomic_set(&device->ref_count, 3);
 556
 557        spin_lock(&dasd_devmap_lock);
 558        if (!devmap->device) {
 559                devmap->device = device;
 560                device->devindex = devmap->devindex;
 561                device->features = devmap->features;
 562                get_device(&cdev->dev);
 563                device->cdev = cdev;
 564                rc = 0;
 565        } else
 566                /* Someone else was faster. */
 567                rc = -EBUSY;
 568        spin_unlock(&dasd_devmap_lock);
 569
 570        if (rc) {
 571                dasd_free_device(device);
 572                return ERR_PTR(rc);
 573        }
 574
 575        spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
 576        dev_set_drvdata(&cdev->dev, device);
 577        spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
 578
 579        return device;
 580}
 581
 582/*
 583 * Wait queue for dasd_delete_device waits.
 584 */
 585static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);
 586
 587/*
 588 * Remove a dasd device structure. The passed referenced
 589 * is destroyed.
 590 */
 591void
 592dasd_delete_device(struct dasd_device *device)
 593{
 594        struct ccw_device *cdev;
 595        struct dasd_devmap *devmap;
 596        unsigned long flags;
 597
 598        /* First remove device pointer from devmap. */
 599        devmap = dasd_find_busid(dev_name(&device->cdev->dev));
 600        BUG_ON(IS_ERR(devmap));
 601        spin_lock(&dasd_devmap_lock);
 602        if (devmap->device != device) {
 603                spin_unlock(&dasd_devmap_lock);
 604                dasd_put_device(device);
 605                return;
 606        }
 607        devmap->device = NULL;
 608        spin_unlock(&dasd_devmap_lock);
 609
 610        /* Disconnect dasd_device structure from ccw_device structure. */
 611        spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
 612        dev_set_drvdata(&device->cdev->dev, NULL);
 613        spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 614
 615        /*
 616         * Drop ref_count by 3, one for the devmap reference, one for
 617         * the cdev reference and one for the passed reference.
 618         */
 619        atomic_sub(3, &device->ref_count);
 620
 621        /* Wait for reference counter to drop to zero. */
 622        wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
 623
 624        /* Disconnect dasd_device structure from ccw_device structure. */
 625        cdev = device->cdev;
 626        device->cdev = NULL;
 627
 628        /* Put ccw_device structure. */
 629        put_device(&cdev->dev);
 630
 631        /* Now the device structure can be freed. */
 632        dasd_free_device(device);
 633}
 634
 635/*
 636 * Reference counter dropped to zero. Wake up waiter
 637 * in dasd_delete_device.
 638 */
 639void
 640dasd_put_device_wake(struct dasd_device *device)
 641{
 642        wake_up(&dasd_delete_wq);
 643}
 644EXPORT_SYMBOL_GPL(dasd_put_device_wake);
 645
 646/*
 647 * Return dasd_device structure associated with cdev.
 648 * This function needs to be called with the ccw device
 649 * lock held. It can be used from interrupt context.
 650 */
 651struct dasd_device *
 652dasd_device_from_cdev_locked(struct ccw_device *cdev)
 653{
 654        struct dasd_device *device = dev_get_drvdata(&cdev->dev);
 655
 656        if (!device)
 657                return ERR_PTR(-ENODEV);
 658        dasd_get_device(device);
 659        return device;
 660}
 661
 662/*
 663 * Return dasd_device structure associated with cdev.
 664 */
 665struct dasd_device *
 666dasd_device_from_cdev(struct ccw_device *cdev)
 667{
 668        struct dasd_device *device;
 669        unsigned long flags;
 670
 671        spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
 672        device = dasd_device_from_cdev_locked(cdev);
 673        spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
 674        return device;
 675}
 676
 677void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device)
 678{
 679        struct dasd_devmap *devmap;
 680
 681        devmap = dasd_find_busid(dev_name(&device->cdev->dev));
 682        if (IS_ERR(devmap))
 683                return;
 684        spin_lock(&dasd_devmap_lock);
 685        gdp->private_data = devmap;
 686        spin_unlock(&dasd_devmap_lock);
 687}
 688
 689struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp)
 690{
 691        struct dasd_device *device;
 692        struct dasd_devmap *devmap;
 693
 694        if (!gdp->private_data)
 695                return NULL;
 696        device = NULL;
 697        spin_lock(&dasd_devmap_lock);
 698        devmap = gdp->private_data;
 699        if (devmap && devmap->device) {
 700                device = devmap->device;
 701                dasd_get_device(device);
 702        }
 703        spin_unlock(&dasd_devmap_lock);
 704        return device;
 705}
 706
 707/*
 708 * SECTION: files in sysfs
 709 */
 710
 711/*
 712 * failfast controls the behaviour, if no path is available
 713 */
 714static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr,
 715                            char *buf)
 716{
 717        struct dasd_devmap *devmap;
 718        int ff_flag;
 719
 720        devmap = dasd_find_busid(dev_name(dev));
 721        if (!IS_ERR(devmap))
 722                ff_flag = (devmap->features & DASD_FEATURE_FAILFAST) != 0;
 723        else
 724                ff_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST) != 0;
 725        return snprintf(buf, PAGE_SIZE, ff_flag ? "1\n" : "0\n");
 726}
 727
 728static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr,
 729              const char *buf, size_t count)
 730{
 731        struct dasd_devmap *devmap;
 732        int val;
 733        char *endp;
 734
 735        devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
 736        if (IS_ERR(devmap))
 737                return PTR_ERR(devmap);
 738
 739        val = simple_strtoul(buf, &endp, 0);
 740        if (((endp + 1) < (buf + count)) || (val > 1))
 741                return -EINVAL;
 742
 743        spin_lock(&dasd_devmap_lock);
 744        if (val)
 745                devmap->features |= DASD_FEATURE_FAILFAST;
 746        else
 747                devmap->features &= ~DASD_FEATURE_FAILFAST;
 748        if (devmap->device)
 749                devmap->device->features = devmap->features;
 750        spin_unlock(&dasd_devmap_lock);
 751        return count;
 752}
 753
 754static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store);
 755
 756/*
 757 * readonly controls the readonly status of a dasd
 758 */
 759static ssize_t
 760dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
 761{
 762        struct dasd_devmap *devmap;
 763        int ro_flag;
 764
 765        devmap = dasd_find_busid(dev_name(dev));
 766        if (!IS_ERR(devmap))
 767                ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;
 768        else
 769                ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;
 770        return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n");
 771}
 772
 773static ssize_t
 774dasd_ro_store(struct device *dev, struct device_attribute *attr,
 775              const char *buf, size_t count)
 776{
 777        struct dasd_devmap *devmap;
 778        struct dasd_device *device;
 779        int val;
 780        char *endp;
 781
 782        devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
 783        if (IS_ERR(devmap))
 784                return PTR_ERR(devmap);
 785
 786        val = simple_strtoul(buf, &endp, 0);
 787        if (((endp + 1) < (buf + count)) || (val > 1))
 788                return -EINVAL;
 789
 790        spin_lock(&dasd_devmap_lock);
 791        if (val)
 792                devmap->features |= DASD_FEATURE_READONLY;
 793        else
 794                devmap->features &= ~DASD_FEATURE_READONLY;
 795        device = devmap->device;
 796        if (device) {
 797                device->features = devmap->features;
 798                val = val || test_bit(DASD_FLAG_DEVICE_RO, &device->flags);
 799        }
 800        spin_unlock(&dasd_devmap_lock);
 801        if (device && device->block && device->block->gdp)
 802                set_disk_ro(device->block->gdp, val);
 803        return count;
 804}
 805
 806static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
 807/*
 808 * erplog controls the logging of ERP related data
 809 * (e.g. failing channel programs).
 810 */
 811static ssize_t
 812dasd_erplog_show(struct device *dev, struct device_attribute *attr, char *buf)
 813{
 814        struct dasd_devmap *devmap;
 815        int erplog;
 816
 817        devmap = dasd_find_busid(dev_name(dev));
 818        if (!IS_ERR(devmap))
 819                erplog = (devmap->features & DASD_FEATURE_ERPLOG) != 0;
 820        else
 821                erplog = (DASD_FEATURE_DEFAULT & DASD_FEATURE_ERPLOG) != 0;
 822        return snprintf(buf, PAGE_SIZE, erplog ? "1\n" : "0\n");
 823}
 824
 825static ssize_t
 826dasd_erplog_store(struct device *dev, struct device_attribute *attr,
 827              const char *buf, size_t count)
 828{
 829        struct dasd_devmap *devmap;
 830        int val;
 831        char *endp;
 832
 833        devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
 834        if (IS_ERR(devmap))
 835                return PTR_ERR(devmap);
 836
 837        val = simple_strtoul(buf, &endp, 0);
 838        if (((endp + 1) < (buf + count)) || (val > 1))
 839                return -EINVAL;
 840
 841        spin_lock(&dasd_devmap_lock);
 842        if (val)
 843                devmap->features |= DASD_FEATURE_ERPLOG;
 844        else
 845                devmap->features &= ~DASD_FEATURE_ERPLOG;
 846        if (devmap->device)
 847                devmap->device->features = devmap->features;
 848        spin_unlock(&dasd_devmap_lock);
 849        return count;
 850}
 851
 852static DEVICE_ATTR(erplog, 0644, dasd_erplog_show, dasd_erplog_store);
 853
 854/*
 855 * use_diag controls whether the driver should use diag rather than ssch
 856 * to talk to the device
 857 */
 858static ssize_t
 859dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
 860{
 861        struct dasd_devmap *devmap;
 862        int use_diag;
 863
 864        devmap = dasd_find_busid(dev_name(dev));
 865        if (!IS_ERR(devmap))
 866                use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;
 867        else
 868                use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;
 869        return sprintf(buf, use_diag ? "1\n" : "0\n");
 870}
 871
 872static ssize_t
 873dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
 874                    const char *buf, size_t count)
 875{
 876        struct dasd_devmap *devmap;
 877        ssize_t rc;
 878        int val;
 879        char *endp;
 880
 881        devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
 882        if (IS_ERR(devmap))
 883                return PTR_ERR(devmap);
 884
 885        val = simple_strtoul(buf, &endp, 0);
 886        if (((endp + 1) < (buf + count)) || (val > 1))
 887                return -EINVAL;
 888
 889        spin_lock(&dasd_devmap_lock);
 890        /* Changing diag discipline flag is only allowed in offline state. */
 891        rc = count;
 892        if (!devmap->device && !(devmap->features & DASD_FEATURE_USERAW)) {
 893                if (val)
 894                        devmap->features |= DASD_FEATURE_USEDIAG;
 895                else
 896                        devmap->features &= ~DASD_FEATURE_USEDIAG;
 897        } else
 898                rc = -EPERM;
 899        spin_unlock(&dasd_devmap_lock);
 900        return rc;
 901}
 902
 903static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
 904
 905/*
 906 * use_raw controls whether the driver should give access to raw eckd data or
 907 * operate in standard mode
 908 */
 909static ssize_t
 910dasd_use_raw_show(struct device *dev, struct device_attribute *attr, char *buf)
 911{
 912        struct dasd_devmap *devmap;
 913        int use_raw;
 914
 915        devmap = dasd_find_busid(dev_name(dev));
 916        if (!IS_ERR(devmap))
 917                use_raw = (devmap->features & DASD_FEATURE_USERAW) != 0;
 918        else
 919                use_raw = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USERAW) != 0;
 920        return sprintf(buf, use_raw ? "1\n" : "0\n");
 921}
 922
 923static ssize_t
 924dasd_use_raw_store(struct device *dev, struct device_attribute *attr,
 925                    const char *buf, size_t count)
 926{
 927        struct dasd_devmap *devmap;
 928        ssize_t rc;
 929        unsigned long val;
 930
 931        devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
 932        if (IS_ERR(devmap))
 933                return PTR_ERR(devmap);
 934
 935        if ((strict_strtoul(buf, 10, &val) != 0) || val > 1)
 936                return -EINVAL;
 937
 938        spin_lock(&dasd_devmap_lock);
 939        /* Changing diag discipline flag is only allowed in offline state. */
 940        rc = count;
 941        if (!devmap->device && !(devmap->features & DASD_FEATURE_USEDIAG)) {
 942                if (val)
 943                        devmap->features |= DASD_FEATURE_USERAW;
 944                else
 945                        devmap->features &= ~DASD_FEATURE_USERAW;
 946        } else
 947                rc = -EPERM;
 948        spin_unlock(&dasd_devmap_lock);
 949        return rc;
 950}
 951
 952static DEVICE_ATTR(raw_track_access, 0644, dasd_use_raw_show,
 953                   dasd_use_raw_store);
 954
 955static ssize_t
 956dasd_discipline_show(struct device *dev, struct device_attribute *attr,
 957                     char *buf)
 958{
 959        struct dasd_device *device;
 960        ssize_t len;
 961
 962        device = dasd_device_from_cdev(to_ccwdev(dev));
 963        if (IS_ERR(device))
 964                goto out;
 965        else if (!device->discipline) {
 966                dasd_put_device(device);
 967                goto out;
 968        } else {
 969                len = snprintf(buf, PAGE_SIZE, "%s\n",
 970                               device->discipline->name);
 971                dasd_put_device(device);
 972                return len;
 973        }
 974out:
 975        len = snprintf(buf, PAGE_SIZE, "none\n");
 976        return len;
 977}
 978
 979static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
 980
 981static ssize_t
 982dasd_device_status_show(struct device *dev, struct device_attribute *attr,
 983                     char *buf)
 984{
 985        struct dasd_device *device;
 986        ssize_t len;
 987
 988        device = dasd_device_from_cdev(to_ccwdev(dev));
 989        if (!IS_ERR(device)) {
 990                switch (device->state) {
 991                case DASD_STATE_NEW:
 992                        len = snprintf(buf, PAGE_SIZE, "new\n");
 993                        break;
 994                case DASD_STATE_KNOWN:
 995                        len = snprintf(buf, PAGE_SIZE, "detected\n");
 996                        break;
 997                case DASD_STATE_BASIC:
 998                        len = snprintf(buf, PAGE_SIZE, "basic\n");
 999                        break;
1000                case DASD_STATE_UNFMT:
1001                        len = snprintf(buf, PAGE_SIZE, "unformatted\n");
1002                        break;
1003                case DASD_STATE_READY:
1004                        len = snprintf(buf, PAGE_SIZE, "ready\n");
1005                        break;
1006                case DASD_STATE_ONLINE:
1007                        len = snprintf(buf, PAGE_SIZE, "online\n");
1008                        break;
1009                default:
1010                        len = snprintf(buf, PAGE_SIZE, "no stat\n");
1011                        break;
1012                }
1013                dasd_put_device(device);
1014        } else
1015                len = snprintf(buf, PAGE_SIZE, "unknown\n");
1016        return len;
1017}
1018
1019static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL);
1020
1021static ssize_t dasd_alias_show(struct device *dev,
1022                               struct device_attribute *attr, char *buf)
1023{
1024        struct dasd_device *device;
1025        struct dasd_uid uid;
1026
1027        device = dasd_device_from_cdev(to_ccwdev(dev));
1028        if (IS_ERR(device))
1029                return sprintf(buf, "0\n");
1030
1031        if (device->discipline && device->discipline->get_uid &&
1032            !device->discipline->get_uid(device, &uid)) {
1033                if (uid.type == UA_BASE_PAV_ALIAS ||
1034                    uid.type == UA_HYPER_PAV_ALIAS) {
1035                        dasd_put_device(device);
1036                        return sprintf(buf, "1\n");
1037                }
1038        }
1039        dasd_put_device(device);
1040
1041        return sprintf(buf, "0\n");
1042}
1043
1044static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL);
1045
1046static ssize_t dasd_vendor_show(struct device *dev,
1047                                struct device_attribute *attr, char *buf)
1048{
1049        struct dasd_device *device;
1050        struct dasd_uid uid;
1051        char *vendor;
1052
1053        device = dasd_device_from_cdev(to_ccwdev(dev));
1054        vendor = "";
1055        if (IS_ERR(device))
1056                return snprintf(buf, PAGE_SIZE, "%s\n", vendor);
1057
1058        if (device->discipline && device->discipline->get_uid &&
1059            !device->discipline->get_uid(device, &uid))
1060                        vendor = uid.vendor;
1061
1062        dasd_put_device(device);
1063
1064        return snprintf(buf, PAGE_SIZE, "%s\n", vendor);
1065}
1066
1067static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
1068
1069#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial    */ 14 + 1 +\
1070                     /* SSID   */ 4 + 1 + /* unit addr */ 2 + 1 +\
1071                     /* vduit */ 32 + 1)
1072
1073static ssize_t
1074dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
1075{
1076        struct dasd_device *device;
1077        struct dasd_uid uid;
1078        char uid_string[UID_STRLEN];
1079        char ua_string[3];
1080
1081        device = dasd_device_from_cdev(to_ccwdev(dev));
1082        uid_string[0] = 0;
1083        if (IS_ERR(device))
1084                return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
1085
1086        if (device->discipline && device->discipline->get_uid &&
1087            !device->discipline->get_uid(device, &uid)) {
1088                switch (uid.type) {
1089                case UA_BASE_DEVICE:
1090                        snprintf(ua_string, sizeof(ua_string), "%02x",
1091                                 uid.real_unit_addr);
1092                        break;
1093                case UA_BASE_PAV_ALIAS:
1094                        snprintf(ua_string, sizeof(ua_string), "%02x",
1095                                 uid.base_unit_addr);
1096                        break;
1097                case UA_HYPER_PAV_ALIAS:
1098                        snprintf(ua_string, sizeof(ua_string), "xx");
1099                        break;
1100                default:
1101                        /* should not happen, treat like base device */
1102                        snprintf(ua_string, sizeof(ua_string), "%02x",
1103                                 uid.real_unit_addr);
1104                        break;
1105                }
1106
1107                if (strlen(uid.vduit) > 0)
1108                        snprintf(uid_string, sizeof(uid_string),
1109                                 "%s.%s.%04x.%s.%s",
1110                                 uid.vendor, uid.serial, uid.ssid, ua_string,
1111                                 uid.vduit);
1112                else
1113                        snprintf(uid_string, sizeof(uid_string),
1114                                 "%s.%s.%04x.%s",
1115                                 uid.vendor, uid.serial, uid.ssid, ua_string);
1116        }
1117        dasd_put_device(device);
1118
1119        return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
1120}
1121static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
1122
1123/*
1124 * extended error-reporting
1125 */
1126static ssize_t
1127dasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf)
1128{
1129        struct dasd_devmap *devmap;
1130        int eer_flag;
1131
1132        devmap = dasd_find_busid(dev_name(dev));
1133        if (!IS_ERR(devmap) && devmap->device)
1134                eer_flag = dasd_eer_enabled(devmap->device);
1135        else
1136                eer_flag = 0;
1137        return snprintf(buf, PAGE_SIZE, eer_flag ? "1\n" : "0\n");
1138}
1139
1140static ssize_t
1141dasd_eer_store(struct device *dev, struct device_attribute *attr,
1142               const char *buf, size_t count)
1143{
1144        struct dasd_devmap *devmap;
1145        int val, rc;
1146        char *endp;
1147
1148        devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
1149        if (IS_ERR(devmap))
1150                return PTR_ERR(devmap);
1151        if (!devmap->device)
1152                return -ENODEV;
1153
1154        val = simple_strtoul(buf, &endp, 0);
1155        if (((endp + 1) < (buf + count)) || (val > 1))
1156                return -EINVAL;
1157
1158        if (val) {
1159                rc = dasd_eer_enable(devmap->device);
1160                if (rc)
1161                        return rc;
1162        } else
1163                dasd_eer_disable(devmap->device);
1164        return count;
1165}
1166
1167static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);
1168
1169/*
1170 * expiration time for default requests
1171 */
1172static ssize_t
1173dasd_expires_show(struct device *dev, struct device_attribute *attr, char *buf)
1174{
1175        struct dasd_device *device;
1176        int len;
1177
1178        device = dasd_device_from_cdev(to_ccwdev(dev));
1179        if (IS_ERR(device))
1180                return -ENODEV;
1181        len = snprintf(buf, PAGE_SIZE, "%lu\n", device->default_expires);
1182        dasd_put_device(device);
1183        return len;
1184}
1185
1186static ssize_t
1187dasd_expires_store(struct device *dev, struct device_attribute *attr,
1188               const char *buf, size_t count)
1189{
1190        struct dasd_device *device;
1191        unsigned long val;
1192
1193        device = dasd_device_from_cdev(to_ccwdev(dev));
1194        if (IS_ERR(device))
1195                return -ENODEV;
1196
1197        if ((strict_strtoul(buf, 10, &val) != 0) ||
1198            (val > DASD_EXPIRES_MAX) || val == 0) {
1199                dasd_put_device(device);
1200                return -EINVAL;
1201        }
1202
1203        if (val)
1204                device->default_expires = val;
1205
1206        dasd_put_device(device);
1207        return count;
1208}
1209
1210static DEVICE_ATTR(expires, 0644, dasd_expires_show, dasd_expires_store);
1211
1212static ssize_t dasd_reservation_policy_show(struct device *dev,
1213                                            struct device_attribute *attr,
1214                                            char *buf)
1215{
1216        struct dasd_devmap *devmap;
1217        int rc = 0;
1218
1219        devmap = dasd_find_busid(dev_name(dev));
1220        if (IS_ERR(devmap)) {
1221                rc = snprintf(buf, PAGE_SIZE, "ignore\n");
1222        } else {
1223                spin_lock(&dasd_devmap_lock);
1224                if (devmap->features & DASD_FEATURE_FAILONSLCK)
1225                        rc = snprintf(buf, PAGE_SIZE, "fail\n");
1226                else
1227                        rc = snprintf(buf, PAGE_SIZE, "ignore\n");
1228                spin_unlock(&dasd_devmap_lock);
1229        }
1230        return rc;
1231}
1232
1233static ssize_t dasd_reservation_policy_store(struct device *dev,
1234                                             struct device_attribute *attr,
1235                                             const char *buf, size_t count)
1236{
1237        struct dasd_devmap *devmap;
1238        int rc;
1239
1240        devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
1241        if (IS_ERR(devmap))
1242                return PTR_ERR(devmap);
1243        rc = 0;
1244        spin_lock(&dasd_devmap_lock);
1245        if (sysfs_streq("ignore", buf))
1246                devmap->features &= ~DASD_FEATURE_FAILONSLCK;
1247        else if (sysfs_streq("fail", buf))
1248                devmap->features |= DASD_FEATURE_FAILONSLCK;
1249        else
1250                rc = -EINVAL;
1251        if (devmap->device)
1252                devmap->device->features = devmap->features;
1253        spin_unlock(&dasd_devmap_lock);
1254        if (rc)
1255                return rc;
1256        else
1257                return count;
1258}
1259
1260static DEVICE_ATTR(reservation_policy, 0644,
1261                   dasd_reservation_policy_show, dasd_reservation_policy_store);
1262
1263static ssize_t dasd_reservation_state_show(struct device *dev,
1264                                           struct device_attribute *attr,
1265                                           char *buf)
1266{
1267        struct dasd_device *device;
1268        int rc = 0;
1269
1270        device = dasd_device_from_cdev(to_ccwdev(dev));
1271        if (IS_ERR(device))
1272                return snprintf(buf, PAGE_SIZE, "none\n");
1273
1274        if (test_bit(DASD_FLAG_IS_RESERVED, &device->flags))
1275                rc = snprintf(buf, PAGE_SIZE, "reserved\n");
1276        else if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags))
1277                rc = snprintf(buf, PAGE_SIZE, "lost\n");
1278        else
1279                rc = snprintf(buf, PAGE_SIZE, "none\n");
1280        dasd_put_device(device);
1281        return rc;
1282}
1283
1284static ssize_t dasd_reservation_state_store(struct device *dev,
1285                                            struct device_attribute *attr,
1286                                            const char *buf, size_t count)
1287{
1288        struct dasd_device *device;
1289        int rc = 0;
1290
1291        device = dasd_device_from_cdev(to_ccwdev(dev));
1292        if (IS_ERR(device))
1293                return -ENODEV;
1294        if (sysfs_streq("reset", buf))
1295                clear_bit(DASD_FLAG_LOCK_STOLEN, &device->flags);
1296        else
1297                rc = -EINVAL;
1298        dasd_put_device(device);
1299
1300        if (rc)
1301                return rc;
1302        else
1303                return count;
1304}
1305
1306static DEVICE_ATTR(last_known_reservation_state, 0644,
1307                   dasd_reservation_state_show, dasd_reservation_state_store);
1308
1309static struct attribute * dasd_attrs[] = {
1310        &dev_attr_readonly.attr,
1311        &dev_attr_discipline.attr,
1312        &dev_attr_status.attr,
1313        &dev_attr_alias.attr,
1314        &dev_attr_vendor.attr,
1315        &dev_attr_uid.attr,
1316        &dev_attr_use_diag.attr,
1317        &dev_attr_raw_track_access.attr,
1318        &dev_attr_eer_enabled.attr,
1319        &dev_attr_erplog.attr,
1320        &dev_attr_failfast.attr,
1321        &dev_attr_expires.attr,
1322        &dev_attr_reservation_policy.attr,
1323        &dev_attr_last_known_reservation_state.attr,
1324        NULL,
1325};
1326
1327static struct attribute_group dasd_attr_group = {
1328        .attrs = dasd_attrs,
1329};
1330
1331/*
1332 * Return value of the specified feature.
1333 */
1334int
1335dasd_get_feature(struct ccw_device *cdev, int feature)
1336{
1337        struct dasd_devmap *devmap;
1338
1339        devmap = dasd_find_busid(dev_name(&cdev->dev));
1340        if (IS_ERR(devmap))
1341                return PTR_ERR(devmap);
1342
1343        return ((devmap->features & feature) != 0);
1344}
1345
1346/*
1347 * Set / reset given feature.
1348 * Flag indicates wether to set (!=0) or the reset (=0) the feature.
1349 */
1350int
1351dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
1352{
1353        struct dasd_devmap *devmap;
1354
1355        devmap = dasd_find_busid(dev_name(&cdev->dev));
1356        if (IS_ERR(devmap))
1357                return PTR_ERR(devmap);
1358
1359        spin_lock(&dasd_devmap_lock);
1360        if (flag)
1361                devmap->features |= feature;
1362        else
1363                devmap->features &= ~feature;
1364        if (devmap->device)
1365                devmap->device->features = devmap->features;
1366        spin_unlock(&dasd_devmap_lock);
1367        return 0;
1368}
1369
1370
1371int
1372dasd_add_sysfs_files(struct ccw_device *cdev)
1373{
1374        return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
1375}
1376
1377void
1378dasd_remove_sysfs_files(struct ccw_device *cdev)
1379{
1380        sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
1381}
1382
1383
1384int
1385dasd_devmap_init(void)
1386{
1387        int i;
1388
1389        /* Initialize devmap structures. */
1390        dasd_max_devindex = 0;
1391        for (i = 0; i < 256; i++)
1392                INIT_LIST_HEAD(&dasd_hashlists[i]);
1393        return 0;
1394}
1395
1396void
1397dasd_devmap_exit(void)
1398{
1399        dasd_forget_ranges();
1400}
1401
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.