2058 lines
66 KiB
C++
2058 lines
66 KiB
C++
|
|
#include "ipmi-oem.hpp"
|
|||
|
|
#include <algorithm>
|
|||
|
|
#include <cstdio>
|
|||
|
|
#include <fcntl.h>
|
|||
|
|
#include <linux/i2c.h>
|
|||
|
|
#include <phosphor-logging/lg2.hpp>
|
|||
|
|
#include <sys/ioctl.h>
|
|||
|
|
#include <unistd.h>
|
|||
|
|
#include <vector>
|
|||
|
|
#include <fstream>
|
|||
|
|
#include <unordered_map>
|
|||
|
|
#include <boost/container/flat_map.hpp>
|
|||
|
|
#include <filesystem>
|
|||
|
|
#include <iostream>
|
|||
|
|
#include <ctime>
|
|||
|
|
#include <iomanip>
|
|||
|
|
#include <nlohmann/json.hpp>
|
|||
|
|
#include <iostream>
|
|||
|
|
#include <string>
|
|||
|
|
#include <cstdint>
|
|||
|
|
#include <dirent.h>
|
|||
|
|
#include <cstring>
|
|||
|
|
#include <cerrno>
|
|||
|
|
|
|||
|
|
#include <xyz/openbmc_project/Software/Activation/server.hpp>
|
|||
|
|
#include <xyz/openbmc_project/Software/Version/server.hpp>
|
|||
|
|
#include <xyz/openbmc_project/State/BMC/server.hpp>
|
|||
|
|
|
|||
|
|
extern "C"
|
|||
|
|
{
|
|||
|
|
#include <i2c/smbus.h>
|
|||
|
|
#include <linux/i2c-dev.h>
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#define PSU0_ADDR 0x58
|
|||
|
|
#define PSU1_ADDR 0x59
|
|||
|
|
#define PSU_READ_ADC_CMD 0x8B
|
|||
|
|
#define PSU_WRITE_ADC_CMD 0x21
|
|||
|
|
#define PSU_ADC_VAL_MIN 0x1730
|
|||
|
|
#define PSU_ADC_VAL_MAX 0x199E
|
|||
|
|
|
|||
|
|
constexpr uint8_t COVER_CPLD_I2C_BUS = 7;
|
|||
|
|
constexpr uint8_t COVER_TMP468_I2C_SLAVE_ADDR = 0x90;
|
|||
|
|
constexpr uint8_t COVER_CPLD_I2C_SLAVE_ADDR = 0xf8;
|
|||
|
|
constexpr uint8_t COVER_OPEN_STATUS_REG = 0x0037;
|
|||
|
|
constexpr uint8_t COVER_OPEN_CONTROL_REG = 0x008e;
|
|||
|
|
constexpr uint8_t COVER_COMMAND_OPENED_STATUS = 0x01;
|
|||
|
|
constexpr uint8_t COVER_COMMAND_CLOSE_STATUS = 0x02;
|
|||
|
|
constexpr uint8_t COVER_COMMAND_UNCERTAIN_STATUS = 0x03;
|
|||
|
|
constexpr uint8_t COVER_REG_OPENED = 0x04;
|
|||
|
|
constexpr uint8_t COVER_REG_CLOSED = 0x05;
|
|||
|
|
constexpr uint8_t COVER_REG_UNCERTAIN_STATUS = 0x07;
|
|||
|
|
constexpr uint8_t MAX_CPU_ID_NUM = 2;
|
|||
|
|
constexpr uint8_t MAX_DIMM_RANK_NUM = 12;
|
|||
|
|
constexpr uint8_t GET_DIMM_TEMP_BUFF_SIZE = MAX_DIMM_RANK_NUM * 2;
|
|||
|
|
constexpr uint8_t maxRetries = 5;
|
|||
|
|
|
|||
|
|
//define for thermal oem command
|
|||
|
|
#define DIMM_SETPOINT_PATH "/tmp/dimm_setpoint"
|
|||
|
|
#define COVER_SETPOINT_PATH "/tmp/cover_setpoint"
|
|||
|
|
#define COVER_STATUS_PATH "/tmp/cover_status"
|
|||
|
|
#define FSC_CONTROL_MODE "/tmp/fsc_control_mode"
|
|||
|
|
#define FSC_ENABLE_STATUS_PATH "/tmp/fsc_enable"
|
|||
|
|
#define MAIN_BMC_BOOT_SOURCE "/sys/devices/platform/ahb/1e620000.spi/access_primary"
|
|||
|
|
#define BACKUP_BMC_BOOT_SOURCE "/sys/devices/platform/ahb/1e620000.spi/access_backup"
|
|||
|
|
|
|||
|
|
using namespace phosphor::logging;
|
|||
|
|
using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
|
|||
|
|
using Activation =
|
|||
|
|
sdbusplus::xyz::openbmc_project::Software::server::Activation;
|
|||
|
|
using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC;
|
|||
|
|
|
|||
|
|
constexpr static const char* softwareServiceName =
|
|||
|
|
"xyz.openbmc_project.Software.BMC.Updater";
|
|||
|
|
constexpr static const char* biosActiveObjectName =
|
|||
|
|
"/xyz/openbmc_project/software/bios_active";
|
|||
|
|
constexpr static const char* softwareVersionInterface =
|
|||
|
|
"xyz.openbmc_project.Software.Version";
|
|||
|
|
constexpr static const char* versionProperty = "Version";
|
|||
|
|
#define BIOSVERSIONLEN 32
|
|||
|
|
|
|||
|
|
constexpr auto DIMMTempSensorBusname = "xyz.openbmc_project.DIMMTempSensor";
|
|||
|
|
constexpr auto dimmLEDInterface = "xyz.openbmc_project.Sensor.dimmLED";
|
|||
|
|
constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
|
|||
|
|
constexpr auto dimmSpdReaderService = "xyz.openbmc_project.DimmSpdReader";
|
|||
|
|
constexpr auto tempInterface = "xyz.openbmc_project.Dimm.Temperature";
|
|||
|
|
constexpr auto voltInterface = "xyz.openbmc_project.Dimm.Voltage";
|
|||
|
|
constexpr auto curInterface = "xyz.openbmc_project.Dimm.Current";
|
|||
|
|
constexpr auto powInterface = "xyz.openbmc_project.Dimm.Power";
|
|||
|
|
constexpr auto dimmInfoPath = "/var/log/dimmInfo.json";
|
|||
|
|
constexpr auto HostMiscDbusName = "xyz.openbmc_project.Host.Misc.Manager";
|
|||
|
|
constexpr auto platformStatePath = "/xyz/openbmc_project/misc/platform_state";
|
|||
|
|
constexpr auto platformStateInterface = "xyz.openbmc_project.State.Host.Misc";
|
|||
|
|
|
|||
|
|
static const std::unordered_map<uint8_t, std::string> dimm_map = {
|
|||
|
|
{ 0x90, "DIMM_CPU0_A_Temp" },
|
|||
|
|
{ 0x92, "DIMM_CPU0_B_Temp" },
|
|||
|
|
{ 0x94, "DIMM_CPU0_C_Temp" },
|
|||
|
|
{ 0x96, "DIMM_CPU0_D_Temp" },
|
|||
|
|
{ 0x98, "DIMM_CPU0_E_Temp" },
|
|||
|
|
{ 0x9A, "DIMM_CPU0_F_Temp" },
|
|||
|
|
{ 0x9C, "DIMM_CPU0_G_Temp" },
|
|||
|
|
{ 0x9E, "DIMM_CPU0_H_Temp" },
|
|||
|
|
{ 0xA0, "DIMM_CPU0_I_Temp" },
|
|||
|
|
{ 0xA2, "DIMM_CPU0_J_Temp" },
|
|||
|
|
{ 0xA4, "DIMM_CPU0_K_Temp" },
|
|||
|
|
{ 0xA6, "DIMM_CPU0_L_Temp" },
|
|||
|
|
{ 0xB0, "DIMM_CPU1_A_Temp" },
|
|||
|
|
{ 0xB2, "DIMM_CPU1_B_Temp" },
|
|||
|
|
{ 0xB4, "DIMM_CPU1_C_Temp" },
|
|||
|
|
{ 0xB6, "DIMM_CPU1_D_Temp" },
|
|||
|
|
{ 0xB8, "DIMM_CPU1_E_Temp" },
|
|||
|
|
{ 0xBA, "DIMM_CPU1_F_Temp" },
|
|||
|
|
{ 0xBC, "DIMM_CPU1_G_Temp" },
|
|||
|
|
{ 0xBE, "DIMM_CPU1_H_Temp" },
|
|||
|
|
{ 0xC0, "DIMM_CPU1_I_Temp" },
|
|||
|
|
{ 0xC2, "DIMM_CPU1_J_Temp" },
|
|||
|
|
{ 0xC4, "DIMM_CPU1_K_Temp" },
|
|||
|
|
{ 0xC6, "DIMM_CPU1_L_Temp" }
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
static const std::unordered_map<uint8_t, std::string> dimm_state_map = {
|
|||
|
|
{ 0x0, "ON" },
|
|||
|
|
{ 0x1, "FAULT" },
|
|||
|
|
{ 0x2, "NA" }
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class DeviceType : uint8_t {
|
|||
|
|
MLB_BMC = 0,
|
|||
|
|
MLB_BIOS,
|
|||
|
|
MLB_CPLD,
|
|||
|
|
PSU,
|
|||
|
|
FPGA,
|
|||
|
|
ALL_BP_CPLD
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
enum class PSUInfoType : uint8_t {
|
|||
|
|
MFG_ID = 1,
|
|||
|
|
MFG_MODEL,
|
|||
|
|
MFG_REVISION,
|
|||
|
|
MFG_DATE,
|
|||
|
|
MFG_LOCATION,
|
|||
|
|
MFG_SERIAL,
|
|||
|
|
PART_NUM,
|
|||
|
|
SERIAL_NUM,
|
|||
|
|
FW_REVISION,
|
|||
|
|
MAX_POUT,
|
|||
|
|
INPUT_LOST,
|
|||
|
|
STATUS,
|
|||
|
|
POWER_UNIT_GROUP,
|
|||
|
|
LOCATION,
|
|||
|
|
HOT_REPLACEABLE,
|
|||
|
|
POWER_SUPPLY_TYPE,
|
|||
|
|
HEALTH,
|
|||
|
|
INPUT_VOLTAGE_RANGE_SWITCH
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
constexpr uint8_t administrator = 0x01;
|
|||
|
|
constexpr uint8_t user = 0x02;
|
|||
|
|
std::vector<uint8_t> adminPasswd = {0xff,administrator,0}; //Encrypted Password Length = 0
|
|||
|
|
std::vector<uint8_t> userPasswd = {0xff,user,0};
|
|||
|
|
|
|||
|
|
void register_ipmi_oem_functions() __attribute__((constructor));
|
|||
|
|
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>> GetDeviceFWVersion(ipmi::Context::ptr ctx,
|
|||
|
|
uint8_t deviceType) {
|
|||
|
|
uint8_t deviceCount = 1;
|
|||
|
|
std::string firstVersion{}, secondVersion{}, thirdVersion{};
|
|||
|
|
ipmi::ObjectTree objectTree;
|
|||
|
|
|
|||
|
|
std::vector<uint8_t> response{};
|
|||
|
|
auto purposeNeed = Version::VersionPurpose::BMC;
|
|||
|
|
|
|||
|
|
switch (static_cast<DeviceType>(deviceType)) {
|
|||
|
|
case DeviceType::MLB_BMC:
|
|||
|
|
break;
|
|||
|
|
case DeviceType::MLB_BIOS:
|
|||
|
|
purposeNeed = Version::VersionPurpose::Host;
|
|||
|
|
break;
|
|||
|
|
case DeviceType::MLB_CPLD:
|
|||
|
|
purposeNeed = Version::VersionPurpose::CPLD;
|
|||
|
|
break;
|
|||
|
|
case DeviceType::PSU:
|
|||
|
|
break;
|
|||
|
|
case DeviceType::FPGA:
|
|||
|
|
break;
|
|||
|
|
case DeviceType::ALL_BP_CPLD:
|
|||
|
|
purposeNeed = Version::VersionPurpose::FBCPLD;
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
objectTree =
|
|||
|
|
ipmi::getAllDbusObjects(*ctx->bus, "/xyz/openbmc_project/software",
|
|||
|
|
"xyz.openbmc_project.Software.ExtendedVersion");
|
|||
|
|
} catch (const sdbusplus::exception_t &e) {
|
|||
|
|
lg2::error("Failed to fetch redundancy object from dbus");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (auto &softObject : objectTree) {
|
|||
|
|
auto service = ipmi::getService(
|
|||
|
|
*ctx->bus, "xyz.openbmc_project.Software.ExtendedVersion",
|
|||
|
|
softObject.first);
|
|||
|
|
auto objValueTree = ipmi::getManagedObjects(
|
|||
|
|
*ctx->bus, service, "/xyz/openbmc_project/software");
|
|||
|
|
|
|||
|
|
for (const auto &objIter : objValueTree) {
|
|||
|
|
try {
|
|||
|
|
auto &intfMap = objIter.second;
|
|||
|
|
auto &versionProps = intfMap.at("xyz.openbmc_project.Software.Version");
|
|||
|
|
auto &activationProps =
|
|||
|
|
intfMap.at("xyz.openbmc_project.Software.Activation");
|
|||
|
|
auto purpose = std::get<std::string>(versionProps.at("Purpose"));
|
|||
|
|
auto activation =
|
|||
|
|
std::get<std::string>(activationProps.at("Activation"));
|
|||
|
|
auto version = std::get<std::string>(versionProps.at("Version"));
|
|||
|
|
if ((Version::convertVersionPurposeFromString(purpose) ==
|
|||
|
|
purposeNeed) &&
|
|||
|
|
(Activation::convertActivationsFromString(activation) ==
|
|||
|
|
Activation::Activations::Active)) {
|
|||
|
|
firstVersion = std::move(version);
|
|||
|
|
break; // Example to find primary version
|
|||
|
|
}
|
|||
|
|
} catch (const std::exception &e) {
|
|||
|
|
lg2::error(e.what());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
firstVersion.resize(16);
|
|||
|
|
secondVersion.resize(16);
|
|||
|
|
thirdVersion.resize(16);
|
|||
|
|
response.push_back(deviceCount);
|
|||
|
|
std::copy(firstVersion.begin(), firstVersion.end(),
|
|||
|
|
std::back_inserter(response));
|
|||
|
|
std::copy(secondVersion.begin(), secondVersion.end(),
|
|||
|
|
std::back_inserter(response));
|
|||
|
|
std::copy(thirdVersion.begin(), thirdVersion.end(),
|
|||
|
|
std::back_inserter(response));
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<> SetFanSpeedControlMode(std::vector<uint8_t> data) {
|
|||
|
|
std::vector<uint8_t> newArray(30);
|
|||
|
|
size_t i = 0;
|
|||
|
|
|
|||
|
|
if(data.size() < 1)
|
|||
|
|
{
|
|||
|
|
lg2::error("invalid request size");
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(data[0] > 2)
|
|||
|
|
{
|
|||
|
|
lg2::error("invalid fan control mode");
|
|||
|
|
return ipmi::responseInvalidFieldRequest();
|
|||
|
|
}
|
|||
|
|
else if(data[0] == FSC_FAN_TABLE_MANUAL)
|
|||
|
|
{
|
|||
|
|
/*request is manual mode */
|
|||
|
|
if(data.size() < 2)
|
|||
|
|
{
|
|||
|
|
lg2::error("invalid request size for manual mode");
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(data[1] != 0)
|
|||
|
|
{
|
|||
|
|
if(data[1] > 100)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseInvalidFieldRequest();
|
|||
|
|
}
|
|||
|
|
/*set all pwm to request manual pwm */
|
|||
|
|
for (i = 1; i < newArray.size(); ++i)
|
|||
|
|
{
|
|||
|
|
newArray[i] = data[1];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
if(data.size() != 31)
|
|||
|
|
{
|
|||
|
|
lg2::error("invalid request size for manual mode");
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
for (i = 1; i < data.size(); ++i)
|
|||
|
|
{
|
|||
|
|
if (data[i] > 100)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseInvalidFieldRequest();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
size_t startIndex = 2;
|
|||
|
|
for (i = 0; i < MAX_FSC_PWM_CHANNEL; ++i)
|
|||
|
|
{
|
|||
|
|
if (startIndex + i < data.size())
|
|||
|
|
{
|
|||
|
|
newArray[i + 1] = data[startIndex + i];
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
newArray[i + 1] = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
/*request is auto mode */
|
|||
|
|
for (i = 0; i < MAX_FSC_PWM_CHANNEL; ++i)
|
|||
|
|
{
|
|||
|
|
newArray[i + 1] = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
newArray[0] = data[0];
|
|||
|
|
std::ofstream outFile(FSC_CONTROL_MODE, std::ios::binary);
|
|||
|
|
if (!outFile) {
|
|||
|
|
lg2::error("Error opening file /tmp/fsc_control_mode");
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
outFile.write(reinterpret_cast<const char*>(newArray.data()), newArray.size());
|
|||
|
|
if (!outFile) {
|
|||
|
|
lg2::error("Error write file /tmp/fsc_control_mode");
|
|||
|
|
outFile.close();
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
outFile.close();
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>> GetFanSpeedControlMode() {
|
|||
|
|
std::vector<uint8_t> response(30);
|
|||
|
|
|
|||
|
|
if(!std::filesystem::exists(FSC_CONTROL_MODE))
|
|||
|
|
{
|
|||
|
|
lg2::error("Error write file /tmp/fsc_control_mode");
|
|||
|
|
response[0] = FSC_FAN_TABLE_AUTO;
|
|||
|
|
response.resize(1);
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::ifstream inputFile(FSC_CONTROL_MODE, std::ios::binary);
|
|||
|
|
|
|||
|
|
if (!inputFile)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inputFile.read(reinterpret_cast<char*>(response.data()), 30);
|
|||
|
|
if(inputFile.gcount() < 30)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
inputFile.close();
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<> SetBIOSPasswordConfig(std::vector<uint8_t> data) {
|
|||
|
|
|
|||
|
|
if(!(data[0] == 0x00 || data[0] == 0x01 || data[0] == 0xff))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Clear Passwd
|
|||
|
|
if(data[1] == administrator)
|
|||
|
|
{
|
|||
|
|
adminPasswd[0] = data[0];
|
|||
|
|
}
|
|||
|
|
else if(data[1] == user)
|
|||
|
|
{
|
|||
|
|
userPasswd[0] = data[0];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (data[0] == 0x01)
|
|||
|
|
{
|
|||
|
|
//todo set passwd
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>> GetBIOSPasswordConfig(std::vector<uint8_t> data) {
|
|||
|
|
std::vector<uint8_t> response(2);
|
|||
|
|
|
|||
|
|
if(!(data[0] == 0x01 || data[0] == 0x02))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (data[0] == administrator)
|
|||
|
|
{
|
|||
|
|
response.at(0) = adminPasswd[0];
|
|||
|
|
response.at(1) = adminPasswd[1];
|
|||
|
|
}
|
|||
|
|
else if (data[0] == user)
|
|||
|
|
{
|
|||
|
|
response.at(0) = userPasswd[0];
|
|||
|
|
response.at(1) = userPasswd[1];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>> GetPSUInfo(uint8_t psuIndex, uint8_t parameter) {
|
|||
|
|
uint8_t success = 0;
|
|||
|
|
psuIndex = psuIndex-1;
|
|||
|
|
std::string psuIndexStr = std::to_string(psuIndex);
|
|||
|
|
std::vector<uint8_t> response (34,0);
|
|||
|
|
constexpr auto PSU_INTERFACE = "xyz.openbmc_project.Configuration.Status";
|
|||
|
|
std::string PSU_PATH = "/xyz/openbmc_project/inventory/system/board/Lux_Baseboard/PSU"
|
|||
|
|
+ psuIndexStr + "_Supply";
|
|||
|
|
std::string PSU_PROP = "Vendor";
|
|||
|
|
std::string type = "string";
|
|||
|
|
std::string propertyValueTmp;
|
|||
|
|
double dpropertyValueTmp = 0;
|
|||
|
|
std::string psuInfo;
|
|||
|
|
PSUInfoType parmType = static_cast<PSUInfoType>(parameter);
|
|||
|
|
|
|||
|
|
switch (parmType) {
|
|||
|
|
case PSUInfoType::MFG_ID:
|
|||
|
|
PSU_PROP = "MFG_ID";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::MFG_MODEL:
|
|||
|
|
PSU_PROP = "MFG_MODEL";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::MFG_REVISION:
|
|||
|
|
PSU_PROP = "MFG_REVISION";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::MFG_DATE:
|
|||
|
|
PSU_PROP = "MFG_DATE";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::MFG_LOCATION:
|
|||
|
|
PSU_PROP = "MFG_LOCATION";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::MFG_SERIAL:
|
|||
|
|
PSU_PROP = "MFG_SERIAL";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::PART_NUM:
|
|||
|
|
PSU_PROP = "PART_NUM";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::SERIAL_NUM:
|
|||
|
|
PSU_PROP = "SERIAL_NUM";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::FW_REVISION:
|
|||
|
|
PSU_PROP = "FW_REVISION";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::MAX_POUT:
|
|||
|
|
PSU_PROP = "MAX_POUT";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::INPUT_LOST:
|
|||
|
|
PSU_PROP = "INPUT_LOST";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::STATUS:
|
|||
|
|
PSU_PROP = "Status";
|
|||
|
|
type = "double";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::POWER_UNIT_GROUP:
|
|||
|
|
PSU_PROP = "POWER_UNIT_GROUP";
|
|||
|
|
type = "double";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::LOCATION:
|
|||
|
|
PSU_PROP = "Name";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::HOT_REPLACEABLE:
|
|||
|
|
PSU_PROP = "HOT_REPLACEABLE";
|
|||
|
|
type = "double";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::POWER_SUPPLY_TYPE:
|
|||
|
|
PSU_PROP = "POWER_SUPPLY_TYPE";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::HEALTH:
|
|||
|
|
type = "null";
|
|||
|
|
break;
|
|||
|
|
case PSUInfoType::INPUT_VOLTAGE_RANGE_SWITCH:
|
|||
|
|
type = "null";
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Get dbus property value
|
|||
|
|
sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
|
|||
|
|
auto settingService = ipmi::getService(bus, PSU_INTERFACE, PSU_PATH.c_str());
|
|||
|
|
auto method = bus.new_method_call(settingService.c_str(), PSU_PATH.c_str(),
|
|||
|
|
"org.freedesktop.DBus.Properties", "Get");
|
|||
|
|
method.append(PSU_INTERFACE, PSU_PROP);
|
|||
|
|
|
|||
|
|
if(type == "string"){
|
|||
|
|
std::variant<std::string> propertyValue{};
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
auto reply = bus.call(method);
|
|||
|
|
reply.read(propertyValue);
|
|||
|
|
propertyValueTmp = std::get<std::string>(propertyValue);
|
|||
|
|
std::cerr << "PSU propertyValueTmp " << propertyValueTmp << "\n";
|
|||
|
|
}
|
|||
|
|
catch (const std::exception& e)
|
|||
|
|
{
|
|||
|
|
lg2::error("Error get PSU Info ");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if(type == "double")
|
|||
|
|
{
|
|||
|
|
std::variant<double> propertyValue{};
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
auto reply = bus.call(method);
|
|||
|
|
reply.read(propertyValue);
|
|||
|
|
dpropertyValueTmp = std::get<double>(propertyValue);
|
|||
|
|
std::cerr << "PSU dpropertyValueTmp " << static_cast<double>(dpropertyValueTmp) << "\n";
|
|||
|
|
}
|
|||
|
|
catch (const std::exception& e)
|
|||
|
|
{
|
|||
|
|
lg2::error("Error get PSU Info ");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Return PSU Info
|
|||
|
|
if(parmType == PSUInfoType::INPUT_LOST)
|
|||
|
|
{
|
|||
|
|
//INPUT_LOST:BIOS 0 = AC Input OK, 1 = AC Input Lost
|
|||
|
|
psuInfo = (propertyValueTmp == "1") ? "0" : "1";
|
|||
|
|
uint8_t acStatus = std::stoi(psuInfo, 0, 16);
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = sizeof(uint16_t);
|
|||
|
|
response.at(2) = acStatus;
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
else if(parmType == PSUInfoType::STATUS)
|
|||
|
|
{
|
|||
|
|
uint8_t status = 0;
|
|||
|
|
if(dpropertyValueTmp != 0 && dpropertyValueTmp != 32768 && dpropertyValueTmp != 32770) //psu status 0x8000 = 32768
|
|||
|
|
{
|
|||
|
|
status = 1;
|
|||
|
|
}
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = sizeof(uint16_t);
|
|||
|
|
response.at(2) = status;
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
else if(parmType == PSUInfoType::MAX_POUT)
|
|||
|
|
{
|
|||
|
|
if(propertyValueTmp == "INVALID")
|
|||
|
|
{
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = 2;
|
|||
|
|
response.at(2) = 0xFF; // 低字节 0xe8
|
|||
|
|
response.at(3) = 0xFF; // 高字节 0x0b
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
uint16_t maxPout = std::stoi(propertyValueTmp, 0, 10); // 0x0be8
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = sizeof(maxPout);
|
|||
|
|
response.at(2) = static_cast<uint8_t>(maxPout & 0xFF); // 低字节 0xe8
|
|||
|
|
response.at(3) = static_cast<uint8_t>((maxPout >> 8) & 0xFF); // 高字节 0x0b
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
else if(parmType == PSUInfoType::POWER_UNIT_GROUP || parmType == PSUInfoType::HOT_REPLACEABLE)
|
|||
|
|
{
|
|||
|
|
int valueTemp = static_cast<uint8_t>(dpropertyValueTmp);
|
|||
|
|
int8_t value = static_cast<int8_t>(valueTemp);
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = sizeof(uint16_t); //bios request uint16_t
|
|||
|
|
response.at(2) = value;
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
else if(parmType == PSUInfoType::POWER_SUPPLY_TYPE)
|
|||
|
|
{
|
|||
|
|
int8_t value = 1;
|
|||
|
|
if(propertyValueTmp == "switching")
|
|||
|
|
{
|
|||
|
|
value = 4;
|
|||
|
|
}
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = sizeof(uint16_t); //bios request
|
|||
|
|
response.at(2) = value;
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
else if(parmType == PSUInfoType::HEALTH)
|
|||
|
|
{
|
|||
|
|
uint8_t health = 3; // 3 = OK
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = sizeof(uint16_t);
|
|||
|
|
response.at(2) = health;
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
else if(parmType == PSUInfoType::INPUT_VOLTAGE_RANGE_SWITCH)
|
|||
|
|
{
|
|||
|
|
uint8_t status = 4; // 4 = Auto-switch
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = sizeof(uint16_t);
|
|||
|
|
response.at(2) = status;
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
psuInfo = std::move(propertyValueTmp);
|
|||
|
|
if(parmType == PSUInfoType::LOCATION)
|
|||
|
|
{
|
|||
|
|
psuInfo = psuInfo.substr(0,4); // PSU0
|
|||
|
|
}
|
|||
|
|
else if(parmType == PSUInfoType::FW_REVISION)
|
|||
|
|
{
|
|||
|
|
psuInfo = psuInfo.substr(0,8); // 00.01.02
|
|||
|
|
}
|
|||
|
|
response.at(0) = success;
|
|||
|
|
response.at(1) = psuInfo.size();
|
|||
|
|
std::copy_n(psuInfo.c_str(), psuInfo.size(),
|
|||
|
|
response.begin() + 2);
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<int32_t> Get12VPSUADCValue(uint8_t psuNum)
|
|||
|
|
{
|
|||
|
|
std::string i2cDev = "/dev/i2c-7";
|
|||
|
|
int fd = -1;
|
|||
|
|
uint8_t addr;
|
|||
|
|
fd = open(i2cDev.c_str(), O_RDWR | O_CLOEXEC);
|
|||
|
|
if (fd < 0)
|
|||
|
|
{
|
|||
|
|
close(fd);
|
|||
|
|
throw std::runtime_error("Unable to open i2c device.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(psuNum == 0) addr = PSU0_ADDR;
|
|||
|
|
else if(psuNum == 1) addr = PSU1_ADDR;
|
|||
|
|
else {
|
|||
|
|
close(fd);
|
|||
|
|
throw std::runtime_error("Invalid PSU Number, range 0 ~ 1.");
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (ioctl(fd, I2C_SLAVE_FORCE, addr) < 0)
|
|||
|
|
{
|
|||
|
|
close(fd);
|
|||
|
|
fd = -1;
|
|||
|
|
throw std::runtime_error("Unable to set i2c slave address.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int32_t val = i2c_smbus_read_word_data(fd, PSU_READ_ADC_CMD);
|
|||
|
|
if (val < 0)
|
|||
|
|
{
|
|||
|
|
close(fd);
|
|||
|
|
fd = -1;
|
|||
|
|
throw std::runtime_error("i2c read failed");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(val);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<> Set12VPSUADCValue(uint8_t psuNum, uint16_t val)
|
|||
|
|
{
|
|||
|
|
std::string i2cDev = "/dev/i2c-7";
|
|||
|
|
int fd = -1;
|
|||
|
|
uint8_t addr;
|
|||
|
|
fd = open(i2cDev.c_str(), O_RDWR | O_CLOEXEC);
|
|||
|
|
if (fd < 0)
|
|||
|
|
{
|
|||
|
|
close(fd);
|
|||
|
|
throw std::runtime_error("Unable to open i2c device.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(psuNum == 0) addr = PSU0_ADDR;
|
|||
|
|
else if(psuNum == 1) addr = PSU1_ADDR;
|
|||
|
|
else {
|
|||
|
|
close(fd);
|
|||
|
|
throw std::runtime_error("PSU Number is out of range: 0 ~ 1.");
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(val < PSU_ADC_VAL_MIN || val > PSU_ADC_VAL_MAX)
|
|||
|
|
{
|
|||
|
|
close(fd);
|
|||
|
|
throw std::runtime_error("ADC Value is out of range: 0x1730 ~ 0x199E.");
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (ioctl(fd, I2C_SLAVE_FORCE, addr) < 0)
|
|||
|
|
{
|
|||
|
|
close(fd);
|
|||
|
|
fd = -1;
|
|||
|
|
throw std::runtime_error("Unable to set i2c slave address.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int32_t ret = i2c_smbus_write_word_data(fd, PSU_WRITE_ADC_CMD, val);
|
|||
|
|
if (ret < 0)
|
|||
|
|
{
|
|||
|
|
close(fd);
|
|||
|
|
fd = -1;
|
|||
|
|
throw std::runtime_error("i2c write failed");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
double combineToDouble(uint8_t tempInteger, uint8_t tempDecimal) {
|
|||
|
|
int exponent = 0;
|
|||
|
|
int decimal = tempDecimal;
|
|||
|
|
while (decimal > 0) {
|
|||
|
|
decimal /= 10;
|
|||
|
|
exponent++;
|
|||
|
|
}
|
|||
|
|
double doubleValue = tempInteger + static_cast<double>(tempDecimal) / pow(10, exponent);
|
|||
|
|
return doubleValue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> GetDIMMTemperatureValue(std::vector<uint8_t> Data) {
|
|||
|
|
uint8_t response = 0;
|
|||
|
|
constexpr auto service = "xyz.openbmc_project.DIMMTempSensor";
|
|||
|
|
constexpr auto dbusProperties = "org.freedesktop.DBus.Properties";
|
|||
|
|
constexpr auto statusInterface = "xyz.openbmc_project.Sensor.Value";
|
|||
|
|
char sensorPath[128];
|
|||
|
|
|
|||
|
|
//BIOS sends 128 byte of data ,Remove the first eight useless bytes
|
|||
|
|
if(Data.size() != 128)
|
|||
|
|
{
|
|||
|
|
std::cout << "BIOS raw data size :" << Data.size() << "\n";
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//struct array
|
|||
|
|
Data.erase(Data.begin(), Data.begin() + 8);
|
|||
|
|
const size_t structCount = Data.size() / sizeof(memory_info_t);
|
|||
|
|
if (Data.size() != structCount * sizeof(memory_info_t)) {
|
|||
|
|
std::cout << "Data size :" << Data.size() << "\n";
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
memory_info_t memoryArray[structCount];
|
|||
|
|
std::memcpy(memoryArray, Data.data(), structCount * sizeof(memory_info_t));
|
|||
|
|
|
|||
|
|
//Map path and temperature
|
|||
|
|
std::map<std::string, int> DIMMTempMap;
|
|||
|
|
double DIMMTemp;
|
|||
|
|
int dimmNum = 0;
|
|||
|
|
for (int socketId = 0; socketId < 2; socketId++) {
|
|||
|
|
for (int channelId = 0; channelId < 12; channelId++) {
|
|||
|
|
int num = 65 + channelId;
|
|||
|
|
char channel = static_cast<char>(num);
|
|||
|
|
snprintf(sensorPath, sizeof(sensorPath),
|
|||
|
|
"/xyz/openbmc_project/sensors/temperature/DIMM_CPU%d_%c_Temp", socketId,channel);
|
|||
|
|
DIMMTemp = combineToDouble(memoryArray[dimmNum].temp_integer,
|
|||
|
|
memoryArray[dimmNum].temp_decimal);
|
|||
|
|
dimmNum++;
|
|||
|
|
DIMMTempMap[sensorPath] = DIMMTemp;
|
|||
|
|
printf("Formatted string: %s ;", sensorPath);
|
|||
|
|
printf("Socket:%d,Channel:%d,temperature%f°C\n",socketId,channelId, DIMMTemp);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Set DIMM temperature to dbus
|
|||
|
|
for (const auto& iter : DIMMTempMap) {
|
|||
|
|
double DIMMTempValue = static_cast<double>(iter.second);
|
|||
|
|
std::variant<double> value{(double)DIMMTempValue};
|
|||
|
|
auto bus = sdbusplus::bus::new_default();
|
|||
|
|
std::string path = iter.first;
|
|||
|
|
auto method = bus.new_method_call(service, path.c_str(),dbusProperties, "Set");
|
|||
|
|
method.append(statusInterface, "Value", value);
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
bus.call_noreply(method);
|
|||
|
|
}
|
|||
|
|
catch (const sdbusplus::exception::exception& e)
|
|||
|
|
{
|
|||
|
|
lg2::info("Error setting DIMM sensor Temp, ERROR = {ERROR}",
|
|||
|
|
"ERROR", e);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(response);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool i2cReadWriteNative(uint8_t bus, uint8_t slaveAddr,
|
|||
|
|
std::vector<uint8_t> writeData,
|
|||
|
|
std::vector<uint8_t> &readData, uint8_t readCount) {
|
|||
|
|
if (writeData.empty() && readCount == 0) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
std::string busPath = "/dev/i2c-" + std::to_string(bus);
|
|||
|
|
int fd = open(busPath.c_str(), O_RDWR);
|
|||
|
|
if (fd < 0) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
struct i2c_msg messages[2];
|
|||
|
|
struct i2c_rdwr_ioctl_data ioctl_data;
|
|||
|
|
if (!writeData.empty()) {
|
|||
|
|
messages[0].addr = slaveAddr;
|
|||
|
|
messages[0].flags = 0;
|
|||
|
|
messages[0].len = writeData.size();
|
|||
|
|
messages[0].buf = writeData.data();
|
|||
|
|
}
|
|||
|
|
if (readCount > 0) {
|
|||
|
|
messages[1].addr = slaveAddr;
|
|||
|
|
messages[1].flags = I2C_M_RD;
|
|||
|
|
messages[1].len = readCount;
|
|||
|
|
messages[1].buf = new uint8_t[readCount];
|
|||
|
|
}
|
|||
|
|
ioctl_data.msgs = messages;
|
|||
|
|
ioctl_data.nmsgs = (writeData.empty() ? 0 : 1) + (readCount > 0 ? 1 : 0);
|
|||
|
|
if (ioctl(fd, I2C_RDWR, &ioctl_data) < 0) {
|
|||
|
|
if (readCount > 0)
|
|||
|
|
delete[] messages[1].buf;
|
|||
|
|
close(fd);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
if (readCount > 0) {
|
|||
|
|
readData.assign(static_cast<uint8_t *>(messages[1].buf),
|
|||
|
|
static_cast<uint8_t *>(messages[1].buf) + readCount);
|
|||
|
|
delete[] messages[1].buf;
|
|||
|
|
}
|
|||
|
|
close(fd);
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>>
|
|||
|
|
ipmiOemI2cReadWrite(uint8_t bus, uint8_t address, uint8_t readCount,
|
|||
|
|
std::vector<uint8_t> writeData) {
|
|||
|
|
std::vector<uint8_t> response(readCount);
|
|||
|
|
if (i2cReadWriteNative(bus, address >> 1, writeData, response, readCount))
|
|||
|
|
return ipmi::responseSuccess(std::move(response));
|
|||
|
|
return ipmi::responseDestinationUnavailable();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemSetDIMMSetPoint(uint8_t dimmSetPoint)
|
|||
|
|
{
|
|||
|
|
uint8_t RspStatus = 0x00;
|
|||
|
|
if(dimmSetPoint > 120)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(dimmSetPoint <= 40)
|
|||
|
|
{
|
|||
|
|
dimmSetPoint = 40;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
dimmSetPoint = 74;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::ofstream outFile(DIMM_SETPOINT_PATH, std::ios::out | std::ios::trunc);
|
|||
|
|
if (!outFile)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
outFile << static_cast<int>(dimmSetPoint);
|
|||
|
|
outFile.close();
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(RspStatus);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemGetDIMMSetPoint()
|
|||
|
|
{
|
|||
|
|
std::ifstream inFile(DIMM_SETPOINT_PATH);
|
|||
|
|
if (!inFile)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string value;
|
|||
|
|
inFile >> value;
|
|||
|
|
|
|||
|
|
if (value.empty() || !std::all_of(value.begin(), value.end(), ::isdigit))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint8_t dimmSetPoint = static_cast<uint8_t>(std::stoi(value));
|
|||
|
|
inFile.close();
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(dimmSetPoint);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemSetCoverStatus(uint8_t coverStatus)
|
|||
|
|
{
|
|||
|
|
uint8_t readCount = 1;
|
|||
|
|
std::vector<uint8_t> response(readCount);
|
|||
|
|
std::vector<uint8_t> writeData(3);
|
|||
|
|
uint8_t RspStatus = 0x00;
|
|||
|
|
|
|||
|
|
if((coverStatus != COVER_COMMAND_OPENED_STATUS) && (coverStatus != COVER_COMMAND_CLOSE_STATUS))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseInvalidFieldRequest();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
writeData[0] = (COVER_OPEN_CONTROL_REG & 0x00ff);
|
|||
|
|
writeData[1] = (COVER_OPEN_CONTROL_REG & 0xff00) >>8;
|
|||
|
|
if(COVER_COMMAND_OPENED_STATUS == coverStatus)
|
|||
|
|
{
|
|||
|
|
writeData[2] = 0x02;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
writeData[2] = 0x01;
|
|||
|
|
}
|
|||
|
|
if(i2cReadWriteNative(COVER_CPLD_I2C_BUS, COVER_CPLD_I2C_SLAVE_ADDR >> 1, writeData, response, readCount))
|
|||
|
|
{
|
|||
|
|
writeData[2] = 0x00;
|
|||
|
|
/*After open or close cover, need write reg to 0x00 */
|
|||
|
|
i2cReadWriteNative(COVER_CPLD_I2C_BUS, COVER_CPLD_I2C_SLAVE_ADDR >> 1, writeData, response, readCount);
|
|||
|
|
return ipmi::responseSuccess(RspStatus);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemGetCoverStatus()
|
|||
|
|
{
|
|||
|
|
uint8_t readCount = 1;
|
|||
|
|
std::vector<uint8_t> response(readCount);
|
|||
|
|
std::vector<uint8_t> writeData(2);
|
|||
|
|
uint8_t coverStatus;
|
|||
|
|
|
|||
|
|
writeData[0] = (COVER_OPEN_STATUS_REG & 0x00ff);
|
|||
|
|
writeData[1] = (COVER_OPEN_STATUS_REG & 0xff00) >>8;
|
|||
|
|
if(i2cReadWriteNative(COVER_CPLD_I2C_BUS, COVER_CPLD_I2C_SLAVE_ADDR >> 1, writeData, response, readCount))
|
|||
|
|
{
|
|||
|
|
coverStatus = response[0] & 0x07;
|
|||
|
|
if(COVER_REG_OPENED == coverStatus)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseSuccess(COVER_COMMAND_OPENED_STATUS);
|
|||
|
|
}
|
|||
|
|
else if(COVER_REG_CLOSED == coverStatus)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseSuccess(COVER_COMMAND_CLOSE_STATUS);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
return ipmi::responseSuccess(COVER_COMMAND_UNCERTAIN_STATUS);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemSetCoverHeatTemp(uint8_t coverTemp)
|
|||
|
|
{
|
|||
|
|
uint8_t RspStatus = 0x00;
|
|||
|
|
if(coverTemp > 80)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::ofstream outFile(COVER_SETPOINT_PATH, std::ios::out | std::ios::trunc);
|
|||
|
|
if (!outFile)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
outFile << static_cast<int>(coverTemp);
|
|||
|
|
outFile.close();
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(RspStatus);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemGetCoverHeatTemp()
|
|||
|
|
{
|
|||
|
|
std::ifstream inFile(COVER_SETPOINT_PATH);
|
|||
|
|
if (!inFile)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string value;
|
|||
|
|
inFile >> value;
|
|||
|
|
|
|||
|
|
if (value.empty() || !std::all_of(value.begin(), value.end(), ::isdigit))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint8_t coverTemp = static_cast<uint8_t>(std::stoi(value));
|
|||
|
|
inFile.close();
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(coverTemp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemGetCurrentCoverTemp()
|
|||
|
|
{
|
|||
|
|
std::vector<uint8_t> writeData(1);
|
|||
|
|
std::vector<uint8_t> readData(2);
|
|||
|
|
uint8_t readtemp;
|
|||
|
|
uint8_t maxtemp;
|
|||
|
|
uint8_t readCount = 2;
|
|||
|
|
uint8_t sensorindex = 0;
|
|||
|
|
|
|||
|
|
for(sensorindex = 0; sensorindex < 4; sensorindex++)
|
|||
|
|
{
|
|||
|
|
writeData[0] = sensorindex + 1; //TMP468 sensor channel is from 1 to 5
|
|||
|
|
if(i2cReadWriteNative(COVER_CPLD_I2C_BUS, COVER_TMP468_I2C_SLAVE_ADDR >> 1, writeData, readData, readCount))
|
|||
|
|
{
|
|||
|
|
if((readData[0] & 0x80) == 0)
|
|||
|
|
{
|
|||
|
|
readtemp = (uint8_t)((((uint16_t)((readData[0] << 8) + readData[1])) >> 3) * 0.0625);
|
|||
|
|
if(maxtemp < readtemp)
|
|||
|
|
{
|
|||
|
|
maxtemp = readtemp;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(maxtemp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemSetCoverFSCEnableStatus(uint8_t fscStatus)
|
|||
|
|
{
|
|||
|
|
uint8_t RspStatus = 0x00;
|
|||
|
|
if(fscStatus > 1)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::ofstream outFile(FSC_ENABLE_STATUS_PATH, std::ios::out | std::ios::trunc);
|
|||
|
|
if (!outFile)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
outFile << static_cast<int>(fscStatus);
|
|||
|
|
outFile.close();
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(RspStatus);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiOemGetCoverFSCEnableStatus()
|
|||
|
|
{
|
|||
|
|
uint8_t fscStatus;
|
|||
|
|
if(!std::filesystem::exists(FSC_ENABLE_STATUS_PATH))
|
|||
|
|
{
|
|||
|
|
fscStatus = 0;
|
|||
|
|
return ipmi::responseSuccess(fscStatus);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::ifstream inFile(FSC_ENABLE_STATUS_PATH);
|
|||
|
|
if (!inFile)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseBusy();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string value;
|
|||
|
|
inFile >> value;
|
|||
|
|
|
|||
|
|
if (value.empty() || !std::all_of(value.begin(), value.end(), ::isdigit))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fscStatus = static_cast<uint8_t>(std::stoi(value));
|
|||
|
|
inFile.close();
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(fscStatus);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>>
|
|||
|
|
ipmiSetGetBiosVersion(const ipmi::Context::ptr& ctx, uint8_t operation,
|
|||
|
|
std::vector<uint8_t> dataToWrite)
|
|||
|
|
{
|
|||
|
|
std::vector<uint8_t> biosVerData;
|
|||
|
|
boost::system::error_code ec;
|
|||
|
|
|
|||
|
|
if ((operation != 0) && (operation != 1))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseInvalidFieldRequest();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (operation == 1) // set bios version
|
|||
|
|
{
|
|||
|
|
auto len = dataToWrite.size();
|
|||
|
|
if ((BIOSVERSIONLEN < len) || (0 == len))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseReqDataLenExceeded();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string writeString;
|
|||
|
|
writeString.assign(dataToWrite.begin(), dataToWrite.end());
|
|||
|
|
|
|||
|
|
ec = ipmi::setDbusProperty(
|
|||
|
|
ctx, softwareServiceName, biosActiveObjectName,
|
|||
|
|
softwareVersionInterface, versionProperty, writeString);
|
|||
|
|
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
lg2::error("Failed in setting bios version property: {EC}", "EC",
|
|||
|
|
ec.message());
|
|||
|
|
return ipmi::responseResponseError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
// get bios version
|
|||
|
|
std::string biosVer;
|
|||
|
|
ec = ipmi::getDbusProperty(ctx, softwareServiceName, biosActiveObjectName,
|
|||
|
|
softwareVersionInterface, versionProperty,
|
|||
|
|
biosVer);
|
|||
|
|
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
lg2::error("Failed in getting bios version property: {EC}", "EC",
|
|||
|
|
ec.message());
|
|||
|
|
return ipmi::responseResponseError();
|
|||
|
|
}
|
|||
|
|
biosVerData.assign(biosVer.begin(), biosVer.end());
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(biosVerData);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool factoryReset(const ipmi::Context::ptr& ctx)
|
|||
|
|
{
|
|||
|
|
constexpr auto softwareServiceName =
|
|||
|
|
"xyz.openbmc_project.Software.BMC.Updater";
|
|||
|
|
constexpr auto softwareRoot = "/xyz/openbmc_project/software";
|
|||
|
|
constexpr auto factoryResetInterface =
|
|||
|
|
"xyz.openbmc_project.Common.FactoryReset";
|
|||
|
|
constexpr auto method = "Reset";
|
|||
|
|
|
|||
|
|
boost::system::error_code ec;
|
|||
|
|
|
|||
|
|
ctx->bus->yield_method_call(ctx->yield, ec, softwareServiceName,
|
|||
|
|
softwareRoot, factoryResetInterface, method);
|
|||
|
|
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
lg2::error("Error resetting BMC: {ERROR}", "ERROR", ec.message());
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static bool resetBmc()
|
|||
|
|
{
|
|||
|
|
/* systemd busname*/
|
|||
|
|
auto systemdBusname = "org.freedesktop.systemd1";
|
|||
|
|
/* systemd path*/
|
|||
|
|
auto systemdPath = "/org/freedesktop/systemd1";
|
|||
|
|
/* systemd interface*/
|
|||
|
|
auto systemdInterface = "org.freedesktop.systemd1.Manager";
|
|||
|
|
auto bus = getSdBus();
|
|||
|
|
auto method = bus->new_method_call(systemdBusname, systemdPath,
|
|||
|
|
systemdInterface, "StartUnit");
|
|||
|
|
method.append("obmc-reboot-delay.service", "replace");
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
bus->call_noreply(method);
|
|||
|
|
}
|
|||
|
|
catch (const std::exception& e)
|
|||
|
|
{
|
|||
|
|
lg2::error("Error reboot failed {ERROR}", "ERROR", e);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<> ipmiOemRestoreFactoryDefault(const ipmi::Context::ptr& ctx)
|
|||
|
|
{
|
|||
|
|
if (!factoryReset(ctx))
|
|||
|
|
{
|
|||
|
|
lg2::error("Restore factory default error.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!resetBmc())
|
|||
|
|
{
|
|||
|
|
lg2::error("Restore factory default reset bmc fail.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lg2::info("Restore factory default success.");
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static void setDimmLEDState(const std::string& sensorPath,const std::string& ledState)
|
|||
|
|
{
|
|||
|
|
auto bus = sdbusplus::bus::new_default();
|
|||
|
|
auto method = bus.new_method_call(DIMMTempSensorBusname, sensorPath.c_str(),
|
|||
|
|
dbusProperties, "Set");
|
|||
|
|
|
|||
|
|
std::variant<std::string> value{ledState};
|
|||
|
|
method.append(dimmLEDInterface, "LEDState", value);
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
bus.call_noreply(method);
|
|||
|
|
}
|
|||
|
|
catch (const sdbusplus::exception::exception& e)
|
|||
|
|
{
|
|||
|
|
lg2::info("Error setting Dimm LED State, ERROR = {ERROR}",
|
|||
|
|
"ERROR", e);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiBiosSetDimmState(std::vector<uint8_t> data) {
|
|||
|
|
|
|||
|
|
//BIOS sends 128 byte of data ,Remove the first eight useless bytes
|
|||
|
|
if(data.size() != 2)
|
|||
|
|
{
|
|||
|
|
std::cerr << "invalid data size :" << (int)data.size() << "\n";
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(dimm_map.find(data[0]) == dimm_map.end())
|
|||
|
|
{
|
|||
|
|
std::cerr << "invalid sensor number :" << (int)data[0] << "\n";
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(data[1] > 2)
|
|||
|
|
{
|
|||
|
|
std::cerr << "invalid dimm sensor " << (int)data[0] << " with state " << (int)data[1] << ".\n";
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string ledStatePath = "/xyz/openbmc_project/sensors/temperature/" + dimm_map.at(data[0]);
|
|||
|
|
std::string dimmState = dimm_state_map.at(data[1]);
|
|||
|
|
|
|||
|
|
setDimmLEDState(ledStatePath, dimmState);
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t>
|
|||
|
|
ipmiOemSetSOLBitrate(const ipmi::Context::ptr& ctx, uint8_t bitrate)
|
|||
|
|
{
|
|||
|
|
uint64_t baudRate = 115200;
|
|||
|
|
boost::system::error_code ec;
|
|||
|
|
|
|||
|
|
if ((bitrate != 0) && (bitrate != 1))
|
|||
|
|
{
|
|||
|
|
return ipmi::responseInvalidFieldRequest();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (bitrate == 0)
|
|||
|
|
{
|
|||
|
|
baudRate = 115200;
|
|||
|
|
}
|
|||
|
|
else if(bitrate == 1)
|
|||
|
|
{
|
|||
|
|
baudRate = 921600;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ec = ipmi::setDbusProperty(ctx,
|
|||
|
|
"xyz.openbmc_project.Console.default",
|
|||
|
|
"/xyz/openbmc_project/console/default",
|
|||
|
|
"xyz.openbmc_project.Console.UART", "NonVbitrate", baudRate);
|
|||
|
|
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
lg2::error("Failed in setting oem sol bitrate property: {EC}", "EC",
|
|||
|
|
ec.message());
|
|||
|
|
return ipmi::responseResponseError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
using BasicVariantType =
|
|||
|
|
std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
|
|||
|
|
int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
|
|||
|
|
uint16_t, uint8_t, bool>;
|
|||
|
|
using PropertyMapType =
|
|||
|
|
boost::container::flat_map<std::string, BasicVariantType>;
|
|||
|
|
int setDimmParaToDbus(ipmi::Context::ptr ctx, const std::string& dimmName, const std::string& type, const std::string& propertyName, double wrValue)
|
|||
|
|
{
|
|||
|
|
boost::system::error_code ec;
|
|||
|
|
std::string path = "/xyz/openbmc_project/dimm/" + dimmName;
|
|||
|
|
std::string interface = "xyz.openbmc_project.Dimm." + type;
|
|||
|
|
|
|||
|
|
ctx->bus->yield_method_call<void>(
|
|||
|
|
ctx->yield, ec, dimmSpdReaderService, path, dbusProperties, "Set",
|
|||
|
|
interface, propertyName, std::variant<double>(wrValue));
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
std::cerr << "Setting DIMM " << dimmName << " " << type << " " << propertyName << " failed. \n";
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline double dimmTempTodouble(int8_t intPart, uint8_t fracPart) {
|
|||
|
|
double temp;
|
|||
|
|
if (intPart & 0x80) {
|
|||
|
|
temp = -1.0 * (std::fabs(intPart) + fracPart / 100.0);
|
|||
|
|
} else {
|
|||
|
|
temp = intPart + fracPart / 100.0;
|
|||
|
|
}
|
|||
|
|
return temp;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiBiosSetDimmPara(ipmi::Context::ptr ctx, std::vector<uint8_t> data) {
|
|||
|
|
|
|||
|
|
size_t size = sizeof(oem_dimm_info_t);
|
|||
|
|
if(data.size() != size)
|
|||
|
|
{
|
|||
|
|
std::cerr << "invalid data size :" << (int)data.size() << "\n";
|
|||
|
|
return ipmi::responseReqDataLenInvalid();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::vector<std::string> tempName = {"TS0", "TS1", "SPD_TS"};
|
|||
|
|
std::vector<std::string> railName = {"SWA", "SWB", "SWC", "SWD", "SWE", "SWF"};
|
|||
|
|
oem_dimm_info_t dimmInfo;
|
|||
|
|
std::memcpy(&dimmInfo, data.data(), size);
|
|||
|
|
int ret = -1;
|
|||
|
|
|
|||
|
|
//dimmId format: ((Socket << 6) | (Channel << 2) | Dimm)
|
|||
|
|
int channel = (dimmInfo.dimmId >> 2) & 0x0f;
|
|||
|
|
int cpuid = (dimmInfo.dimmId >> 6) & 0x03;
|
|||
|
|
|
|||
|
|
if(cpuid > 1 || channel > 11)
|
|||
|
|
{
|
|||
|
|
std::cerr << "invalid dimmid :" << (int)dimmInfo.dimmId << "\n";
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::string dimmName = "DIMM_CPU" + std::string(1, '0' + cpuid) + "_" + std::string(1, 'A' + channel);
|
|||
|
|
|
|||
|
|
//Set temperature
|
|||
|
|
double temp[3];
|
|||
|
|
temp[0] = dimmTempTodouble(dimmInfo.dimmTemp.TS0_int, dimmInfo.dimmTemp.TS0_frac);
|
|||
|
|
temp[1] = dimmTempTodouble(dimmInfo.dimmTemp.TS1_int, dimmInfo.dimmTemp.TS1_frac);
|
|||
|
|
temp[2] = dimmTempTodouble(dimmInfo.dimmTemp.SPD_int, dimmInfo.dimmTemp.SPD_frac);
|
|||
|
|
for(int i=0; i<3; i++) {
|
|||
|
|
ret = setDimmParaToDbus(ctx, dimmName, "Temperature", tempName[i], temp[i]);
|
|||
|
|
if(ret < 0)
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Set voltage
|
|||
|
|
double railData[6];
|
|||
|
|
railData[0] = static_cast<double>(dimmInfo.dimmVolt.SWA) / 1000.0;
|
|||
|
|
railData[1] = static_cast<double>(dimmInfo.dimmVolt.SWB) / 1000.0;
|
|||
|
|
railData[2] = static_cast<double>(dimmInfo.dimmVolt.SWC) / 1000.0;
|
|||
|
|
railData[3] = static_cast<double>(dimmInfo.dimmVolt.SWD) / 1000.0;
|
|||
|
|
railData[4] = static_cast<double>(dimmInfo.dimmVolt.SWE) / 1000.0;
|
|||
|
|
railData[5] = static_cast<double>(dimmInfo.dimmVolt.SWF) / 1000.0;
|
|||
|
|
for(int i=0; i<6; i++) {
|
|||
|
|
ret = setDimmParaToDbus(ctx, dimmName, "Voltage", railName[i], railData[i]);
|
|||
|
|
if(ret < 0)
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Set Current
|
|||
|
|
railData[0] = static_cast<double>(dimmInfo.dimmCur.SWA) / 1000.0;
|
|||
|
|
railData[1] = static_cast<double>(dimmInfo.dimmCur.SWB) / 1000.0;
|
|||
|
|
railData[2] = static_cast<double>(dimmInfo.dimmCur.SWC) / 1000.0;
|
|||
|
|
railData[3] = static_cast<double>(dimmInfo.dimmCur.SWD) / 1000.0;
|
|||
|
|
railData[4] = static_cast<double>(dimmInfo.dimmCur.SWE) / 1000.0;
|
|||
|
|
railData[5] = static_cast<double>(dimmInfo.dimmCur.SWF) / 1000.0;
|
|||
|
|
for(int i=0; i<4; i++) {
|
|||
|
|
ret = setDimmParaToDbus(ctx, dimmName, "Current", railName[i], railData[i]);
|
|||
|
|
if(ret < 0)
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Set power
|
|||
|
|
railData[0] = static_cast<double>(dimmInfo.dimmPow.SWA) / 1000.0;
|
|||
|
|
railData[1] = static_cast<double>(dimmInfo.dimmPow.SWB) / 1000.0;
|
|||
|
|
railData[2] = static_cast<double>(dimmInfo.dimmPow.SWC) / 1000.0;
|
|||
|
|
railData[3] = static_cast<double>(dimmInfo.dimmPow.SWD) / 1000.0;
|
|||
|
|
railData[4] = static_cast<double>(dimmInfo.dimmPow.SWE) / 1000.0;
|
|||
|
|
railData[5] = static_cast<double>(dimmInfo.dimmPow.SWF) / 1000.0;
|
|||
|
|
for(int i=0; i<4; i++) {
|
|||
|
|
ret = setDimmParaToDbus(ctx, dimmName, "Power", railName[i], railData[i]);
|
|||
|
|
if(ret < 0)
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline int8_t getTempIntPart (double temp) {
|
|||
|
|
int16_t int_part = static_cast<int16_t>(temp);
|
|||
|
|
if(int_part > INT8_MAX) int_part = INT8_MAX;
|
|||
|
|
if(int_part < INT8_MIN) int_part = INT8_MIN;
|
|||
|
|
return static_cast<uint8_t>(int_part);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline uint8_t getTempFracPart (double temp) {
|
|||
|
|
uint8_t frac_part = 0;
|
|||
|
|
int16_t int_part = static_cast<int16_t>(temp);
|
|||
|
|
if(int_part & 0x80) {
|
|||
|
|
frac_part = static_cast<uint8_t>((int_part - temp) * 100);
|
|||
|
|
} else {
|
|||
|
|
frac_part = static_cast<uint8_t>((temp - int_part) * 100);
|
|||
|
|
}
|
|||
|
|
return frac_part;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline uint16_t doubleToU16 (double data) {
|
|||
|
|
uint32_t temp = static_cast<uint32_t>(std::floor(data * 1000.0));
|
|||
|
|
if(temp > UINT16_MAX) temp = UINT16_MAX;
|
|||
|
|
|
|||
|
|
return static_cast<uint16_t>(temp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>> ipmiBiosGetDimmPara(ipmi::Context::ptr ctx, uint8_t dimmId) {
|
|||
|
|
|
|||
|
|
oem_dimm_info_t dimmInfo;
|
|||
|
|
memset((void *)&dimmInfo, 0xFF, sizeof(oem_dimm_info_t));
|
|||
|
|
boost::system::error_code ec;
|
|||
|
|
size_t size = sizeof(oem_dimm_info_t);
|
|||
|
|
std::vector<uint8_t> byte_vector(size);
|
|||
|
|
|
|||
|
|
int channel = (dimmId >> 2) & 0x0f;
|
|||
|
|
int cpuid = (dimmId >> 6) & 0x03;
|
|||
|
|
if(cpuid > 1 || channel > 11)
|
|||
|
|
{
|
|||
|
|
std::cerr << "invalid dimmId :" << (int)dimmId << "\n";
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
dimmInfo.dimmId = dimmId;
|
|||
|
|
std::string dimmName = "DIMM_CPU" + std::string(1, '0' + cpuid) + "_" + std::string(1, 'A' + channel);
|
|||
|
|
std::string path = "/xyz/openbmc_project/dimm/" + dimmName;
|
|||
|
|
|
|||
|
|
//Get temperature
|
|||
|
|
PropertyMapType propTemp =
|
|||
|
|
ctx->bus->yield_method_call<PropertyMapType>(
|
|||
|
|
ctx->yield, ec, dimmSpdReaderService, path,
|
|||
|
|
dbusProperties, "GetAll", tempInterface);
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
std::cerr << "Getting DIMM " << dimmName << " Temperature failed." << "\n";
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
auto ts0_temp = std::get_if<double>(&propTemp["TS0"]);
|
|||
|
|
auto ts1_temp = std::get_if<double>(&propTemp["TS1"]);
|
|||
|
|
auto spd_temp = std::get_if<double>(&propTemp["SPD_TS"]);
|
|||
|
|
|
|||
|
|
if(!std::isnan(*ts0_temp)) {
|
|||
|
|
dimmInfo.dimmTemp.TS0_int = getTempIntPart(*ts0_temp);
|
|||
|
|
dimmInfo.dimmTemp.TS0_frac = getTempFracPart(*ts0_temp);
|
|||
|
|
}
|
|||
|
|
if(!std::isnan(*ts1_temp)) {
|
|||
|
|
dimmInfo.dimmTemp.TS1_int = getTempIntPart(*ts1_temp);
|
|||
|
|
dimmInfo.dimmTemp.TS1_frac = getTempFracPart(*ts1_temp);
|
|||
|
|
}
|
|||
|
|
if(!std::isnan(*spd_temp)) {
|
|||
|
|
dimmInfo.dimmTemp.SPD_int = getTempIntPart(*spd_temp);
|
|||
|
|
dimmInfo.dimmTemp.SPD_frac = getTempFracPart(*spd_temp);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//Get voltage
|
|||
|
|
ec.clear();
|
|||
|
|
PropertyMapType propVolt =
|
|||
|
|
ctx->bus->yield_method_call<PropertyMapType>(
|
|||
|
|
ctx->yield, ec, dimmSpdReaderService, path,
|
|||
|
|
dbusProperties, "GetAll", voltInterface);
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
std::cerr << "Getting DIMM " << dimmName << " Voltage failed." << "\n";
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
auto swa = std::get_if<double>(&propVolt["SWA"]);
|
|||
|
|
auto swb = std::get_if<double>(&propVolt["SWB"]);
|
|||
|
|
auto swc = std::get_if<double>(&propVolt["SWC"]);
|
|||
|
|
auto swd = std::get_if<double>(&propVolt["SWD"]);
|
|||
|
|
auto swe = std::get_if<double>(&propVolt["SWE"]);
|
|||
|
|
auto swf = std::get_if<double>(&propVolt["SWF"]);
|
|||
|
|
if(!std::isnan(*swa))
|
|||
|
|
dimmInfo.dimmVolt.SWA = doubleToU16(*swa);
|
|||
|
|
if(!std::isnan(*swb))
|
|||
|
|
dimmInfo.dimmVolt.SWB = doubleToU16(*swb);
|
|||
|
|
if(!std::isnan(*swc))
|
|||
|
|
dimmInfo.dimmVolt.SWC = doubleToU16(*swc);
|
|||
|
|
if(!std::isnan(*swd))
|
|||
|
|
dimmInfo.dimmVolt.SWD = doubleToU16(*swd);
|
|||
|
|
if(!std::isnan(*swe))
|
|||
|
|
dimmInfo.dimmVolt.SWE = doubleToU16(*swe);
|
|||
|
|
if(!std::isnan(*swf))
|
|||
|
|
dimmInfo.dimmVolt.SWF = doubleToU16(*swf);
|
|||
|
|
|
|||
|
|
//Get Current
|
|||
|
|
ec.clear();
|
|||
|
|
PropertyMapType propCur =
|
|||
|
|
ctx->bus->yield_method_call<PropertyMapType>(
|
|||
|
|
ctx->yield, ec, dimmSpdReaderService, path,
|
|||
|
|
dbusProperties, "GetAll", curInterface);
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
std::cerr << "Getting DIMM " << dimmName << " Current failed." << "\n";
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
swa = std::get_if<double>(&propCur["SWA"]);
|
|||
|
|
swb = std::get_if<double>(&propCur["SWB"]);
|
|||
|
|
swc = std::get_if<double>(&propCur["SWC"]);
|
|||
|
|
swd = std::get_if<double>(&propCur["SWD"]);
|
|||
|
|
swe = std::get_if<double>(&propCur["SWE"]);
|
|||
|
|
swf = std::get_if<double>(&propCur["SWF"]);
|
|||
|
|
if(!std::isnan(*swa))
|
|||
|
|
dimmInfo.dimmCur.SWA = doubleToU16(*swa);
|
|||
|
|
if(!std::isnan(*swb))
|
|||
|
|
dimmInfo.dimmCur.SWB = doubleToU16(*swb);
|
|||
|
|
if(!std::isnan(*swc))
|
|||
|
|
dimmInfo.dimmCur.SWC = doubleToU16(*swc);
|
|||
|
|
if(!std::isnan(*swd))
|
|||
|
|
dimmInfo.dimmCur.SWD = doubleToU16(*swd);
|
|||
|
|
if(!std::isnan(*swe))
|
|||
|
|
dimmInfo.dimmCur.SWE = doubleToU16(*swe);
|
|||
|
|
if(!std::isnan(*swf))
|
|||
|
|
dimmInfo.dimmCur.SWF = doubleToU16(*swf);
|
|||
|
|
|
|||
|
|
//Set power
|
|||
|
|
ec.clear();
|
|||
|
|
PropertyMapType propPow =
|
|||
|
|
ctx->bus->yield_method_call<PropertyMapType>(
|
|||
|
|
ctx->yield, ec, dimmSpdReaderService, path,
|
|||
|
|
dbusProperties, "GetAll", powInterface);
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
std::cerr << "Getting DIMM " << dimmName << " Power failed." << "\n";
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
swa = std::get_if<double>(&propPow["SWA"]);
|
|||
|
|
swb = std::get_if<double>(&propPow["SWB"]);
|
|||
|
|
swc = std::get_if<double>(&propPow["SWC"]);
|
|||
|
|
swd = std::get_if<double>(&propPow["SWD"]);
|
|||
|
|
swe = std::get_if<double>(&propPow["SWE"]);
|
|||
|
|
swf = std::get_if<double>(&propPow["SWF"]);
|
|||
|
|
if(!std::isnan(*swa))
|
|||
|
|
dimmInfo.dimmPow.SWA = doubleToU16(*swa);
|
|||
|
|
if(!std::isnan(*swb))
|
|||
|
|
dimmInfo.dimmPow.SWB = doubleToU16(*swb);
|
|||
|
|
if(!std::isnan(*swc))
|
|||
|
|
dimmInfo.dimmPow.SWC = doubleToU16(*swc);
|
|||
|
|
if(!std::isnan(*swd))
|
|||
|
|
dimmInfo.dimmPow.SWD = doubleToU16(*swd);
|
|||
|
|
if(!std::isnan(*swe))
|
|||
|
|
dimmInfo.dimmPow.SWE = doubleToU16(*swe);
|
|||
|
|
if(!std::isnan(*swf))
|
|||
|
|
dimmInfo.dimmPow.SWF = doubleToU16(*swf);
|
|||
|
|
|
|||
|
|
std::memcpy(byte_vector.data(), &dimmInfo, size);
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(byte_vector);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool getPlatformState(ipmi::Context::ptr ctx)
|
|||
|
|
{
|
|||
|
|
bool* espiPltRst = nullptr;
|
|||
|
|
bool* i3cSwitch = nullptr;
|
|||
|
|
boost::system::error_code ec;
|
|||
|
|
//Set power
|
|||
|
|
ec.clear();
|
|||
|
|
PropertyMapType propPow =
|
|||
|
|
ctx->bus->yield_method_call<PropertyMapType>(
|
|||
|
|
ctx->yield, ec, HostMiscDbusName, platformStatePath,
|
|||
|
|
dbusProperties, "GetAll", platformStateInterface);
|
|||
|
|
if (ec)
|
|||
|
|
{
|
|||
|
|
std::cerr << "Failed to read platform State" << "\n";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
espiPltRst = std::get_if<bool>(&propPow["ESpiPlatformReset"]);
|
|||
|
|
i3cSwitch = std::get_if<bool>(&propPow["dimmI3cSwitch"]);
|
|||
|
|
|
|||
|
|
if(espiPltRst == nullptr || i3cSwitch == nullptr)
|
|||
|
|
return false;
|
|||
|
|
else {
|
|||
|
|
return *espiPltRst && *i3cSwitch;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static std::vector<uint8_t> convertDoubleToTwoBytes(std::optional<double> value)
|
|||
|
|
{
|
|||
|
|
if(!value.has_value()) {
|
|||
|
|
return std::vector<uint8_t>{0xFF, 0xFF};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
double val = value.value();
|
|||
|
|
|
|||
|
|
if (val < 0.0 || val > 255.994) {
|
|||
|
|
return std::vector<uint8_t>{0xFF, 0xFF};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
long long scaled = std::llround(val * 100.0);
|
|||
|
|
|
|||
|
|
if (scaled < 0 || scaled > 25599) {
|
|||
|
|
return std::vector<uint8_t>{0xFF, 0xFF};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint8_t integerPart = static_cast<uint8_t>(scaled / 100);
|
|||
|
|
uint8_t fractionalRounded = static_cast<uint8_t>(scaled % 100);
|
|||
|
|
|
|||
|
|
return std::vector<uint8_t>{integerPart, fractionalRounded};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename T>
|
|||
|
|
static std::optional<T> getDIMMData(const nlohmann::json& js, const std::string& dimmName,
|
|||
|
|
DataType dataType, auto indexId)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
static_assert(std::is_arithmetic_v<T>, "The return type must be an arithmetic type");
|
|||
|
|
|
|||
|
|
if (!js.contains(dimmName)) {
|
|||
|
|
return std::nullopt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const nlohmann::json& dimmData = js[dimmName];
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
if (dataType == DataType::TEMPERATURE) {
|
|||
|
|
auto sensor = static_cast<TempSensor>(indexId);
|
|||
|
|
|
|||
|
|
switch (sensor) {
|
|||
|
|
case TempSensor::TS0: {
|
|||
|
|
auto value = dimmData["Temperature_DegreesC"]["TS0"];
|
|||
|
|
if (std::isnan(value.get<double>())) return std::nullopt;
|
|||
|
|
return static_cast<T>(value.get<double>());
|
|||
|
|
}
|
|||
|
|
case TempSensor::TS1: {
|
|||
|
|
auto value = dimmData["Temperature_DegreesC"]["TS1"];
|
|||
|
|
if (std::isnan(value.get<double>())) return std::nullopt;
|
|||
|
|
return static_cast<T>(value.get<double>());
|
|||
|
|
}
|
|||
|
|
case TempSensor::SPD_TS: {
|
|||
|
|
auto value = dimmData["Temperature_DegreesC"]["SPD_TS"];
|
|||
|
|
if (std::isnan(value.get<double>())) return std::nullopt;
|
|||
|
|
return static_cast<T>(value.get<double>());
|
|||
|
|
}
|
|||
|
|
case TempSensor::MAX_TS01: {
|
|||
|
|
auto ts0 = dimmData["Temperature_DegreesC"]["TS0"];
|
|||
|
|
auto ts1 = dimmData["Temperature_DegreesC"]["TS1"];
|
|||
|
|
|
|||
|
|
bool ts0_valid = !std::isnan(ts0.get<double>());
|
|||
|
|
bool ts1_valid = !std::isnan(ts1.get<double>());
|
|||
|
|
|
|||
|
|
if (ts0_valid && ts1_valid) {
|
|||
|
|
return static_cast<T>(std::max(
|
|||
|
|
ts0.get<double>(),
|
|||
|
|
ts1.get<double>()
|
|||
|
|
));
|
|||
|
|
} else if (ts0_valid) {
|
|||
|
|
return static_cast<T>(ts0.get<double>());
|
|||
|
|
} else if (ts1_valid) {
|
|||
|
|
return static_cast<T>(ts1.get<double>());
|
|||
|
|
} else {
|
|||
|
|
return std::nullopt;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
default:
|
|||
|
|
return std::nullopt;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (dataType == DataType::CURRENT) {
|
|||
|
|
auto channel = static_cast<RailChannel>(indexId);
|
|||
|
|
std::string channelStr;
|
|||
|
|
|
|||
|
|
switch (channel) {
|
|||
|
|
case RailChannel::SWA: channelStr = "SWA"; break;
|
|||
|
|
case RailChannel::SWB: channelStr = "SWB"; break;
|
|||
|
|
case RailChannel::SWC: channelStr = "SWC"; break;
|
|||
|
|
case RailChannel::SWD: channelStr = "SWD"; break;
|
|||
|
|
case RailChannel::SWE: channelStr = "SWE"; break;
|
|||
|
|
case RailChannel::SWF: channelStr = "SWF"; break;
|
|||
|
|
default: return std::nullopt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
auto value = dimmData["Current_Ampere"][channelStr];
|
|||
|
|
if (std::isnan(value.get<double>())) return std::nullopt;
|
|||
|
|
return static_cast<T>(value.get<double>());
|
|||
|
|
}
|
|||
|
|
else if (dataType == DataType::POWER) {
|
|||
|
|
auto channel = static_cast<RailChannel>(indexId);
|
|||
|
|
std::string channelStr;
|
|||
|
|
|
|||
|
|
switch (channel) {
|
|||
|
|
case RailChannel::SWA: channelStr = "SWA"; break;
|
|||
|
|
case RailChannel::SWB: channelStr = "SWB"; break;
|
|||
|
|
case RailChannel::SWC: channelStr = "SWC"; break;
|
|||
|
|
case RailChannel::SWD: channelStr = "SWD"; break;
|
|||
|
|
case RailChannel::SWE: channelStr = "SWE"; break;
|
|||
|
|
case RailChannel::SWF: channelStr = "SWF"; break;
|
|||
|
|
default: return std::nullopt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
auto value = dimmData["Power_Watt"][channelStr];
|
|||
|
|
if (std::isnan(value.get<double>())) return std::nullopt;
|
|||
|
|
return static_cast<T>(value.get<double>());
|
|||
|
|
}
|
|||
|
|
else if (dataType == DataType::VOLTAGE) {
|
|||
|
|
auto channel = static_cast<RailChannel>(indexId);
|
|||
|
|
std::string channelStr;
|
|||
|
|
|
|||
|
|
switch (channel) {
|
|||
|
|
case RailChannel::SWA: channelStr = "SWA"; break;
|
|||
|
|
case RailChannel::SWB: channelStr = "SWB"; break;
|
|||
|
|
case RailChannel::SWC: channelStr = "SWC"; break;
|
|||
|
|
case RailChannel::SWD: channelStr = "SWD"; break;
|
|||
|
|
case RailChannel::SWE: channelStr = "SWE"; break;
|
|||
|
|
case RailChannel::SWF: channelStr = "SWF"; break;
|
|||
|
|
default: return std::nullopt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
auto value = dimmData["Voltage_Volt"][channelStr];
|
|||
|
|
if (std::isnan(value.get<double>())) return std::nullopt;
|
|||
|
|
return static_cast<T>(value.get<double>());
|
|||
|
|
}
|
|||
|
|
else if (dataType == DataType::STATUS) {
|
|||
|
|
auto reg = static_cast<StatusReg>(indexId);
|
|||
|
|
std::string regStr;
|
|||
|
|
|
|||
|
|
char hexStr[5];
|
|||
|
|
snprintf(hexStr, sizeof(hexStr), "0x%02x", static_cast<int>(reg));
|
|||
|
|
regStr = hexStr;
|
|||
|
|
|
|||
|
|
if (!dimmData["Status_Reg"].contains(regStr)) {
|
|||
|
|
return std::nullopt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
auto value = dimmData["Status_Reg"][regStr];
|
|||
|
|
return static_cast<T>(value.get<int>());
|
|||
|
|
}
|
|||
|
|
} catch (std::exception& e) {
|
|||
|
|
return std::nullopt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return std::nullopt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/****************************************************************************
|
|||
|
|
reqId: 0:TS0 1:TS1 2:SPD_TEMP 3: Max Temp 4:Voltage 5:Current 6: Status Reg
|
|||
|
|
*****************************************************************************/
|
|||
|
|
ipmi::RspType<std::vector<uint8_t>> ipmiGetDimmTemp(uint8_t reqId)
|
|||
|
|
{
|
|||
|
|
bool retry;
|
|||
|
|
uint8_t attempts = 0;
|
|||
|
|
const nlohmann::json empty{};
|
|||
|
|
nlohmann::json js;
|
|||
|
|
|
|||
|
|
if(reqId > 6) {
|
|||
|
|
std::cout << "invalid reqId :" << (int)reqId << std::endl;
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::vector<uint8_t> byte_vector;
|
|||
|
|
|
|||
|
|
do
|
|||
|
|
{
|
|||
|
|
retry = false;
|
|||
|
|
const std::filesystem::path path(dimmInfoPath);
|
|||
|
|
|
|||
|
|
std::ifstream jsonInputFile(path);
|
|||
|
|
if (jsonInputFile.is_open()) {
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
js = nlohmann::json::parse(jsonInputFile);
|
|||
|
|
}
|
|||
|
|
catch (const std::exception& e)
|
|||
|
|
{
|
|||
|
|
++attempts;
|
|||
|
|
retry = true;
|
|||
|
|
jsonInputFile.close();
|
|||
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
++attempts;
|
|||
|
|
retry = true;
|
|||
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|||
|
|
}
|
|||
|
|
} while ((attempts < maxRetries) && retry);
|
|||
|
|
|
|||
|
|
if(attempts == maxRetries) {
|
|||
|
|
std::cout << "Failed to parse json file " << std::endl;
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for(int cpuid = 0; cpuid < MAX_CPU_ID_NUM; cpuid++)
|
|||
|
|
{
|
|||
|
|
for(int i = 0; i < MAX_DIMM_RANK_NUM; i++)
|
|||
|
|
{
|
|||
|
|
dimm_temp_sensor_t tempSensor;
|
|||
|
|
memset(&tempSensor, 0xFF, sizeof(dimm_temp_sensor_t));
|
|||
|
|
|
|||
|
|
std::string dimmName = "DIMM_CPU" + std::string(1, '0' + cpuid)
|
|||
|
|
+ "_" + std::string(1, 'A' + i);
|
|||
|
|
std::optional<double> temp, swa, swb, swc, swd, swe, swf;
|
|||
|
|
std::optional<uint8_t> r4, r5, r6, r7, r8, r9, ra, rb;
|
|||
|
|
|
|||
|
|
switch(static_cast<ReqId>(reqId))
|
|||
|
|
{
|
|||
|
|
case ReqId::TS0:
|
|||
|
|
temp = getDIMMData<double>(js, dimmName, DataType::TEMPERATURE, TempSensor::TS0);
|
|||
|
|
break;
|
|||
|
|
case ReqId::TS1:
|
|||
|
|
temp = getDIMMData<double>(js, dimmName, DataType::TEMPERATURE, TempSensor::TS1);
|
|||
|
|
break;
|
|||
|
|
case ReqId::SPD_TEMP:
|
|||
|
|
temp = getDIMMData<double>(js, dimmName, DataType::TEMPERATURE, TempSensor::SPD_TS);
|
|||
|
|
break;
|
|||
|
|
case ReqId::MAX_TEMP:
|
|||
|
|
temp = getDIMMData<double>(js, dimmName, DataType::TEMPERATURE, TempSensor::MAX_TS01);
|
|||
|
|
break;
|
|||
|
|
case ReqId::VOLTAGE:
|
|||
|
|
swa = getDIMMData<double>(js, dimmName, DataType::VOLTAGE, RailChannel::SWA);
|
|||
|
|
swb = getDIMMData<double>(js, dimmName, DataType::VOLTAGE, RailChannel::SWB);
|
|||
|
|
swc = getDIMMData<double>(js, dimmName, DataType::VOLTAGE, RailChannel::SWC);
|
|||
|
|
swd = getDIMMData<double>(js, dimmName, DataType::VOLTAGE, RailChannel::SWD);
|
|||
|
|
swe = getDIMMData<double>(js, dimmName, DataType::VOLTAGE, RailChannel::SWE);
|
|||
|
|
swf = getDIMMData<double>(js, dimmName, DataType::VOLTAGE, RailChannel::SWF);
|
|||
|
|
break;
|
|||
|
|
case ReqId::CURRENT:
|
|||
|
|
swa = getDIMMData<double>(js, dimmName, DataType::CURRENT, RailChannel::SWA);
|
|||
|
|
swb = getDIMMData<double>(js, dimmName, DataType::CURRENT, RailChannel::SWB);
|
|||
|
|
swc = getDIMMData<double>(js, dimmName, DataType::CURRENT, RailChannel::SWC);
|
|||
|
|
swd = getDIMMData<double>(js, dimmName, DataType::CURRENT, RailChannel::SWD);
|
|||
|
|
swe = getDIMMData<double>(js, dimmName, DataType::CURRENT, RailChannel::SWE);
|
|||
|
|
swf = getDIMMData<double>(js, dimmName, DataType::CURRENT, RailChannel::SWF);
|
|||
|
|
break;
|
|||
|
|
case ReqId::STATUS_REG:
|
|||
|
|
r4 = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_04);
|
|||
|
|
r5 = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_05);
|
|||
|
|
r6 = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_06);
|
|||
|
|
r7 = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_07);
|
|||
|
|
r8 = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_08);
|
|||
|
|
r9 = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_09);
|
|||
|
|
ra = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_0A);
|
|||
|
|
rb = getDIMMData<uint8_t>(js, dimmName, DataType::STATUS, StatusReg::REG_0B);
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
std::cout << "invalid reqId :" << (int)reqId << std::endl;
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(reqId <= 3) {
|
|||
|
|
if(temp) {
|
|||
|
|
tempSensor.int_part = getTempIntPart(*temp);
|
|||
|
|
tempSensor.frac_part = getTempFracPart(*temp);
|
|||
|
|
}
|
|||
|
|
byte_vector.push_back(static_cast<uint8_t>(tempSensor.int_part));
|
|||
|
|
byte_vector.push_back(tempSensor.frac_part);
|
|||
|
|
}
|
|||
|
|
else if(reqId == 6) {
|
|||
|
|
for (const auto& opt : {r4, r5, r6, r7, r8, r9, ra, rb}) {
|
|||
|
|
byte_vector.push_back(opt.value_or(0xFF));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
for (const auto& rail : {swa, swb, swc, swd, swe, swf}) {
|
|||
|
|
auto bytes = convertDoubleToTwoBytes(rail);
|
|||
|
|
byte_vector.insert(byte_vector.end(), bytes.begin(), bytes.end());
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess(byte_vector);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ipmi::RspType<uint8_t> ipmiSwitchBMCFw(uint8_t bootsource)
|
|||
|
|
{
|
|||
|
|
char cmd[256] = {0};
|
|||
|
|
if(bootsource !=1 && bootsource !=2)
|
|||
|
|
{
|
|||
|
|
return ipmi::responseParmOutOfRange();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if(bootsource == 1)//switch bmc to main flash
|
|||
|
|
{
|
|||
|
|
if(std::filesystem::exists(MAIN_BMC_BOOT_SOURCE))
|
|||
|
|
{
|
|||
|
|
memset(cmd, 0 , sizeof(cmd));
|
|||
|
|
snprintf(cmd, sizeof(cmd), "echo 1 > %s", MAIN_BMC_BOOT_SOURCE);
|
|||
|
|
if(system(cmd))
|
|||
|
|
{
|
|||
|
|
lg2::error("Set BMC boot from main flash failed.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
return ipmi::responseCommandNotAvailable();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if(bootsource == 2)//switch bmc to backup flash
|
|||
|
|
{
|
|||
|
|
if(std::filesystem::exists(BACKUP_BMC_BOOT_SOURCE))
|
|||
|
|
{
|
|||
|
|
memset(cmd, 0 , sizeof(cmd));
|
|||
|
|
snprintf(cmd, sizeof(cmd), "echo 1 > %s", BACKUP_BMC_BOOT_SOURCE);
|
|||
|
|
if(system(cmd))
|
|||
|
|
{
|
|||
|
|
lg2::error("Set BMC boot from backup flash failed.");
|
|||
|
|
return ipmi::responseUnspecifiedError();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
return ipmi::responseCommandNotAvailable();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ipmi::responseSuccess();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
void register_ipmi_oem_functions() {
|
|||
|
|
// <Get Device Firmware Version>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetDeviceFWVersion,
|
|||
|
|
ipmi::Privilege::Admin, GetDeviceFWVersion);
|
|||
|
|
|
|||
|
|
// <Set Fan speed control mode>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSetFanSpeedControlMode,
|
|||
|
|
ipmi::Privilege::Admin, SetFanSpeedControlMode);
|
|||
|
|
|
|||
|
|
// <Get Fan speed control mode>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetFanSpeedControlMode,
|
|||
|
|
ipmi::Privilege::Admin, GetFanSpeedControlMode);
|
|||
|
|
|
|||
|
|
// <Set BIOS Password Config>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSetBIOSPasswordConfig,
|
|||
|
|
ipmi::Privilege::Admin, SetBIOSPasswordConfig);
|
|||
|
|
|
|||
|
|
// <Get BIOS Password Config>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetBIOSPasswordConfig,
|
|||
|
|
ipmi::Privilege::Admin, GetBIOSPasswordConfig);
|
|||
|
|
|
|||
|
|
// <Get PSU Info>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetPSUInfo,
|
|||
|
|
ipmi::Privilege::Admin, GetPSUInfo);
|
|||
|
|
|
|||
|
|
// <Get 12V PSU ADC Value>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGet12VPSUADCValue,
|
|||
|
|
ipmi::Privilege::Admin, Get12VPSUADCValue);
|
|||
|
|
|
|||
|
|
// <Set 12V PSU ADC Value>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSet12VPSUADCValue,
|
|||
|
|
ipmi::Privilege::Admin, Set12VPSUADCValue);
|
|||
|
|
|
|||
|
|
// <Get Memory Info>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdDIMMTemperatureValue,
|
|||
|
|
ipmi::Privilege::Admin, GetDIMMTemperatureValue);
|
|||
|
|
|
|||
|
|
// <OEM I2C Read Write>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdOemI2CReadWrite,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemI2cReadWrite);
|
|||
|
|
|
|||
|
|
// <OEM Set DIMM Setpoint>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSetDIMMSetPoint,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemSetDIMMSetPoint);
|
|||
|
|
|
|||
|
|
// <OEM Get DIMM Setpoint>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetDIMMSetPoint,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemGetDIMMSetPoint);
|
|||
|
|
|
|||
|
|
// <OEM Set heat cover status>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSetCoverStatus,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemSetCoverStatus);
|
|||
|
|
|
|||
|
|
// <OEM Get heat cover status>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetCoverStatus,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemGetCoverStatus);
|
|||
|
|
|
|||
|
|
// <OEM Set heat cover temperature>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSetCoverPreHeatTemperature,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemSetCoverHeatTemp);
|
|||
|
|
|
|||
|
|
// <OEM heat cover temperature>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetCoverPreHeatTemperature,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemGetCoverHeatTemp);
|
|||
|
|
|
|||
|
|
// <OEM Set/Get BIOS Version>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetSetBiosVer,
|
|||
|
|
ipmi::Privilege::Admin, ipmiSetGetBiosVersion);
|
|||
|
|
|
|||
|
|
// <OEM restore factory default>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdRestoreFactoryDefault,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemRestoreFactoryDefault);
|
|||
|
|
|
|||
|
|
// <BIOS set Dimm State to BMC>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdBiosSetDimmState,
|
|||
|
|
ipmi::Privilege::Admin, ipmiBiosSetDimmState);
|
|||
|
|
|
|||
|
|
// <OEM set sol bitrate>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSetSOLBitrate,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemSetSOLBitrate);
|
|||
|
|
|
|||
|
|
// <BIOS set Dimm Parameters to BMC>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdBiosSetDimmPara,
|
|||
|
|
ipmi::Privilege::Admin, ipmiBiosSetDimmPara);
|
|||
|
|
|
|||
|
|
// <BIOS get Dimm Parameters to BMC>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdBiosGetDimmPara,
|
|||
|
|
ipmi::Privilege::Admin, ipmiBiosGetDimmPara);
|
|||
|
|
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetDimmTemp,
|
|||
|
|
ipmi::Privilege::Admin, ipmiGetDimmTemp);
|
|||
|
|
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetCoverCurrentTemp,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemGetCurrentCoverTemp);
|
|||
|
|
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSetCoverFSCEnableStatus,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemSetCoverFSCEnableStatus);
|
|||
|
|
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdGetCoverFSCEnableStatus,
|
|||
|
|
ipmi::Privilege::Admin, ipmiOemGetCoverFSCEnableStatus);
|
|||
|
|
|
|||
|
|
// <OEM Switch BMC Main Backup Flash>
|
|||
|
|
ipmi::registerOemHandler(ipmi::prioOem, ipmi::oemIANA,
|
|||
|
|
ipmi::ipmiOem::cmdSwitchBMCFw,
|
|||
|
|
ipmi::Privilege::Admin, ipmiSwitchBMCFw);
|
|||
|
|
}
|