File 0001-Ledctl-slots-management-94.patch of Package ledmon

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

openSUSE Build Service is sponsored by