|
Packit Service |
db8df9 |
/*
|
|
Packit Service |
db8df9 |
* Intel(R) Enclosure LED Utilities
|
|
Packit Service |
db8df9 |
* Copyright (c) 2016-2019, Intel Corporation
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
db8df9 |
* under the terms and conditions of the GNU General Public License,
|
|
Packit Service |
db8df9 |
* version 2, as published by the Free Software Foundation.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit Service |
db8df9 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit Service |
db8df9 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit Service |
db8df9 |
* more details.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
* You should have received a copy of the GNU General Public License along with
|
|
Packit Service |
db8df9 |
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
db8df9 |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
db8df9 |
*
|
|
Packit Service |
db8df9 |
*/
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include <errno.h>
|
|
Packit Service |
db8df9 |
#include <limits.h>
|
|
Packit Service |
db8df9 |
#include <stdlib.h>
|
|
Packit Service |
db8df9 |
#include <stdint.h>
|
|
Packit Service |
db8df9 |
#include <stdio.h>
|
|
Packit Service |
db8df9 |
#include <string.h>
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#include "config.h"
|
|
Packit Service |
db8df9 |
#include "list.h"
|
|
Packit Service |
db8df9 |
#include "pci_slot.h"
|
|
Packit Service |
db8df9 |
#include "status.h"
|
|
Packit Service |
db8df9 |
#include "sysfs.h"
|
|
Packit Service |
db8df9 |
#include "utils.h"
|
|
Packit Service |
db8df9 |
#include "vmdssd.h"
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#define ATTENTION_OFF 0xF /* (1111) Attention Off, Power Off */
|
|
Packit Service |
db8df9 |
#define ATTENTION_LOCATE 0x7 /* (0111) Attention Off, Power On */
|
|
Packit Service |
db8df9 |
#define ATTENTION_REBUILD 0x5 /* (0101) Attention On, Power On */
|
|
Packit Service |
db8df9 |
#define ATTENTION_FAILURE 0xD /* (1101) Attention On, Power Off */
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
#define SYSFS_PCIEHP "/sys/module/pciehp"
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static char *get_slot_from_syspath(char *path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *cur, *ret = NULL;
|
|
Packit Service |
db8df9 |
char *temp_path = str_dup(path);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
cur = strtok(temp_path, "/");
|
|
Packit Service |
db8df9 |
while (cur != NULL) {
|
|
Packit Service |
db8df9 |
char *next = strtok(NULL, "/");
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if ((next != NULL) && strcmp(next, "nvme") == 0)
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
cur = next;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
cur = strtok(cur, ".");
|
|
Packit Service |
db8df9 |
if (cur)
|
|
Packit Service |
db8df9 |
ret = str_dup(cur);
|
|
Packit Service |
db8df9 |
free(temp_path);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return ret;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static void get_ctrl(enum ibpi_pattern ibpi, uint16_t *new)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
switch (ibpi) {
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_LOCATE:
|
|
Packit Service |
db8df9 |
*new = ATTENTION_LOCATE;
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_FAILED_DRIVE:
|
|
Packit Service |
db8df9 |
*new = ATTENTION_FAILURE;
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
case IBPI_PATTERN_REBUILD:
|
|
Packit Service |
db8df9 |
*new = ATTENTION_REBUILD;
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
default:
|
|
Packit Service |
db8df9 |
*new = ATTENTION_OFF;
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
static int check_slot_module(const char *slot_path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char module_path[PATH_MAX], real_module_path[PATH_MAX];
|
|
Packit Service |
db8df9 |
struct list dir;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
// check if slot is managed by pciehp driver
|
|
Packit Service |
db8df9 |
snprintf(module_path, PATH_MAX, "%s/module", slot_path);
|
|
Packit Service |
db8df9 |
if (scan_dir(module_path, &dir) == 0) {
|
|
Packit Service |
db8df9 |
list_erase(&dir;;
|
|
Packit Service |
db8df9 |
if (realpath(module_path, real_module_path) == NULL)
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
if (strcmp(real_module_path, SYSFS_PCIEHP) != 0)
|
|
Packit Service |
db8df9 |
__set_errno_and_return(EINVAL);
|
|
Packit Service |
db8df9 |
} else {
|
|
Packit Service |
db8df9 |
__set_errno_and_return(ENOENT);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
struct pci_slot *vmdssd_find_pci_slot(char *device_path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char *pci_addr;
|
|
Packit Service |
db8df9 |
struct pci_slot *slot = NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
pci_addr = get_slot_from_syspath(device_path);
|
|
Packit Service |
db8df9 |
if (!pci_addr)
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
list_for_each(sysfs_get_pci_slots(), slot) {
|
|
Packit Service |
db8df9 |
if (strcmp(slot->address, pci_addr) == 0)
|
|
Packit Service |
db8df9 |
break;
|
|
Packit Service |
db8df9 |
slot = NULL;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
free(pci_addr);
|
|
Packit Service |
db8df9 |
if (slot == NULL || check_slot_module(slot->sysfs_path) < 0)
|
|
Packit Service |
db8df9 |
return NULL;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return slot;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
int vmdssd_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
char attention_path[PATH_MAX];
|
|
Packit Service |
db8df9 |
char buf[WRITE_BUFFER_SIZE];
|
|
Packit Service |
db8df9 |
uint16_t val;
|
|
Packit Service |
db8df9 |
struct pci_slot *slot;
|
|
Packit Service |
db8df9 |
char *short_name = strrchr(device->sysfs_path, '/');
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (short_name)
|
|
Packit Service |
db8df9 |
short_name++;
|
|
Packit Service |
db8df9 |
else
|
|
Packit Service |
db8df9 |
short_name = device->sysfs_path;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if (ibpi == device->ibpi_prev)
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
if ((ibpi < IBPI_PATTERN_NORMAL) || (ibpi > IBPI_PATTERN_LOCATE_OFF))
|
|
Packit Service |
db8df9 |
__set_errno_and_return(ERANGE);
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
slot = vmdssd_find_pci_slot(device->sysfs_path);
|
|
Packit Service |
db8df9 |
if (!slot) {
|
|
Packit Service |
db8df9 |
log_debug("PCI hotplug slot not found for %s\n", short_name);
|
|
Packit Service |
db8df9 |
__set_errno_and_return(ENODEV);
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
log_debug("%s before: 0x%x\n", short_name,
|
|
Packit Service |
db8df9 |
get_int(slot->sysfs_path, 0, "attention"));
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
get_ctrl(ibpi, &val;;
|
|
Packit Service |
db8df9 |
snprintf(buf, WRITE_BUFFER_SIZE, "%u", val);
|
|
Packit Service |
db8df9 |
snprintf(attention_path, PATH_MAX, "%s/attention", slot->sysfs_path);
|
|
Packit Service |
db8df9 |
if (buf_write(attention_path, buf) != (ssize_t) strlen(buf)) {
|
|
Packit Service |
db8df9 |
log_error("%s write error: %d\n", slot->sysfs_path, errno);
|
|
Packit Service |
db8df9 |
return -1;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
log_debug("%s after: 0x%x\n", short_name,
|
|
Packit Service |
db8df9 |
get_int(slot->sysfs_path, 0, "attention"));
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
return 0;
|
|
Packit Service |
db8df9 |
}
|
|
Packit Service |
db8df9 |
|
|
Packit Service |
db8df9 |
char *vmdssd_get_path(const char *cntrl_path)
|
|
Packit Service |
db8df9 |
{
|
|
Packit Service |
db8df9 |
return str_dup(cntrl_path);
|
|
Packit Service |
db8df9 |
}
|