From 862a77460a2996076ae4866f6832e171ea79d5a100f70092d8813722d7580ed0 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Mon, 18 Jul 2022 19:38:42 +0000 Subject: [PATCH] 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 --- 0001-Ledctl-slots-management-94.patch | 1365 +++++++++++++++++++++++++ 0002-add-Dell-15G-servers.patch | 56 + ledmon-0.95.tar.gz | 3 - ledmon-0.96.tar.gz | 3 + ledmon.changes | 14 + ledmon.spec | 8 +- 6 files changed, 1443 insertions(+), 6 deletions(-) create mode 100644 0001-Ledctl-slots-management-94.patch create mode 100644 0002-add-Dell-15G-servers.patch delete mode 100644 ledmon-0.95.tar.gz create mode 100644 ledmon-0.96.tar.gz diff --git a/0001-Ledctl-slots-management-94.patch b/0001-Ledctl-slots-management-94.patch new file mode 100644 index 0000000..56ed475 --- /dev/null +++ b/0001-Ledctl-slots-management-94.patch @@ -0,0 +1,1365 @@ +From a56e8bf096c04ea0c76ca026e07402f05ce58ca4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kinga=20Ta=C5=84ska?= +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 +--- + 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 ++ ++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 is type of controller ++(vmd, NPEM) that should be scanned here. ++ ++=item B<-G> or B<--get-slot> B<--controller>=I B<--device>=I ++ ++Displays slot details of given device. I is devnode of selected drive. ++ ++=item B<-G> or B<--get-slot> B<--controller>=I B<--slot>=I ++ ++Displays details of given slot. I is unique slot identifier. ++ ++=item B<-S> or B<--set-slot> B<--controller>=I B<--slot>=I B<--state>=I ++ ++Changes led state for given slot. I is type of the controller. ++I is unique slot identifier. I 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 ++ ++#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 + diff --git a/0002-add-Dell-15G-servers.patch b/0002-add-Dell-15G-servers.patch new file mode 100644 index 0000000..3cf44a8 --- /dev/null +++ b/0002-add-Dell-15G-servers.patch @@ -0,0 +1,56 @@ +From 7274b21797d1ad76a2f4ccd2e3f70279e50512b4 Mon Sep 17 00:00:00 2001 +From: prabhakar +Date: Tue, 5 Jul 2022 08:16:18 -0400 +Subject: [PATCH 2/2] add Dell 15G servers + +--- + src/dellssd.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/src/dellssd.c b/src/dellssd.c +index 5a7ac5f4a629..fce3110d62d5 100644 +--- a/src/dellssd.c ++++ b/src/dellssd.c +@@ -93,6 +93,9 @@ enum { + DELL_13G_MODULAR = 0x21, + DELL_14G_MONOLITHIC = 0x30, + DELL_14G_MODULAR = 0x31, ++ DELL_15G_MONOLITHIC = 0x40, ++ DELL_15G_MODULAR = 0x41, ++ + }; + + int get_dell_server_type() +@@ -125,6 +128,9 @@ int get_dell_server_type() + case DELL_13G_MODULAR: + case DELL_14G_MONOLITHIC: + case DELL_14G_MODULAR: ++ case DELL_15G_MONOLITHIC: ++ case DELL_15G_MODULAR: ++ + gen = rdata[10]; + return gen; + default: +@@ -166,6 +172,9 @@ static int ipmi_setled(int b, int d, int f, int state) + break; + case DELL_14G_MONOLITHIC: + case DELL_14G_MODULAR: ++ case DELL_15G_MONOLITHIC: ++ case DELL_15G_MODULAR: ++ + data[1] = DELL_OEM_STORAGE_GETDRVMAP_14G; + break; + } +@@ -206,6 +215,9 @@ static int ipmi_setled(int b, int d, int f, int state) + break; + case DELL_14G_MONOLITHIC: + case DELL_14G_MODULAR: ++ case DELL_15G_MONOLITHIC: ++ case DELL_15G_MODULAR: ++ + data[1] = DELL_OEM_STORAGE_SETDRVSTATUS_14G; + break; + } +-- +2.34.1 + diff --git a/ledmon-0.95.tar.gz b/ledmon-0.95.tar.gz deleted file mode 100644 index e4f6887..0000000 --- a/ledmon-0.95.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8f3cec0d8f111e68ab2fff4aeb797193523be3753a51c94b22dac867af201ca7 -size 82048 diff --git a/ledmon-0.96.tar.gz b/ledmon-0.96.tar.gz new file mode 100644 index 0000000..95d5de8 --- /dev/null +++ b/ledmon-0.96.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97534302a60f03b90e69228a6a56096cf3fdfc8eb31fea52a974445268fdf5d9 +size 83222 diff --git a/ledmon.changes b/ledmon.changes index 05d35a7..5223eb8 100644 --- a/ledmon.changes +++ b/ledmon.changes @@ -1,3 +1,17 @@ +------------------------------------------------------------------- +Mon Jul 18 15:09:00 UTC 2022 - Heming Zhao + +- 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 + ------------------------------------------------------------------- Fri Oct 15 07:28:48 UTC 2021 - Johannes Segitz diff --git a/ledmon.spec b/ledmon.spec index 085c3d4..ca626ea 100644 --- a/ledmon.spec +++ b/ledmon.spec @@ -1,7 +1,7 @@ # # spec file for package ledmon # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,14 +17,16 @@ Name: ledmon -Version: 0.95 +Version: 0.96 Release: 0 Summary: Enclosure LED Utilities License: GPL-2.0-only Group: Hardware/Other URL: https://github.com/intel/ledmon/ Source0: https://github.com/intel/ledmon/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz -Patch0: harden_ledmon.service.patch +Patch0: harden_ledmon.service.patch +Patch1: 0001-Ledctl-slots-management-94.patch +Patch2: 0002-add-Dell-15G-servers.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: libsgutils-devel