Source
x
// SPDX-License-Identifier: GPL-2.0-only
/*
* Enclosure Services
*
* Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com>
*
**-----------------------------------------------------------------------------
**
**
**-----------------------------------------------------------------------------
*/
static LIST_HEAD(container_list);
static DEFINE_MUTEX(container_list_lock);
static struct class enclosure_class;
/**
* 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 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 *start)
{
struct enclosure_device *edev;
mutex_lock(&container_list_lock);
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);
return NULL;
}
EXPORT_SYMBOL_GPL(enclosure_find);
/**
* enclosure_for_each_device - calls a function for each enclosure
* @fn: the function to call
* @data: the data to pass to each call
*
* Loops over all the enclosures calling the function.
*
* Note, this function uses a mutex which will be held across calls to
* @fn, so it must have non atomic context, and @fn may (although it
* should not) sleep or otherwise cause the mutex to be held for
* indefinite periods
*/
int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *),
void *data)
{
int error = 0;
struct enclosure_device *edev;
mutex_lock(&container_list_lock);
list_for_each_entry(edev, &container_list, node) {
error = fn(edev, data);