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.c100
1 files changed, 65 insertions, 35 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index a7a340b1d713..a50cfa51aa3c 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -380,30 +380,34 @@ int ccw_device_set_offline(struct ccw_device *cdev)
380 } 380 }
381 cdev->online = 0; 381 cdev->online = 0;
382 spin_lock_irq(cdev->ccwlock); 382 spin_lock_irq(cdev->ccwlock);
383 ret = ccw_device_offline(cdev); 383 /* Wait until a final state or DISCONNECTED is reached */
384 if (ret == -ENODEV) { 384 while (!dev_fsm_final_state(cdev) &&
385 if (cdev->private->state != DEV_STATE_NOT_OPER) { 385 cdev->private->state != DEV_STATE_DISCONNECTED) {
386 cdev->private->state = DEV_STATE_OFFLINE;
387 dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
388 }
389 spin_unlock_irq(cdev->ccwlock); 386 spin_unlock_irq(cdev->ccwlock);
390 /* Give up reference from ccw_device_set_online(). */ 387 wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
391 put_device(&cdev->dev); 388 cdev->private->state == DEV_STATE_DISCONNECTED));
392 return ret; 389 spin_lock_irq(cdev->ccwlock);
393 } 390 }
391 ret = ccw_device_offline(cdev);
392 if (ret)
393 goto error;
394 spin_unlock_irq(cdev->ccwlock); 394 spin_unlock_irq(cdev->ccwlock);
395 if (ret == 0) { 395 wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
396 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); 396 cdev->private->state == DEV_STATE_DISCONNECTED));
397 /* Give up reference from ccw_device_set_online(). */ 397 /* Give up reference from ccw_device_set_online(). */
398 put_device(&cdev->dev); 398 put_device(&cdev->dev);
399 } else { 399 return 0;
400 CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " 400
401 "device 0.%x.%04x\n", 401error:
402 ret, cdev->private->dev_id.ssid, 402 CIO_MSG_EVENT(0, "ccw_device_offline returned %d, device 0.%x.%04x\n",
403 cdev->private->dev_id.devno); 403 ret, cdev->private->dev_id.ssid,
404 cdev->online = 1; 404 cdev->private->dev_id.devno);
405 } 405 cdev->private->state = DEV_STATE_OFFLINE;
406 return ret; 406 dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
407 spin_unlock_irq(cdev->ccwlock);
408 /* Give up reference from ccw_device_set_online(). */
409 put_device(&cdev->dev);
410 return -ENODEV;
407} 411}
408 412
409/** 413/**
@@ -421,6 +425,7 @@ int ccw_device_set_offline(struct ccw_device *cdev)
421int ccw_device_set_online(struct ccw_device *cdev) 425int ccw_device_set_online(struct ccw_device *cdev)
422{ 426{
423 int ret; 427 int ret;
428 int ret2;
424 429
425 if (!cdev) 430 if (!cdev)
426 return -ENODEV; 431 return -ENODEV;
@@ -444,28 +449,53 @@ int ccw_device_set_online(struct ccw_device *cdev)
444 put_device(&cdev->dev); 449 put_device(&cdev->dev);
445 return ret; 450 return ret;
446 } 451 }
447 if (cdev->private->state != DEV_STATE_ONLINE) { 452 spin_lock_irq(cdev->ccwlock);
453 /* Check if online processing was successful */
454 if ((cdev->private->state != DEV_STATE_ONLINE) &&
455 (cdev->private->state != DEV_STATE_W4SENSE)) {
456 spin_unlock_irq(cdev->ccwlock);
448 /* Give up online reference since onlining failed. */ 457 /* Give up online reference since onlining failed. */
449 put_device(&cdev->dev); 458 put_device(&cdev->dev);
450 return -ENODEV; 459 return -ENODEV;
451 } 460 }
452 if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { 461 spin_unlock_irq(cdev->ccwlock);
453 cdev->online = 1; 462 if (cdev->drv->set_online)
454 return 0; 463 ret = cdev->drv->set_online(cdev);
455 } 464 if (ret)
465 goto rollback;
466 cdev->online = 1;
467 return 0;
468
469rollback:
456 spin_lock_irq(cdev->ccwlock); 470 spin_lock_irq(cdev->ccwlock);
457 ret = ccw_device_offline(cdev); 471 /* Wait until a final state or DISCONNECTED is reached */
472 while (!dev_fsm_final_state(cdev) &&
473 cdev->private->state != DEV_STATE_DISCONNECTED) {
474 spin_unlock_irq(cdev->ccwlock);
475 wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
476 cdev->private->state == DEV_STATE_DISCONNECTED));
477 spin_lock_irq(cdev->ccwlock);
478 }
479 ret2 = ccw_device_offline(cdev);
480 if (ret2)
481 goto error;
458 spin_unlock_irq(cdev->ccwlock); 482 spin_unlock_irq(cdev->ccwlock);
459 if (ret == 0) 483 wait_event(cdev->private->wait_q, (dev_fsm_final_state(cdev) ||
460 wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); 484 cdev->private->state == DEV_STATE_DISCONNECTED));
461 else
462 CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
463 "device 0.%x.%04x\n",
464 ret, cdev->private->dev_id.ssid,
465 cdev->private->dev_id.devno);
466 /* Give up online reference since onlining failed. */ 485 /* Give up online reference since onlining failed. */
467 put_device(&cdev->dev); 486 put_device(&cdev->dev);
468 return (ret == 0) ? -ENODEV : ret; 487 return ret;
488
489error:
490 CIO_MSG_EVENT(0, "rollback ccw_device_offline returned %d, "
491 "device 0.%x.%04x\n",
492 ret2, cdev->private->dev_id.ssid,
493 cdev->private->dev_id.devno);
494 cdev->private->state = DEV_STATE_OFFLINE;
495 spin_unlock_irq(cdev->ccwlock);
496 /* Give up online reference since onlining failed. */
497 put_device(&cdev->dev);
498 return ret;
469} 499}
470 500
471static int online_store_handle_offline(struct ccw_device *cdev) 501static int online_store_handle_offline(struct ccw_device *cdev)