diff options
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 67 |
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 51238e7555bb..8baa9cd3794c 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -334,20 +334,29 @@ ccw_device_oper_notify(struct work_struct *work) | |||
334 | struct ccw_device *cdev; | 334 | struct ccw_device *cdev; |
335 | struct subchannel *sch; | 335 | struct subchannel *sch; |
336 | int ret; | 336 | int ret; |
337 | unsigned long flags; | ||
337 | 338 | ||
338 | priv = container_of(work, struct ccw_device_private, kick_work); | 339 | priv = container_of(work, struct ccw_device_private, kick_work); |
339 | cdev = priv->cdev; | 340 | cdev = priv->cdev; |
341 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
340 | sch = to_subchannel(cdev->dev.parent); | 342 | sch = to_subchannel(cdev->dev.parent); |
341 | ret = (sch->driver && sch->driver->notify) ? | 343 | if (sch->driver && sch->driver->notify) { |
342 | sch->driver->notify(&sch->dev, CIO_OPER) : 0; | 344 | spin_unlock_irqrestore(cdev->ccwlock, flags); |
343 | if (!ret) | 345 | ret = sch->driver->notify(&sch->dev, CIO_OPER); |
344 | /* Driver doesn't want device back. */ | 346 | spin_lock_irqsave(cdev->ccwlock, flags); |
345 | ccw_device_do_unreg_rereg(work); | 347 | } else |
346 | else { | 348 | ret = 0; |
349 | if (ret) { | ||
347 | /* Reenable channel measurements, if needed. */ | 350 | /* Reenable channel measurements, if needed. */ |
351 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
348 | cmf_reenable(cdev); | 352 | cmf_reenable(cdev); |
353 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
349 | wake_up(&cdev->private->wait_q); | 354 | wake_up(&cdev->private->wait_q); |
350 | } | 355 | } |
356 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
357 | if (!ret) | ||
358 | /* Driver doesn't want device back. */ | ||
359 | ccw_device_do_unreg_rereg(work); | ||
351 | } | 360 | } |
352 | 361 | ||
353 | /* | 362 | /* |
@@ -534,15 +543,21 @@ ccw_device_nopath_notify(struct work_struct *work) | |||
534 | struct ccw_device *cdev; | 543 | struct ccw_device *cdev; |
535 | struct subchannel *sch; | 544 | struct subchannel *sch; |
536 | int ret; | 545 | int ret; |
546 | unsigned long flags; | ||
537 | 547 | ||
538 | priv = container_of(work, struct ccw_device_private, kick_work); | 548 | priv = container_of(work, struct ccw_device_private, kick_work); |
539 | cdev = priv->cdev; | 549 | cdev = priv->cdev; |
550 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
540 | sch = to_subchannel(cdev->dev.parent); | 551 | sch = to_subchannel(cdev->dev.parent); |
541 | /* Extra sanity. */ | 552 | /* Extra sanity. */ |
542 | if (sch->lpm) | 553 | if (sch->lpm) |
543 | return; | 554 | goto out_unlock; |
544 | ret = (sch->driver && sch->driver->notify) ? | 555 | if (sch->driver && sch->driver->notify) { |
545 | sch->driver->notify(&sch->dev, CIO_NO_PATH) : 0; | 556 | spin_unlock_irqrestore(cdev->ccwlock, flags); |
557 | ret = sch->driver->notify(&sch->dev, CIO_NO_PATH); | ||
558 | spin_lock_irqsave(cdev->ccwlock, flags); | ||
559 | } else | ||
560 | ret = 0; | ||
546 | if (!ret) { | 561 | if (!ret) { |
547 | if (get_device(&sch->dev)) { | 562 | if (get_device(&sch->dev)) { |
548 | /* Driver doesn't want to keep device. */ | 563 | /* Driver doesn't want to keep device. */ |
@@ -562,6 +577,8 @@ ccw_device_nopath_notify(struct work_struct *work) | |||
562 | cdev->private->state = DEV_STATE_DISCONNECTED; | 577 | cdev->private->state = DEV_STATE_DISCONNECTED; |
563 | wake_up(&cdev->private->wait_q); | 578 | wake_up(&cdev->private->wait_q); |
564 | } | 579 | } |
580 | out_unlock: | ||
581 | spin_unlock_irqrestore(cdev->ccwlock, flags); | ||
565 | } | 582 | } |
566 | 583 | ||
567 | void | 584 | void |
@@ -607,10 +624,13 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) | |||
607 | default: | 624 | default: |
608 | /* Reset oper notify indication after verify error. */ | 625 | /* Reset oper notify indication after verify error. */ |
609 | cdev->private->flags.donotify = 0; | 626 | cdev->private->flags.donotify = 0; |
610 | PREPARE_WORK(&cdev->private->kick_work, | 627 | if (cdev->online) { |
611 | ccw_device_nopath_notify); | 628 | PREPARE_WORK(&cdev->private->kick_work, |
612 | queue_work(ccw_device_notify_work, &cdev->private->kick_work); | 629 | ccw_device_nopath_notify); |
613 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | 630 | queue_work(ccw_device_notify_work, |
631 | &cdev->private->kick_work); | ||
632 | } else | ||
633 | ccw_device_done(cdev, DEV_STATE_NOT_OPER); | ||
614 | break; | 634 | break; |
615 | } | 635 | } |
616 | } | 636 | } |
@@ -756,15 +776,22 @@ static void | |||
756 | ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) | 776 | ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) |
757 | { | 777 | { |
758 | struct subchannel *sch; | 778 | struct subchannel *sch; |
779 | int ret; | ||
759 | 780 | ||
760 | sch = to_subchannel(cdev->dev.parent); | 781 | sch = to_subchannel(cdev->dev.parent); |
761 | if (sch->driver->notify && | 782 | if (sch->driver->notify) { |
762 | sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) { | 783 | spin_unlock_irq(cdev->ccwlock); |
763 | ccw_device_set_timeout(cdev, 0); | 784 | ret = sch->driver->notify(&sch->dev, |
764 | cdev->private->flags.fake_irb = 0; | 785 | sch->lpm ? CIO_GONE : CIO_NO_PATH); |
765 | cdev->private->state = DEV_STATE_DISCONNECTED; | 786 | spin_lock_irq(cdev->ccwlock); |
766 | wake_up(&cdev->private->wait_q); | 787 | } else |
767 | return; | 788 | ret = 0; |
789 | if (ret) { | ||
790 | ccw_device_set_timeout(cdev, 0); | ||
791 | cdev->private->flags.fake_irb = 0; | ||
792 | cdev->private->state = DEV_STATE_DISCONNECTED; | ||
793 | wake_up(&cdev->private->wait_q); | ||
794 | return; | ||
768 | } | 795 | } |
769 | cdev->private->state = DEV_STATE_NOT_OPER; | 796 | cdev->private->state = DEV_STATE_NOT_OPER; |
770 | cio_disable_subchannel(sch); | 797 | cio_disable_subchannel(sch); |