diff options
Diffstat (limited to 'drivers/s390/block/dasd_devmap.c')
-rw-r--r-- | drivers/s390/block/dasd_devmap.c | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 9af02c79ce8a..91cf971f0652 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -258,8 +258,12 @@ dasd_parse_keyword( char *parsestring ) { | |||
258 | return residual_str; | 258 | return residual_str; |
259 | } | 259 | } |
260 | if (strncmp("nopav", parsestring, length) == 0) { | 260 | if (strncmp("nopav", parsestring, length) == 0) { |
261 | dasd_nopav = 1; | 261 | if (MACHINE_IS_VM) |
262 | MESSAGE(KERN_INFO, "%s", "disable PAV mode"); | 262 | MESSAGE(KERN_INFO, "%s", "'nopav' not supported on VM"); |
263 | else { | ||
264 | dasd_nopav = 1; | ||
265 | MESSAGE(KERN_INFO, "%s", "disable PAV mode"); | ||
266 | } | ||
263 | return residual_str; | 267 | return residual_str; |
264 | } | 268 | } |
265 | if (strncmp("fixedbuffers", parsestring, length) == 0) { | 269 | if (strncmp("fixedbuffers", parsestring, length) == 0) { |
@@ -523,17 +527,17 @@ dasd_create_device(struct ccw_device *cdev) | |||
523 | { | 527 | { |
524 | struct dasd_devmap *devmap; | 528 | struct dasd_devmap *devmap; |
525 | struct dasd_device *device; | 529 | struct dasd_device *device; |
530 | unsigned long flags; | ||
526 | int rc; | 531 | int rc; |
527 | 532 | ||
528 | devmap = dasd_devmap_from_cdev(cdev); | 533 | devmap = dasd_devmap_from_cdev(cdev); |
529 | if (IS_ERR(devmap)) | 534 | if (IS_ERR(devmap)) |
530 | return (void *) devmap; | 535 | return (void *) devmap; |
531 | cdev->dev.driver_data = devmap; | ||
532 | 536 | ||
533 | device = dasd_alloc_device(); | 537 | device = dasd_alloc_device(); |
534 | if (IS_ERR(device)) | 538 | if (IS_ERR(device)) |
535 | return device; | 539 | return device; |
536 | atomic_set(&device->ref_count, 2); | 540 | atomic_set(&device->ref_count, 3); |
537 | 541 | ||
538 | spin_lock(&dasd_devmap_lock); | 542 | spin_lock(&dasd_devmap_lock); |
539 | if (!devmap->device) { | 543 | if (!devmap->device) { |
@@ -552,6 +556,11 @@ dasd_create_device(struct ccw_device *cdev) | |||
552 | dasd_free_device(device); | 556 | dasd_free_device(device); |
553 | return ERR_PTR(rc); | 557 | return ERR_PTR(rc); |
554 | } | 558 | } |
559 | |||
560 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); | ||
561 | cdev->dev.driver_data = device; | ||
562 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); | ||
563 | |||
555 | return device; | 564 | return device; |
556 | } | 565 | } |
557 | 566 | ||
@@ -569,6 +578,7 @@ dasd_delete_device(struct dasd_device *device) | |||
569 | { | 578 | { |
570 | struct ccw_device *cdev; | 579 | struct ccw_device *cdev; |
571 | struct dasd_devmap *devmap; | 580 | struct dasd_devmap *devmap; |
581 | unsigned long flags; | ||
572 | 582 | ||
573 | /* First remove device pointer from devmap. */ | 583 | /* First remove device pointer from devmap. */ |
574 | devmap = dasd_find_busid(device->cdev->dev.bus_id); | 584 | devmap = dasd_find_busid(device->cdev->dev.bus_id); |
@@ -582,9 +592,16 @@ dasd_delete_device(struct dasd_device *device) | |||
582 | devmap->device = NULL; | 592 | devmap->device = NULL; |
583 | spin_unlock(&dasd_devmap_lock); | 593 | spin_unlock(&dasd_devmap_lock); |
584 | 594 | ||
585 | /* Drop ref_count by 2, one for the devmap reference and | 595 | /* Disconnect dasd_device structure from ccw_device structure. */ |
586 | * one for the passed reference. */ | 596 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
587 | atomic_sub(2, &device->ref_count); | 597 | device->cdev->dev.driver_data = NULL; |
598 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
599 | |||
600 | /* | ||
601 | * Drop ref_count by 3, one for the devmap reference, one for | ||
602 | * the cdev reference and one for the passed reference. | ||
603 | */ | ||
604 | atomic_sub(3, &device->ref_count); | ||
588 | 605 | ||
589 | /* Wait for reference counter to drop to zero. */ | 606 | /* Wait for reference counter to drop to zero. */ |
590 | wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0); | 607 | wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0); |
@@ -593,9 +610,6 @@ dasd_delete_device(struct dasd_device *device) | |||
593 | cdev = device->cdev; | 610 | cdev = device->cdev; |
594 | device->cdev = NULL; | 611 | device->cdev = NULL; |
595 | 612 | ||
596 | /* Disconnect dasd_devmap structure from ccw_device structure. */ | ||
597 | cdev->dev.driver_data = NULL; | ||
598 | |||
599 | /* Put ccw_device structure. */ | 613 | /* Put ccw_device structure. */ |
600 | put_device(&cdev->dev); | 614 | put_device(&cdev->dev); |
601 | 615 | ||
@@ -615,21 +629,32 @@ dasd_put_device_wake(struct dasd_device *device) | |||
615 | 629 | ||
616 | /* | 630 | /* |
617 | * Return dasd_device structure associated with cdev. | 631 | * Return dasd_device structure associated with cdev. |
632 | * This function needs to be called with the ccw device | ||
633 | * lock held. It can be used from interrupt context. | ||
634 | */ | ||
635 | struct dasd_device * | ||
636 | dasd_device_from_cdev_locked(struct ccw_device *cdev) | ||
637 | { | ||
638 | struct dasd_device *device = cdev->dev.driver_data; | ||
639 | |||
640 | if (!device) | ||
641 | return ERR_PTR(-ENODEV); | ||
642 | dasd_get_device(device); | ||
643 | return device; | ||
644 | } | ||
645 | |||
646 | /* | ||
647 | * Return dasd_device structure associated with cdev. | ||
618 | */ | 648 | */ |
619 | struct dasd_device * | 649 | struct dasd_device * |
620 | dasd_device_from_cdev(struct ccw_device *cdev) | 650 | dasd_device_from_cdev(struct ccw_device *cdev) |
621 | { | 651 | { |
622 | struct dasd_devmap *devmap; | ||
623 | struct dasd_device *device; | 652 | struct dasd_device *device; |
653 | unsigned long flags; | ||
624 | 654 | ||
625 | device = ERR_PTR(-ENODEV); | 655 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); |
626 | spin_lock(&dasd_devmap_lock); | 656 | device = dasd_device_from_cdev_locked(cdev); |
627 | devmap = cdev->dev.driver_data; | 657 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); |
628 | if (devmap && devmap->device) { | ||
629 | device = devmap->device; | ||
630 | dasd_get_device(device); | ||
631 | } | ||
632 | spin_unlock(&dasd_devmap_lock); | ||
633 | return device; | 658 | return device; |
634 | } | 659 | } |
635 | 660 | ||
@@ -730,16 +755,17 @@ static ssize_t | |||
730 | dasd_discipline_show(struct device *dev, struct device_attribute *attr, | 755 | dasd_discipline_show(struct device *dev, struct device_attribute *attr, |
731 | char *buf) | 756 | char *buf) |
732 | { | 757 | { |
733 | struct dasd_devmap *devmap; | 758 | struct dasd_device *device; |
734 | char *dname; | 759 | ssize_t len; |
735 | 760 | ||
736 | spin_lock(&dasd_devmap_lock); | 761 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
737 | dname = "none"; | 762 | if (!IS_ERR(device) && device->discipline) { |
738 | devmap = dev->driver_data; | 763 | len = snprintf(buf, PAGE_SIZE, "%s\n", |
739 | if (devmap && devmap->device && devmap->device->discipline) | 764 | device->discipline->name); |
740 | dname = devmap->device->discipline->name; | 765 | dasd_put_device(device); |
741 | spin_unlock(&dasd_devmap_lock); | 766 | } else |
742 | return snprintf(buf, PAGE_SIZE, "%s\n", dname); | 767 | len = snprintf(buf, PAGE_SIZE, "none\n"); |
768 | return len; | ||
743 | } | 769 | } |
744 | 770 | ||
745 | static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); | 771 | static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL); |