static struct class enclosure_class;
 
 /**
- * enclosure_find - find an enclosure given a device
- * @dev:       the device to find for
+ * enclosure_find - find an enclosure given a parent device
+ * @dev:       the parent to match against
+ * @start:     Optional enclosure device to start from (NULL if none)
  *
- * Looks through the list of registered enclosures to see
- * if it can find a match for a device.  Returns NULL if no
- * enclosure is found. Obtains a reference to the enclosure class
- * device which must be released with device_put().
+ * Looks through the list of registered enclosures to find all those
+ * with @dev as a parent.  Returns NULL if no enclosure is
+ * found. @start can be used as a starting point to obtain multiple
+ * enclosures per parent (should begin with NULL and then be set to
+ * each returned enclosure device). Obtains a reference to the
+ * enclosure class device which must be released with device_put().
+ * If @start is not NULL, a reference must be taken on it which is
+ * released before returning (this allows a loop through all
+ * enclosures to exit with only the reference on the enclosure of
+ * interest held).  Note that the @dev may correspond to the actual
+ * device housing the enclosure, in which case no iteration via @start
+ * is required.
  */
-struct enclosure_device *enclosure_find(struct device *dev)
+struct enclosure_device *enclosure_find(struct device *dev,
+                                       struct enclosure_device *start)
 {
        struct enclosure_device *edev;
 
        mutex_lock(&container_list_lock);
-       list_for_each_entry(edev, &container_list, node) {
-               if (edev->edev.parent == dev) {
-                       get_device(&edev->edev);
-                       mutex_unlock(&container_list_lock);
-                       return edev;
+       edev = list_prepare_entry(start, &container_list, node);
+       if (start)
+               put_device(&start->edev);
+
+       list_for_each_entry_continue(edev, &container_list, node) {
+               struct device *parent = edev->edev.parent;
+               /* parent might not be immediate, so iterate up to
+                * the root of the tree if necessary */
+               while (parent) {
+                       if (parent == dev) {
+                               get_device(&edev->edev);
+                               mutex_unlock(&container_list_lock);
+                               return edev;
+                       }
+                       parent = parent->parent;
                }
        }
        mutex_unlock(&container_list_lock);
 
 
        if (!scsi_device_enclosure(sdev)) {
                /* not an enclosure, but might be in one */
-               edev = enclosure_find(&sdev->host->shost_gendev);
-               if (edev) {
+               struct enclosure_device *prev = NULL;
+
+               while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) {
                        ses_match_to_enclosure(edev, sdev);
-                       put_device(&edev->edev);
+                       prev = edev;
                }
                return -ENODEV;
        }
        if (!scsi_device_enclosure(sdev))
                return;
 
-       edev = enclosure_find(cdev->parent);
+       /*  exact match to this enclosure */
+       edev = enclosure_find(cdev->parent, NULL);
        if (!edev)
                return;
 
 
 int enclosure_add_device(struct enclosure_device *enclosure, int component,
                         struct device *dev);
 int enclosure_remove_device(struct enclosure_device *enclosure, int component);
-struct enclosure_device *enclosure_find(struct device *dev);
+struct enclosure_device *enclosure_find(struct device *dev,
+                                       struct enclosure_device *start);
 int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *),
                              void *data);