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