ledmon/0001-Ledctl-slots-management-94.patch
Dirk Mueller 862a77460a Accepting request 990005 from home:hmzhao:branches:Base:System
- 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
2022-07-18 19:38:42 +00:00

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