Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ SUBDIRS = include
LIB_SRCS = ahci.c block.c cntrl.c enclosure.c utils.c list.c \
raid.c scsi.c tail.c sysfs.c smp.c dellssd.c \
pci_slot.c vmdssd.c amd.c amd_sgpio.c amd_ipmi.c\
ipmi.c npem.c ses.c slot.c \
ipmi.c npem.c ses.c slot.c kernel_npem.c\
ahci.h amd_sgpio.h block.h cntrl.h dellssd.h utils.h \
enclosure.h list.h pci_slot.h raid.h scsi.h \
ses.h tail.h smp.h status.h sysfs.h \
vmdssd.h ipmi.h amd.h amd_ipmi.h npem.h libled_internal.c \
slot.h libled_private.h libled_internal.h
kernel_npem.h slot.h libled_private.h libled_internal.h

# Make a convenience library, to be used for led tools and the shared library
noinst_LTLIBRARIES = libledinternal.la
Expand Down
10 changes: 9 additions & 1 deletion src/lib/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "block.h"
#include "config.h"
#include "dellssd.h"
#include "kernel_npem.h"
#include "libled_private.h"
#include "npem.h"
#include "pci_slot.h"
Expand Down Expand Up @@ -76,6 +77,9 @@ static void _set_send_message_fn(struct block_device *device)
else
device->send_message_fn = scsi_ses_write;
break;
case LED_CNTRL_TYPE_KERNEL_NPEM:
device->send_message_fn = kernel_npem_write;
break;
case LED_CNTRL_TYPE_DELLSSD:
device->send_message_fn = dellssd_write;
break;
Expand Down Expand Up @@ -137,6 +141,8 @@ static char *_get_host(char *path, struct cntrl_device *cntrl)
result = scsi_get_host_path(path, cntrl->sysfs_path);
else if (cntrl->cntrl_type == LED_CNTRL_TYPE_AHCI)
result = ahci_get_port_path(path);
else if (cntrl->cntrl_type == LED_CNTRL_TYPE_KERNEL_NPEM)
result = kernel_npem_get_path(cntrl->sysfs_path);
else if (cntrl->cntrl_type == LED_CNTRL_TYPE_DELLSSD)
result = dellssd_get_path(cntrl->sysfs_path);
else if (cntrl->cntrl_type == LED_CNTRL_TYPE_VMD)
Expand All @@ -158,6 +164,7 @@ static int is_host_id_supported(const struct block_device *bd)
case LED_CNTRL_TYPE_DELLSSD:
case LED_CNTRL_TYPE_VMD:
case LED_CNTRL_TYPE_NPEM:
case LED_CNTRL_TYPE_KERNEL_NPEM:
return 0;
default:
return 1;
Expand Down Expand Up @@ -188,7 +195,8 @@ struct cntrl_device *block_get_controller(const struct list *cntrl_list, char *p
if (cntrl) {
if (strncmp(cntrl->sysfs_path, path,
strnlen(cntrl->sysfs_path, PATH_MAX)) == 0) {
if (cntrl->cntrl_type == LED_CNTRL_TYPE_NPEM)
if ((cntrl->cntrl_type == LED_CNTRL_TYPE_NPEM) ||
(cntrl->cntrl_type == LED_CNTRL_TYPE_KERNEL_NPEM))
return cntrl;
non_npem_cntrl = cntrl;
}
Expand Down
8 changes: 8 additions & 0 deletions src/lib/cntrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "amd.h"
#include "cntrl.h"
#include "config.h"
#include "kernel_npem.h"
#include "list.h"
#include "libled_private.h"
#include "npem.h"
Expand Down Expand Up @@ -179,6 +180,10 @@ static int _is_npem_cntrl(const char *path, struct led_ctx *ctx)
return is_npem_capable(path, ctx);
}

static int _is_kernel_npem_cntrl(const char *path)
{
return is_kernel_npem_present(path);
}
/**
* @brief Determines the type of controller.
*
Expand All @@ -200,6 +205,8 @@ static enum led_cntrl_type _get_type(const char *path, struct led_ctx *ctx)
type = LED_CNTRL_TYPE_NPEM;
} else if (_is_vmd_cntrl(path)) {
type = LED_CNTRL_TYPE_VMD;
} else if (_is_kernel_npem_cntrl(path)) {
type = LED_CNTRL_TYPE_KERNEL_NPEM;
} else if (_is_dellssd_cntrl(path, ctx)) {
type = LED_CNTRL_TYPE_DELLSSD;
} else if (_is_storage_controller(path)) {
Expand Down Expand Up @@ -400,6 +407,7 @@ struct cntrl_device *cntrl_device_init(const char *path, struct led_ctx *ctx)
case LED_CNTRL_TYPE_SCSI:
case LED_CNTRL_TYPE_VMD:
case LED_CNTRL_TYPE_NPEM:
case LED_CNTRL_TYPE_KERNEL_NPEM:
em_enabled = 1;
break;
case LED_CNTRL_TYPE_AHCI:
Expand Down
1 change: 1 addition & 0 deletions src/lib/include/led/libled.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ enum led_cntrl_type {
LED_CNTRL_TYPE_AHCI = 4,
LED_CNTRL_TYPE_NPEM = 5,
LED_CNTRL_TYPE_AMD = 6,
LED_CNTRL_TYPE_KERNEL_NPEM = 7,
};

/**
Expand Down
204 changes: 204 additions & 0 deletions src/lib/kernel_npem.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2022 Intel Corporation.
// Copyright (C) 2025 Dell Inc.

/* System headers */
#include <stdio.h>
#include <string.h>
#include <pci/pci.h>
#include <time.h>
#include <stdbool.h>
#include <sys/stat.h>

/* Local headers */
#include "libled_private.h"
#include "cntrl.h"
#include "npem.h"
#include "utils.h"

/* NPEM OK Capable/Control */
#define PCI_NPEM_OK_CAP 0x004
/* NPEM Locate Capable/Control */
#define PCI_NPEM_LOCATE_CAP 0x008
/* NPEM Fail Capable/Control */
#define PCI_NPEM_FAIL_CAP 0x010
/* NPEM Rebuild Capable/Control */
#define PCI_NPEM_REBUILD_CAP 0x020
/* NPEM Predicted Failure Analysis Capable/Control */
#define PCI_NPEM_PFA_CAP 0x040
/* NPEM Hot Spare Capable/Control */
#define PCI_NPEM_HOT_SPARE_CAP 0x080
/* NPEM in a Critical Array Capable/Control */
#define PCI_NPEM_CRA_CAP 0x100
/* NPEM in a Failed Array Capable/Control */
#define PCI_NPEM_FA_CAP 0x200

static const struct ibpi2value ibpi_to_npem_capability[] = {
{LED_IBPI_PATTERN_NORMAL, PCI_NPEM_OK_CAP},
{LED_IBPI_PATTERN_ONESHOT_NORMAL, PCI_NPEM_OK_CAP},
{LED_IBPI_PATTERN_DEGRADED, PCI_NPEM_CRA_CAP},
{LED_IBPI_PATTERN_HOTSPARE, PCI_NPEM_HOT_SPARE_CAP},
{LED_IBPI_PATTERN_REBUILD, PCI_NPEM_REBUILD_CAP},
{LED_IBPI_PATTERN_FAILED_ARRAY, PCI_NPEM_FA_CAP},
{LED_IBPI_PATTERN_PFA, PCI_NPEM_PFA_CAP},
{LED_IBPI_PATTERN_FAILED_DRIVE, PCI_NPEM_FAIL_CAP},
{LED_IBPI_PATTERN_LOCATE, PCI_NPEM_LOCATE_CAP},
{LED_IBPI_PATTERN_LOCATE_OFF, PCI_NPEM_OK_CAP},
{LED_IBPI_PATTERN_UNKNOWN, 0}
};

struct kernel_npem_led {
int bitmask;
char *sysfs_led_name;
};

const struct kernel_npem_led kernel_npem_leds[] = {
{PCI_NPEM_OK_CAP, "enclosure:ok"},
{PCI_NPEM_LOCATE_CAP, "enclosure:locate"},
{PCI_NPEM_FAIL_CAP, "enclosure:fail"},
{PCI_NPEM_REBUILD_CAP, "enclosure:rebuild"},
{PCI_NPEM_PFA_CAP, "enclosure:pfa"},
{PCI_NPEM_HOT_SPARE_CAP, "enclosure:hotspare"},
{PCI_NPEM_CRA_CAP, "enclosure:ica"},
{PCI_NPEM_FA_CAP, "enclosure:ifa"},
};

char *kernel_npem_get_path(const char *cntrl_path)
{
return strdup(cntrl_path);
}

#define make_led_path(sysfs_led_path, sysfs_path, sysfs_led_name) \
snprintf(sysfs_led_path, sizeof(sysfs_led_path), "%s/leds/%s:%s/brightness", \
sysfs_path, basename(sysfs_path), sysfs_led_name)

static u32 read_kernel_npem_register(const char *sysfs_path)
{
char led_path[PATH_MAX];
int i;
u32 reg = 0;

for (i = 0; i < ARRAY_SIZE(kernel_npem_leds); i++) {
make_led_path(led_path, sysfs_path, kernel_npem_leds[i].sysfs_led_name);
reg |= get_int("/", 0, led_path) ? kernel_npem_leds[i].bitmask : 0;
}
return reg;
}

static int write_kernel_npem_register(const char *sysfs_path, u32 val)
{
char led_path[PATH_MAX], val_text[4];
int i;
struct stat sb;

for (i = 0; i < ARRAY_SIZE(kernel_npem_leds); i++) {
make_led_path(led_path, sysfs_path, kernel_npem_leds[i].sysfs_led_name);
snprintf(val_text, sizeof(val_text), val & kernel_npem_leds[i].bitmask ? "1" : "0");
if (!stat(led_path, &sb))
buf_write(led_path, val_text);
}
return 0;
}

static u32 kernel_npem_supported_mask(const char *sysfs_path)
{
char led_path[PATH_MAX];
int i;
struct stat sb;
u32 supported = 0;

for (i = 0; i < ARRAY_SIZE(kernel_npem_leds); i++) {
make_led_path(led_path, sysfs_path, kernel_npem_leds[i].sysfs_led_name);
if (!stat(led_path, &sb))
supported |= kernel_npem_leds[i].bitmask;
}
return supported;
}

int is_kernel_npem_present(const char *path)
{
return kernel_npem_supported_mask(path) ? 1 : 0;
}

enum led_ibpi_pattern kernel_npem_get_state(struct slot_property *slot)
{
const char *path = slot->slot_spec.cntrl->sysfs_path;
const struct ibpi2value *ibpi2val;
u32 reg;

reg = read_kernel_npem_register(path);
ibpi2val = get_by_bits(reg, ibpi_to_npem_capability,
ARRAY_SIZE(ibpi_to_npem_capability));

return ibpi2val->ibpi;
}

status_t kernel_npem_set_slot(struct led_ctx *ctx, const char *sysfs_path,
enum led_ibpi_pattern state)
{
const struct ibpi2value *ibpi2val;
u32 requested, supported;

ibpi2val = get_by_ibpi(state, ibpi_to_npem_capability,
ARRAY_SIZE(ibpi_to_npem_capability));

if (ibpi2val->ibpi == LED_IBPI_PATTERN_UNKNOWN) {
lib_log(ctx, LED_LOG_LEVEL_INFO,
"KERNEL_NPEM: Controller doesn't support %s pattern\n", ibpi2str(state));
return STATUS_INVALID_STATE;
}

requested = (u32)ibpi2val->value;
supported = kernel_npem_supported_mask(sysfs_path);

if (!(requested & supported))
/*
* Allow OK (normal and locate_off states) to turn off other
* states even if OK state isn't actually supported.
*/
if (requested != PCI_NPEM_OK_CAP) {
lib_log(ctx, LED_LOG_LEVEL_INFO,
"KERNEL_NPEM: Controller %s doesn't support %s pattern\n",
sysfs_path, ibpi2str(state));
return STATUS_INVALID_STATE;
}

write_kernel_npem_register(sysfs_path, requested);

return STATUS_SUCCESS;
}

status_t kernel_npem_set_state(struct slot_property *slot, enum led_ibpi_pattern state)
{
return kernel_npem_set_slot(slot->slot_spec.cntrl->ctx,
slot->slot_spec.cntrl->sysfs_path, state);
}

const struct slot_property_common kernel_npem_slot_common = {
.cntrl_type = LED_CNTRL_TYPE_KERNEL_NPEM,
.get_state_fn = kernel_npem_get_state,
.set_slot_fn = kernel_npem_set_state,
};

struct slot_property *kernel_npem_slot_property_init(struct cntrl_device *kernel_npem_cntrl)
{
struct slot_property *result = calloc(1, sizeof(struct slot_property));

if (result == NULL)
return NULL;

result->bl_device = get_block_device_from_sysfs_path(kernel_npem_cntrl->ctx,
kernel_npem_cntrl->sysfs_path, true);
result->slot_spec.cntrl = kernel_npem_cntrl;
snprintf(result->slot_id, PATH_MAX, "%s", kernel_npem_cntrl->sysfs_path);
result->c = &kernel_npem_slot_common;
return result;
}

status_t kernel_npem_write(struct block_device *device, enum led_ibpi_pattern ibpi)
{
if (ibpi < LED_IBPI_PATTERN_NORMAL || ibpi > LED_IBPI_PATTERN_LOCATE_OFF)
return STATUS_INVALID_STATE;

return kernel_npem_set_slot(device->cntrl->ctx, device->cntrl->sysfs_path, ibpi);
}
53 changes: 53 additions & 0 deletions src/lib/kernel_npem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2022 Intel Corporation.
// Copyright (C) 2025 Dell Inc.

#ifndef _KERNEL_NPEM_H_INCLUDED_
#define _KERNEL_NPEM_H_INCLUDED_

/* Project headers */
#include <led/libled.h>

/* Local headers */
#include "block.h"
#include "cntrl.h"
#include "slot.h"
#include "status.h"


int is_kernel_npem_present(const char *path);
status_t kernel_npem_write(struct block_device *device, enum led_ibpi_pattern ibpi);
char *kernel_npem_get_path(const char *cntrl_path);

/**
* @brief Gets slot information.
*
* This function fills slot information related to the slot.
*
* @param[in] slot Pointer to the slot property element.
*
* @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
*/
enum led_ibpi_pattern kernel_npem_get_state(struct slot_property *slot);

/**
* @brief Sets led state for slot.
*
* This function sets given led state for slot.
*
* @param[in] slot Requested slot.
* @param[in] state IBPI state based on slot request.
*
* @return STATUS_SUCCESS if successful, otherwise a valid status_t status code.
*/
status_t kernel_npem_set_state(struct slot_property *slot, enum led_ibpi_pattern state);

/**
* @brief Initializes a slot_property for a specified NPEM controller.
*
* @param[in] npem_cntrl Specified npem controller for this slot
* @return struct slot_property* if successful, else NULL on allocation failure
*/
struct slot_property *kernel_npem_slot_property_init(struct cntrl_device *npem_cntrl);

#endif // _KERNEL_NPEM_H_INCLUDED_
4 changes: 3 additions & 1 deletion src/lib/libled.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ led_status_t led_slot_set(struct led_ctx *ctx, struct led_slot_list_entry *se,
bool led_controller_slot_support(enum led_cntrl_type cntrl)
{
return (cntrl == LED_CNTRL_TYPE_NPEM || cntrl == LED_CNTRL_TYPE_SCSI ||
cntrl == LED_CNTRL_TYPE_VMD);
cntrl == LED_CNTRL_TYPE_VMD) ||
cntrl == LED_CNTRL_TYPE_KERNEL_NPEM;
}

struct led_slot_list_entry *led_slot_next(struct led_slot_list *sl)
Expand Down Expand Up @@ -311,6 +312,7 @@ static const char * const ctrl_type_str[] = {
[LED_CNTRL_TYPE_AHCI] = "AHCI",
[LED_CNTRL_TYPE_NPEM] = "NPEM",
[LED_CNTRL_TYPE_AMD] = "AMD",
[LED_CNTRL_TYPE_KERNEL_NPEM] = "Kernel NPEM",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh one last thing. On Linux systems spaces are avoided, so please check it to KERNEL_NPEM
I see that there is "Dell SSD" and you did it for consistently but I still think that changing it to avoid "" every time is better

};

enum led_cntrl_type led_string_to_cntrl_type(const char *cntrl_str)
Expand Down
5 changes: 5 additions & 0 deletions src/lib/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "config.h"
#include "cntrl.h"
#include "enclosure.h"
#include "kernel_npem.h"
#include "list.h"
#include "libled_private.h"
#include "npem.h"
Expand Down Expand Up @@ -412,6 +413,10 @@ static void _scan_slots(struct led_ctx *ctx)
slot = npem_slot_property_init(cntrl_device);
if (slot)
list_append_ctx(&ctx->sys.slots_list, slot, ctx);
} else if (cntrl_device->cntrl_type == LED_CNTRL_TYPE_KERNEL_NPEM) {
slot = kernel_npem_slot_property_init(cntrl_device);
if (slot)
list_append_ctx(&ctx->sys.slots_list, slot, ctx);
}
}

Expand Down
Loading