diff options
-rw-r--r-- | drivers/s390/cio/device.c | 109 |
1 files changed, 62 insertions, 47 deletions
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e322111fb369..c3fc205e3bc0 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -413,11 +413,60 @@ ccw_device_set_online(struct ccw_device *cdev) | |||
413 | return (ret == 0) ? -ENODEV : ret; | 413 | return (ret == 0) ? -ENODEV : ret; |
414 | } | 414 | } |
415 | 415 | ||
416 | static ssize_t | 416 | static void online_store_handle_offline(struct ccw_device *cdev) |
417 | online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 417 | { |
418 | if (cdev->private->state == DEV_STATE_DISCONNECTED) | ||
419 | ccw_device_remove_disconnected(cdev); | ||
420 | else if (cdev->drv && cdev->drv->set_offline) | ||
421 | ccw_device_set_offline(cdev); | ||
422 | } | ||
423 | |||
424 | static int online_store_recog_and_online(struct ccw_device *cdev) | ||
425 | { | ||
426 | int ret; | ||
427 | |||
428 | /* Do device recognition, if needed. */ | ||
429 | if (cdev->id.cu_type == 0) { | ||
430 | ret = ccw_device_recognition(cdev); | ||
431 | if (ret) { | ||
432 | printk(KERN_WARNING"Couldn't start recognition " | ||
433 | "for device %s (ret=%d)\n", | ||
434 | cdev->dev.bus_id, ret); | ||
435 | return ret; | ||
436 | } | ||
437 | wait_event(cdev->private->wait_q, | ||
438 | cdev->private->flags.recog_done); | ||
439 | } | ||
440 | if (cdev->drv && cdev->drv->set_online) | ||
441 | ccw_device_set_online(cdev); | ||
442 | return 0; | ||
443 | } | ||
444 | static void online_store_handle_online(struct ccw_device *cdev, int force) | ||
445 | { | ||
446 | int ret; | ||
447 | |||
448 | ret = online_store_recog_and_online(cdev); | ||
449 | if (ret) | ||
450 | return; | ||
451 | if (force && cdev->private->state == DEV_STATE_BOXED) { | ||
452 | ret = ccw_device_stlck(cdev); | ||
453 | if (ret) { | ||
454 | printk(KERN_WARNING"ccw_device_stlck for device %s " | ||
455 | "returned %d!\n", cdev->dev.bus_id, ret); | ||
456 | return; | ||
457 | } | ||
458 | if (cdev->id.cu_type == 0) | ||
459 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
460 | online_store_recog_and_online(cdev); | ||
461 | } | ||
462 | |||
463 | } | ||
464 | |||
465 | static ssize_t online_store (struct device *dev, struct device_attribute *attr, | ||
466 | const char *buf, size_t count) | ||
418 | { | 467 | { |
419 | struct ccw_device *cdev = to_ccwdev(dev); | 468 | struct ccw_device *cdev = to_ccwdev(dev); |
420 | int i, force, ret; | 469 | int i, force; |
421 | char *tmp; | 470 | char *tmp; |
422 | 471 | ||
423 | if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) | 472 | if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) |
@@ -434,51 +483,17 @@ online_store (struct device *dev, struct device_attribute *attr, const char *buf | |||
434 | force = 0; | 483 | force = 0; |
435 | i = simple_strtoul(buf, &tmp, 16); | 484 | i = simple_strtoul(buf, &tmp, 16); |
436 | } | 485 | } |
437 | if (i == 1) { | 486 | |
438 | /* Do device recognition, if needed. */ | 487 | switch (i) { |
439 | if (cdev->id.cu_type == 0) { | 488 | case 0: |
440 | ret = ccw_device_recognition(cdev); | 489 | online_store_handle_offline(cdev); |
441 | if (ret) { | 490 | break; |
442 | printk(KERN_WARNING"Couldn't start recognition " | 491 | case 1: |
443 | "for device %s (ret=%d)\n", | 492 | online_store_handle_online(cdev, force); |
444 | cdev->dev.bus_id, ret); | 493 | break; |
445 | goto out; | 494 | default: |
446 | } | 495 | count = -EINVAL; |
447 | wait_event(cdev->private->wait_q, | ||
448 | cdev->private->flags.recog_done); | ||
449 | } | ||
450 | if (cdev->drv && cdev->drv->set_online) | ||
451 | ccw_device_set_online(cdev); | ||
452 | } else if (i == 0) { | ||
453 | if (cdev->private->state == DEV_STATE_DISCONNECTED) | ||
454 | ccw_device_remove_disconnected(cdev); | ||
455 | else if (cdev->drv && cdev->drv->set_offline) | ||
456 | ccw_device_set_offline(cdev); | ||
457 | } | ||
458 | if (force && cdev->private->state == DEV_STATE_BOXED) { | ||
459 | ret = ccw_device_stlck(cdev); | ||
460 | if (ret) { | ||
461 | printk(KERN_WARNING"ccw_device_stlck for device %s " | ||
462 | "returned %d!\n", cdev->dev.bus_id, ret); | ||
463 | goto out; | ||
464 | } | ||
465 | /* Do device recognition, if needed. */ | ||
466 | if (cdev->id.cu_type == 0) { | ||
467 | cdev->private->state = DEV_STATE_NOT_OPER; | ||
468 | ret = ccw_device_recognition(cdev); | ||
469 | if (ret) { | ||
470 | printk(KERN_WARNING"Couldn't start recognition " | ||
471 | "for device %s (ret=%d)\n", | ||
472 | cdev->dev.bus_id, ret); | ||
473 | goto out; | ||
474 | } | ||
475 | wait_event(cdev->private->wait_q, | ||
476 | cdev->private->flags.recog_done); | ||
477 | } | ||
478 | if (cdev->drv && cdev->drv->set_online) | ||
479 | ccw_device_set_online(cdev); | ||
480 | } | 496 | } |
481 | out: | ||
482 | if (cdev->drv) | 497 | if (cdev->drv) |
483 | module_put(cdev->drv->owner); | 498 | module_put(cdev->drv->owner); |
484 | atomic_set(&cdev->private->onoff, 0); | 499 | atomic_set(&cdev->private->onoff, 0); |