1/* 2 * bus driver for ccwgroup 3 * 4 * Copyright IBM Corp. 2002, 2009 5 * 6 * Author(s): Arnd Bergmann (arndb@de.ibm.com) 7 * Cornelia Huck (cornelia.huck@de.ibm.com) 8 */ 9#include <linux/module.h> 10#include <linux/errno.h> 11#include <linux/slab.h> 12#include <linux/list.h> 13#include <linux/device.h> 14#include <linux/init.h> 15#include <linux/ctype.h> 16#include <linux/dcache.h> 17 18#include <asm/ccwdev.h> 19#include <asm/ccwgroup.h> 20 21#define CCW_BUS_ID_SIZE 20 22 23/* In Linux 2.4, we had a channel device layer called "chandev" 24 * that did all sorts of obscure stuff for networking devices. 25 * This is another driver that serves as a replacement for just 26 * one of its functions, namely the translation of single subchannels 27 * to devices that use multiple subchannels. 28 */ 29 30/* a device matches a driver if all its slave devices match the same 31 * entry of the driver */ 32static int 33ccwgroup_bus_match (struct device * dev, struct device_driver * drv) 34{ 35 struct ccwgroup_device *gdev; 36 struct ccwgroup_driver *gdrv; 37 38 gdev = to_ccwgroupdev(dev); 39 gdrv = to_ccwgroupdrv(drv); 40 41 if (gdev->creator_id == gdrv->driver_id) 42 return 1; 43 44 return 0; 45} 46static int 47ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env) 48{ 49 /* TODO */ 50 return 0; 51} 52 53static struct bus_type ccwgroup_bus_type; 54 55static void 56__ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) 57{ 58 int i; 59 char str[8]; 60 61 for (i = 0; i < gdev->count; i++) { 62 sprintf(str, "cdev%d", i); 63 sysfs_remove_link(&gdev->dev.kobj, str); 64 sysfs_remove_link(&gdev->cdev[i]->dev.kobj, "group_device"); 65 } 66 67} 68 69/* 70 * Provide an 'ungroup' attribute so the user can remove group devices no 71 * longer needed or accidentially created. Saves memory :) 72 */ 73static void ccwgroup_ungroup_callback(struct device *dev) 74{ 75 struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 76 77 mutex_lock(&gdev->reg_mutex); 78 if (device_is_registered(&gdev->dev)) { 79 __ccwgroup_remove_symlinks(gdev); 80 device_unregister(dev); 81 } 82 mutex_unlock(&gdev->reg_mutex); 83} 84 85static ssize_t 86ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 87{ 88 struct ccwgroup_device *gdev; 89 int rc; 90 91 gdev = to_ccwgroupdev(dev); 92 93 /* Prevent concurrent online/offline processing and ungrouping. */ 94 if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) 95 return -EAGAIN; 96 if (gdev->state != CCWGROUP_OFFLINE) { 97 rc = -EINVAL; 98 goto out; 99 } 100 /* Note that we cannot unregister the device from one of its 101 * attribute methods, so we have to use this roundabout approach. 102 */ 103 rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); 104out: 105 if (rc) { 106 if (rc != -EAGAIN) 107 /* Release onoff "lock" when ungrouping failed. */ 108 atomic_set(&gdev->onoff, 0); 109 return rc; 110 } 111 return count; 112} 113 114static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store); 115 116static void 117ccwgroup_release (struct device *dev) 118{ 119 struct ccwgroup_device *gdev; 120 int i; 121 122 gdev = to_ccwgroupdev(dev); 123 124 for (i = 0; i < gdev->count; i++) { 125 if (gdev->cdev[i]) { 126 spin_lock_irq(gdev->cdev[i]->ccwlock); 127 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) 128 dev_set_drvdata(&gdev->cdev[i]->dev, NULL); 129 spin_unlock_irq(gdev->cdev[i]->ccwlock); 130 put_device(&gdev->cdev[i]->dev); 131 } 132 } 133 kfree(gdev); 134} 135 136static int 137__ccwgroup_create_symlinks(struct ccwgroup_device *gdev) 138{ 139 char str[8]; 140 int i, rc; 141 142 for (i = 0; i < gdev->count; i++) { 143 rc = sysfs_create_link(&gdev->cdev[i]->dev.kobj, &gdev->dev.kobj, 144 "group_device"); 145 if (rc) { 146 for (--i; i >= 0; i--) 147 sysfs_remove_link(&gdev->cdev[i]->dev.kobj, 148 "group_device"); 149 return rc; 150 } 151 } 152 for (i = 0; i < gdev->count; i++) { 153 sprintf(str, "cdev%d", i); 154 rc = sysfs_create_link(&gdev->dev.kobj, &gdev->cdev[i]->dev.kobj, 155 str); 156 if (rc) { 157 for (--i; i >= 0; i--) { 158 sprintf(str, "cdev%d", i); 159 sysfs_remove_link(&gdev->dev.kobj, str); 160 } 161 for (i = 0; i < gdev->count; i++) 162 sysfs_remove_link(&gdev->cdev[i]->dev.kobj, 163 "group_device"); 164 return rc; 165 } 166 } 167 return 0; 168} 169 170static int __get_next_bus_id(const char **buf, char *bus_id) 171{ 172 int rc, len; 173 char *start, *end; 174 175 start = (char *)*buf; 176 end = strchr(start, ','); 177 if (!end) { 178 /* Last entry. Strip trailing newline, if applicable. */ 179 end = strchr(start, '\n'); 180 if (end) 181 *end = '\0'; 182 len = strlen(start) + 1; 183 } else { 184 len = end - start + 1; 185 end++; 186 } 187 if (len < CCW_BUS_ID_SIZE) { 188 strlcpy(bus_id, start, len); 189 rc = 0; 190 } else 191 rc = -EINVAL; 192 *buf = end; 193 return rc; 194} 195 196static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE]) 197{ 198 int cssid, ssid, devno; 199 200 /* Must be of form %x.%x.%04x */ 201 if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) 202 return 0; 203 return 1; 204} 205 206/** 207 * ccwgroup_create_from_string() - create and register a ccw group device 208 * @root: parent device for the new device 209 * @creator_id: identifier of creating driver 210 * @cdrv: ccw driver of slave devices 211 * @num_devices: number of slave devices 212 * @buf: buffer containing comma separated bus ids of slave devices 213 * 214 * Create and register a new ccw group device as a child of @root. Slave 215 * devices are obtained from the list of bus ids given in @buf and must all 216 * belong to @cdrv. 217 * Returns: 218 * %0 on success and an error code on failure. 219 * Context: 220 * non-atomic 221 */ 222int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, 223 struct ccw_driver *cdrv, int num_devices, 224 const char *buf) 225{ 226 struct ccwgroup_device *gdev; 227 int rc, i; 228 char tmp_bus_id[CCW_BUS_ID_SIZE]; 229 const char *curr_buf; 230 231 gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), 232 GFP_KERNEL); 233 if (!gdev) 234 return -ENOMEM; 235 236 atomic_set(&gdev->onoff, 0); 237 mutex_init(&gdev->reg_mutex); 238 mutex_lock(&gdev->reg_mutex); 239 gdev->creator_id = creator_id; 240 gdev->count = num_devices; 241 gdev->dev.bus = &ccwgroup_bus_type; 242 gdev->dev.parent = root; 243 gdev->dev.release = ccwgroup_release; 244 device_initialize(&gdev->dev); 245 246 curr_buf = buf; 247 for (i = 0; i < num_devices && curr_buf; i++) { 248 rc = __get_next_bus_id(&curr_buf, tmp_bus_id); 249 if (rc != 0) 250 goto error; 251 if (!__is_valid_bus_id(tmp_bus_id)) { 252 rc = -EINVAL; 253 goto error; 254 } 255 gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id); 256 /* 257 * All devices have to be of the same type in 258 * order to be grouped. 259 */ 260 if (!gdev->cdev[i] 261 || gdev->cdev[i]->id.driver_info != 262 gdev->cdev[0]->id.driver_info) { 263 rc = -EINVAL; 264 goto error; 265 } 266 /* Don't allow a device to belong to more than one group. */ 267 spin_lock_irq(gdev->cdev[i]->ccwlock); 268 if (dev_get_drvdata(&gdev->cdev[i]->dev)) { 269 spin_unlock_irq(gdev->cdev[i]->ccwlock); 270 rc = -EINVAL; 271 goto error; 272 } 273 dev_set_drvdata(&gdev->cdev[i]->dev, gdev); 274 spin_unlock_irq(gdev->cdev[i]->ccwlock); 275 } 276 /* Check for sufficient number of bus ids. */ 277 if (i < num_devices && !curr_buf) { 278 rc = -EINVAL; 279 goto error; 280 } 281 /* Check for trailing stuff. */ 282 if (i == num_devices && strlen(curr_buf) > 0) { 283 rc = -EINVAL; 284 goto error; 285 } 286 287 dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); 288 289 rc = device_add(&gdev->dev); 290 if (rc) 291 goto error; 292 get_device(&gdev->dev); 293 rc = device_create_file(&gdev->dev, &dev_attr_ungroup); 294 295 if (rc) { 296 device_unregister(&gdev->dev); 297 goto error; 298 } 299 300 rc = __ccwgroup_create_symlinks(gdev); 301 if (!rc) { 302 mutex_unlock(&gdev->reg_mutex); 303 put_device(&gdev->dev); 304 return 0; 305 } 306 device_remove_file(&gdev->dev, &dev_attr_ungroup); 307 device_unregister(&gdev->dev); 308error: 309 for (i = 0; i < num_devices; i++) 310 if (gdev->cdev[i]) { 311 spin_lock_irq(gdev->cdev[i]->ccwlock); 312 if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) 313 dev_set_drvdata(&gdev->cdev[i]->dev, NULL); 314 spin_unlock_irq(gdev->cdev[i]->ccwlock); 315 put_device(&gdev->cdev[i]->dev); 316 gdev->cdev[i] = NULL; 317 } 318 mutex_unlock(&gdev->reg_mutex); 319 put_device(&gdev->dev); 320 return rc; 321} 322EXPORT_SYMBOL(ccwgroup_create_from_string); 323 324static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, 325 void *data); 326 327static struct notifier_block ccwgroup_nb = { 328 .notifier_call = ccwgroup_notifier 329}; 330 331static int __init init_ccwgroup(void) 332{ 333 int ret; 334 335 ret = bus_register(&ccwgroup_bus_type); 336 if (ret) 337 return ret; 338 339 ret = bus_register_notifier(&ccwgroup_bus_type, &ccwgroup_nb); 340 if (ret) 341 bus_unregister(&ccwgroup_bus_type); 342 343 return ret; 344} 345 346static void __exit cleanup_ccwgroup(void) 347{ 348 bus_unregister_notifier(&ccwgroup_bus_type, &ccwgroup_nb); 349 bus_unregister(&ccwgroup_bus_type); 350} 351 352module_init(init_ccwgroup); 353module_exit(cleanup_ccwgroup); 354 355/************************** driver stuff ******************************/ 356 357static int 358ccwgroup_set_online(struct ccwgroup_device *gdev) 359{ 360 struct ccwgroup_driver *gdrv; 361 int ret; 362 363 if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) 364 return -EAGAIN; 365 if (gdev->state == CCWGROUP_ONLINE) { 366 ret = 0; 367 goto out; 368 } 369 if (!gdev->dev.driver) { 370 ret = -EINVAL; 371 goto out; 372 } 373 gdrv = to_ccwgroupdrv (gdev->dev.driver); 374 if ((ret = gdrv->set_online ? gdrv->set_online(gdev) : 0)) 375 goto out; 376 377 gdev->state = CCWGROUP_ONLINE; 378 out: 379 atomic_set(&gdev->onoff, 0); 380 return ret; 381} 382 383static int 384ccwgroup_set_offline(struct ccwgroup_device *gdev) 385{ 386 struct ccwgroup_driver *gdrv; 387 int ret; 388 389 if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) 390 return -EAGAIN; 391 if (gdev->state == CCWGROUP_OFFLINE) { 392 ret = 0; 393 goto out; 394 } 395 if (!gdev->dev.driver) { 396 ret = -EINVAL; 397 goto out; 398 } 399 gdrv = to_ccwgroupdrv (gdev->dev.driver); 400 if ((ret = gdrv->set_offline ? gdrv->set_offline(gdev) : 0)) 401 goto out; 402 403 gdev->state = CCWGROUP_OFFLINE; 404 out: 405 atomic_set(&gdev->onoff, 0); 406 return ret; 407} 408 409static ssize_t 410ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 411{ 412 struct ccwgroup_device *gdev; 413 struct ccwgroup_driver *gdrv; 414 unsigned long value; 415 int ret; 416 417 if (!dev->driver) 418 return -ENODEV; 419 420 gdev = to_ccwgroupdev(dev); 421 gdrv = to_ccwgroupdrv(dev->driver); 422 423 if (!try_module_get(gdrv->owner)) 424 return -EINVAL; 425 426 ret = strict_strtoul(buf, 0, &value); 427 if (ret) 428 goto out; 429 430 if (value == 1) 431 ret = ccwgroup_set_online(gdev); 432 else if (value == 0) 433 ret = ccwgroup_set_offline(gdev); 434 else 435 ret = -EINVAL; 436out: 437 module_put(gdrv->owner); 438 return (ret == 0) ? count : ret; 439} 440 441static ssize_t 442ccwgroup_online_show (struct device *dev, struct device_attribute *attr, char *buf) 443{ 444 int online; 445 446 online = (to_ccwgroupdev(dev)->state == CCWGROUP_ONLINE); 447 448 return sprintf(buf, online ? "1\n" : "0\n"); 449} 450 451static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store); 452 453static int 454ccwgroup_probe (struct device *dev) 455{ 456 struct ccwgroup_device *gdev; 457 struct ccwgroup_driver *gdrv; 458 459 int ret; 460 461 gdev = to_ccwgroupdev(dev); 462 gdrv = to_ccwgroupdrv(dev->driver); 463 464 if ((ret = device_create_file(dev, &dev_attr_online))) 465 return ret; 466 467 ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV; 468 if (ret) 469 device_remove_file(dev, &dev_attr_online); 470 471 return ret; 472} 473 474static int 475ccwgroup_remove (struct device *dev) 476{ 477 struct ccwgroup_device *gdev; 478 struct ccwgroup_driver *gdrv; 479 480 device_remove_file(dev, &dev_attr_online); 481 device_remove_file(dev, &dev_attr_ungroup); 482 483 if (!dev->driver) 484 return 0; 485 486 gdev = to_ccwgroupdev(dev); 487 gdrv = to_ccwgroupdrv(dev->driver); 488 489 if (gdrv->remove) 490 gdrv->remove(gdev); 491 492 return 0; 493} 494 495static void ccwgroup_shutdown(struct device *dev) 496{ 497 struct ccwgroup_device *gdev; 498 struct ccwgroup_driver *gdrv; 499 500 if (!dev->driver) 501 return; 502 503 gdev = to_ccwgroupdev(dev); 504 gdrv = to_ccwgroupdrv(dev->driver); 505 506 if (gdrv->shutdown) 507 gdrv->shutdown(gdev); 508} 509 510static int ccwgroup_pm_prepare(struct device *dev) 511{ 512 struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 513 struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); 514 515 /* Fail while device is being set online/offline. */ 516 if (atomic_read(&gdev->onoff)) 517 return -EAGAIN; 518 519 if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) 520 return 0; 521 522 return gdrv->prepare ? gdrv->prepare(gdev) : 0; 523} 524 525static void ccwgroup_pm_complete(struct device *dev) 526{ 527 struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 528 struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); 529 530 if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) 531 return; 532 533 if (gdrv->complete) 534 gdrv->complete(gdev); 535} 536 537static int ccwgroup_pm_freeze(struct device *dev) 538{ 539 struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 540 struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); 541 542 if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) 543 return 0; 544 545 return gdrv->freeze ? gdrv->freeze(gdev) : 0; 546} 547 548static int ccwgroup_pm_thaw(struct device *dev) 549{ 550 struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 551 struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); 552 553 if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) 554 return 0; 555 556 return gdrv->thaw ? gdrv->thaw(gdev) : 0; 557} 558 559static int ccwgroup_pm_restore(struct device *dev) 560{ 561 struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 562 struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); 563 564 if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) 565 return 0; 566 567 return gdrv->restore ? gdrv->restore(gdev) : 0; 568} 569 570static const struct dev_pm_ops ccwgroup_pm_ops = { 571 .prepare = ccwgroup_pm_prepare, 572 .complete = ccwgroup_pm_complete, 573 .freeze = ccwgroup_pm_freeze, 574 .thaw = ccwgroup_pm_thaw, 575 .restore = ccwgroup_pm_restore, 576}; 577 578static struct bus_type ccwgroup_bus_type = { 579 .name = "ccwgroup", 580 .match = ccwgroup_bus_match, 581 .uevent = ccwgroup_uevent, 582 .probe = ccwgroup_probe, 583 .remove = ccwgroup_remove, 584 .shutdown = ccwgroup_shutdown, 585 .pm = &ccwgroup_pm_ops, 586}; 587 588 589static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, 590 void *data) 591{ 592 struct device *dev = data; 593 594 if (action == BUS_NOTIFY_UNBIND_DRIVER) 595 device_schedule_callback(dev, ccwgroup_ungroup_callback); 596 597 return NOTIFY_OK; 598} 599 600 601/** 602 * ccwgroup_driver_register() - register a ccw group driver 603 * @cdriver: driver to be registered 604 * 605 * This function is mainly a wrapper around driver_register(). 606 */ 607int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) 608{ 609 /* register our new driver with the core */ 610 cdriver->driver.bus = &ccwgroup_bus_type; 611 cdriver->driver.name = cdriver->name; 612 cdriver->driver.owner = cdriver->owner; 613 614 return driver_register(&cdriver->driver); 615} 616 617static int 618__ccwgroup_match_all(struct device *dev, void *data) 619{ 620 return 1; 621} 622 623/** 624 * ccwgroup_driver_unregister() - deregister a ccw group driver 625 * @cdriver: driver to be deregistered 626 * 627 * This function is mainly a wrapper around driver_unregister(). 628 */ 629void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) 630{ 631 struct device *dev; 632 633 /* We don't want ccwgroup devices to live longer than their driver. */ 634 get_driver(&cdriver->driver); 635 while ((dev = driver_find_device(&cdriver->driver, NULL, NULL, 636 __ccwgroup_match_all))) { 637 struct ccwgroup_device *gdev = to_ccwgroupdev(dev); 638 639 mutex_lock(&gdev->reg_mutex); 640 __ccwgroup_remove_symlinks(gdev); 641 device_unregister(dev); 642 mutex_unlock(&gdev->reg_mutex); 643 put_device(dev); 644 } 645 put_driver(&cdriver->driver); 646 driver_unregister(&cdriver->driver); 647} 648 649/** 650 * ccwgroup_probe_ccwdev() - probe function for slave devices 651 * @cdev: ccw device to be probed 652 * 653 * This is a dummy probe function for ccw devices that are slave devices in 654 * a ccw group device. 655 * Returns: 656 * always %0 657 */ 658int ccwgroup_probe_ccwdev(struct ccw_device *cdev) 659{ 660 return 0; 661} 662 663static struct ccwgroup_device * 664__ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) 665{ 666 struct ccwgroup_device *gdev; 667 668 gdev = dev_get_drvdata(&cdev->dev); 669 if (gdev) { 670 if (get_device(&gdev->dev)) { 671 mutex_lock(&gdev->reg_mutex); 672 if (device_is_registered(&gdev->dev)) 673 return gdev; 674 mutex_unlock(&gdev->reg_mutex); 675 put_device(&gdev->dev); 676 } 677 return NULL; 678 } 679 return NULL; 680} 681 682/** 683 * ccwgroup_remove_ccwdev() - remove function for slave devices 684 * @cdev: ccw device to be removed 685 * 686 * This is a remove function for ccw devices that are slave devices in a ccw 687 * group device. It sets the ccw device offline and also deregisters the 688 * embedding ccw group device. 689 */ 690void ccwgroup_remove_ccwdev(struct ccw_device *cdev) 691{ 692 struct ccwgroup_device *gdev; 693 694 /* Ignore offlining errors, device is gone anyway. */ 695 ccw_device_set_offline(cdev); 696 /* If one of its devices is gone, the whole group is done for. */ 697 gdev = __ccwgroup_get_gdev_by_cdev(cdev); 698 if (gdev) { 699 __ccwgroup_remove_symlinks(gdev); 700 device_unregister(&gdev->dev); 701 mutex_unlock(&gdev->reg_mutex); 702 put_device(&gdev->dev); 703 } 704} 705 706MODULE_LICENSE("GPL"); 707EXPORT_SYMBOL(ccwgroup_driver_register); 708EXPORT_SYMBOL(ccwgroup_driver_unregister); 709EXPORT_SYMBOL(ccwgroup_probe_ccwdev); 710EXPORT_SYMBOL(ccwgroup_remove_ccwdev); 711