Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Enclosure Services
0004  *
0005  * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
0006  *
0007 **-----------------------------------------------------------------------------
0008 **
0009 **
0010 **-----------------------------------------------------------------------------
0011 */
0012 #include <linux/device.h>
0013 #include <linux/enclosure.h>
0014 #include <linux/err.h>
0015 #include <linux/list.h>
0016 #include <linux/kernel.h>
0017 #include <linux/module.h>
0018 #include <linux/mutex.h>
0019 #include <linux/slab.h>
0020 
0021 static LIST_HEAD(container_list);
0022 static DEFINE_MUTEX(container_list_lock);
0023 static struct class enclosure_class;
0024 
0025 /**
0026  * enclosure_find - find an enclosure given a parent device
0027  * @dev:    the parent to match against
0028  * @start:  Optional enclosure device to start from (NULL if none)
0029  *
0030  * Looks through the list of registered enclosures to find all those
0031  * with @dev as a parent.  Returns NULL if no enclosure is
0032  * found. @start can be used as a starting point to obtain multiple
0033  * enclosures per parent (should begin with NULL and then be set to
0034  * each returned enclosure device). Obtains a reference to the
0035  * enclosure class device which must be released with device_put().
0036  * If @start is not NULL, a reference must be taken on it which is
0037  * released before returning (this allows a loop through all
0038  * enclosures to exit with only the reference on the enclosure of
0039  * interest held).  Note that the @dev may correspond to the actual
0040  * device housing the enclosure, in which case no iteration via @start
0041  * is required.
0042  */
0043 struct enclosure_device *enclosure_find(struct device *dev,
0044                     struct enclosure_device *start)
0045 {
0046     struct enclosure_device *edev;
0047 
0048     mutex_lock(&container_list_lock);
0049     edev = list_prepare_entry(start, &container_list, node);
0050     if (start)
0051         put_device(&start->edev);
0052 
0053     list_for_each_entry_continue(edev, &container_list, node) {
0054         struct device *parent = edev->edev.parent;
0055         /* parent might not be immediate, so iterate up to
0056          * the root of the tree if necessary */
0057         while (parent) {
0058             if (parent == dev) {
0059                 get_device(&edev->edev);
0060                 mutex_unlock(&container_list_lock);
0061                 return edev;
0062             }
0063             parent = parent->parent;
0064         }
0065     }
0066     mutex_unlock(&container_list_lock);
0067 
0068     return NULL;
0069 }
0070 EXPORT_SYMBOL_GPL(enclosure_find);
0071 
0072 /**
0073  * enclosure_for_each_device - calls a function for each enclosure
0074  * @fn:     the function to call
0075  * @data:   the data to pass to each call
0076  *
0077  * Loops over all the enclosures calling the function.
0078  *
0079  * Note, this function uses a mutex which will be held across calls to
0080  * @fn, so it must have non atomic context, and @fn may (although it
0081  * should not) sleep or otherwise cause the mutex to be held for
0082  * indefinite periods
0083  */
0084 int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *),
0085                   void *data)
0086 {
0087     int error = 0;
0088     struct enclosure_device *edev;
0089 
0090     mutex_lock(&container_list_lock);
0091     list_for_each_entry(edev, &container_list, node) {
0092         error = fn(edev, data);
0093         if (error)
0094             break;
0095     }
0096     mutex_unlock(&container_list_lock);
0097 
0098     return error;
0099 }
0100 EXPORT_SYMBOL_GPL(enclosure_for_each_device);
0101 
0102 /**
0103  * enclosure_register - register device as an enclosure
0104  *
0105  * @dev:    device containing the enclosure
0106  * @name:   chosen device name
0107  * @components: number of components in the enclosure
0108  * @cb:         platform call-backs
0109  *
0110  * This sets up the device for being an enclosure.  Note that @dev does
0111  * not have to be a dedicated enclosure device.  It may be some other type
0112  * of device that additionally responds to enclosure services
0113  */
0114 struct enclosure_device *
0115 enclosure_register(struct device *dev, const char *name, int components,
0116            struct enclosure_component_callbacks *cb)
0117 {
0118     struct enclosure_device *edev =
0119         kzalloc(struct_size(edev, component, components), GFP_KERNEL);
0120     int err, i;
0121 
0122     BUG_ON(!cb);
0123 
0124     if (!edev)
0125         return ERR_PTR(-ENOMEM);
0126 
0127     edev->components = components;
0128 
0129     edev->edev.class = &enclosure_class;
0130     edev->edev.parent = get_device(dev);
0131     edev->cb = cb;
0132     dev_set_name(&edev->edev, "%s", name);
0133     err = device_register(&edev->edev);
0134     if (err)
0135         goto err;
0136 
0137     for (i = 0; i < components; i++) {
0138         edev->component[i].number = -1;
0139         edev->component[i].slot = -1;
0140         edev->component[i].power_status = -1;
0141     }
0142 
0143     mutex_lock(&container_list_lock);
0144     list_add_tail(&edev->node, &container_list);
0145     mutex_unlock(&container_list_lock);
0146 
0147     return edev;
0148 
0149  err:
0150     put_device(edev->edev.parent);
0151     kfree(edev);
0152     return ERR_PTR(err);
0153 }
0154 EXPORT_SYMBOL_GPL(enclosure_register);
0155 
0156 static struct enclosure_component_callbacks enclosure_null_callbacks;
0157 
0158 /**
0159  * enclosure_unregister - remove an enclosure
0160  *
0161  * @edev:   the registered enclosure to remove;
0162  */
0163 void enclosure_unregister(struct enclosure_device *edev)
0164 {
0165     int i;
0166 
0167     mutex_lock(&container_list_lock);
0168     list_del(&edev->node);
0169     mutex_unlock(&container_list_lock);
0170 
0171     for (i = 0; i < edev->components; i++)
0172         if (edev->component[i].number != -1)
0173             device_unregister(&edev->component[i].cdev);
0174 
0175     /* prevent any callbacks into service user */
0176     edev->cb = &enclosure_null_callbacks;
0177     device_unregister(&edev->edev);
0178 }
0179 EXPORT_SYMBOL_GPL(enclosure_unregister);
0180 
0181 #define ENCLOSURE_NAME_SIZE 64
0182 #define COMPONENT_NAME_SIZE 64
0183 
0184 static void enclosure_link_name(struct enclosure_component *cdev, char *name)
0185 {
0186     strcpy(name, "enclosure_device:");
0187     strcat(name, dev_name(&cdev->cdev));
0188 }
0189 
0190 static void enclosure_remove_links(struct enclosure_component *cdev)
0191 {
0192     char name[ENCLOSURE_NAME_SIZE];
0193 
0194     enclosure_link_name(cdev, name);
0195 
0196     /*
0197      * In odd circumstances, like multipath devices, something else may
0198      * already have removed the links, so check for this condition first.
0199      */
0200     if (cdev->dev->kobj.sd)
0201         sysfs_remove_link(&cdev->dev->kobj, name);
0202 
0203     if (cdev->cdev.kobj.sd)
0204         sysfs_remove_link(&cdev->cdev.kobj, "device");
0205 }
0206 
0207 static int enclosure_add_links(struct enclosure_component *cdev)
0208 {
0209     int error;
0210     char name[ENCLOSURE_NAME_SIZE];
0211 
0212     error = sysfs_create_link(&cdev->cdev.kobj, &cdev->dev->kobj, "device");
0213     if (error)
0214         return error;
0215 
0216     enclosure_link_name(cdev, name);
0217     error = sysfs_create_link(&cdev->dev->kobj, &cdev->cdev.kobj, name);
0218     if (error)
0219         sysfs_remove_link(&cdev->cdev.kobj, "device");
0220 
0221     return error;
0222 }
0223 
0224 static void enclosure_release(struct device *cdev)
0225 {
0226     struct enclosure_device *edev = to_enclosure_device(cdev);
0227 
0228     put_device(cdev->parent);
0229     kfree(edev);
0230 }
0231 
0232 static void enclosure_component_release(struct device *dev)
0233 {
0234     struct enclosure_component *cdev = to_enclosure_component(dev);
0235 
0236     if (cdev->dev) {
0237         enclosure_remove_links(cdev);
0238         put_device(cdev->dev);
0239     }
0240     put_device(dev->parent);
0241 }
0242 
0243 static struct enclosure_component *
0244 enclosure_component_find_by_name(struct enclosure_device *edev,
0245                 const char *name)
0246 {
0247     int i;
0248     const char *cname;
0249     struct enclosure_component *ecomp;
0250 
0251     if (!edev || !name || !name[0])
0252         return NULL;
0253 
0254     for (i = 0; i < edev->components; i++) {
0255         ecomp = &edev->component[i];
0256         cname = dev_name(&ecomp->cdev);
0257         if (ecomp->number != -1 &&
0258             cname && cname[0] &&
0259             !strcmp(cname, name))
0260             return ecomp;
0261     }
0262 
0263     return NULL;
0264 }
0265 
0266 static const struct attribute_group *enclosure_component_groups[];
0267 
0268 /**
0269  * enclosure_component_alloc - prepare a new enclosure component
0270  * @edev:   the enclosure to add the component
0271  * @number: the device number
0272  * @type:   the type of component being added
0273  * @name:   an optional name to appear in sysfs (leave NULL if none)
0274  *
0275  * The name is optional for enclosures that give their components a unique
0276  * name.  If not, leave the field NULL and a name will be assigned.
0277  *
0278  * Returns a pointer to the enclosure component or an error.
0279  */
0280 struct enclosure_component *
0281 enclosure_component_alloc(struct enclosure_device *edev,
0282               unsigned int number,
0283               enum enclosure_component_type type,
0284               const char *name)
0285 {
0286     struct enclosure_component *ecomp;
0287     struct device *cdev;
0288     int i;
0289     char newname[COMPONENT_NAME_SIZE];
0290 
0291     if (number >= edev->components)
0292         return ERR_PTR(-EINVAL);
0293 
0294     ecomp = &edev->component[number];
0295 
0296     if (ecomp->number != -1)
0297         return ERR_PTR(-EINVAL);
0298 
0299     ecomp->type = type;
0300     ecomp->number = number;
0301     cdev = &ecomp->cdev;
0302     cdev->parent = get_device(&edev->edev);
0303 
0304     if (name && name[0]) {
0305         /* Some hardware (e.g. enclosure in RX300 S6) has components
0306          * with non unique names. Registering duplicates in sysfs
0307          * will lead to warnings during bootup. So make the names
0308          * unique by appending consecutive numbers -1, -2, ... */
0309         i = 1;
0310         snprintf(newname, COMPONENT_NAME_SIZE,
0311              "%s", name);
0312         while (enclosure_component_find_by_name(edev, newname))
0313             snprintf(newname, COMPONENT_NAME_SIZE,
0314                  "%s-%i", name, i++);
0315         dev_set_name(cdev, "%s", newname);
0316     } else
0317         dev_set_name(cdev, "%u", number);
0318 
0319     cdev->release = enclosure_component_release;
0320     cdev->groups = enclosure_component_groups;
0321 
0322     return ecomp;
0323 }
0324 EXPORT_SYMBOL_GPL(enclosure_component_alloc);
0325 
0326 /**
0327  * enclosure_component_register - publishes an initialized enclosure component
0328  * @ecomp:  component to add
0329  *
0330  * Returns 0 on successful registration, releases the component otherwise
0331  */
0332 int enclosure_component_register(struct enclosure_component *ecomp)
0333 {
0334     struct device *cdev;
0335     int err;
0336 
0337     cdev = &ecomp->cdev;
0338     err = device_register(cdev);
0339     if (err) {
0340         ecomp->number = -1;
0341         put_device(cdev);
0342         return err;
0343     }
0344 
0345     return 0;
0346 }
0347 EXPORT_SYMBOL_GPL(enclosure_component_register);
0348 
0349 /**
0350  * enclosure_add_device - add a device as being part of an enclosure
0351  * @edev:   the enclosure device being added to.
0352  * @component:  the number of the component
0353  * @dev:    the device being added
0354  *
0355  * Declares a real device to reside in slot (or identifier) @num of an
0356  * enclosure.  This will cause the relevant sysfs links to appear.
0357  * This function may also be used to change a device associated with
0358  * an enclosure without having to call enclosure_remove_device() in
0359  * between.
0360  *
0361  * Returns zero on success or an error.
0362  */
0363 int enclosure_add_device(struct enclosure_device *edev, int component,
0364              struct device *dev)
0365 {
0366     struct enclosure_component *cdev;
0367     int err;
0368 
0369     if (!edev || component >= edev->components)
0370         return -EINVAL;
0371 
0372     cdev = &edev->component[component];
0373 
0374     if (cdev->dev == dev)
0375         return -EEXIST;
0376 
0377     if (cdev->dev) {
0378         enclosure_remove_links(cdev);
0379         put_device(cdev->dev);
0380     }
0381     cdev->dev = get_device(dev);
0382     err = enclosure_add_links(cdev);
0383     if (err) {
0384         put_device(cdev->dev);
0385         cdev->dev = NULL;
0386     }
0387     return err;
0388 }
0389 EXPORT_SYMBOL_GPL(enclosure_add_device);
0390 
0391 /**
0392  * enclosure_remove_device - remove a device from an enclosure
0393  * @edev:   the enclosure device
0394  * @dev:    device to remove/put
0395  *
0396  * Returns zero on success or an error.
0397  *
0398  */
0399 int enclosure_remove_device(struct enclosure_device *edev, struct device *dev)
0400 {
0401     struct enclosure_component *cdev;
0402     int i;
0403 
0404     if (!edev || !dev)
0405         return -EINVAL;
0406 
0407     for (i = 0; i < edev->components; i++) {
0408         cdev = &edev->component[i];
0409         if (cdev->dev == dev) {
0410             enclosure_remove_links(cdev);
0411             put_device(dev);
0412             cdev->dev = NULL;
0413             return 0;
0414         }
0415     }
0416     return -ENODEV;
0417 }
0418 EXPORT_SYMBOL_GPL(enclosure_remove_device);
0419 
0420 /*
0421  * sysfs pieces below
0422  */
0423 
0424 static ssize_t components_show(struct device *cdev,
0425                    struct device_attribute *attr, char *buf)
0426 {
0427     struct enclosure_device *edev = to_enclosure_device(cdev);
0428 
0429     return sysfs_emit(buf, "%d\n", edev->components);
0430 }
0431 static DEVICE_ATTR_RO(components);
0432 
0433 static ssize_t id_show(struct device *cdev,
0434                  struct device_attribute *attr,
0435                  char *buf)
0436 {
0437     struct enclosure_device *edev = to_enclosure_device(cdev);
0438 
0439     if (edev->cb->show_id)
0440         return edev->cb->show_id(edev, buf);
0441     return -EINVAL;
0442 }
0443 static DEVICE_ATTR_RO(id);
0444 
0445 static struct attribute *enclosure_class_attrs[] = {
0446     &dev_attr_components.attr,
0447     &dev_attr_id.attr,
0448     NULL,
0449 };
0450 ATTRIBUTE_GROUPS(enclosure_class);
0451 
0452 static struct class enclosure_class = {
0453     .name           = "enclosure",
0454     .owner          = THIS_MODULE,
0455     .dev_release        = enclosure_release,
0456     .dev_groups     = enclosure_class_groups,
0457 };
0458 
0459 static const char *const enclosure_status[] = {
0460     [ENCLOSURE_STATUS_UNSUPPORTED] = "unsupported",
0461     [ENCLOSURE_STATUS_OK] = "OK",
0462     [ENCLOSURE_STATUS_CRITICAL] = "critical",
0463     [ENCLOSURE_STATUS_NON_CRITICAL] = "non-critical",
0464     [ENCLOSURE_STATUS_UNRECOVERABLE] = "unrecoverable",
0465     [ENCLOSURE_STATUS_NOT_INSTALLED] = "not installed",
0466     [ENCLOSURE_STATUS_UNKNOWN] = "unknown",
0467     [ENCLOSURE_STATUS_UNAVAILABLE] = "unavailable",
0468     [ENCLOSURE_STATUS_MAX] = NULL,
0469 };
0470 
0471 static const char *const enclosure_type[] = {
0472     [ENCLOSURE_COMPONENT_DEVICE] = "device",
0473     [ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device",
0474 };
0475 
0476 static ssize_t get_component_fault(struct device *cdev,
0477                    struct device_attribute *attr, char *buf)
0478 {
0479     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0480     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0481 
0482     if (edev->cb->get_fault)
0483         edev->cb->get_fault(edev, ecomp);
0484     return sysfs_emit(buf, "%d\n", ecomp->fault);
0485 }
0486 
0487 static ssize_t set_component_fault(struct device *cdev,
0488                    struct device_attribute *attr,
0489                    const char *buf, size_t count)
0490 {
0491     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0492     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0493     int val = simple_strtoul(buf, NULL, 0);
0494 
0495     if (edev->cb->set_fault)
0496         edev->cb->set_fault(edev, ecomp, val);
0497     return count;
0498 }
0499 
0500 static ssize_t get_component_status(struct device *cdev,
0501                     struct device_attribute *attr,char *buf)
0502 {
0503     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0504     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0505 
0506     if (edev->cb->get_status)
0507         edev->cb->get_status(edev, ecomp);
0508     return sysfs_emit(buf, "%s\n", enclosure_status[ecomp->status]);
0509 }
0510 
0511 static ssize_t set_component_status(struct device *cdev,
0512                     struct device_attribute *attr,
0513                     const char *buf, size_t count)
0514 {
0515     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0516     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0517     int i;
0518 
0519     for (i = 0; enclosure_status[i]; i++) {
0520         if (strncmp(buf, enclosure_status[i],
0521                 strlen(enclosure_status[i])) == 0 &&
0522             (buf[strlen(enclosure_status[i])] == '\n' ||
0523              buf[strlen(enclosure_status[i])] == '\0'))
0524             break;
0525     }
0526 
0527     if (enclosure_status[i] && edev->cb->set_status) {
0528         edev->cb->set_status(edev, ecomp, i);
0529         return count;
0530     } else
0531         return -EINVAL;
0532 }
0533 
0534 static ssize_t get_component_active(struct device *cdev,
0535                     struct device_attribute *attr, char *buf)
0536 {
0537     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0538     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0539 
0540     if (edev->cb->get_active)
0541         edev->cb->get_active(edev, ecomp);
0542     return sysfs_emit(buf, "%d\n", ecomp->active);
0543 }
0544 
0545 static ssize_t set_component_active(struct device *cdev,
0546                     struct device_attribute *attr,
0547                     const char *buf, size_t count)
0548 {
0549     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0550     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0551     int val = simple_strtoul(buf, NULL, 0);
0552 
0553     if (edev->cb->set_active)
0554         edev->cb->set_active(edev, ecomp, val);
0555     return count;
0556 }
0557 
0558 static ssize_t get_component_locate(struct device *cdev,
0559                     struct device_attribute *attr, char *buf)
0560 {
0561     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0562     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0563 
0564     if (edev->cb->get_locate)
0565         edev->cb->get_locate(edev, ecomp);
0566     return sysfs_emit(buf, "%d\n", ecomp->locate);
0567 }
0568 
0569 static ssize_t set_component_locate(struct device *cdev,
0570                     struct device_attribute *attr,
0571                     const char *buf, size_t count)
0572 {
0573     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0574     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0575     int val = simple_strtoul(buf, NULL, 0);
0576 
0577     if (edev->cb->set_locate)
0578         edev->cb->set_locate(edev, ecomp, val);
0579     return count;
0580 }
0581 
0582 static ssize_t get_component_power_status(struct device *cdev,
0583                       struct device_attribute *attr,
0584                       char *buf)
0585 {
0586     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0587     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0588 
0589     if (edev->cb->get_power_status)
0590         edev->cb->get_power_status(edev, ecomp);
0591 
0592     /* If still uninitialized, the callback failed or does not exist. */
0593     if (ecomp->power_status == -1)
0594         return (edev->cb->get_power_status) ? -EIO : -ENOTTY;
0595 
0596     return sysfs_emit(buf, "%s\n", ecomp->power_status ? "on" : "off");
0597 }
0598 
0599 static ssize_t set_component_power_status(struct device *cdev,
0600                       struct device_attribute *attr,
0601                       const char *buf, size_t count)
0602 {
0603     struct enclosure_device *edev = to_enclosure_device(cdev->parent);
0604     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0605     int val;
0606 
0607     if (strncmp(buf, "on", 2) == 0 &&
0608         (buf[2] == '\n' || buf[2] == '\0'))
0609         val = 1;
0610     else if (strncmp(buf, "off", 3) == 0 &&
0611         (buf[3] == '\n' || buf[3] == '\0'))
0612         val = 0;
0613     else
0614         return -EINVAL;
0615 
0616     if (edev->cb->set_power_status)
0617         edev->cb->set_power_status(edev, ecomp, val);
0618     return count;
0619 }
0620 
0621 static ssize_t get_component_type(struct device *cdev,
0622                   struct device_attribute *attr, char *buf)
0623 {
0624     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0625 
0626     return sysfs_emit(buf, "%s\n", enclosure_type[ecomp->type]);
0627 }
0628 
0629 static ssize_t get_component_slot(struct device *cdev,
0630                   struct device_attribute *attr, char *buf)
0631 {
0632     struct enclosure_component *ecomp = to_enclosure_component(cdev);
0633     int slot;
0634 
0635     /* if the enclosure does not override then use 'number' as a stand-in */
0636     if (ecomp->slot >= 0)
0637         slot = ecomp->slot;
0638     else
0639         slot = ecomp->number;
0640 
0641     return sysfs_emit(buf, "%d\n", slot);
0642 }
0643 
0644 static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
0645             set_component_fault);
0646 static DEVICE_ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
0647            set_component_status);
0648 static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
0649            set_component_active);
0650 static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
0651            set_component_locate);
0652 static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status,
0653            set_component_power_status);
0654 static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL);
0655 static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL);
0656 
0657 static struct attribute *enclosure_component_attrs[] = {
0658     &dev_attr_fault.attr,
0659     &dev_attr_status.attr,
0660     &dev_attr_active.attr,
0661     &dev_attr_locate.attr,
0662     &dev_attr_power_status.attr,
0663     &dev_attr_type.attr,
0664     &dev_attr_slot.attr,
0665     NULL
0666 };
0667 ATTRIBUTE_GROUPS(enclosure_component);
0668 
0669 static int __init enclosure_init(void)
0670 {
0671     return class_register(&enclosure_class);
0672 }
0673 
0674 static void __exit enclosure_exit(void)
0675 {
0676     class_unregister(&enclosure_class);
0677 }
0678 
0679 module_init(enclosure_init);
0680 module_exit(enclosure_exit);
0681 
0682 MODULE_AUTHOR("James Bottomley");
0683 MODULE_DESCRIPTION("Enclosure Services");
0684 MODULE_LICENSE("GPL v2");