linux/drivers/misc/enclosure.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Enclosure Services
   4 *
   5 * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
   6 *
   7**-----------------------------------------------------------------------------
   8**
   9**
  10**-----------------------------------------------------------------------------
  11*/
  12#include <linux/device.h>
  13#include <linux/enclosure.h>
  14#include <linux/err.h>
  15#include <linux/list.h>
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/mutex.h>
  19#include <linux/slab.h>
  20
  21static LIST_HEAD(container_list);
  22static DEFINE_MUTEX(container_list_lock);
  23static struct class enclosure_class;
  24
  25/**
  26 * enclosure_find - find an enclosure given a parent device
  27 * @dev:        the parent to match against
  28 * @start:      Optional enclosure device to start from (NULL if none)
  29 *
  30 * Looks through the list of registered enclosures to find all those
  31 * with @dev as a parent.  Returns NULL if no enclosure is
  32 * found. @start can be used as a starting point to obtain multiple
  33 * enclosures per parent (should begin with NULL and then be set to
  34 * each returned enclosure device). Obtains a reference to the
  35 * enclosure class device which must be released with device_put().
  36 * If @start is not NULL, a reference must be taken on it which is
  37 * released before returning (this allows a loop through all
  38 * enclosures to exit with only the reference on the enclosure of
  39 * interest held).  Note that the @dev may correspond to the actual
  40 * device housing the enclosure, in which case no iteration via @start
  41 * is required.
  42 */
  43struct enclosure_device *enclosure_find(struct device *dev,
  44                                        struct enclosure_device *start)
  45{
  46        struct enclosure_device *edev;
  47
  48        mutex_lock(&container_list_lock);
  49        edev = list_prepare_entry(start, &container_list, node);
  50        if (start)
  51                put_device(&start->edev);
  52
  53        list_for_each_entry_continue(edev, &container_list, node) {
  54                struct device *parent = edev->edev.parent;
  55                /* parent might not be immediate, so iterate up to
  56                 * the root of the tree if necessary */
  57                while (parent) {
  58                        if (parent == dev) {
  59                                get_device(&edev->edev);
  60                                mutex_unlock(&container_list_lock);
  61                                return edev;
  62                        }
  63                        parent = parent->parent;
  64                }
  65        }
  66        mutex_unlock(&container_list_lock);
  67
  68        return NULL;
  69}
  70EXPORT_SYMBOL_GPL(enclosure_find);
  71
  72/**
  73 * enclosure_for_each_device - calls a function for each enclosure
  74 * @fn:         the function to call
  75 * @data:       the data to pass to each call
  76 *
  77 * Loops over all the enclosures calling the function.
  78 *
  79 * Note, this function uses a mutex which will be held across calls to
  80 * @fn, so it must have non atomic context, and @fn may (although it
  81 * should not) sleep or otherwise cause the mutex to be held for
  82 * indefinite periods
  83 */
  84int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *),
  85                              void *data)
  86{
  87        int error = 0;
  88        struct enclosure_device *edev;
  89
  90        mutex_lock(&container_list_lock);
  91        list_for_each_entry(edev, &container_list, node) {
  92                error = fn(edev, data);
  93                if (error)
  94                        break;
  95        }
  96        mutex_unlock(&container_list_lock);
  97
  98        return error;
  99}
 100EXPORT_SYMBOL_GPL(enclosure_for_each_device);
 101
 102/**
 103 * enclosure_register - register device as an enclosure
 104 *
 105 * @dev:        device containing the enclosure
 106 * @name:       chosen device name
 107 * @components: number of components in the enclosure
 108 * @cb:         platform call-backs
 109 *
 110 * This sets up the device for being an enclosure.  Note that @dev does
 111 * not have to be a dedicated enclosure device.  It may be some other type
 112 * of device that additionally responds to enclosure services
 113 */
 114struct enclosure_device *
 115enclosure_register(struct device *dev, const char *name, int components,
 116                   struct enclosure_component_callbacks *cb)
 117{
 118        struct enclosure_device *edev =
 119                kzalloc(struct_size(edev, component, components), GFP_KERNEL);
 120        int err, i;
 121
 122        BUG_ON(!cb);
 123
 124        if (!edev)
 125                return ERR_PTR(-ENOMEM);
 126
 127        edev->components = components;
 128
 129        edev->edev.class = &enclosure_class;
 130        edev->edev.parent = get_device(dev);
 131        edev->cb = cb;
 132        dev_set_name(&edev->edev, "%s", name);
 133        err = device_register(&edev->edev);
 134        if (err)
 135                goto err;
 136
 137        for (i = 0; i < components; i++) {
 138                edev->component[i].number = -1;
 139                edev->component[i].slot = -1;
 140                edev->component[i].power_status = -1;
 141        }
 142
 143        mutex_lock(&container_list_lock);
 144        list_add_tail(&edev->node, &container_list);
 145        mutex_unlock(&container_list_lock);
 146
 147        return edev;
 148
 149 err:
 150        put_device(edev->edev.parent);
 151        kfree(edev);
 152        return ERR_PTR(err);
 153}
 154EXPORT_SYMBOL_GPL(enclosure_register);
 155
 156static struct enclosure_component_callbacks enclosure_null_callbacks;
 157
 158/**
 159 * enclosure_unregister - remove an enclosure
 160 *
 161 * @edev:       the registered enclosure to remove;
 162 */
 163void enclosure_unregister(struct enclosure_device *edev)
 164{
 165        int i;
 166
 167        mutex_lock(&container_list_lock);
 168        list_del(&edev->node);
 169        mutex_unlock(&container_list_lock);
 170
 171        for (i = 0; i < edev->components; i++)
 172                if (edev->component[i].number != -1)
 173                        device_unregister(&edev->component[i].cdev);
 174
 175        /* prevent any callbacks into service user */
 176        edev->cb = &enclosure_null_callbacks;
 177        device_unregister(&edev->edev);
 178}
 179EXPORT_SYMBOL_GPL(enclosure_unregister);
 180
 181#define ENCLOSURE_NAME_SIZE     64
 182#define COMPONENT_NAME_SIZE     64
 183
 184static void enclosure_link_name(struct enclosure_component *cdev, char *name)
 185{
 186        strcpy(name, "enclosure_device:");
 187        strcat(name, dev_name(&cdev->cdev));
 188}
 189
 190static void enclosure_remove_links(struct enclosure_component *cdev)
 191{
 192        char name[ENCLOSURE_NAME_SIZE];
 193
 194        enclosure_link_name(cdev, name);
 195
 196        /*
 197         * In odd circumstances, like multipath devices, something else may
 198         * already have removed the links, so check for this condition first.
 199         */
 200        if (cdev->dev->kobj.sd)
 201                sysfs_remove_link(&cdev->dev->kobj, name);
 202
 203        if (cdev->cdev.kobj.sd)
 204                sysfs_remove_link(&cdev->cdev.kobj, "device");
 205}
 206
 207static int enclosure_add_links(struct enclosure_component *cdev)
 208{
 209        int error;
 210        char name[ENCLOSURE_NAME_SIZE];
 211
 212        error = sysfs_create_link(&cdev->cdev.kobj, &cdev->dev->kobj, "device");
 213        if (error)
 214                return error;
 215
 216        enclosure_link_name(cdev, name);
 217        error = sysfs_create_link(&cdev->dev->kobj, &cdev->cdev.kobj, name);
 218        if (error)
 219                sysfs_remove_link(&cdev->cdev.kobj, "device");
 220
 221        return error;
 222}
 223
 224static void enclosure_release(struct device *cdev)
 225{
 226        struct enclosure_device *edev = to_enclosure_device(cdev);
 227
 228        put_device(cdev->parent);
 229        kfree(edev);
 230}
 231
 232static void enclosure_component_release(struct device *dev)
 233{
 234        struct enclosure_component *cdev = to_enclosure_component(dev);
 235
 236        if (cdev->dev) {
 237                enclosure_remove_links(cdev);
 238                put_device(cdev->dev);
 239        }
 240        put_device(dev->parent);
 241}
 242
 243static struct enclosure_component *
 244enclosure_component_find_by_name(struct enclosure_device *edev,
 245                                const char *name)
 246{
 247        int i;
 248        const char *cname;
 249        struct enclosure_component *ecomp;
 250
 251        if (!edev || !name || !name[0])
 252                return NULL;
 253
 254        for (i = 0; i < edev->components; i++) {
 255                ecomp = &edev->component[i];
 256                cname = dev_name(&ecomp->cdev);
 257                if (ecomp->number != -1 &&
 258                    cname && cname[0] &&
 259                    !strcmp(cname, name))
 260                        return ecomp;
 261        }
 262
 263        return NULL;
 264}
 265
 266static const struct attribute_group *enclosure_component_groups[];
 267
 268/**
 269 * enclosure_component_alloc - prepare a new enclosure component
 270 * @edev:       the enclosure to add the component
 271 * @number:     the device number
 272 * @type:       the type of component being added
 273 * @name:       an optional name to appear in sysfs (leave NULL if none)
 274 *
 275 * The name is optional for enclosures that give their components a unique
 276 * name.  If not, leave the field NULL and a name will be assigned.
 277 *
 278 * Returns a pointer to the enclosure component or an error.
 279 */
 280struct enclosure_component *
 281enclosure_component_alloc(struct enclosure_device *edev,
 282                          unsigned int number,
 283                          enum enclosure_component_type type,
 284                          const char *name)
 285{
 286        struct enclosure_component *ecomp;
 287        struct device *cdev;
 288        int i;
 289        char newname[COMPONENT_NAME_SIZE];
 290
 291        if (number >= edev->components)
 292                return ERR_PTR(-EINVAL);
 293
 294        ecomp = &edev->component[number];
 295
 296        if (ecomp->number != -1)
 297                return ERR_PTR(-EINVAL);
 298
 299        ecomp->type = type;
 300        ecomp->number = number;
 301        cdev = &ecomp->cdev;
 302        cdev->parent = get_device(&edev->edev);
 303
 304        if (name && name[0]) {
 305                /* Some hardware (e.g. enclosure in RX300 S6) has components
 306                 * with non unique names. Registering duplicates in sysfs
 307                 * will lead to warnings during bootup. So make the names
 308                 * unique by appending consecutive numbers -1, -2, ... */
 309                i = 1;
 310                snprintf(newname, COMPONENT_NAME_SIZE,
 311                         "%s", name);
 312                while (enclosure_component_find_by_name(edev, newname))
 313                        snprintf(newname, COMPONENT_NAME_SIZE,
 314                                 "%s-%i", name, i++);
 315                dev_set_name(cdev, "%s", newname);
 316        } else
 317                dev_set_name(cdev, "%u", number);
 318
 319        cdev->release = enclosure_component_release;
 320        cdev->groups = enclosure_component_groups;
 321
 322        return ecomp;
 323}
 324EXPORT_SYMBOL_GPL(enclosure_component_alloc);
 325
 326/**
 327 * enclosure_component_register - publishes an initialized enclosure component
 328 * @ecomp:      component to add
 329 *
 330 * Returns 0 on successful registration, releases the component otherwise
 331 */
 332int enclosure_component_register(struct enclosure_component *ecomp)
 333{
 334        struct device *cdev;
 335        int err;
 336
 337        cdev = &ecomp->cdev;
 338        err = device_register(cdev);
 339        if (err) {
 340                ecomp->number = -1;
 341                put_device(cdev);
 342                return err;
 343        }
 344
 345        return 0;
 346}
 347EXPORT_SYMBOL_GPL(enclosure_component_register);
 348
 349/**
 350 * enclosure_add_device - add a device as being part of an enclosure
 351 * @edev:       the enclosure device being added to.
 352 * @component:  the number of the component
 353 * @dev:        the device being added
 354 *
 355 * Declares a real device to reside in slot (or identifier) @num of an
 356 * enclosure.  This will cause the relevant sysfs links to appear.
 357 * This function may also be used to change a device associated with
 358 * an enclosure without having to call enclosure_remove_device() in
 359 * between.
 360 *
 361 * Returns zero on success or an error.
 362 */
 363int enclosure_add_device(struct enclosure_device *edev, int component,
 364                         struct device *dev)
 365{
 366        struct enclosure_component *cdev;
 367        int err;
 368
 369        if (!edev || component >= edev->components)
 370                return -EINVAL;
 371
 372        cdev = &edev->component[component];
 373
 374        if (cdev->dev == dev)
 375                return -EEXIST;
 376
 377        if (cdev->dev) {
 378                enclosure_remove_links(cdev);
 379                put_device(cdev->dev);
 380        }
 381        cdev->dev = get_device(dev);
 382        err = enclosure_add_links(cdev);
 383        if (err) {
 384                put_device(cdev->dev);
 385                cdev->dev = NULL;
 386        }
 387        return err;
 388}
 389EXPORT_SYMBOL_GPL(enclosure_add_device);
 390
 391/**
 392 * enclosure_remove_device - remove a device from an enclosure
 393 * @edev:       the enclosure device
 394 * @dev:        device to remove/put
 395 *
 396 * Returns zero on success or an error.
 397 *
 398 */
 399int enclosure_remove_device(struct enclosure_device *edev, struct device *dev)
 400{
 401        struct enclosure_component *cdev;
 402        int i;
 403
 404        if (!edev || !dev)
 405                return -EINVAL;
 406
 407        for (i = 0; i < edev->components; i++) {
 408                cdev = &edev->component[i];
 409                if (cdev->dev == dev) {
 410                        enclosure_remove_links(cdev);
 411                        put_device(dev);
 412                        cdev->dev = NULL;
 413                        return 0;
 414                }
 415        }
 416        return -ENODEV;
 417}
 418EXPORT_SYMBOL_GPL(enclosure_remove_device);
 419
 420/*
 421 * sysfs pieces below
 422 */
 423
 424static ssize_t components_show(struct device *cdev,
 425                               struct device_attribute *attr, char *buf)
 426{
 427        struct enclosure_device *edev = to_enclosure_device(cdev);
 428
 429        return snprintf(buf, 40, "%d\n", edev->components);
 430}
 431static DEVICE_ATTR_RO(components);
 432
 433static ssize_t id_show(struct device *cdev,
 434                                 struct device_attribute *attr,
 435                                 char *buf)
 436{
 437        struct enclosure_device *edev = to_enclosure_device(cdev);
 438
 439        if (edev->cb->show_id)
 440                return edev->cb->show_id(edev, buf);
 441        return -EINVAL;
 442}
 443static DEVICE_ATTR_RO(id);
 444
 445static struct attribute *enclosure_class_attrs[] = {
 446        &dev_attr_components.attr,
 447        &dev_attr_id.attr,
 448        NULL,
 449};
 450ATTRIBUTE_GROUPS(enclosure_class);
 451
 452static struct class enclosure_class = {
 453        .name                   = "enclosure",
 454        .owner                  = THIS_MODULE,
 455        .dev_release            = enclosure_release,
 456        .dev_groups             = enclosure_class_groups,
 457};
 458
 459static const char *const enclosure_status[] = {
 460        [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported",
 461        [ENCLOSURE_STATUS_OK] = "OK",
 462        [ENCLOSURE_STATUS_CRITICAL] = "critical",
 463        [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical",
 464        [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable",
 465        [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed",
 466        [ENCLOSURE_STATUS_UNKNOWN] = "unknown",
 467        [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable",
 468        [ENCLOSURE_STATUS_MAX] = NULL,
 469};
 470
 471static const char *const enclosure_type[] = {
 472        [ENCLOSURE_COMPONENT_DEVICE] = "device",
 473        [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device",
 474};
 475
 476static ssize_t get_component_fault(struct device *cdev,
 477                                   struct device_attribute *attr, char *buf)
 478{
 479        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 480        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 481
 482        if (edev->cb->get_fault)
 483                edev->cb->get_fault(edev, ecomp);
 484        return snprintf(buf, 40, "%d\n", ecomp->fault);
 485}
 486
 487static ssize_t set_component_fault(struct device *cdev,
 488                                   struct device_attribute *attr,
 489                                   const char *buf, size_t count)
 490{
 491        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 492        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 493        int val = simple_strtoul(buf, NULL, 0);
 494
 495        if (edev->cb->set_fault)
 496                edev->cb->set_fault(edev, ecomp, val);
 497        return count;
 498}
 499
 500static ssize_t get_component_status(struct device *cdev,
 501                                    struct device_attribute *attr,char *buf)
 502{
 503        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 504        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 505
 506        if (edev->cb->get_status)
 507                edev->cb->get_status(edev, ecomp);
 508        return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]);
 509}
 510
 511static ssize_t set_component_status(struct device *cdev,
 512                                    struct device_attribute *attr,
 513                                    const char *buf, size_t count)
 514{
 515        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 516        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 517        int i;
 518
 519        for (i = 0; enclosure_status[i]; i++) {
 520                if (strncmp(buf, enclosure_status[i],
 521                            strlen(enclosure_status[i])) == 0 &&
 522                    (buf[strlen(enclosure_status[i])] == '\n' ||
 523                     buf[strlen(enclosure_status[i])] == '\0'))
 524                        break;
 525        }
 526
 527        if (enclosure_status[i] && edev->cb->set_status) {
 528                edev->cb->set_status(edev, ecomp, i);
 529                return count;
 530        } else
 531                return -EINVAL;
 532}
 533
 534static ssize_t get_component_active(struct device *cdev,
 535                                    struct device_attribute *attr, char *buf)
 536{
 537        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 538        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 539
 540        if (edev->cb->get_active)
 541                edev->cb->get_active(edev, ecomp);
 542        return snprintf(buf, 40, "%d\n", ecomp->active);
 543}
 544
 545static ssize_t set_component_active(struct device *cdev,
 546                                    struct device_attribute *attr,
 547                                    const char *buf, size_t count)
 548{
 549        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 550        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 551        int val = simple_strtoul(buf, NULL, 0);
 552
 553        if (edev->cb->set_active)
 554                edev->cb->set_active(edev, ecomp, val);
 555        return count;
 556}
 557
 558static ssize_t get_component_locate(struct device *cdev,
 559                                    struct device_attribute *attr, char *buf)
 560{
 561        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 562        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 563
 564        if (edev->cb->get_locate)
 565                edev->cb->get_locate(edev, ecomp);
 566        return snprintf(buf, 40, "%d\n", ecomp->locate);
 567}
 568
 569static ssize_t set_component_locate(struct device *cdev,
 570                                    struct device_attribute *attr,
 571                                    const char *buf, size_t count)
 572{
 573        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 574        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 575        int val = simple_strtoul(buf, NULL, 0);
 576
 577        if (edev->cb->set_locate)
 578                edev->cb->set_locate(edev, ecomp, val);
 579        return count;
 580}
 581
 582static ssize_t get_component_power_status(struct device *cdev,
 583                                          struct device_attribute *attr,
 584                                          char *buf)
 585{
 586        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 587        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 588
 589        if (edev->cb->get_power_status)
 590                edev->cb->get_power_status(edev, ecomp);
 591
 592        /* If still uninitialized, the callback failed or does not exist. */
 593        if (ecomp->power_status == -1)
 594                return (edev->cb->get_power_status) ? -EIO : -ENOTTY;
 595
 596        return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off");
 597}
 598
 599static ssize_t set_component_power_status(struct device *cdev,
 600                                          struct device_attribute *attr,
 601                                          const char *buf, size_t count)
 602{
 603        struct enclosure_device *edev = to_enclosure_device(cdev->parent);
 604        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 605        int val;
 606
 607        if (strncmp(buf, "on", 2) == 0 &&
 608            (buf[2] == '\n' || buf[2] == '\0'))
 609                val = 1;
 610        else if (strncmp(buf, "off", 3) == 0 &&
 611            (buf[3] == '\n' || buf[3] == '\0'))
 612                val = 0;
 613        else
 614                return -EINVAL;
 615
 616        if (edev->cb->set_power_status)
 617                edev->cb->set_power_status(edev, ecomp, val);
 618        return count;
 619}
 620
 621static ssize_t get_component_type(struct device *cdev,
 622                                  struct device_attribute *attr, char *buf)
 623{
 624        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 625
 626        return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]);
 627}
 628
 629static ssize_t get_component_slot(struct device *cdev,
 630                                  struct device_attribute *attr, char *buf)
 631{
 632        struct enclosure_component *ecomp = to_enclosure_component(cdev);
 633        int slot;
 634
 635        /* if the enclosure does not override then use 'number' as a stand-in */
 636        if (ecomp->slot >= 0)
 637                slot = ecomp->slot;
 638        else
 639                slot = ecomp->number;
 640
 641        return snprintf(buf, 40, "%d\n", slot);
 642}
 643
 644static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
 645                    set_component_fault);
 646static DEVICE_ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
 647                   set_component_status);
 648static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
 649                   set_component_active);
 650static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
 651                   set_component_locate);
 652static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status,
 653                   set_component_power_status);
 654static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL);
 655static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL);
 656
 657static struct attribute *enclosure_component_attrs[] = {
 658        &dev_attr_fault.attr,
 659        &dev_attr_status.attr,
 660        &dev_attr_active.attr,
 661        &dev_attr_locate.attr,
 662        &dev_attr_power_status.attr,
 663        &dev_attr_type.attr,
 664        &dev_attr_slot.attr,
 665        NULL
 666};
 667ATTRIBUTE_GROUPS(enclosure_component);
 668
 669static int __init enclosure_init(void)
 670{
 671        return class_register(&enclosure_class);
 672}
 673
 674static void __exit enclosure_exit(void)
 675{
 676        class_unregister(&enclosure_class);
 677}
 678
 679module_init(enclosure_init);
 680module_exit(enclosure_exit);
 681
 682MODULE_AUTHOR("James Bottomley");
 683MODULE_DESCRIPTION("Enclosure Services");
 684MODULE_LICENSE("GPL v2");
 685