|
Packit |
7e09eb |
/*
|
|
Packit |
7e09eb |
* AMD IPMI LED control
|
|
Packit |
7e09eb |
* Copyright (C) 2019, Advanced Micro Devices, Inc.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit |
7e09eb |
* under the terms and conditions of the GNU General Public License,
|
|
Packit |
7e09eb |
* version 2, as published by the Free Software Foundation.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit |
7e09eb |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit |
7e09eb |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
Packit |
7e09eb |
* more details.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
* You should have received a copy of the GNU General Public License along with
|
|
Packit |
7e09eb |
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
7e09eb |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
7e09eb |
*
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#include <errno.h>
|
|
Packit |
7e09eb |
#include <fcntl.h>
|
|
Packit |
7e09eb |
#include <limits.h>
|
|
Packit |
7e09eb |
#include <stdint.h>
|
|
Packit |
7e09eb |
#include <stdio.h>
|
|
Packit |
7e09eb |
#include <stdlib.h>
|
|
Packit |
7e09eb |
#include <string.h>
|
|
Packit |
7e09eb |
#include <unistd.h>
|
|
Packit |
7e09eb |
#include <libgen.h>
|
|
Packit |
7e09eb |
#include <inttypes.h>
|
|
Packit |
7e09eb |
#include <sys/stat.h>
|
|
Packit |
7e09eb |
#include <sys/mman.h>
|
|
Packit |
7e09eb |
#include <sys/sysinfo.h>
|
|
Packit |
7e09eb |
#include <sys/file.h>
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#if _HAVE_DMALLOC_H
|
|
Packit |
7e09eb |
#include <dmalloc.h>
|
|
Packit |
7e09eb |
#endif
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
#include "config.h"
|
|
Packit |
7e09eb |
#include "ibpi.h"
|
|
Packit |
7e09eb |
#include "list.h"
|
|
Packit |
7e09eb |
#include "utils.h"
|
|
Packit |
7e09eb |
#include "amd.h"
|
|
Packit |
7e09eb |
#include "ipmi.h"
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static uint8_t amd_ibpi_ipmi_register[] = {
|
|
Packit |
7e09eb |
[IBPI_PATTERN_PFA] = 0x41,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_LOCATE] = 0x42,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_FAILED_DRIVE] = 0x44,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_FAILED_ARRAY] = 0x45,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_REBUILD] = 0x46,
|
|
Packit |
7e09eb |
[IBPI_PATTERN_HOTSPARE] = 0x47,
|
|
Packit |
7e09eb |
};
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* The path we are given should be similar to
|
|
Packit |
7e09eb |
* /sys/devices/pci0000:e0/0000:e0:03.3/0000:e3:00.0
|
|
Packit |
7e09eb |
* ^^^^^^^^^^
|
|
Packit |
7e09eb |
* We need to retrieve the address from the path (indicated above)
|
|
Packit |
7e09eb |
* then use it to find the corresponding address for a slot in
|
|
Packit |
7e09eb |
* /sys/bus/pci_slots to determine the icorrect port for the NVMe device.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
static int _get_ipmi_nvme_port(char *path)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int rc;
|
|
Packit |
7e09eb |
char *p, *f;
|
|
Packit |
7e09eb |
struct list dir;
|
|
Packit |
7e09eb |
const char *dir_path;
|
|
Packit |
7e09eb |
char *port_name;
|
|
Packit |
7e09eb |
int port = -1;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
p = strrchr(path, '/');
|
|
Packit |
7e09eb |
if (!p) {
|
|
Packit |
7e09eb |
log_error("Couldn't parse NVMe path to determine port\n");
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
p++;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* p now points to the address, remove the bits after the '.' */
|
|
Packit |
7e09eb |
f = strchr(p, '.');
|
|
Packit |
7e09eb |
if (!f) {
|
|
Packit |
7e09eb |
log_error("Couldn't parse NVMe port address\n");
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
*f = '\0';
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = scan_dir("/sys/bus/pci/slots", &dir;;
|
|
Packit |
7e09eb |
if (rc)
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
list_for_each(&dir, dir_path) {
|
|
Packit |
7e09eb |
port_name = get_text(dir_path, "address");
|
|
Packit |
7e09eb |
if (port_name && !strcmp(port_name, p)) {
|
|
Packit |
7e09eb |
char *dname = strrchr(dir_path, '/');
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
dname++;
|
|
Packit |
7e09eb |
port = strtol(dname, NULL, 0);
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
list_erase(&dir;;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Some platfroms require an adjustment to the port value based
|
|
Packit |
7e09eb |
* on how they are numbered by the BIOS.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
switch (amd_platform) {
|
|
Packit |
7e09eb |
case AMD_PLATFORM_DAYTONA_X:
|
|
Packit |
7e09eb |
port -= 2;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case AMD_PLATFORM_ETHANOL_X:
|
|
Packit |
7e09eb |
port -= 7;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
default:
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Validate port. Some BIOSes provide port values that are
|
|
Packit |
7e09eb |
* not valid.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
if ((port < 0) || (port > 24)) {
|
|
Packit |
7e09eb |
log_error("Invalid NVMe physical port %d\n", port);
|
|
Packit |
7e09eb |
port = -1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return port;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _get_ipmi_sata_port(const char *start_path)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int port;
|
|
Packit |
7e09eb |
char *p, *t;
|
|
Packit |
7e09eb |
char path[PATH_MAX];
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
strncpy(path, start_path, PATH_MAX);
|
|
Packit |
7e09eb |
path[PATH_MAX - 1] = 0;
|
|
Packit |
7e09eb |
t = p = strstr(path, "ata");
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (!p)
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* terminate the path after the ataXX/ part */
|
|
Packit |
7e09eb |
p = strchr(p, '/');
|
|
Packit |
7e09eb |
if (!p)
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
*p = '\0';
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* skip past 'ata' to get the ata port number */
|
|
Packit |
7e09eb |
t += 3;
|
|
Packit |
7e09eb |
port = strtoul(t, NULL, 10);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return port;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _get_amd_ipmi_drive(const char *start_path,
|
|
Packit |
7e09eb |
struct amd_drive *drive)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int found;
|
|
Packit |
7e09eb |
char path[PATH_MAX];
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
found = _find_file_path(start_path, "nvme", path, PATH_MAX);
|
|
Packit |
7e09eb |
if (found) {
|
|
Packit |
7e09eb |
drive->port = _get_ipmi_nvme_port(path);
|
|
Packit |
7e09eb |
if (drive->port < 0) {
|
|
Packit |
7e09eb |
log_error("Could not retrieve port number\n");
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
drive->drive_bay = 1 << (drive->port - 1);
|
|
Packit |
7e09eb |
drive->dev = AMD_NVME_DEVICE;
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
int shift;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
drive->port = _get_ipmi_sata_port(start_path);
|
|
Packit |
7e09eb |
if (drive->port < 0) {
|
|
Packit |
7e09eb |
log_error("Could not retrieve port number\n");
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* IPMI control is handled through the MG9098 chips on
|
|
Packit |
7e09eb |
* the platform, where each MG9098 chip can control up
|
|
Packit |
7e09eb |
* to 8 drives. Since we can have multiple MG9098 chips,
|
|
Packit |
7e09eb |
* we need the drive bay relative to the set of 8 controlled
|
|
Packit |
7e09eb |
* by the MG9098 chip.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
shift = drive->port - 1;
|
|
Packit |
7e09eb |
if (shift >= 8)
|
|
Packit |
7e09eb |
shift %= 8;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
drive->drive_bay = 1 << shift;
|
|
Packit |
7e09eb |
drive->dev = AMD_SATA_DEVICE;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
log_debug("AMD Drive: port: %d, bay %x\n", drive->port,
|
|
Packit |
7e09eb |
drive->drive_bay);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _ipmi_platform_channel(struct amd_drive *drive)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int rc = 0;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
switch (amd_platform) {
|
|
Packit |
7e09eb |
case AMD_PLATFORM_ETHANOL_X:
|
|
Packit |
7e09eb |
drive->channel = 0xd;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case AMD_PLATFORM_DAYTONA_X:
|
|
Packit |
7e09eb |
drive->channel = 0x17;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
default:
|
|
Packit |
7e09eb |
rc = -1;
|
|
Packit |
7e09eb |
log_error("AMD Platform does not have a defined IPMI channel\n");
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _ipmi_platform_slave_address(struct amd_drive *drive)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int rc = 0;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
switch (amd_platform) {
|
|
Packit |
7e09eb |
case AMD_PLATFORM_ETHANOL_X:
|
|
Packit |
7e09eb |
drive->slave_addr = 0xc0;
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
case AMD_PLATFORM_DAYTONA_X:
|
|
Packit |
7e09eb |
if (drive->dev == AMD_NO_DEVICE) {
|
|
Packit |
7e09eb |
/* Assume base slave address, we may not be able
|
|
Packit |
7e09eb |
* to retrieve a valid amd_drive yet.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
drive->slave_addr = 0xc0;
|
|
Packit |
7e09eb |
} else if (drive->dev == AMD_NVME_DEVICE) {
|
|
Packit |
7e09eb |
/* On DaytonaX systems only drive bays 19 - 24
|
|
Packit |
7e09eb |
* support NVMe devices so use the slave address
|
|
Packit |
7e09eb |
* for the corresponding MG9098 chip.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
drive->slave_addr = 0xc4;
|
|
Packit |
7e09eb |
} else {
|
|
Packit |
7e09eb |
if (drive->port <= 8)
|
|
Packit |
7e09eb |
drive->slave_addr = 0xc0;
|
|
Packit |
7e09eb |
else if (drive->port > 8 && drive->port < 17)
|
|
Packit |
7e09eb |
drive->slave_addr = 0xc2;
|
|
Packit |
7e09eb |
else
|
|
Packit |
7e09eb |
drive->slave_addr = 0xc4;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
default:
|
|
Packit |
7e09eb |
rc = -1;
|
|
Packit |
7e09eb |
log_error("AMD Platform does not have a defined IPMI slave address\n");
|
|
Packit |
7e09eb |
break;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _set_ipmi_register(int enable, uint8_t reg,
|
|
Packit |
7e09eb |
struct amd_drive *drive)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int rc;
|
|
Packit |
7e09eb |
int status, data_sz;
|
|
Packit |
7e09eb |
uint8_t drives_status;
|
|
Packit |
7e09eb |
uint8_t new_drives_status;
|
|
Packit |
7e09eb |
uint8_t cmd_data[5];
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
memset(cmd_data, 0, sizeof(cmd_data));
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = _ipmi_platform_channel(drive);
|
|
Packit |
7e09eb |
rc |= _ipmi_platform_slave_address(drive);
|
|
Packit |
7e09eb |
if (rc)
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
cmd_data[0] = drive->channel;
|
|
Packit |
7e09eb |
cmd_data[1] = drive->slave_addr;
|
|
Packit |
7e09eb |
cmd_data[2] = 0x1;
|
|
Packit |
7e09eb |
cmd_data[3] = reg;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Find current register setting */
|
|
Packit |
7e09eb |
status = 0;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
log_debug("Retrieving current register status\n");
|
|
Packit |
7e09eb |
log_debug(REG_FMT_2, "channel", cmd_data[0], "slave addr", cmd_data[1]);
|
|
Packit |
7e09eb |
log_debug(REG_FMT_2, "len", cmd_data[2], "register", cmd_data[3]);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = ipmicmd(BMC_SA, 0x0, 0x6, 0x52, 4, &cmd_data, 1, &data_sz,
|
|
Packit |
7e09eb |
&status);
|
|
Packit |
7e09eb |
if (rc) {
|
|
Packit |
7e09eb |
log_error("Could not determine current register %x setting\n",
|
|
Packit |
7e09eb |
reg);
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
drives_status = status;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (enable)
|
|
Packit |
7e09eb |
new_drives_status = drives_status | drive->drive_bay;
|
|
Packit |
7e09eb |
else
|
|
Packit |
7e09eb |
new_drives_status = drives_status & ~drive->drive_bay;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Set the appropriate status */
|
|
Packit |
7e09eb |
status = 0;
|
|
Packit |
7e09eb |
cmd_data[4] = new_drives_status;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
log_debug("Updating register status: %x -> %x\n", drives_status,
|
|
Packit |
7e09eb |
new_drives_status);
|
|
Packit |
7e09eb |
log_debug(REG_FMT_2, "channel", cmd_data[0], "slave addr", cmd_data[1]);
|
|
Packit |
7e09eb |
log_debug(REG_FMT_2, "len", cmd_data[2], "register", cmd_data[3]);
|
|
Packit |
7e09eb |
log_debug(REG_FMT_1, "status", cmd_data[4]);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = ipmicmd(BMC_SA, 0x0, 0x6, 0x52, 5, &cmd_data, 1, &data_sz,
|
|
Packit |
7e09eb |
&status);
|
|
Packit |
7e09eb |
if (rc) {
|
|
Packit |
7e09eb |
log_error("Could not enable register %x\n", reg);
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _enable_smbus_control(struct amd_drive *drive)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
log_debug("Enabling SMBUS Control\n");
|
|
Packit |
7e09eb |
return _set_ipmi_register(1, 0x3c, drive);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _enable_ibpi_state(struct amd_drive *drive, enum ibpi_pattern ibpi)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
log_debug("Enabling %s LED\n", ibpi2str(ibpi));
|
|
Packit |
7e09eb |
return _set_ipmi_register(1, amd_ibpi_ipmi_register[ibpi], drive);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _disable_ibpi_state(struct amd_drive *drive, enum ibpi_pattern ibpi)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
log_debug("Disabling %s LED\n", ibpi2str(ibpi));
|
|
Packit |
7e09eb |
return _set_ipmi_register(0, amd_ibpi_ipmi_register[ibpi], drive);
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
static int _disable_all_ibpi_states(struct amd_drive *drive)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int rc;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = _disable_ibpi_state(drive, IBPI_PATTERN_PFA);
|
|
Packit |
7e09eb |
rc |= _disable_ibpi_state(drive, IBPI_PATTERN_LOCATE);
|
|
Packit |
7e09eb |
rc |= _disable_ibpi_state(drive, IBPI_PATTERN_FAILED_DRIVE);
|
|
Packit |
7e09eb |
rc |= _disable_ibpi_state(drive, IBPI_PATTERN_FAILED_ARRAY);
|
|
Packit |
7e09eb |
rc |= _disable_ibpi_state(drive, IBPI_PATTERN_REBUILD);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
int _amd_ipmi_em_enabled(const char *path)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int rc;
|
|
Packit |
7e09eb |
int status, data_sz;
|
|
Packit |
7e09eb |
uint8_t cmd_data[4];
|
|
Packit |
7e09eb |
struct amd_drive drive;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
memset(&drive, 0, sizeof(struct amd_drive));
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = _ipmi_platform_channel(&drive);
|
|
Packit |
7e09eb |
rc |= _ipmi_platform_slave_address(&drive);
|
|
Packit |
7e09eb |
if (rc)
|
|
Packit |
7e09eb |
return -1;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
cmd_data[0] = drive.channel;
|
|
Packit |
7e09eb |
cmd_data[1] = drive.slave_addr;
|
|
Packit |
7e09eb |
cmd_data[2] = 0x1;
|
|
Packit |
7e09eb |
cmd_data[3] = 0x63;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
status = 0;
|
|
Packit |
7e09eb |
rc = ipmicmd(BMC_SA, 0x0, 0x6, 0x52, 4, &cmd_data, 1,
|
|
Packit |
7e09eb |
&data_sz, &status);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (rc) {
|
|
Packit |
7e09eb |
log_error("Can't determine MG9098 Status\n");
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (status != 98) {
|
|
Packit |
7e09eb |
log_error("Not a MG9098\n");
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return 1;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
int _amd_ipmi_write(struct block_device *device, enum ibpi_pattern ibpi)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
int rc;
|
|
Packit |
7e09eb |
struct amd_drive drive;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
log_info("\n");
|
|
Packit |
7e09eb |
log_info("Setting %s...", ibpi2str(ibpi));
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = _get_amd_ipmi_drive(device->cntrl_path, &drive);
|
|
Packit |
7e09eb |
if (rc)
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if ((ibpi == IBPI_PATTERN_NORMAL) ||
|
|
Packit |
7e09eb |
(ibpi == IBPI_PATTERN_ONESHOT_NORMAL)) {
|
|
Packit |
7e09eb |
rc = _disable_all_ibpi_states(&drive);
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
if (ibpi == IBPI_PATTERN_LOCATE_OFF) {
|
|
Packit |
7e09eb |
rc = _disable_ibpi_state(&drive, IBPI_PATTERN_LOCATE);
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = _enable_smbus_control(&drive);
|
|
Packit |
7e09eb |
if (rc)
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
rc = _enable_ibpi_state(&drive, ibpi);
|
|
Packit |
7e09eb |
if (rc)
|
|
Packit |
7e09eb |
return rc;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return 0;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
char *_amd_ipmi_get_path(const char *cntrl_path, const char *sysfs_path)
|
|
Packit |
7e09eb |
{
|
|
Packit |
7e09eb |
char *p, *t;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* For NVMe devices we can just dup the path sysfs path */
|
|
Packit |
7e09eb |
p = strstr(cntrl_path, "nvme");
|
|
Packit |
7e09eb |
if (p)
|
|
Packit |
7e09eb |
return strdup(sysfs_path);
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* For SATA devices we need everything up to 'ataXX/' in the path */
|
|
Packit |
7e09eb |
p = strdup(cntrl_path);
|
|
Packit |
7e09eb |
if (!p)
|
|
Packit |
7e09eb |
return NULL;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Find the beginning of the ataXX piece of the path */
|
|
Packit |
7e09eb |
t = strstr(p, "ata");
|
|
Packit |
7e09eb |
if (!t)
|
|
Packit |
7e09eb |
return NULL;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
/* Move to the '/' after the ataXX piece of the path and terminate the
|
|
Packit |
7e09eb |
* string there.
|
|
Packit |
7e09eb |
*/
|
|
Packit |
7e09eb |
t = strchr(t, '/');
|
|
Packit |
7e09eb |
if (!t)
|
|
Packit |
7e09eb |
return NULL;
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
*++t = '\0';
|
|
Packit |
7e09eb |
|
|
Packit |
7e09eb |
return p;
|
|
Packit |
7e09eb |
}
|
|
Packit |
7e09eb |
|