|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* Intel(R) Enclosure LED Utilities
|
|
Packit Service |
db8df9 |
* Copyright (C) 2009-2019 Intel Corporation.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
db8df9 |
* under the terms and conditions of the GNU General Public License,
|
|
Packit Service |
db8df9 |
* version 2, as published by the Free Software Foundation.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit Service |
db8df9 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit Service |
db8df9 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit Service |
db8df9 |
* more details.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* You should have received a copy of the GNU General Public License along with
|
|
Packit Service |
db8df9 |
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
db8df9 |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include <fcntl.h>
|
|
Packit Service |
db8df9 |
#include <limits.h>
|
|
Packit Service |
db8df9 |
#include <stdint.h>
|
|
Packit Service |
db8df9 |
#include <stdlib.h>
|
|
Packit Service |
db8df9 |
#include <string.h>
|
|
Packit Service |
db8df9 |
#include <sys/types.h>
|
|
Packit Service |
db8df9 |
#include <unistd.h>
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#if _HAVE_DMALLOC_H
|
|
Packit Service |
db8df9 |
#include <dmalloc.h>
|
|
Packit Service |
db8df9 |
#endif
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include "block.h"
|
|
Packit Service |
db8df9 |
#include "cntrl.h"
|
|
Packit Service |
db8df9 |
#include "config.h"
|
|
Packit Service |
db8df9 |
#include "config_file.h"
|
|
Packit Service |
db8df9 |
#include "enclosure.h"
|
|
Packit Service |
db8df9 |
#include "ibpi.h"
|
|
Packit Service |
db8df9 |
#include "list.h"
|
|
Packit Service |
db8df9 |
#include "pci_slot.h"
|
|
Packit Service |
db8df9 |
#include "raid.h"
|
|
Packit Service |
db8df9 |
#include "slave.h"
|
|
Packit Service |
db8df9 |
#include "stdio.h"
|
|
Packit Service |
db8df9 |
#include "sysfs.h"
|
|
Packit Service |
db8df9 |
#include "utils.h"
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
#define SYSFS_CLASS_BLOCK "/sys/block"
|
|
Packit Service |
db8df9 |
#define SYSFS_CLASS_ENCLOSURE "/sys/class/enclosure"
|
|
Packit Service |
db8df9 |
#define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
|
|
Packit Service |
db8df9 |
#define SYSFS_PCI_SLOTS "/sys/bus/pci/slots"
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* This is internal variable global to sysfs module only. It is a list of
|
|
Packit Service |
db8df9 |
* block devices registered in the system. Use sysfs_init()
|
|
Packit Service |
db8df9 |
* function to initialize the variable. Use sysfs_scan() function to populate
|
|
Packit Service |
db8df9 |
* the list. Use sysfs_reset() function to delete the content of the list.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static struct list sysfs_block_list;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* This is internal variable global to sysfs module only. It is a list of
|
|
Packit Service |
db8df9 |
* RAID volumes registered in the system. Use sysfs_init()
|
|
Packit Service |
db8df9 |
* function to initialize the variable. Use sysfs_scan() function to populate
|
|
Packit Service |
db8df9 |
* the list. Use sysfs_reset() function to delete the content of the list.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static struct list volum_list;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* This is internal variable global to sysfs module only. It is a list of
|
|
Packit Service |
db8df9 |
* storage controller devices registered in the system and
|
|
Packit Service |
db8df9 |
* supported by Intel(R) Enclosure LEDs Control Utility. Use sysfs_init()
|
|
Packit Service |
db8df9 |
* function to initialize the variable. Use sysfs_scan() function to populate
|
|
Packit Service |
db8df9 |
* the list. Use sysfs_reset() function to delete the content of the list.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static struct list cntrl_list;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* This is internal variable global to sysfs module only. It is a list of
|
|
Packit Service |
db8df9 |
* slave devices registered in the system. Use sysfs_init()
|
|
Packit Service |
db8df9 |
* function to initialize the variable. Use sysfs_scan() function to populate
|
|
Packit Service |
db8df9 |
* the list. Use sysfs_reset() function to delete the content of the list.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static struct list slave_list;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* This is internal variable global to sysfs module only. It is a list of
|
|
Packit Service |
db8df9 |
* RAID containers registered in the system. Use sysfs_init()
|
|
Packit Service |
db8df9 |
* function to initialize the variable. Use sysfs_scan() function to populate
|
|
Packit Service |
db8df9 |
* the list. Use sysfs_reset() function to delete the content of the list.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static struct list cntnr_list;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* This is internal variable global to sysfs module only. It is a to list of
|
|
Packit Service |
db8df9 |
* enclosures registered in the system.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static struct list enclo_list;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* This is internal variable global to sysfs module only. It is a list of
|
|
Packit Service |
db8df9 |
* PCI slots registered in the system. Use sysfs_init()
|
|
Packit Service |
db8df9 |
* function to initialize the variable. Use sysfs_scan() function to populate
|
|
Packit Service |
db8df9 |
* the list. Use sysfs_reset() function to delete the content of the list.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static struct list slots_list;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* @brief Determine device type.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This is internal function of sysfs module. The function determines a type of
|
|
Packit Service |
db8df9 |
* RAID device either it is VOLUME or CONTAINER device. The information required
|
|
Packit Service |
db8df9 |
* if read from 'metadata_version' attribute from sysfs. External and native
|
|
Packit Service |
db8df9 |
* RAID devices are reported as volumes with no distinction between both types.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @param[in] path Path to RAID device in sysfs tree.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @return Type of RAID device if successful, otherwise DEVICE_TYPE_UNKNOWN.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static enum device_type _get_device_type(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
enum device_type result = DEVICE_TYPE_UNKNOWN;
|
|
Packit Service |
db8df9 |
char *p = get_text(path, "md/metadata_version");
|
|
Packit Service |
db8df9 |
if (p != NULL) {
|
|
Packit Service |
db8df9 |
if (strlen(p) > 0) {
|
|
Packit Service |
db8df9 |
if (strncmp(p, "external:", 9) == 0) {
|
|
Packit Service |
db8df9 |
if (p[9] == '/' || p[9] == '-')
|
|
Packit Service |
db8df9 |
result = DEVICE_TYPE_VOLUME;
|
|
Packit Service |
db8df9 |
else
|
|
Packit Service |
db8df9 |
result = DEVICE_TYPE_CONTAINER;
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
result = DEVICE_TYPE_VOLUME;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
free(p);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return result;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* @brief Gets device major and minor.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This is internal function of sysfs module. The function retrieves major and
|
|
Packit Service |
db8df9 |
* minor of device from sysfs attribute. Each block device has 'dev' attribute
|
|
Packit Service |
db8df9 |
* where major and minor separated by colon are stored.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @param[in] path Path to block device in sysfs tree.
|
|
Packit Service |
db8df9 |
* @param[in] d_id Placeholder where major and minor of device
|
|
Packit Service |
db8df9 |
* will be stored. If this argument is NULL the
|
|
Packit Service |
db8df9 |
* behavior of function is unspecified.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @return The function does not return a value.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _get_id(const char *path, struct device_id *d_id)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char temp[PATH_MAX];
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
snprintf(temp, sizeof(temp), "%s/dev", path);
|
|
Packit Service |
db8df9 |
get_id(temp, d_id);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* @brief Adds slave device to RAID volume.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This is internal function of sysfs module. The function puts slave device on
|
|
Packit Service |
db8df9 |
* list of slave devices of RAID volume. The memory is allocated and structure
|
|
Packit Service |
db8df9 |
* fields populated. RAID device is link to slave device.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @param[in] path Path to 'md' directory of RAID device in sysfs
|
|
Packit Service |
db8df9 |
* tree.
|
|
Packit Service |
db8df9 |
* @param[in] raid Pointer to RAID device structure corresponding
|
|
Packit Service |
db8df9 |
* to 'path' argument.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @return The function does not return a value.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _slave_vol_add(const char *path, struct raid_device *raid)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct slave_device *device;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
char *t = strrchr(path, '/');
|
|
Packit Service |
db8df9 |
if (strncmp(t + 1, "dev-", 4) == 0) {
|
|
Packit Service |
db8df9 |
device = slave_device_init(path, &sysfs_block_list);
|
|
Packit Service |
db8df9 |
if (device) {
|
|
Packit Service |
db8df9 |
device->raid = raid;
|
|
Packit Service |
db8df9 |
list_append(&slave_list, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* @brief Checks for duplicate entries on list of slave devices.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This is internal function of sysfs module. The functions checks if the given
|
|
Packit Service |
db8df9 |
* slave device is already on list with slave devices. This function is used by
|
|
Packit Service |
db8df9 |
* _slave_cnt_add() function to avoid duplicate entries.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @param[in] slave Pointer to slave device structure to check.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @return 1 the given device is on the list, otherwise the function returns 0.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static int _is_duplicate(struct slave_device *slave)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct slave_device *device;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&slave_list, device) {
|
|
Packit Service |
db8df9 |
if (device->block == slave->block)
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
* @brief Checks if given disk can be removed from sysfs_block_list if
|
|
Packit Service |
db8df9 |
* metatada is not present.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This is internal function (action) of sysfs module. The slave_list keeps
|
|
Packit Service |
db8df9 |
* all devices with metadata (raid devices). If disk is not included in slave
|
|
Packit Service |
db8df9 |
* list there is not metadata on it.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* @return 1 if can be removed, otherwise 0.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static int _is_non_raid_device(struct block_device *block_device)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct slave_device *slave_device;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&slave_list, slave_device) {
|
|
Packit Service |
db8df9 |
if (strcmp(slave_device->block->sysfs_path,
|
|
Packit Service |
db8df9 |
block_device->sysfs_path) == 0)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _slave_cnt_add(const char *path, struct raid_device *raid)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct slave_device *device;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
char *t = strrchr(path, '/');
|
|
Packit Service |
db8df9 |
if (strncmp(t + 1, "dev-", 4) == 0) {
|
|
Packit Service |
db8df9 |
device = slave_device_init(path, &sysfs_block_list);
|
|
Packit Service |
db8df9 |
if (device) {
|
|
Packit Service |
db8df9 |
if (!_is_duplicate(device)) {
|
|
Packit Service |
db8df9 |
device->raid = raid;
|
|
Packit Service |
db8df9 |
list_append(&slave_list, device);
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
slave_device_fini(device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _link_raid_device(struct raid_device *device, enum device_type type)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char temp[PATH_MAX];
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
snprintf(temp, sizeof(temp), "%s/md", device->sysfs_path);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (scan_dir(temp, &dir) == 0) {
|
|
Packit Service |
db8df9 |
const char *dir_path;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&dir, dir_path) {
|
|
Packit Service |
db8df9 |
if (type == DEVICE_TYPE_VOLUME)
|
|
Packit Service |
db8df9 |
_slave_vol_add(dir_path, device);
|
|
Packit Service |
db8df9 |
else if (type == DEVICE_TYPE_CONTAINER)
|
|
Packit Service |
db8df9 |
_slave_cnt_add(dir_path, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _block_add(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct block_device *device = block_device_init(&cntrl_list, path);
|
|
Packit Service |
db8df9 |
if (device)
|
|
Packit Service |
db8df9 |
list_append(&sysfs_block_list, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _volum_add(const char *path, unsigned int device_num)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct raid_device *device =
|
|
Packit Service |
db8df9 |
raid_device_init(path, device_num, DEVICE_TYPE_VOLUME);
|
|
Packit Service |
db8df9 |
if (device)
|
|
Packit Service |
db8df9 |
list_append(&volum_list, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _cntnr_add(const char *path, unsigned int device_num)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct raid_device *device =
|
|
Packit Service |
db8df9 |
raid_device_init(path, device_num, DEVICE_TYPE_CONTAINER);
|
|
Packit Service |
db8df9 |
if (device)
|
|
Packit Service |
db8df9 |
list_append(&cntnr_list, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _raid_add(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct device_id device_id;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
_get_id(path, &device_id);
|
|
Packit Service |
db8df9 |
if (device_id.major == 9) {
|
|
Packit Service |
db8df9 |
switch (_get_device_type(path)) {
|
|
Packit Service |
db8df9 |
case DEVICE_TYPE_VOLUME:
|
|
Packit Service |
db8df9 |
_volum_add(path, device_id.minor);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case DEVICE_TYPE_CONTAINER:
|
|
Packit Service |
db8df9 |
_cntnr_add(path, device_id.minor);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case DEVICE_TYPE_UNKNOWN:
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _cntrl_add(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct cntrl_device *device = cntrl_device_init(path);
|
|
Packit Service |
db8df9 |
if (device)
|
|
Packit Service |
db8df9 |
list_append(&cntrl_list, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _enclo_add(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct enclosure_device *device = enclosure_device_init(path);
|
|
Packit Service |
db8df9 |
if (device)
|
|
Packit Service |
db8df9 |
list_append(&enclo_list, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _slots_add(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct pci_slot *device = pci_slot_init(path);
|
|
Packit Service |
db8df9 |
if (device)
|
|
Packit Service |
db8df9 |
list_append(&slots_list, device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _check_raid(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *t = strrchr(path, '/');
|
|
Packit Service |
db8df9 |
if (strncmp(t + 1, "md", 2) == 0)
|
|
Packit Service |
db8df9 |
_raid_add(path);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _check_cntrl(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char link[PATH_MAX];
|
|
Packit Service |
db8df9 |
if (realpath(path, link) != NULL)
|
|
Packit Service |
db8df9 |
_cntrl_add(link);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _check_enclo(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char link[PATH_MAX];
|
|
Packit Service |
db8df9 |
if (realpath(path, link) != NULL)
|
|
Packit Service |
db8df9 |
_enclo_add(link);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _scan_block(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
if (scan_dir(SYSFS_CLASS_BLOCK, &dir) == 0) {
|
|
Packit Service |
db8df9 |
const char *dir_path;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&dir, dir_path)
|
|
Packit Service |
db8df9 |
_block_add(dir_path);
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _scan_raid(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
if (scan_dir(SYSFS_CLASS_BLOCK, &dir) == 0) {
|
|
Packit Service |
db8df9 |
const char *dir_path;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&dir, dir_path)
|
|
Packit Service |
db8df9 |
_check_raid(dir_path);
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _scan_cntrl(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
if (scan_dir(SYSFS_PCI_DEVICES, &dir) == 0) {
|
|
Packit Service |
db8df9 |
const char *dir_path;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&dir, dir_path)
|
|
Packit Service |
db8df9 |
_check_cntrl(dir_path);
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _scan_slave(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct raid_device *device;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&volum_list, device)
|
|
Packit Service |
db8df9 |
_link_raid_device(device, DEVICE_TYPE_VOLUME);
|
|
Packit Service |
db8df9 |
list_for_each(&cntnr_list, device)
|
|
Packit Service |
db8df9 |
_link_raid_device(device, DEVICE_TYPE_CONTAINER);
|
|
Packit Service |
db8df9 |
if (conf.raid_members_only) {
|
|
Packit Service |
db8df9 |
struct node *node;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each_node(&sysfs_block_list, node) {
|
|
Packit Service |
db8df9 |
if (_is_non_raid_device(node->item))
|
|
Packit Service |
db8df9 |
list_delete(node);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _scan_enclo(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
if (scan_dir(SYSFS_CLASS_ENCLOSURE, &dir) == 0) {
|
|
Packit Service |
db8df9 |
const char *dir_path;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&dir, dir_path)
|
|
Packit Service |
db8df9 |
_check_enclo(dir_path);
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _scan_slots(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
if (scan_dir(SYSFS_PCI_SLOTS, &dir) == 0) {
|
|
Packit Service |
db8df9 |
const char *dir_path;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&dir, dir_path)
|
|
Packit Service |
db8df9 |
_slots_add(dir_path);
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static int _is_failed_array(struct raid_device *raid)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
if (raid->degraded > 0) {
|
|
Packit Service |
db8df9 |
switch (raid->level) {
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_1:
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_10:
|
|
Packit Service |
db8df9 |
return (raid->degraded == raid->raid_disks);
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_4:
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_5:
|
|
Packit Service |
db8df9 |
return (raid->degraded > 1);
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_6:
|
|
Packit Service |
db8df9 |
return (raid->degraded > 2);
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_LINEAR:
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_UNKNOWN:
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_0:
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case RAID_LEVEL_FAULTY:
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _set_block_state(struct block_device *block, enum ibpi_pattern ibpi)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *debug_dev = strrchr(block->sysfs_path, '/');
|
|
Packit Service |
db8df9 |
debug_dev = debug_dev ? debug_dev + 1 : block->sysfs_path;
|
|
Packit Service |
db8df9 |
log_debug("(%s): device: %s, state: %s", __func__, debug_dev,
|
|
Packit Service |
db8df9 |
ibpi2str(ibpi));
|
|
Packit Service |
db8df9 |
if (block->ibpi < ibpi)
|
|
Packit Service |
db8df9 |
block->ibpi = ibpi;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _set_array_state(struct raid_device *raid,
|
|
Packit Service |
db8df9 |
struct block_device *block)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
switch (raid->sync_action) {
|
|
Packit Service |
db8df9 |
case RAID_ACTION_UNKNOWN:
|
|
Packit Service |
db8df9 |
case RAID_ACTION_IDLE:
|
|
Packit Service |
db8df9 |
case RAID_ACTION_FROZEN:
|
|
Packit Service |
db8df9 |
_set_block_state(block, IBPI_PATTERN_NORMAL);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case RAID_ACTION_RESHAPE:
|
|
Packit Service |
db8df9 |
if (conf.blink_on_migration)
|
|
Packit Service |
db8df9 |
_set_block_state(block, IBPI_PATTERN_REBUILD);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case RAID_ACTION_CHECK:
|
|
Packit Service |
db8df9 |
case RAID_ACTION_RESYNC:
|
|
Packit Service |
db8df9 |
case RAID_ACTION_REPAIR:
|
|
Packit Service |
db8df9 |
if (conf.blink_on_init)
|
|
Packit Service |
db8df9 |
_set_block_state(block, IBPI_PATTERN_REBUILD);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case RAID_ACTION_RECOVER:
|
|
Packit Service |
db8df9 |
if (conf.rebuild_blink_on_all)
|
|
Packit Service |
db8df9 |
_set_block_state(block, IBPI_PATTERN_REBUILD);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/**
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
static void _determine(struct slave_device *device)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
if (!device->block->raid_dev ||
|
|
Packit Service |
db8df9 |
(device->block->raid_dev->type == DEVICE_TYPE_CONTAINER &&
|
|
Packit Service |
db8df9 |
device->raid->type == DEVICE_TYPE_VOLUME)) {
|
|
Packit Service |
db8df9 |
raid_device_fini(device->block->raid_dev);
|
|
Packit Service |
db8df9 |
device->block->raid_dev = raid_device_duplicate(device->raid);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if ((device->state & SLAVE_STATE_FAULTY) != 0) {
|
|
Packit Service |
db8df9 |
_set_block_state(device->block, IBPI_PATTERN_FAILED_DRIVE);
|
|
Packit Service |
db8df9 |
} else if ((device->
|
|
Packit Service |
db8df9 |
state & (SLAVE_STATE_BLOCKED | SLAVE_STATE_WRITE_MOSTLY)) != 0) {
|
|
Packit Service |
db8df9 |
_set_block_state(device->block, IBPI_PATTERN_NORMAL);
|
|
Packit Service |
db8df9 |
} else if ((device->state & SLAVE_STATE_SPARE) != 0) {
|
|
Packit Service |
db8df9 |
if (_is_failed_array(device->raid) == 0) {
|
|
Packit Service |
db8df9 |
if (device->raid->sync_action != RAID_ACTION_RESHAPE ||
|
|
Packit Service |
db8df9 |
conf.blink_on_migration == 1)
|
|
Packit Service |
db8df9 |
_set_block_state(device->block,
|
|
Packit Service |
db8df9 |
IBPI_PATTERN_REBUILD);
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
_set_block_state(device->block, IBPI_PATTERN_HOTSPARE);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
} else if ((device->state & SLAVE_STATE_IN_SYNC) != 0) {
|
|
Packit Service |
db8df9 |
switch (_is_failed_array(device->raid)) {
|
|
Packit Service |
db8df9 |
case 0:
|
|
Packit Service |
db8df9 |
_set_block_state(device->block, IBPI_PATTERN_DEGRADED);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case 1:
|
|
Packit Service |
db8df9 |
_set_block_state(device->block,
|
|
Packit Service |
db8df9 |
IBPI_PATTERN_FAILED_ARRAY);
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
_set_array_state(device->raid, device->block);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void _determine_slaves(struct list *local_slave_list)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct slave_device *device;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(local_slave_list, device)
|
|
Packit Service |
db8df9 |
_determine(device);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
void sysfs_init(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
list_init(&sysfs_block_list, (item_free_t)block_device_fini);
|
|
Packit Service |
db8df9 |
list_init(&volum_list, (item_free_t)raid_device_fini);
|
|
Packit Service |
db8df9 |
list_init(&cntrl_list, (item_free_t)cntrl_device_fini);
|
|
Packit Service |
db8df9 |
list_init(&slave_list, (item_free_t)slave_device_fini);
|
|
Packit Service |
db8df9 |
list_init(&cntnr_list, (item_free_t)raid_device_fini);
|
|
Packit Service |
db8df9 |
list_init(&enclo_list, (item_free_t)enclosure_device_fini);
|
|
Packit Service |
db8df9 |
list_init(&slots_list, (item_free_t)pci_slot_fini);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
void sysfs_reset(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
list_erase(&sysfs_block_list);
|
|
Packit Service |
db8df9 |
list_erase(&volum_list);
|
|
Packit Service |
db8df9 |
list_erase(&cntrl_list);
|
|
Packit Service |
db8df9 |
list_erase(&slave_list);
|
|
Packit Service |
db8df9 |
list_erase(&cntnr_list);
|
|
Packit Service |
db8df9 |
list_erase(&enclo_list);
|
|
Packit Service |
db8df9 |
list_erase(&slots_list);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
void sysfs_scan(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
_scan_enclo();
|
|
Packit Service |
db8df9 |
_scan_cntrl();
|
|
Packit Service |
db8df9 |
_scan_slots();
|
|
Packit Service |
db8df9 |
_scan_block();
|
|
Packit Service |
db8df9 |
_scan_raid();
|
|
Packit Service |
db8df9 |
_scan_slave();
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
_determine_slaves(&slave_list);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* The function reutrns list of enclosure devices attached to SAS/SCSI storage
|
|
Packit Service |
db8df9 |
* controller(s).
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
const struct list *sysfs_get_enclosure_devices(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
return &enclo_list;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* The function returns list of controller devices present in the system.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
const struct list *sysfs_get_cntrl_devices(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
return &cntrl_list;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* The function returns list of RAID volumes present in the system.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
const struct list *sysfs_get_volumes(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
return &volum_list;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
const struct list *sysfs_get_block_devices(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
return &sysfs_block_list;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
const struct list *sysfs_get_pci_slots(void)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
return &slots_list;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* The function checks if the given storage controller has enclosure device(s)
|
|
Packit Service |
db8df9 |
* attached.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
int sysfs_enclosure_attached_to_cntrl(const char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
struct enclosure_device *device;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(&enclo_list, device) {
|
|
Packit Service |
db8df9 |
if ((device->sysfs_path != NULL) &&
|
|
Packit Service |
db8df9 |
(strncmp(device->sysfs_path, path, strlen(path)) == 0))
|
|
Packit Service |
db8df9 |
return 1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* This function checks driver type.
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
int sysfs_check_driver(const char *path, const char *driver)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char buf[PATH_MAX];
|
|
Packit Service |
db8df9 |
char driver_path[PATH_MAX];
|
|
Packit Service |
db8df9 |
char *link;
|
|
Packit Service |
db8df9 |
int found = 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
snprintf(buf, sizeof(buf), "%s/driver", path);
|
|
Packit Service |
db8df9 |
snprintf(driver_path, sizeof(driver_path), "/%s", driver);
|
|
Packit Service |
db8df9 |
link = realpath(buf, NULL);
|
|
Packit Service |
db8df9 |
if (link && strstr(link, driver_path))
|
|
Packit Service |
db8df9 |
found = 1;
|
|
Packit Service |
db8df9 |
free(link);
|
|
Packit Service |
db8df9 |
return found;
|
|
Packit Service |
db8df9 |
}
|