diff options
Diffstat (limited to 'drivers/s390/cio/ccwgroup.c')
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 73 |
1 files changed, 56 insertions, 17 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b91c1719b075..22ce765d537e 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -315,16 +315,32 @@ error: | |||
315 | } | 315 | } |
316 | EXPORT_SYMBOL(ccwgroup_create_from_string); | 316 | EXPORT_SYMBOL(ccwgroup_create_from_string); |
317 | 317 | ||
318 | static int __init | 318 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, |
319 | init_ccwgroup (void) | 319 | void *data); |
320 | |||
321 | static struct notifier_block ccwgroup_nb = { | ||
322 | .notifier_call = ccwgroup_notifier | ||
323 | }; | ||
324 | |||
325 | static int __init init_ccwgroup(void) | ||
320 | { | 326 | { |
321 | return bus_register (&ccwgroup_bus_type); | 327 | int ret; |
328 | |||
329 | ret = bus_register(&ccwgroup_bus_type); | ||
330 | if (ret) | ||
331 | return ret; | ||
332 | |||
333 | ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb); | ||
334 | if (ret) | ||
335 | bus_unregister(&ccwgroup_bus_type); | ||
336 | |||
337 | return ret; | ||
322 | } | 338 | } |
323 | 339 | ||
324 | static void __exit | 340 | static void __exit cleanup_ccwgroup(void) |
325 | cleanup_ccwgroup (void) | ||
326 | { | 341 | { |
327 | bus_unregister (&ccwgroup_bus_type); | 342 | bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb); |
343 | bus_unregister(&ccwgroup_bus_type); | ||
328 | } | 344 | } |
329 | 345 | ||
330 | module_init(init_ccwgroup); | 346 | module_init(init_ccwgroup); |
@@ -392,27 +408,28 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
392 | unsigned long value; | 408 | unsigned long value; |
393 | int ret; | 409 | int ret; |
394 | 410 | ||
395 | gdev = to_ccwgroupdev(dev); | ||
396 | if (!dev->driver) | 411 | if (!dev->driver) |
397 | return count; | 412 | return -ENODEV; |
413 | |||
414 | gdev = to_ccwgroupdev(dev); | ||
415 | gdrv = to_ccwgroupdrv(dev->driver); | ||
398 | 416 | ||
399 | gdrv = to_ccwgroupdrv (gdev->dev.driver); | ||
400 | if (!try_module_get(gdrv->owner)) | 417 | if (!try_module_get(gdrv->owner)) |
401 | return -EINVAL; | 418 | return -EINVAL; |
402 | 419 | ||
403 | ret = strict_strtoul(buf, 0, &value); | 420 | ret = strict_strtoul(buf, 0, &value); |
404 | if (ret) | 421 | if (ret) |
405 | goto out; | 422 | goto out; |
406 | ret = count; | 423 | |
407 | if (value == 1) | 424 | if (value == 1) |
408 | ccwgroup_set_online(gdev); | 425 | ret = ccwgroup_set_online(gdev); |
409 | else if (value == 0) | 426 | else if (value == 0) |
410 | ccwgroup_set_offline(gdev); | 427 | ret = ccwgroup_set_offline(gdev); |
411 | else | 428 | else |
412 | ret = -EINVAL; | 429 | ret = -EINVAL; |
413 | out: | 430 | out: |
414 | module_put(gdrv->owner); | 431 | module_put(gdrv->owner); |
415 | return ret; | 432 | return (ret == 0) ? count : ret; |
416 | } | 433 | } |
417 | 434 | ||
418 | static ssize_t | 435 | static ssize_t |
@@ -454,13 +471,18 @@ ccwgroup_remove (struct device *dev) | |||
454 | struct ccwgroup_device *gdev; | 471 | struct ccwgroup_device *gdev; |
455 | struct ccwgroup_driver *gdrv; | 472 | struct ccwgroup_driver *gdrv; |
456 | 473 | ||
474 | device_remove_file(dev, &dev_attr_online); | ||
475 | device_remove_file(dev, &dev_attr_ungroup); | ||
476 | |||
477 | if (!dev->driver) | ||
478 | return 0; | ||
479 | |||
457 | gdev = to_ccwgroupdev(dev); | 480 | gdev = to_ccwgroupdev(dev); |
458 | gdrv = to_ccwgroupdrv(dev->driver); | 481 | gdrv = to_ccwgroupdrv(dev->driver); |
459 | 482 | ||
460 | device_remove_file(dev, &dev_attr_online); | 483 | if (gdrv->remove) |
461 | |||
462 | if (gdrv && gdrv->remove) | ||
463 | gdrv->remove(gdev); | 484 | gdrv->remove(gdev); |
485 | |||
464 | return 0; | 486 | return 0; |
465 | } | 487 | } |
466 | 488 | ||
@@ -469,9 +491,13 @@ static void ccwgroup_shutdown(struct device *dev) | |||
469 | struct ccwgroup_device *gdev; | 491 | struct ccwgroup_device *gdev; |
470 | struct ccwgroup_driver *gdrv; | 492 | struct ccwgroup_driver *gdrv; |
471 | 493 | ||
494 | if (!dev->driver) | ||
495 | return; | ||
496 | |||
472 | gdev = to_ccwgroupdev(dev); | 497 | gdev = to_ccwgroupdev(dev); |
473 | gdrv = to_ccwgroupdrv(dev->driver); | 498 | gdrv = to_ccwgroupdrv(dev->driver); |
474 | if (gdrv && gdrv->shutdown) | 499 | |
500 | if (gdrv->shutdown) | ||
475 | gdrv->shutdown(gdev); | 501 | gdrv->shutdown(gdev); |
476 | } | 502 | } |
477 | 503 | ||
@@ -484,6 +510,19 @@ static struct bus_type ccwgroup_bus_type = { | |||
484 | .shutdown = ccwgroup_shutdown, | 510 | .shutdown = ccwgroup_shutdown, |
485 | }; | 511 | }; |
486 | 512 | ||
513 | |||
514 | static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, | ||
515 | void *data) | ||
516 | { | ||
517 | struct device *dev = data; | ||
518 | |||
519 | if (action == BUS_NOTIFY_UNBIND_DRIVER) | ||
520 | device_schedule_callback(dev, ccwgroup_ungroup_callback); | ||
521 | |||
522 | return NOTIFY_OK; | ||
523 | } | ||
524 | |||
525 | |||
487 | /** | 526 | /** |
488 | * ccwgroup_driver_register() - register a ccw group driver | 527 | * ccwgroup_driver_register() - register a ccw group driver |
489 | * @cdriver: driver to be registered | 528 | * @cdriver: driver to be registered |