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