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