Dirk Mueller
862a77460a
- Update to version 0.96: (PED-85) * Manual updates, clarify --listed-only option * Fix cache indexing of ATA port * Fixes in regard to macros * Fix memory leak in amd_ipmi.c * Fix NULL pointer dereferences in sysfs.c * Make messages appear in service log immediately - add patches after 0.96: + 0001-Ledctl-slots-management-94.patch + 0002-add-Dell-15G-servers.patch OBS-URL: https://build.opensuse.org/request/show/990005 OBS-URL: https://build.opensuse.org/package/show/Base:System/ledmon?expand=0&rev=43
1366 lines
39 KiB
Diff
1366 lines
39 KiB
Diff
From a56e8bf096c04ea0c76ca026e07402f05ce58ca4 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Kinga=20Ta=C5=84ska?= <kinga.tanska@intel.com>
|
|
Date: Tue, 14 Jun 2022 12:11:45 +0200
|
|
Subject: [PATCH 1/2] Ledctl - slots management (#94)
|
|
|
|
* ledctl: add commands to support empty slots blinking
|
|
* ledctl: --get-slot implementation for vmd
|
|
* ledctl: --list-slots implementation for vmd
|
|
* ledctl: --set-slot implementation for vmd
|
|
* ledctl: --get-slot implementation for npem
|
|
* ledctl: --list-slots implementation for npem
|
|
* ledctl: --set-slot implementation for npem
|
|
|
|
Add new interface which allows to read or modify led state for devices
|
|
by controller's slots. It allows to manage empty slots in cases where:
|
|
- drive is not connected.
|
|
- drive is connected, but non-standard driver is used (uio, vfio).
|
|
|
|
Slot identifier will used to manage led state. Following commands are added:
|
|
--get-slot
|
|
--list-slots
|
|
--set-slot
|
|
Support for VMD and NPEM is added.
|
|
|
|
Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
|
|
---
|
|
doc/ledctl.pod | 36 ++++++
|
|
src/Makefile.am | 2 +-
|
|
src/block.c | 12 ++
|
|
src/block.h | 15 ++-
|
|
src/ledctl.c | 329 ++++++++++++++++++++++++++++++++++++++++++++++--
|
|
src/npem.c | 145 ++++++++++++++++++---
|
|
src/npem.h | 28 +++++
|
|
src/pci_slot.c | 102 ++++++++++++++-
|
|
src/pci_slot.h | 35 +++++-
|
|
src/slot.h | 63 ++++++++++
|
|
src/sysfs.c | 1 -
|
|
src/sysfs.h | 4 +-
|
|
src/utils.c | 49 +++++++-
|
|
src/utils.h | 15 ++-
|
|
src/vmdssd.c | 63 +++++-----
|
|
src/vmdssd.h | 11 +-
|
|
16 files changed, 833 insertions(+), 77 deletions(-)
|
|
create mode 100644 src/slot.h
|
|
|
|
diff --git a/doc/ledctl.pod b/doc/ledctl.pod
|
|
index 774d04b2b0e2..a0da95e4c734 100644
|
|
--- a/doc/ledctl.pod
|
|
+++ b/doc/ledctl.pod
|
|
@@ -324,6 +324,42 @@ Displays version of ledctl and information about the license and exits.
|
|
Prints information (system path and type) of all controllers detected by
|
|
ledmon and exits.
|
|
|
|
+=item B<-P> or B<--list-slots> B<--controller>=I<controller>
|
|
+
|
|
+Prints all slots for the controller. Slot definition depends on the controller
|
|
+and is unique across all controllers of the same type.
|
|
+
|
|
+Definitions for supported controllers are described below:
|
|
+
|
|
+=over
|
|
+
|
|
+=item
|
|
+
|
|
+VMD - PCI Express Hot Plug Controller Driver slot number
|
|
+
|
|
+=item
|
|
+
|
|
+NPEM - PCI Express Downstream Port address
|
|
+
|
|
+=back
|
|
+
|
|
+Command returns a list of all slots for the controller with current state and
|
|
+attached device name (if any). I<controller> is type of controller
|
|
+(vmd, NPEM) that should be scanned here.
|
|
+
|
|
+=item B<-G> or B<--get-slot> B<--controller>=I<controller> B<--device>=I<device>
|
|
+
|
|
+Displays slot details of given device. I<device> is devnode of selected drive.
|
|
+
|
|
+=item B<-G> or B<--get-slot> B<--controller>=I<controller> B<--slot>=I<slot>
|
|
+
|
|
+Displays details of given slot. I<slot> is unique slot identifier.
|
|
+
|
|
+=item B<-S> or B<--set-slot> B<--controller>=I<controller> B<--slot>=I<slot> B<--state>=I<IBPI_state>
|
|
+
|
|
+Changes led state for given slot. I<controller> is type of the controller.
|
|
+I<slot> is unique slot identifier. I<IBPI_state> is led pattern.
|
|
+
|
|
=item B<-x> or B<--listed-only>
|
|
|
|
With this option ledctl will change state only on devices listed in CLI. The
|
|
diff --git a/src/Makefile.am b/src/Makefile.am
|
|
index f7786206a510..34311a2699a7 100644
|
|
--- a/src/Makefile.am
|
|
+++ b/src/Makefile.am
|
|
@@ -26,7 +26,7 @@ COMMON_SRCS = ahci.c block.c cntrl.c config_file.c enclosure.c list.c \
|
|
vmdssd.h ipmi.h amd.h amd_ipmi.h npem.h
|
|
|
|
LEDMON_SRCS = ledmon.c pidfile.c $(COMMON_SRCS)
|
|
-LEDCTL_SRCS = ledctl.c $(COMMON_SRCS)
|
|
+LEDCTL_SRCS = ledctl.c slot.h $(COMMON_SRCS)
|
|
|
|
|
|
sbin_PROGRAMS = ledmon ledctl
|
|
diff --git a/src/block.c b/src/block.c
|
|
index c61c577cb2c8..3d1815cb11a3 100644
|
|
--- a/src/block.c
|
|
+++ b/src/block.c
|
|
@@ -215,6 +215,18 @@ struct _host_type *block_get_host(struct cntrl_device *cntrl, int host_id)
|
|
return hosts;
|
|
}
|
|
|
|
+struct block_device *get_block_device_from_sysfs_path(char *sub_path)
|
|
+{
|
|
+ struct block_device *device;
|
|
+
|
|
+ list_for_each(sysfs_get_block_devices(), device) {
|
|
+ if (strstr(device->sysfs_path, sub_path))
|
|
+ return device;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
/*
|
|
* Allocates a new block device structure. See block.h for details.
|
|
*/
|
|
diff --git a/src/block.h b/src/block.h
|
|
index 820f2d72325e..00b9fd73a19d 100644
|
|
--- a/src/block.h
|
|
+++ b/src/block.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* Intel(R) Enclosure LED Utilities
|
|
- * Copyright (C) 2009-2018 Intel Corporation.
|
|
+ * Copyright (C) 2009-2022 Intel Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
@@ -25,6 +25,7 @@
|
|
#include "time.h"
|
|
#include "list.h"
|
|
#include "raid.h"
|
|
+#include "status.h"
|
|
|
|
struct block_device;
|
|
|
|
@@ -227,4 +228,16 @@ struct _host_type *block_get_host(struct cntrl_device *cntrl, int host_id);
|
|
int block_compare(const struct block_device *bd_old,
|
|
const struct block_device *bd_new);
|
|
|
|
+/**
|
|
+ * @brief Finds block device which name contains sub-path.
|
|
+ *
|
|
+ * This function scans block devices and checks their sysfs path
|
|
+ * to find any which contains PCI address specified for device in path.
|
|
+ *
|
|
+ * @param[in] sub_path Sub path.
|
|
+ *
|
|
+ * @return first block device containing sub-path if any, otherwise NULL.
|
|
+ */
|
|
+struct block_device *get_block_device_from_sysfs_path(char *sub_path);
|
|
+
|
|
#endif /* _BLOCK_H_INCLUDED_ */
|
|
diff --git a/src/ledctl.c b/src/ledctl.c
|
|
index caedc1a4834d..c20986230739 100644
|
|
--- a/src/ledctl.c
|
|
+++ b/src/ledctl.c
|
|
@@ -42,12 +42,13 @@
|
|
#include "cntrl.h"
|
|
#include "config.h"
|
|
#include "config_file.h"
|
|
-#include "ibpi.h"
|
|
+#include "slot.h"
|
|
#include "list.h"
|
|
+#include "npem.h"
|
|
+#include "pci_slot.h"
|
|
#include "scsi.h"
|
|
#include "status.h"
|
|
#include "sysfs.h"
|
|
-#include "utils.h"
|
|
|
|
/**
|
|
* @brief An IBPI state structure.
|
|
@@ -69,6 +70,73 @@ struct ibpi_state {
|
|
*/
|
|
static struct list ibpi_list;
|
|
|
|
+/**
|
|
+ * @brief Pointer to a get slot function.
|
|
+ *
|
|
+ * The pointer to a function which will print slot details.
|
|
+ *
|
|
+ * @param[in] device Name of the device.
|
|
+ * @param[in] slot Unique identifier of the slot.
|
|
+ * @param[in] res Pointer to slot response.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+typedef status_t (*get_slot_t) (char *device, char *slot, struct slot_response *res);
|
|
+
|
|
+/**
|
|
+ * @brief Pointer to a set slot function.
|
|
+ *
|
|
+ * The pointer to a function which will set slot details.
|
|
+ *
|
|
+ * @param[in] slot Unique identifier of the slot.
|
|
+ * @param[in] state IBPI state based on slot request.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+typedef status_t (*set_slot_t) (char *slot, enum ibpi_pattern state);
|
|
+
|
|
+/**
|
|
+ * @brief slot request parametres
|
|
+ *
|
|
+ * This structure contains all possible parameters for slot related commands.
|
|
+ */
|
|
+struct slot_request {
|
|
+ /**
|
|
+ * Option given in the request.
|
|
+ */
|
|
+ int chosen_opt;
|
|
+
|
|
+ /**
|
|
+ * Name of the device.
|
|
+ */
|
|
+ char device[PATH_MAX];
|
|
+
|
|
+ /**
|
|
+ * Unique slot identifier.
|
|
+ */
|
|
+ char slot[PATH_MAX];
|
|
+
|
|
+ /**
|
|
+ * Type of the controller.
|
|
+ */
|
|
+ enum cntrl_type cntrl;
|
|
+
|
|
+ /**
|
|
+ * IBPI state.
|
|
+ */
|
|
+ enum ibpi_pattern state;
|
|
+
|
|
+ /**
|
|
+ * Pointer to the get slot function.
|
|
+ */
|
|
+ get_slot_t get_slot_fn;
|
|
+
|
|
+ /**
|
|
+ * Pointer to the set slot function.
|
|
+ */
|
|
+ set_slot_t set_slot_fn;
|
|
+};
|
|
+
|
|
/**
|
|
* @brief IBPI pattern names.
|
|
*
|
|
@@ -76,7 +144,7 @@ static struct list ibpi_list;
|
|
* this entries to translate enumeration type values into the string.
|
|
*/
|
|
const char *ibpi_str[] = {
|
|
- [IBPI_PATTERN_UNKNOWN] = "",
|
|
+ [IBPI_PATTERN_UNKNOWN] = "UNKNOWN",
|
|
[IBPI_PATTERN_NORMAL] = "NORMAL",
|
|
[IBPI_PATTERN_ONESHOT_NORMAL] = "",
|
|
[IBPI_PATTERN_DEGRADED] = "ICA",
|
|
@@ -112,6 +180,13 @@ static int possible_params[] = {
|
|
OPT_VERSION,
|
|
OPT_LIST_CTRL,
|
|
OPT_LISTED_ONLY,
|
|
+ OPT_LIST_SLOTS,
|
|
+ OPT_GET_SLOT,
|
|
+ OPT_SET_SLOT,
|
|
+ OPT_CONTROLLER,
|
|
+ OPT_DEVICE,
|
|
+ OPT_SLOT,
|
|
+ OPT_STATE,
|
|
OPT_ALL,
|
|
OPT_DEBUG,
|
|
OPT_ERROR,
|
|
@@ -126,6 +201,43 @@ static const int possible_params_size = sizeof(possible_params)
|
|
|
|
static int listed_only;
|
|
|
|
+enum cntrl_type get_cntrl_type(const char *cntrl)
|
|
+{
|
|
+ if (strcasecmp(cntrl, "vmd") == 0)
|
|
+ return CNTRL_TYPE_VMD;
|
|
+ else if (strcasecmp(cntrl, "npem") == 0)
|
|
+ return CNTRL_TYPE_NPEM;
|
|
+ return CNTRL_TYPE_UNKNOWN;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Determines a slot functions based on controller.
|
|
+ *
|
|
+ * This function determines slot functions based on
|
|
+ * controller type.
|
|
+ *
|
|
+ * @param[in] ctrl_type Controller type.
|
|
+ * @param[in] slot_req Pointer to the slot request.
|
|
+ *
|
|
+ * @return This function does not return a value.
|
|
+ */
|
|
+static void _get_slot_ctrl_fn(enum cntrl_type ctrl_type, struct slot_request *slot_req)
|
|
+{
|
|
+ switch (ctrl_type) {
|
|
+ case CNTRL_TYPE_VMD:
|
|
+ slot_req->get_slot_fn = pci_get_slot;
|
|
+ slot_req->set_slot_fn = pci_set_slot;
|
|
+ break;
|
|
+ case CNTRL_TYPE_NPEM:
|
|
+ slot_req->get_slot_fn = npem_get_slot;
|
|
+ slot_req->set_slot_fn = npem_set_slot;
|
|
+ break;
|
|
+ default:
|
|
+ log_debug("Slot functions could not be set because the controller type %s does not "
|
|
+ "support slots managing.", ctrl_type);
|
|
+ }
|
|
+}
|
|
+
|
|
static void ibpi_state_fini(struct ibpi_state *p)
|
|
{
|
|
list_clear(&p->block_list);
|
|
@@ -186,16 +298,25 @@ static void _ledctl_help(void)
|
|
progname);
|
|
printf("Mandatory arguments for long options are mandatory for short options, too.\n\n");
|
|
print_opt("--listed-only", "-x",
|
|
- "Ledctl will change state only for given devices.");
|
|
+ "Ledctl will change state only for given devices.");
|
|
print_opt("--list-controllers", "-L",
|
|
- "Displays list of controllers detected by ledmon.");
|
|
+ "Displays list of controllers detected by ledmon.");
|
|
+ print_opt("--list-slots --controller CONTROLLER", "-P -c CONTROLLER",
|
|
+ "List slots under the controller, their led states, slot numbers and "
|
|
+ "devnodes connected.");
|
|
+ print_opt("--get-slot --controller CONTROLLER --device DEVNODE / --slot SLOT",
|
|
+ "-G -c CONTROLLER -d DEVNODE / -p SLOT",
|
|
+ "Prints slot information, its led state, slot number and devnode.");
|
|
+ print_opt("--set-slot --controller CONTROLLER --slot SLOT --state STATE",
|
|
+ "-S -c CONTROLLER -p SLOT -s STATE", "Sets given state for chosen slot "
|
|
+ "under the controller.");
|
|
print_opt("--log=PATH", "-l PATH",
|
|
- "Use local log file instead /var/log/ledctl.log.");
|
|
+ "Use local log file instead /var/log/ledctl.log.");
|
|
print_opt("--help", "-h", "Displays this help text.");
|
|
print_opt("--version", "-v",
|
|
- "Displays version and license information.");
|
|
+ "Displays version and license information.");
|
|
print_opt("--log-level=VALUE", "-l VALUE",
|
|
- "Allows user to set ledctl verbose level in logs.");
|
|
+ "Allows user to set ledctl verbose level in logs.");
|
|
printf("\nPatterns:\n"
|
|
"\tCommon patterns are:\n"
|
|
"\t\tlocate, locate_off, normal, off, degraded, rebuild,\n" ""
|
|
@@ -555,6 +676,156 @@ static status_t _cmdline_parse_non_root(int argc, char *argv[])
|
|
return status;
|
|
}
|
|
|
|
+/**
|
|
+ * @brief Inits slot request structure with initial values.
|
|
+ *
|
|
+ * @param[in] slot_req structure with slot request
|
|
+ *
|
|
+ * @return This function does not return a value.
|
|
+ */
|
|
+static void slot_request_init(struct slot_request *slot_req)
|
|
+{
|
|
+ memset(slot_req, 0, sizeof(struct slot_request));
|
|
+
|
|
+ slot_req->chosen_opt = OPT_NULL_ELEMENT;
|
|
+ slot_req->state = IBPI_PATTERN_UNKNOWN;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Inits slot response structure with initial values.
|
|
+ *
|
|
+ * @param[in] slot_res structure with slot response
|
|
+ *
|
|
+ * @return This function does not return a value.
|
|
+ */
|
|
+static void slot_response_init(struct slot_response *slot_res)
|
|
+{
|
|
+ memset(slot_res, 0, sizeof(struct slot_response));
|
|
+
|
|
+ slot_res->state = IBPI_PATTERN_UNKNOWN;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Verifies slot request parameters.
|
|
+ *
|
|
+ * @param[in] slot_req structure with slot request
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+static status_t slot_verify_request(struct slot_request *slot_req)
|
|
+{
|
|
+ if (slot_req->cntrl == CNTRL_TYPE_UNKNOWN) {
|
|
+ log_error("Invalid controller in the request.");
|
|
+ return STATUS_INVALID_CONTROLLER;
|
|
+ }
|
|
+ if (slot_req->chosen_opt == OPT_SET_SLOT && slot_req->state == IBPI_PATTERN_UNKNOWN) {
|
|
+ log_error("Invalid IBPI state in the request.");
|
|
+ return STATUS_INVALID_STATE;
|
|
+ }
|
|
+ if (!slot_req->get_slot_fn && !slot_req->set_slot_fn) {
|
|
+ log_error("The controller type %s doesn't support slot functionality.",
|
|
+ slot_req->cntrl);
|
|
+ return STATUS_INVALID_CONTROLLER;
|
|
+ }
|
|
+ if (slot_req->device[0] && slot_req->slot[0]) {
|
|
+ log_error("Device and slot parameters are exclusive.");
|
|
+ return STATUS_DATA_ERROR;
|
|
+ }
|
|
+
|
|
+ return STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+static status_t get_state_for_slot(char *slot, struct slot_request *slot_req)
|
|
+{
|
|
+ struct slot_response slot_res;
|
|
+ status_t status = STATUS_SUCCESS;
|
|
+
|
|
+ slot_response_init(&slot_res);
|
|
+ status = slot_req->get_slot_fn(NULL, slot, &slot_res);
|
|
+ if (status == STATUS_SUCCESS)
|
|
+ print_slot_state(&slot_res);
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief List slots connected to given controller
|
|
+ *
|
|
+ * This function scans all available slots connected to given controller
|
|
+ * and prints their led states and names of the connected devices (if exist).
|
|
+ *
|
|
+ * @param[in] slot_req Structure with slot request.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+static status_t list_slots(struct slot_request *slot_req)
|
|
+{
|
|
+ status_t status = STATUS_SUCCESS;
|
|
+
|
|
+ switch (slot_req->cntrl) {
|
|
+ case CNTRL_TYPE_VMD:
|
|
+ {
|
|
+ struct pci_slot *slot;
|
|
+
|
|
+ list_for_each(sysfs_get_pci_slots(), slot)
|
|
+ status = get_state_for_slot(slot->sysfs_path, slot_req);
|
|
+ return status;
|
|
+ }
|
|
+ case CNTRL_TYPE_NPEM:
|
|
+ {
|
|
+ struct cntrl_device *ctrl_dev;
|
|
+
|
|
+ list_for_each(sysfs_get_cntrl_devices(), ctrl_dev) {
|
|
+ if (ctrl_dev->cntrl_type != CNTRL_TYPE_NPEM)
|
|
+ continue;
|
|
+ status = get_state_for_slot(ctrl_dev->sysfs_path, slot_req);
|
|
+ }
|
|
+ return status;
|
|
+ }
|
|
+ default:
|
|
+ return STATUS_NOT_SUPPORTED;
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Executes proper slot mode function.
|
|
+ *
|
|
+ * @param[in] slot_req Structure with slot request.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+status_t slot_execute(struct slot_request *slot_req)
|
|
+{
|
|
+ struct slot_response slot_res;
|
|
+ status_t status = STATUS_SUCCESS;
|
|
+
|
|
+ slot_response_init(&slot_res);
|
|
+
|
|
+ switch (slot_req->chosen_opt) {
|
|
+ case OPT_LIST_SLOTS:
|
|
+ return list_slots(slot_req);
|
|
+ case OPT_SET_SLOT:
|
|
+ status = slot_req->get_slot_fn(slot_req->device, slot_req->slot, &slot_res);
|
|
+ if (slot_res.state == slot_req->state) {
|
|
+ log_warning("Led state: %s is already set for the slot.",
|
|
+ ibpi2str(slot_req->state));
|
|
+ return STATUS_SUCCESS;
|
|
+ }
|
|
+ if (status != STATUS_SUCCESS)
|
|
+ return status;
|
|
+ status = slot_req->set_slot_fn(slot_res.slot, slot_req->state);
|
|
+ if (status != STATUS_SUCCESS)
|
|
+ return status;
|
|
+ case OPT_GET_SLOT:
|
|
+ status = slot_req->get_slot_fn(slot_req->device, slot_req->slot, &slot_res);
|
|
+ if (status == STATUS_SUCCESS)
|
|
+ print_slot_state(&slot_res);
|
|
+ return status;
|
|
+ default:
|
|
+ return STATUS_NOT_SUPPORTED;
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
* @brief Command line parser - options.
|
|
*
|
|
@@ -567,7 +838,7 @@ static status_t _cmdline_parse_non_root(int argc, char *argv[])
|
|
*
|
|
* @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
*/
|
|
-static status_t _cmdline_parse(int argc, char *argv[])
|
|
+static status_t _cmdline_parse(int argc, char *argv[], struct slot_request *req)
|
|
{
|
|
int opt, opt_index = -1;
|
|
status_t status = STATUS_SUCCESS;
|
|
@@ -614,6 +885,34 @@ static status_t _cmdline_parse(int argc, char *argv[])
|
|
sysfs_reset();
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
+ case 'G':
|
|
+ req->chosen_opt = OPT_GET_SLOT;
|
|
+ break;
|
|
+ case 'P':
|
|
+ req->chosen_opt = OPT_LIST_SLOTS;
|
|
+ break;
|
|
+ case 'S':
|
|
+ req->chosen_opt = OPT_SET_SLOT;
|
|
+ break;
|
|
+ case 'c':
|
|
+ req->cntrl = get_cntrl_type(optarg);
|
|
+ _get_slot_ctrl_fn(req->cntrl, req);
|
|
+ break;
|
|
+ case 's':
|
|
+ {
|
|
+ struct ibpi_state *state = _ibpi_state_get(optarg);
|
|
+
|
|
+ if (state)
|
|
+ req->state = state->ibpi;
|
|
+ free(state);
|
|
+ break;
|
|
+ }
|
|
+ case 'd':
|
|
+ strncpy(req->device, optarg, PATH_MAX - 1);
|
|
+ break;
|
|
+ case 'p':
|
|
+ strncpy(req->slot, optarg, PATH_MAX - 1);
|
|
+ break;
|
|
case ':':
|
|
case '?':
|
|
default:
|
|
@@ -712,6 +1011,7 @@ static status_t _init_ledctl_conf(void)
|
|
int main(int argc, char *argv[])
|
|
{
|
|
status_t status;
|
|
+ struct slot_request slot_req;
|
|
|
|
setup_options(&longopt, &shortopt, possible_params,
|
|
possible_params_size);
|
|
@@ -732,7 +1032,9 @@ int main(int argc, char *argv[])
|
|
return status;
|
|
if (on_exit(_ledctl_fini, progname))
|
|
exit(STATUS_ONEXIT_ERROR);
|
|
- if (_cmdline_parse(argc, argv))
|
|
+ slot_request_init(&slot_req);
|
|
+ status = _cmdline_parse(argc, argv, &slot_req);
|
|
+ if (status != STATUS_SUCCESS)
|
|
exit(STATUS_CMDLINE_ERROR);
|
|
free(shortopt);
|
|
free(longopt);
|
|
@@ -746,6 +1048,13 @@ int main(int argc, char *argv[])
|
|
list_init(&ibpi_list, (item_free_t)ibpi_state_fini);
|
|
sysfs_init();
|
|
sysfs_scan();
|
|
+ if (slot_req.chosen_opt != OPT_NULL_ELEMENT) {
|
|
+ status = slot_verify_request(&slot_req);
|
|
+ if (status == STATUS_SUCCESS)
|
|
+ return slot_execute(&slot_req);
|
|
+ else
|
|
+ exit(status);
|
|
+ }
|
|
status = _cmdline_ibpi_parse(argc, argv);
|
|
if (status != STATUS_SUCCESS) {
|
|
log_debug("main(): _ibpi_parse() failed (status=%s).",
|
|
diff --git a/src/npem.c b/src/npem.c
|
|
index 4f836ee8571d..4b08966bd13a 100644
|
|
--- a/src/npem.c
|
|
+++ b/src/npem.c
|
|
@@ -25,7 +25,9 @@
|
|
|
|
#include "config.h"
|
|
#include "cntrl.h"
|
|
+#include "list.h"
|
|
#include "npem.h"
|
|
+#include "sysfs.h"
|
|
#include "utils.h"
|
|
|
|
#define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */
|
|
@@ -57,19 +59,32 @@
|
|
|
|
#define PCI_NPEM_STATUS_CC 0x01 /* NPEM Command Completed */
|
|
|
|
-const int ibpi_to_npem_capability[] = {
|
|
- [IBPI_PATTERN_NORMAL] = PCI_NPEM_OK_CAP,
|
|
- [IBPI_PATTERN_ONESHOT_NORMAL] = PCI_NPEM_OK_CAP,
|
|
- [IBPI_PATTERN_DEGRADED] = PCI_NPEM_CRA_CAP,
|
|
- [IBPI_PATTERN_HOTSPARE] = PCI_NPEM_HOT_SPARE_CAP,
|
|
- [IBPI_PATTERN_REBUILD] = PCI_NPEM_REBUILD_CAP,
|
|
- [IBPI_PATTERN_FAILED_ARRAY] = PCI_NPEM_FA_CAP,
|
|
- [IBPI_PATTERN_PFA] = PCI_NPEM_PFA_CAP,
|
|
- [IBPI_PATTERN_FAILED_DRIVE] = PCI_NPEM_FAIL_CAP,
|
|
- [IBPI_PATTERN_LOCATE] = PCI_NPEM_LOCATE_CAP,
|
|
- [IBPI_PATTERN_LOCATE_OFF] = PCI_NPEM_OK_CAP,
|
|
+const struct ibpi_value ibpi_to_npem_capability[] = {
|
|
+ {IBPI_PATTERN_NORMAL, PCI_NPEM_OK_CAP},
|
|
+ {IBPI_PATTERN_ONESHOT_NORMAL, PCI_NPEM_OK_CAP},
|
|
+ {IBPI_PATTERN_DEGRADED, PCI_NPEM_CRA_CAP},
|
|
+ {IBPI_PATTERN_HOTSPARE, PCI_NPEM_HOT_SPARE_CAP},
|
|
+ {IBPI_PATTERN_REBUILD, PCI_NPEM_REBUILD_CAP},
|
|
+ {IBPI_PATTERN_FAILED_ARRAY, PCI_NPEM_FA_CAP},
|
|
+ {IBPI_PATTERN_PFA, PCI_NPEM_PFA_CAP},
|
|
+ {IBPI_PATTERN_FAILED_DRIVE, PCI_NPEM_FAIL_CAP},
|
|
+ {IBPI_PATTERN_LOCATE, PCI_NPEM_LOCATE_CAP},
|
|
+ {IBPI_PATTERN_LOCATE_OFF, PCI_NPEM_OK_CAP},
|
|
+ {IBPI_PATTERN_UNKNOWN}
|
|
};
|
|
|
|
+static enum ibpi_pattern npem_capability_to_ibpi(const u32 reg)
|
|
+{
|
|
+ const struct ibpi_value *tmp = ibpi_to_npem_capability;
|
|
+
|
|
+ while (tmp->ibpi != IBPI_PATTERN_UNKNOWN) {
|
|
+ if (reg & tmp->value)
|
|
+ break;
|
|
+ tmp++;
|
|
+ }
|
|
+ return tmp->ibpi;
|
|
+}
|
|
+
|
|
static struct pci_access *get_pci_access()
|
|
{
|
|
struct pci_access *pacc;
|
|
@@ -131,8 +146,10 @@ int is_npem_capable(const char *path)
|
|
struct pci_access *pacc = get_pci_access();
|
|
struct pci_dev *pdev;
|
|
|
|
- if (!pacc)
|
|
+ if (!pacc) {
|
|
+ log_error("NPEM: Unable to initialize pci access for %s\n", path);
|
|
return 0;
|
|
+ }
|
|
|
|
pdev = get_pci_dev(pacc, path);
|
|
|
|
@@ -215,7 +232,9 @@ int npem_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
}
|
|
|
|
reg = read_npem_register(pdev, PCI_NPEM_CAP_REG);
|
|
- if ((reg & ibpi_to_npem_capability[ibpi]) == 0) {
|
|
+ u32 cap = (u32)get_value_for_ibpi(ibpi, ibpi_to_npem_capability);
|
|
+
|
|
+ if ((reg & cap) == 0) {
|
|
log_debug("NPEM: Controller %s doesn't support %s pattern\n",
|
|
npem_cntrl->sysfs_path, ibpi_str[ibpi]);
|
|
ibpi = IBPI_PATTERN_NORMAL;
|
|
@@ -223,7 +242,8 @@ int npem_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
|
|
reg = read_npem_register(pdev, PCI_NPEM_CTRL_REG);
|
|
val = (reg & PCI_NPEM_RESERVED);
|
|
- val = (val | PCI_NPEM_CAP | ibpi_to_npem_capability[ibpi]);
|
|
+ cap = (u32)get_value_for_ibpi(ibpi, ibpi_to_npem_capability);
|
|
+ val = (val | PCI_NPEM_CAP | cap);
|
|
|
|
write_npem_register(pdev, PCI_NPEM_CTRL_REG, val);
|
|
if (npem_wait_command(pdev)) {
|
|
@@ -244,3 +264,100 @@ char *npem_get_path(const char *cntrl_path)
|
|
{
|
|
return str_dup(cntrl_path);
|
|
}
|
|
+
|
|
+status_t npem_get_slot(char *device, char *slot_path, struct slot_response *slot_res)
|
|
+{
|
|
+ struct pci_dev *pdev = NULL;
|
|
+ struct block_device *block_device = NULL;
|
|
+ struct pci_access *pacc = get_pci_access();
|
|
+ status_t status = STATUS_SUCCESS;
|
|
+ char *path = NULL;
|
|
+ u32 reg;
|
|
+
|
|
+ if (!pacc) {
|
|
+ log_error("NPEM: Unable to initialize pci access for %s\n", path);
|
|
+ return STATUS_NULL_POINTER;
|
|
+ }
|
|
+
|
|
+ if (device && device[0] != '\0') {
|
|
+ block_device = get_block_device_from_sysfs_path(basename(device));
|
|
+ if (block_device)
|
|
+ path = block_device->cntrl->sysfs_path;
|
|
+ } else if (slot_path && slot_path[0] != '\0') {
|
|
+ struct cntrl_device *ctrl_dev;
|
|
+
|
|
+ list_for_each(sysfs_get_cntrl_devices(), ctrl_dev) {
|
|
+ if (ctrl_dev->cntrl_type != CNTRL_TYPE_NPEM)
|
|
+ continue;
|
|
+ if (strcmp(basename(ctrl_dev->sysfs_path), basename(slot_path)) != 0)
|
|
+ continue;
|
|
+ path = ctrl_dev->sysfs_path;
|
|
+ block_device = get_block_device_from_sysfs_path(path);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (path) {
|
|
+ pdev = get_pci_dev(pacc, path);
|
|
+ } else {
|
|
+ log_debug("NPEM: unable to get sysfs path for the controller.");
|
|
+ pci_cleanup(pacc);
|
|
+ return STATUS_INVALID_PATH;
|
|
+ }
|
|
+
|
|
+ if (!pdev) {
|
|
+ log_error("NPEM: Unable to get pci device for %s\n", path);
|
|
+ pci_cleanup(pacc);
|
|
+ return STATUS_NULL_POINTER;
|
|
+ }
|
|
+
|
|
+ reg = read_npem_register(pdev, PCI_NPEM_CTRL_REG);
|
|
+ slot_res->state = npem_capability_to_ibpi(reg);
|
|
+ snprintf(slot_res->slot, PATH_MAX, "%s", path);
|
|
+
|
|
+ if (block_device)
|
|
+ snprintf(slot_res->device, PATH_MAX, "/dev/%s", basename(block_device->sysfs_path));
|
|
+ else
|
|
+ snprintf(slot_res->device, PATH_MAX, "(empty)");
|
|
+
|
|
+ pci_free_dev(pdev);
|
|
+ pci_cleanup(pacc);
|
|
+ return status;
|
|
+}
|
|
+
|
|
+status_t npem_set_slot(char *slot_path, enum ibpi_pattern state)
|
|
+{
|
|
+ struct pci_dev *pdev = NULL;
|
|
+ struct pci_access *pacc = get_pci_access();
|
|
+ status_t status = STATUS_SUCCESS;
|
|
+ u32 val;
|
|
+ u32 reg;
|
|
+ u32 cap;
|
|
+
|
|
+ if (!pacc) {
|
|
+ log_error("NPEM: Unable to initialize pci access for %s\n", slot_path);
|
|
+ return STATUS_NULL_POINTER;
|
|
+ }
|
|
+
|
|
+ pdev = get_pci_dev(pacc, slot_path);
|
|
+ if (!pdev) {
|
|
+ log_error("NPEM: Unable to get pci device for %s\n", slot_path);
|
|
+ pci_cleanup(pacc);
|
|
+ return STATUS_NULL_POINTER;
|
|
+ }
|
|
+
|
|
+ reg = read_npem_register(pdev, PCI_NPEM_CTRL_REG);
|
|
+ val = (reg & PCI_NPEM_RESERVED);
|
|
+ cap = (u32)get_value_for_ibpi(state, ibpi_to_npem_capability);
|
|
+ val = (val | PCI_NPEM_CAP | cap);
|
|
+
|
|
+ write_npem_register(pdev, PCI_NPEM_CTRL_REG, val);
|
|
+ if (npem_wait_command(pdev)) {
|
|
+ log_error("NPEM: Write timeout for %s\n", slot_path);
|
|
+ status = STATUS_FILE_WRITE_ERROR;
|
|
+ }
|
|
+
|
|
+ pci_free_dev(pdev);
|
|
+ pci_cleanup(pacc);
|
|
+ return status;
|
|
+}
|
|
diff --git a/src/npem.h b/src/npem.h
|
|
index 5fa3f11d0ba3..8f4dd7b96151 100644
|
|
--- a/src/npem.h
|
|
+++ b/src/npem.h
|
|
@@ -21,9 +21,37 @@
|
|
#define NPEM_H_INCLUDED_
|
|
#include "block.h"
|
|
#include "ibpi.h"
|
|
+#include "slot.h"
|
|
+#include "status.h"
|
|
|
|
int is_npem_capable(const char *path);
|
|
int npem_write(struct block_device *device, enum ibpi_pattern ibpi);
|
|
char *npem_get_path(const char *cntrl_path);
|
|
|
|
+/**
|
|
+ * @brief Gets led state for slot.
|
|
+ *
|
|
+ * This function finds slot connected to given identifier
|
|
+ * and fills slot response related to the slot.
|
|
+ *
|
|
+ * @param[in] device Requested device name.
|
|
+ * @param[in] slot_num Requested identifier of the slot.
|
|
+ * @param[in] slot_res Pointer to the slot response.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+status_t npem_get_slot(char *device, char *slot_num, struct slot_response *slot_res);
|
|
+
|
|
+/**
|
|
+ * @brief Sets led state for slot.
|
|
+ *
|
|
+ * This function finds slot connected to given number or device name
|
|
+ * and set given led state.
|
|
+ *
|
|
+ * @param[in] slot_num Requested number of the slot.
|
|
+ * @param[in] state IBPI state based on slot request.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+status_t npem_set_slot(char *slot_num, enum ibpi_pattern state);
|
|
#endif // NPEM_H_INCLUDED_
|
|
diff --git a/src/pci_slot.c b/src/pci_slot.c
|
|
index b15e1947c043..1e03dbabe91d 100644
|
|
--- a/src/pci_slot.c
|
|
+++ b/src/pci_slot.c
|
|
@@ -29,7 +29,9 @@
|
|
|
|
#include "config.h"
|
|
#include "pci_slot.h"
|
|
+#include "sysfs.h"
|
|
#include "utils.h"
|
|
+#include "vmdssd.h"
|
|
|
|
/*
|
|
* Allocates memory for PCI hotplug slot structure and initializes fields of
|
|
@@ -44,12 +46,6 @@ struct pci_slot *pci_slot_init(const char *path)
|
|
return NULL;
|
|
result->sysfs_path = str_dup(path);
|
|
result->address = get_text(path, "address");
|
|
- result->attention = get_int(path, -1, "attention");
|
|
-
|
|
- if (result->attention == -1) {
|
|
- pci_slot_fini(result);
|
|
- return NULL;
|
|
- }
|
|
|
|
return result;
|
|
}
|
|
@@ -66,3 +62,97 @@ void pci_slot_fini(struct pci_slot *slot)
|
|
free(slot);
|
|
}
|
|
}
|
|
+
|
|
+/**
|
|
+ * @brief Finds PCI slot by number of the slot.
|
|
+ *
|
|
+ * @param[in] slot_number Number of the slot
|
|
+ *
|
|
+ * @return Struct with pci slot if successful, otherwise the function returns NULL pointer.
|
|
+ */
|
|
+static struct pci_slot *find_pci_slot_by_number(char *slot_number)
|
|
+{
|
|
+ struct pci_slot *slot = NULL;
|
|
+ char *temp;
|
|
+
|
|
+ if (slot_number == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ list_for_each(sysfs_get_pci_slots(), slot) {
|
|
+ temp = basename(slot->sysfs_path);
|
|
+ if (temp && strncmp(temp, slot_number, PATH_MAX) == 0)
|
|
+ return slot;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Sets the slot response.
|
|
+ *
|
|
+ * @param[in] slot Struct with PCI slot parameters.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+static status_t set_slot_response(struct pci_slot *slot, struct slot_response *slot_res)
|
|
+{
|
|
+ struct block_device *bl_device;
|
|
+ status_t status = STATUS_SUCCESS;
|
|
+ int attention = get_int(slot->sysfs_path, -1, "attention");
|
|
+
|
|
+ if (attention == -1)
|
|
+ return STATUS_INVALID_STATE;
|
|
+
|
|
+ slot_res->state = get_ibpi_for_value(attention, ibpi_to_attention);
|
|
+ snprintf(slot_res->slot, PATH_MAX, "%s", basename(slot->sysfs_path));
|
|
+
|
|
+ bl_device = get_block_device_from_sysfs_path(slot->address);
|
|
+ if (bl_device)
|
|
+ snprintf(slot_res->device, PATH_MAX, "/dev/%s", basename(bl_device->sysfs_path));
|
|
+ else
|
|
+ snprintf(slot_res->device, PATH_MAX, "(empty)");
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+status_t pci_get_slot(char *device, char *slot_path, struct slot_response *slot_res)
|
|
+{
|
|
+ struct pci_slot *slot = NULL;
|
|
+ struct block_device *block_device = NULL;
|
|
+
|
|
+ if (device && device[0] != '\0') {
|
|
+ char *sub_path = basename(device);
|
|
+ if (sub_path == NULL) {
|
|
+ log_error("Device name %s is invalid.", device);
|
|
+ return STATUS_DATA_ERROR;
|
|
+ }
|
|
+
|
|
+ block_device = get_block_device_from_sysfs_path(sub_path + 1);
|
|
+ if (block_device == NULL) {
|
|
+ log_error("Device %s not found.", device);
|
|
+ return STATUS_DATA_ERROR;
|
|
+ }
|
|
+ slot = vmdssd_find_pci_slot(block_device->sysfs_path);
|
|
+ } else if (slot_path && slot_path[0] != '\0') {
|
|
+ slot = find_pci_slot_by_number(basename(slot_path));
|
|
+ }
|
|
+
|
|
+ if (slot == NULL) {
|
|
+ log_error("Specified slot was not found.");
|
|
+ return STATUS_DATA_ERROR;
|
|
+ }
|
|
+
|
|
+ return set_slot_response(slot, slot_res);
|
|
+}
|
|
+
|
|
+status_t pci_set_slot(char *slot_path, enum ibpi_pattern state)
|
|
+{
|
|
+ struct pci_slot *slot = NULL;
|
|
+
|
|
+ slot = find_pci_slot_by_number(basename(slot_path));
|
|
+ if (slot == NULL) {
|
|
+ log_error("Slot %s not found.", slot_path);
|
|
+ return STATUS_NULL_POINTER;
|
|
+ }
|
|
+
|
|
+ return vmdssd_write_attention_buf(slot, state);
|
|
+}
|
|
diff --git a/src/pci_slot.h b/src/pci_slot.h
|
|
index b971de3d89b7..9a181ce6057e 100644
|
|
--- a/src/pci_slot.h
|
|
+++ b/src/pci_slot.h
|
|
@@ -20,6 +20,10 @@
|
|
#ifndef PCI_SLOT_H_INCLUDED_
|
|
#define PCI_SLOT_H_INCLUDED_
|
|
|
|
+#include "ibpi.h"
|
|
+#include "slot.h"
|
|
+#include "status.h"
|
|
+
|
|
/**
|
|
* @brief PCI hotplug slot structure.
|
|
*
|
|
@@ -35,11 +39,6 @@ struct pci_slot {
|
|
* PCI hotplug slot address.
|
|
*/
|
|
char *address;
|
|
-
|
|
- /**
|
|
- * State of the Amber LED of the PCI slot.
|
|
- */
|
|
- int attention;
|
|
};
|
|
|
|
/**
|
|
@@ -69,4 +68,30 @@ struct pci_slot *pci_slot_init(const char *path);
|
|
*/
|
|
void pci_slot_fini(struct pci_slot *slot);
|
|
|
|
+/**
|
|
+ * @brief Gets led state for slot.
|
|
+ *
|
|
+ * This function finds slot connected to given identifier
|
|
+ * and fills slot response related to the slot.
|
|
+ *
|
|
+ * @param[in] device Requested device name.
|
|
+ * @param[in] slot_num Requested identifier of the slot.
|
|
+ * @param[in] slot_res Pointer to the slot response.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+status_t pci_get_slot(char *device, char *slot_num, struct slot_response *slot_res);
|
|
+
|
|
+/**
|
|
+ * @brief Sets led state for slot.
|
|
+ *
|
|
+ * This function finds slot connected to given number or device name
|
|
+ * and set given led state.
|
|
+ *
|
|
+ * @param[in] slot_num Requested number of the slot.
|
|
+ * @param[in] state IBPI state based on slot request.
|
|
+ *
|
|
+ * @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
|
|
+ */
|
|
+status_t pci_set_slot(char *slot_num, enum ibpi_pattern state);
|
|
#endif // PCI_SLOT_H_INCLUDED_
|
|
diff --git a/src/slot.h b/src/slot.h
|
|
new file mode 100644
|
|
index 000000000000..82b2e9405b89
|
|
--- /dev/null
|
|
+++ b/src/slot.h
|
|
@@ -0,0 +1,63 @@
|
|
+/*
|
|
+ * Intel(R) Enclosure LED Utilities
|
|
+ * Copyright (C) 2022-2022 Intel Corporation.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms and conditions of the GNU General Public License,
|
|
+ * version 2, as published by the Free Software Foundation.
|
|
+ *
|
|
+ * This program is distributed in the hope it will be useful, but WITHOUT
|
|
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ * more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License along with
|
|
+ * this program; if not, write to the Free Software Foundation, Inc.,
|
|
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef SLOT_H_
|
|
+#define SLOT_H_
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+#include "ibpi.h"
|
|
+#include "utils.h"
|
|
+
|
|
+/**
|
|
+ * @brief slot response parameters
|
|
+ *
|
|
+ * This structure contains slot properties.
|
|
+ */
|
|
+struct slot_response {
|
|
+ /**
|
|
+ * Name of the device.
|
|
+ */
|
|
+ char device[PATH_MAX];
|
|
+
|
|
+ /**
|
|
+ * Unique slot identifier.
|
|
+ */
|
|
+ char slot[PATH_MAX];
|
|
+
|
|
+ /**
|
|
+ * IBPI state.
|
|
+ */
|
|
+ enum ibpi_pattern state;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * @brief Print address, slot identifier and led state.
|
|
+ *
|
|
+ * @param[in] res Structure with slot response.
|
|
+ *
|
|
+ * @return This function does not return a value.
|
|
+ */
|
|
+static inline void print_slot_state(struct slot_response *res)
|
|
+{
|
|
+ printf("slot: %-15s led state: %-15s device: %-15s\n",
|
|
+ basename(res->slot), ibpi2str(res->state), res->device);
|
|
+}
|
|
+
|
|
+#endif // SLOT_H_INCLUDED_
|
|
diff --git a/src/sysfs.c b/src/sysfs.c
|
|
index 87e83391f328..f1f9caad05a3 100644
|
|
--- a/src/sysfs.c
|
|
+++ b/src/sysfs.c
|
|
@@ -48,7 +48,6 @@
|
|
*/
|
|
#define SYSFS_CLASS_BLOCK "/sys/block"
|
|
#define SYSFS_CLASS_ENCLOSURE "/sys/class/enclosure"
|
|
-#define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
|
|
#define SYSFS_PCI_SLOTS "/sys/bus/pci/slots"
|
|
|
|
/**
|
|
diff --git a/src/sysfs.h b/src/sysfs.h
|
|
index efebea840cee..ea0109f6aa33 100644
|
|
--- a/src/sysfs.h
|
|
+++ b/src/sysfs.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* Intel(R) Enclosure LED Utilities
|
|
- * Copyright (C) 2009-2018 Intel Corporation.
|
|
+ * Copyright (C) 2009-2022 Intel Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
@@ -22,6 +22,8 @@
|
|
|
|
#include "status.h"
|
|
|
|
+#define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
|
|
+
|
|
/**
|
|
* @brief Initializes sysfs module.
|
|
*
|
|
diff --git a/src/utils.c b/src/utils.c
|
|
index 7f52194f5d1c..085cdb1d5c2f 100644
|
|
--- a/src/utils.c
|
|
+++ b/src/utils.c
|
|
@@ -505,7 +505,7 @@ int get_log_fd(void)
|
|
|
|
void print_opt(const char *long_opt, const char *short_opt, const char *desc)
|
|
{
|
|
- printf("%-20s%-10s%s\n", long_opt, short_opt, desc);
|
|
+ printf("%-70s%-40s%s\n", long_opt, short_opt, desc);
|
|
}
|
|
|
|
/**
|
|
@@ -581,6 +581,13 @@ struct option longopt_all[] = {
|
|
[OPT_LIST_CTRL] = {"list-controllers", no_argument, NULL, 'L'},
|
|
[OPT_LISTED_ONLY] = {"listed-only", no_argument, NULL, 'x'},
|
|
[OPT_FOREGROUND] = {"foreground", no_argument, NULL, '\0'},
|
|
+ [OPT_LIST_SLOTS] = {"list-slots", no_argument, NULL, 'P'},
|
|
+ [OPT_GET_SLOT] = {"get-slot", no_argument, NULL, 'G'},
|
|
+ [OPT_SET_SLOT] = {"set-slot", no_argument, NULL, 'S'},
|
|
+ [OPT_CONTROLLER] = {"controller", required_argument, NULL, 'c'},
|
|
+ [OPT_DEVICE] = {"device", required_argument, NULL, 'd'},
|
|
+ [OPT_SLOT] = {"slot", required_argument, NULL, 'p'},
|
|
+ [OPT_STATE] = {"state", required_argument, NULL, 's'},
|
|
[OPT_NULL_ELEMENT] = {NULL, no_argument, NULL, '\0'}
|
|
};
|
|
|
|
@@ -699,3 +706,43 @@ const char *ibpi2str(enum ibpi_pattern ibpi)
|
|
|
|
return ret;
|
|
}
|
|
+
|
|
+/**
|
|
+ * @brief Returns value based on IBPI state
|
|
+ *
|
|
+ * @param[in] value Value for led state.
|
|
+ * @param[in] ibpi_values Array with defined IBPI states and values.
|
|
+ *
|
|
+ * @return Integer value which represents given IBPI state.
|
|
+ */
|
|
+int get_value_for_ibpi(enum ibpi_pattern ibpi, const struct ibpi_value ibpi_values[])
|
|
+{
|
|
+ const struct ibpi_value *tmp = ibpi_values;
|
|
+
|
|
+ while (tmp->ibpi != IBPI_PATTERN_UNKNOWN) {
|
|
+ if (tmp->ibpi == ibpi)
|
|
+ break;
|
|
+ tmp++;
|
|
+ }
|
|
+ return tmp->value;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * @brief Returns IBPI pattern based on value
|
|
+ *
|
|
+ * @param[in] value Value for led state.
|
|
+ * @param[in] ibpi_values Array with defined IBPI states and values.
|
|
+ *
|
|
+ * @return Enum with IBPI value, which represents given value.
|
|
+ */
|
|
+enum ibpi_pattern get_ibpi_for_value(const int value, const struct ibpi_value ibpi_values[])
|
|
+{
|
|
+ const struct ibpi_value *tmp = ibpi_values;
|
|
+
|
|
+ while (tmp->ibpi != IBPI_PATTERN_UNKNOWN) {
|
|
+ if (tmp->value == value)
|
|
+ break;
|
|
+ tmp++;
|
|
+ }
|
|
+ return tmp->ibpi;
|
|
+}
|
|
diff --git a/src/utils.h b/src/utils.h
|
|
index 3f5a77fc6f74..5ef3020e6dce 100644
|
|
--- a/src/utils.h
|
|
+++ b/src/utils.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* Intel(R) Enclosure LED Utilities
|
|
- * Copyright (C) 2009-2019 Intel Corporation.
|
|
+ * Copyright (C) 2009-2022 Intel Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
@@ -59,6 +59,10 @@ struct log_level_info {
|
|
int priority;
|
|
};
|
|
|
|
+struct ibpi_value {
|
|
+ int ibpi, value;
|
|
+};
|
|
+
|
|
/**
|
|
*/
|
|
#define PREFIX_DEBUG " DEBUG: "
|
|
@@ -418,6 +422,13 @@ enum opt {
|
|
OPT_LIST_CTRL,
|
|
OPT_LISTED_ONLY,
|
|
OPT_FOREGROUND,
|
|
+ OPT_LIST_SLOTS,
|
|
+ OPT_GET_SLOT,
|
|
+ OPT_SET_SLOT,
|
|
+ OPT_CONTROLLER,
|
|
+ OPT_DEVICE,
|
|
+ OPT_SLOT,
|
|
+ OPT_STATE,
|
|
OPT_NULL_ELEMENT
|
|
};
|
|
|
|
@@ -428,5 +439,7 @@ int get_option_id(const char *optarg);
|
|
status_t set_verbose_level(int log_level);
|
|
|
|
const char *ibpi2str(enum ibpi_pattern ibpi);
|
|
+int get_value_for_ibpi(enum ibpi_pattern ibpi, const struct ibpi_value ibpi_values[]);
|
|
+enum ibpi_pattern get_ibpi_for_value(const int value, const struct ibpi_value ibpi_values[]);
|
|
|
|
#endif /* _UTILS_H_INCLUDED_ */
|
|
diff --git a/src/vmdssd.c b/src/vmdssd.c
|
|
index 3c6d24bdc604..015d3489c276 100644
|
|
--- a/src/vmdssd.c
|
|
+++ b/src/vmdssd.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* Intel(R) Enclosure LED Utilities
|
|
- * Copyright (c) 2016-2019, Intel Corporation
|
|
+ * Copyright (c) 2016-2022, Intel Corporation
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
@@ -37,6 +37,13 @@
|
|
#define ATTENTION_REBUILD 0x5 /* (0101) Attention On, Power On */
|
|
#define ATTENTION_FAILURE 0xD /* (1101) Attention On, Power Off */
|
|
|
|
+struct ibpi_value ibpi_to_attention[] = {
|
|
+ {IBPI_PATTERN_LOCATE, ATTENTION_LOCATE},
|
|
+ {IBPI_PATTERN_FAILED_DRIVE, ATTENTION_FAILURE},
|
|
+ {IBPI_PATTERN_REBUILD, ATTENTION_REBUILD},
|
|
+ {IBPI_PATTERN_LOCATE_OFF, ATTENTION_OFF}
|
|
+};
|
|
+
|
|
#define SYSFS_PCIEHP "/sys/module/pciehp"
|
|
|
|
static char *get_slot_from_syspath(char *path)
|
|
@@ -61,24 +68,6 @@ static char *get_slot_from_syspath(char *path)
|
|
return ret;
|
|
}
|
|
|
|
-static void get_ctrl(enum ibpi_pattern ibpi, uint16_t *new)
|
|
-{
|
|
- switch (ibpi) {
|
|
- case IBPI_PATTERN_LOCATE:
|
|
- *new = ATTENTION_LOCATE;
|
|
- break;
|
|
- case IBPI_PATTERN_FAILED_DRIVE:
|
|
- *new = ATTENTION_FAILURE;
|
|
- break;
|
|
- case IBPI_PATTERN_REBUILD:
|
|
- *new = ATTENTION_REBUILD;
|
|
- break;
|
|
- default:
|
|
- *new = ATTENTION_OFF;
|
|
- break;
|
|
- }
|
|
-}
|
|
-
|
|
static int check_slot_module(const char *slot_path)
|
|
{
|
|
char module_path[PATH_MAX], real_module_path[PATH_MAX];
|
|
@@ -120,11 +109,29 @@ struct pci_slot *vmdssd_find_pci_slot(char *device_path)
|
|
return slot;
|
|
}
|
|
|
|
-int vmdssd_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
+status_t vmdssd_write_attention_buf(struct pci_slot *slot, enum ibpi_pattern ibpi)
|
|
{
|
|
char attention_path[PATH_MAX];
|
|
char buf[WRITE_BUFFER_SIZE];
|
|
uint16_t val;
|
|
+
|
|
+ log_debug("%s before: 0x%x\n", slot->address,
|
|
+ get_int(slot->sysfs_path, 0, "attention"));
|
|
+ val = get_value_for_ibpi(ibpi, ibpi_to_attention);
|
|
+ snprintf(buf, WRITE_BUFFER_SIZE, "%u", val);
|
|
+ snprintf(attention_path, PATH_MAX, "%s/attention", slot->sysfs_path);
|
|
+ if (buf_write(attention_path, buf) != (ssize_t) strnlen(buf, WRITE_BUFFER_SIZE)) {
|
|
+ log_error("%s write error: %d\n", slot->sysfs_path, errno);
|
|
+ return STATUS_FILE_WRITE_ERROR;
|
|
+ }
|
|
+ log_debug("%s after: 0x%x\n", slot->address,
|
|
+ get_int(slot->sysfs_path, 0, "attention"));
|
|
+
|
|
+ return STATUS_SUCCESS;
|
|
+}
|
|
+
|
|
+int vmdssd_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
+{
|
|
struct pci_slot *slot;
|
|
char *short_name = strrchr(device->sysfs_path, '/');
|
|
|
|
@@ -145,21 +152,7 @@ int vmdssd_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
__set_errno_and_return(ENODEV);
|
|
}
|
|
|
|
- log_debug("%s before: 0x%x\n", short_name,
|
|
- get_int(slot->sysfs_path, 0, "attention"));
|
|
-
|
|
- get_ctrl(ibpi, &val);
|
|
- snprintf(buf, WRITE_BUFFER_SIZE, "%u", val);
|
|
- snprintf(attention_path, PATH_MAX, "%s/attention", slot->sysfs_path);
|
|
- if (buf_write(attention_path, buf) != (ssize_t) strnlen(buf, WRITE_BUFFER_SIZE)) {
|
|
- log_error("%s write error: %d\n", slot->sysfs_path, errno);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- log_debug("%s after: 0x%x\n", short_name,
|
|
- get_int(slot->sysfs_path, 0, "attention"));
|
|
-
|
|
- return 0;
|
|
+ return vmdssd_write_attention_buf(slot, ibpi);
|
|
}
|
|
|
|
char *vmdssd_get_path(const char *cntrl_path)
|
|
diff --git a/src/vmdssd.h b/src/vmdssd.h
|
|
index 4c90fcb35ea2..f07d989280bc 100644
|
|
--- a/src/vmdssd.h
|
|
+++ b/src/vmdssd.h
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
* Intel(R) Enclosure LED Utilities
|
|
- * Copyright (c) 2016-2019, Intel Corporation
|
|
+ * Copyright (c) 2016-2022, Intel Corporation
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
@@ -22,9 +22,18 @@
|
|
|
|
#include "block.h"
|
|
#include "ibpi.h"
|
|
+#include "utils.h"
|
|
+
|
|
+#define ATTENTION_OFF 0xF /* (1111) Attention Off, Power Off */
|
|
+#define ATTENTION_LOCATE 0x7 /* (0111) Attention Off, Power On */
|
|
+#define ATTENTION_REBUILD 0x5 /* (0101) Attention On, Power On */
|
|
+#define ATTENTION_FAILURE 0xD /* (1101) Attention On, Power Off */
|
|
+
|
|
+extern struct ibpi_value ibpi_to_attention[];
|
|
|
|
int vmdssd_write(struct block_device *device, enum ibpi_pattern ibpi);
|
|
char *vmdssd_get_path(const char *cntrl_path);
|
|
struct pci_slot *vmdssd_find_pci_slot(char *device_path);
|
|
+status_t vmdssd_write_attention_buf(struct pci_slot *slot, enum ibpi_pattern ibpi);
|
|
|
|
#endif
|
|
--
|
|
2.34.1
|
|
|