diff options
-rw-r--r-- | drivers/misc/enclosure.c | 44 | ||||
-rw-r--r-- | drivers/scsi/ses.c | 10 | ||||
-rw-r--r-- | include/linux/enclosure.h | 3 |
3 files changed, 40 insertions, 17 deletions
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 348443bdb23b..789d12128c24 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c | |||
@@ -33,24 +33,44 @@ static DEFINE_MUTEX(container_list_lock); | |||
33 | static struct class enclosure_class; | 33 | static struct class enclosure_class; |
34 | 34 | ||
35 | /** | 35 | /** |
36 | * enclosure_find - find an enclosure given a device | 36 | * enclosure_find - find an enclosure given a parent device |
37 | * @dev: the device to find for | 37 | * @dev: the parent to match against |
38 | * @start: Optional enclosure device to start from (NULL if none) | ||
38 | * | 39 | * |
39 | * Looks through the list of registered enclosures to see | 40 | * Looks through the list of registered enclosures to find all those |
40 | * if it can find a match for a device. Returns NULL if no | 41 | * with @dev as a parent. Returns NULL if no enclosure is |
41 | * enclosure is found. Obtains a reference to the enclosure class | 42 | * found. @start can be used as a starting point to obtain multiple |
42 | * device which must be released with device_put(). | 43 | * enclosures per parent (should begin with NULL and then be set to |
44 | * each returned enclosure device). Obtains a reference to the | ||
45 | * enclosure class device which must be released with device_put(). | ||
46 | * If @start is not NULL, a reference must be taken on it which is | ||
47 | * released before returning (this allows a loop through all | ||
48 | * enclosures to exit with only the reference on the enclosure of | ||
49 | * interest held). Note that the @dev may correspond to the actual | ||
50 | * device housing the enclosure, in which case no iteration via @start | ||
51 | * is required. | ||
43 | */ | 52 | */ |
44 | struct enclosure_device *enclosure_find(struct device *dev) | 53 | struct enclosure_device *enclosure_find(struct device *dev, |
54 | struct enclosure_device *start) | ||
45 | { | 55 | { |
46 | struct enclosure_device *edev; | 56 | struct enclosure_device *edev; |
47 | 57 | ||
48 | mutex_lock(&container_list_lock); | 58 | mutex_lock(&container_list_lock); |
49 | list_for_each_entry(edev, &container_list, node) { | 59 | edev = list_prepare_entry(start, &container_list, node); |
50 | if (edev->edev.parent == dev) { | 60 | if (start) |
51 | get_device(&edev->edev); | 61 | put_device(&start->edev); |
52 | mutex_unlock(&container_list_lock); | 62 | |
53 | return edev; | 63 | list_for_each_entry_continue(edev, &container_list, node) { |
64 | struct device *parent = edev->edev.parent; | ||
65 | /* parent might not be immediate, so iterate up to | ||
66 | * the root of the tree if necessary */ | ||
67 | while (parent) { | ||
68 | if (parent == dev) { | ||
69 | get_device(&edev->edev); | ||
70 | mutex_unlock(&container_list_lock); | ||
71 | return edev; | ||
72 | } | ||
73 | parent = parent->parent; | ||
54 | } | 74 | } |
55 | } | 75 | } |
56 | mutex_unlock(&container_list_lock); | 76 | mutex_unlock(&container_list_lock); |
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 4f618f487356..e1b8c828f03a 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c | |||
@@ -413,10 +413,11 @@ static int ses_intf_add(struct device *cdev, | |||
413 | 413 | ||
414 | if (!scsi_device_enclosure(sdev)) { | 414 | if (!scsi_device_enclosure(sdev)) { |
415 | /* not an enclosure, but might be in one */ | 415 | /* not an enclosure, but might be in one */ |
416 | edev = enclosure_find(&sdev->host->shost_gendev); | 416 | struct enclosure_device *prev = NULL; |
417 | if (edev) { | 417 | |
418 | while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { | ||
418 | ses_match_to_enclosure(edev, sdev); | 419 | ses_match_to_enclosure(edev, sdev); |
419 | put_device(&edev->edev); | 420 | prev = edev; |
420 | } | 421 | } |
421 | return -ENODEV; | 422 | return -ENODEV; |
422 | } | 423 | } |
@@ -625,7 +626,8 @@ static void ses_intf_remove(struct device *cdev, | |||
625 | if (!scsi_device_enclosure(sdev)) | 626 | if (!scsi_device_enclosure(sdev)) |
626 | return; | 627 | return; |
627 | 628 | ||
628 | edev = enclosure_find(cdev->parent); | 629 | /* exact match to this enclosure */ |
630 | edev = enclosure_find(cdev->parent, NULL); | ||
629 | if (!edev) | 631 | if (!edev) |
630 | return; | 632 | return; |
631 | 633 | ||
diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h index 4332442b1b57..d77811e9ed84 100644 --- a/include/linux/enclosure.h +++ b/include/linux/enclosure.h | |||
@@ -123,7 +123,8 @@ enclosure_component_register(struct enclosure_device *, unsigned int, | |||
123 | int enclosure_add_device(struct enclosure_device *enclosure, int component, | 123 | int enclosure_add_device(struct enclosure_device *enclosure, int component, |
124 | struct device *dev); | 124 | struct device *dev); |
125 | int enclosure_remove_device(struct enclosure_device *enclosure, int component); | 125 | int enclosure_remove_device(struct enclosure_device *enclosure, int component); |
126 | struct enclosure_device *enclosure_find(struct device *dev); | 126 | struct enclosure_device *enclosure_find(struct device *dev, |
127 | struct enclosure_device *start); | ||
127 | int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), | 128 | int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), |
128 | void *data); | 129 | void *data); |
129 | 130 | ||