aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device_fsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/device_fsm.c')
-rw-r--r--drivers/s390/cio/device_fsm.c67
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 }
580out_unlock:
581 spin_unlock_irqrestore(cdev->ccwlock, flags);
565} 582}
566 583
567void 584void
@@ -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
756ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) 776ccw_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);