Blame src/sysfs.c

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
}