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