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