diff options
Diffstat (limited to 'drivers/s390/cio/device.c')
| -rw-r--r-- | drivers/s390/cio/device.c | 44 |
1 files changed, 13 insertions, 31 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e28f8ae53453..c4d2f667a2f6 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
| @@ -457,12 +457,13 @@ int ccw_device_set_online(struct ccw_device *cdev) | |||
| 457 | return (ret == 0) ? -ENODEV : ret; | 457 | return (ret == 0) ? -ENODEV : ret; |
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | static void online_store_handle_offline(struct ccw_device *cdev) | 460 | static int online_store_handle_offline(struct ccw_device *cdev) |
| 461 | { | 461 | { |
| 462 | if (cdev->private->state == DEV_STATE_DISCONNECTED) | 462 | if (cdev->private->state == DEV_STATE_DISCONNECTED) |
| 463 | ccw_device_remove_disconnected(cdev); | 463 | ccw_device_remove_disconnected(cdev); |
| 464 | else if (cdev->drv && cdev->drv->set_offline) | 464 | else if (cdev->online && cdev->drv && cdev->drv->set_offline) |
| 465 | ccw_device_set_offline(cdev); | 465 | return ccw_device_set_offline(cdev); |
| 466 | return 0; | ||
| 466 | } | 467 | } |
| 467 | 468 | ||
| 468 | static int online_store_recog_and_online(struct ccw_device *cdev) | 469 | static int online_store_recog_and_online(struct ccw_device *cdev) |
| @@ -530,13 +531,10 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, | |||
| 530 | goto out; | 531 | goto out; |
| 531 | switch (i) { | 532 | switch (i) { |
| 532 | case 0: | 533 | case 0: |
| 533 | online_store_handle_offline(cdev); | 534 | ret = online_store_handle_offline(cdev); |
| 534 | ret = count; | ||
| 535 | break; | 535 | break; |
| 536 | case 1: | 536 | case 1: |
| 537 | ret = online_store_handle_online(cdev, force); | 537 | ret = online_store_handle_online(cdev, force); |
| 538 | if (!ret) | ||
| 539 | ret = count; | ||
| 540 | break; | 538 | break; |
| 541 | default: | 539 | default: |
| 542 | ret = -EINVAL; | 540 | ret = -EINVAL; |
| @@ -545,7 +543,7 @@ out: | |||
| 545 | if (cdev->drv) | 543 | if (cdev->drv) |
| 546 | module_put(cdev->drv->owner); | 544 | module_put(cdev->drv->owner); |
| 547 | atomic_set(&cdev->private->onoff, 0); | 545 | atomic_set(&cdev->private->onoff, 0); |
| 548 | return ret; | 546 | return (ret < 0) ? ret : count; |
| 549 | } | 547 | } |
| 550 | 548 | ||
| 551 | static ssize_t | 549 | static ssize_t |
| @@ -681,35 +679,22 @@ get_orphaned_ccwdev_by_dev_id(struct channel_subsystem *css, | |||
| 681 | return dev ? to_ccwdev(dev) : NULL; | 679 | return dev ? to_ccwdev(dev) : NULL; |
| 682 | } | 680 | } |
| 683 | 681 | ||
| 684 | static void | 682 | void ccw_device_do_unbind_bind(struct work_struct *work) |
| 685 | ccw_device_add_changed(struct work_struct *work) | ||
| 686 | { | ||
| 687 | struct ccw_device_private *priv; | ||
| 688 | struct ccw_device *cdev; | ||
| 689 | |||
| 690 | priv = container_of(work, struct ccw_device_private, kick_work); | ||
| 691 | cdev = priv->cdev; | ||
| 692 | if (device_add(&cdev->dev)) { | ||
| 693 | put_device(&cdev->dev); | ||
| 694 | return; | ||
| 695 | } | ||
| 696 | set_bit(1, &cdev->private->registered); | ||
| 697 | } | ||
| 698 | |||
| 699 | void ccw_device_do_unreg_rereg(struct work_struct *work) | ||
| 700 | { | 683 | { |
| 701 | struct ccw_device_private *priv; | 684 | struct ccw_device_private *priv; |
| 702 | struct ccw_device *cdev; | 685 | struct ccw_device *cdev; |
| 703 | struct subchannel *sch; | 686 | struct subchannel *sch; |
| 687 | int ret; | ||
| 704 | 688 | ||
| 705 | priv = container_of(work, struct ccw_device_private, kick_work); | 689 | priv = container_of(work, struct ccw_device_private, kick_work); |
| 706 | cdev = priv->cdev; | 690 | cdev = priv->cdev; |
| 707 | sch = to_subchannel(cdev->dev.parent); | 691 | sch = to_subchannel(cdev->dev.parent); |
| 708 | 692 | ||
| 709 | ccw_device_unregister(cdev); | 693 | if (test_bit(1, &cdev->private->registered)) { |
| 710 | PREPARE_WORK(&cdev->private->kick_work, | 694 | device_release_driver(&cdev->dev); |
| 711 | ccw_device_add_changed); | 695 | ret = device_attach(&cdev->dev); |
| 712 | queue_work(ccw_device_work, &cdev->private->kick_work); | 696 | WARN_ON(ret == -ENODEV); |
| 697 | } | ||
| 713 | } | 698 | } |
| 714 | 699 | ||
| 715 | static void | 700 | static void |
| @@ -1035,8 +1020,6 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) | |||
| 1035 | void | 1020 | void |
| 1036 | io_subchannel_recog_done(struct ccw_device *cdev) | 1021 | io_subchannel_recog_done(struct ccw_device *cdev) |
| 1037 | { | 1022 | { |
| 1038 | struct subchannel *sch; | ||
| 1039 | |||
| 1040 | if (css_init_done == 0) { | 1023 | if (css_init_done == 0) { |
| 1041 | cdev->private->flags.recog_done = 1; | 1024 | cdev->private->flags.recog_done = 1; |
| 1042 | return; | 1025 | return; |
| @@ -1047,7 +1030,6 @@ io_subchannel_recog_done(struct ccw_device *cdev) | |||
| 1047 | /* Remove device found not operational. */ | 1030 | /* Remove device found not operational. */ |
| 1048 | if (!get_device(&cdev->dev)) | 1031 | if (!get_device(&cdev->dev)) |
| 1049 | break; | 1032 | break; |
| 1050 | sch = to_subchannel(cdev->dev.parent); | ||
| 1051 | PREPARE_WORK(&cdev->private->kick_work, | 1033 | PREPARE_WORK(&cdev->private->kick_work, |
| 1052 | ccw_device_call_sch_unregister); | 1034 | ccw_device_call_sch_unregister); |
| 1053 | queue_work(slow_path_wq, &cdev->private->kick_work); | 1035 | queue_work(slow_path_wq, &cdev->private->kick_work); |
