aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/cio/device.c')
-rw-r--r--drivers/s390/cio/device.c43
1 files changed, 27 insertions, 16 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index c4d2f667a2f6..35441fa16be1 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -310,8 +310,6 @@ static void ccw_device_remove_orphan_cb(struct work_struct *work)
310 put_device(&cdev->dev); 310 put_device(&cdev->dev);
311} 311}
312 312
313static void ccw_device_call_sch_unregister(struct work_struct *work);
314
315static void 313static void
316ccw_device_remove_disconnected(struct ccw_device *cdev) 314ccw_device_remove_disconnected(struct ccw_device *cdev)
317{ 315{
@@ -335,11 +333,10 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
335 spin_unlock_irqrestore(cdev->ccwlock, flags); 333 spin_unlock_irqrestore(cdev->ccwlock, flags);
336 PREPARE_WORK(&cdev->private->kick_work, 334 PREPARE_WORK(&cdev->private->kick_work,
337 ccw_device_remove_orphan_cb); 335 ccw_device_remove_orphan_cb);
336 queue_work(slow_path_wq, &cdev->private->kick_work);
338 } else 337 } else
339 /* Deregister subchannel, which will kill the ccw device. */ 338 /* Deregister subchannel, which will kill the ccw device. */
340 PREPARE_WORK(&cdev->private->kick_work, 339 ccw_device_schedule_sch_unregister(cdev);
341 ccw_device_call_sch_unregister);
342 queue_work(slow_path_wq, &cdev->private->kick_work);
343} 340}
344 341
345/** 342/**
@@ -471,7 +468,7 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
471 int ret; 468 int ret;
472 469
473 /* Do device recognition, if needed. */ 470 /* Do device recognition, if needed. */
474 if (cdev->id.cu_type == 0) { 471 if (cdev->private->state == DEV_STATE_BOXED) {
475 ret = ccw_device_recognition(cdev); 472 ret = ccw_device_recognition(cdev);
476 if (ret) { 473 if (ret) {
477 CIO_MSG_EVENT(0, "Couldn't start recognition " 474 CIO_MSG_EVENT(0, "Couldn't start recognition "
@@ -482,17 +479,21 @@ static int online_store_recog_and_online(struct ccw_device *cdev)
482 } 479 }
483 wait_event(cdev->private->wait_q, 480 wait_event(cdev->private->wait_q,
484 cdev->private->flags.recog_done); 481 cdev->private->flags.recog_done);
482 if (cdev->private->state != DEV_STATE_OFFLINE)
483 /* recognition failed */
484 return -EAGAIN;
485 } 485 }
486 if (cdev->drv && cdev->drv->set_online) 486 if (cdev->drv && cdev->drv->set_online)
487 ccw_device_set_online(cdev); 487 ccw_device_set_online(cdev);
488 return 0; 488 return 0;
489} 489}
490
490static int online_store_handle_online(struct ccw_device *cdev, int force) 491static int online_store_handle_online(struct ccw_device *cdev, int force)
491{ 492{
492 int ret; 493 int ret;
493 494
494 ret = online_store_recog_and_online(cdev); 495 ret = online_store_recog_and_online(cdev);
495 if (ret) 496 if (ret && !force)
496 return ret; 497 return ret;
497 if (force && cdev->private->state == DEV_STATE_BOXED) { 498 if (force && cdev->private->state == DEV_STATE_BOXED) {
498 ret = ccw_device_stlck(cdev); 499 ret = ccw_device_stlck(cdev);
@@ -500,7 +501,9 @@ static int online_store_handle_online(struct ccw_device *cdev, int force)
500 return ret; 501 return ret;
501 if (cdev->id.cu_type == 0) 502 if (cdev->id.cu_type == 0)
502 cdev->private->state = DEV_STATE_NOT_OPER; 503 cdev->private->state = DEV_STATE_NOT_OPER;
503 online_store_recog_and_online(cdev); 504 ret = online_store_recog_and_online(cdev);
505 if (ret)
506 return ret;
504 } 507 }
505 return 0; 508 return 0;
506} 509}
@@ -512,7 +515,11 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr,
512 int force, ret; 515 int force, ret;
513 unsigned long i; 516 unsigned long i;
514 517
515 if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) 518 if ((cdev->private->state != DEV_STATE_OFFLINE &&
519 cdev->private->state != DEV_STATE_ONLINE &&
520 cdev->private->state != DEV_STATE_BOXED &&
521 cdev->private->state != DEV_STATE_DISCONNECTED) ||
522 atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
516 return -EAGAIN; 523 return -EAGAIN;
517 524
518 if (cdev->drv && !try_module_get(cdev->drv->owner)) { 525 if (cdev->drv && !try_module_get(cdev->drv->owner)) {
@@ -1014,6 +1021,13 @@ static void ccw_device_call_sch_unregister(struct work_struct *work)
1014 put_device(&sch->dev); 1021 put_device(&sch->dev);
1015} 1022}
1016 1023
1024void ccw_device_schedule_sch_unregister(struct ccw_device *cdev)
1025{
1026 PREPARE_WORK(&cdev->private->kick_work,
1027 ccw_device_call_sch_unregister);
1028 queue_work(slow_path_wq, &cdev->private->kick_work);
1029}
1030
1017/* 1031/*
1018 * subchannel recognition done. Called from the state machine. 1032 * subchannel recognition done. Called from the state machine.
1019 */ 1033 */
@@ -1025,19 +1039,17 @@ io_subchannel_recog_done(struct ccw_device *cdev)
1025 return; 1039 return;
1026 } 1040 }
1027 switch (cdev->private->state) { 1041 switch (cdev->private->state) {
1042 case DEV_STATE_BOXED:
1043 /* Device did not respond in time. */
1028 case DEV_STATE_NOT_OPER: 1044 case DEV_STATE_NOT_OPER:
1029 cdev->private->flags.recog_done = 1; 1045 cdev->private->flags.recog_done = 1;
1030 /* Remove device found not operational. */ 1046 /* Remove device found not operational. */
1031 if (!get_device(&cdev->dev)) 1047 if (!get_device(&cdev->dev))
1032 break; 1048 break;
1033 PREPARE_WORK(&cdev->private->kick_work, 1049 ccw_device_schedule_sch_unregister(cdev);
1034 ccw_device_call_sch_unregister);
1035 queue_work(slow_path_wq, &cdev->private->kick_work);
1036 if (atomic_dec_and_test(&ccw_device_init_count)) 1050 if (atomic_dec_and_test(&ccw_device_init_count))
1037 wake_up(&ccw_device_init_wq); 1051 wake_up(&ccw_device_init_wq);
1038 break; 1052 break;
1039 case DEV_STATE_BOXED:
1040 /* Device did not respond in time. */
1041 case DEV_STATE_OFFLINE: 1053 case DEV_STATE_OFFLINE:
1042 /* 1054 /*
1043 * We can't register the device in interrupt context so 1055 * We can't register the device in interrupt context so
@@ -1551,8 +1563,7 @@ static int purge_fn(struct device *dev, void *data)
1551 goto out; 1563 goto out;
1552 CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid, 1564 CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid,
1553 priv->dev_id.devno); 1565 priv->dev_id.devno);
1554 PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); 1566 ccw_device_schedule_sch_unregister(cdev);
1555 queue_work(slow_path_wq, &cdev->private->kick_work);
1556 1567
1557out: 1568out:
1558 /* Abort loop in case of pending signal. */ 1569 /* Abort loop in case of pending signal. */