blob: ec168f4e0acecdfcd49af9f5a432af24d65d2511 [file] [log] [blame]
#pragma once
#include "config.h"
#include "libpldmresponder/pdr.hpp"
#include "libpldmresponder/utils.hpp"
#include <stdint.h>
#include <map>
#include "libpldm/platform.h"
#include "libpldm/states.h"
namespace pldm
{
using Response = std::vector<uint8_t>;
namespace responder
{
namespace platform
{
/** @brief Register handlers for commands from the platform spec
*/
void registerHandlers();
} // namespace platform
/** @brief Handler for GetPDR
*
* @param[in] request - Request message payload
* @param[in] payloadLength - Request payload length
* @param[out] Response - Response message written here
*/
Response getPDR(const pldm_msg* request, size_t payloadLength);
/** @brief Handler for setStateEffecterStates
*
* @param[in] request - Request message
* @param[in] payloadLength - Request payload length
* @return Response - PLDM Response message
*/
Response setStateEffecterStates(const pldm_msg* request, size_t payloadLength);
/** @brief Function to set the effecter requested by pldm requester
* @param[in] dBusIntf - The interface object
* @param[in] effecterId - Effecter ID sent by the requester to act on
* @param[in] stateField - The state field data for each of the states, equal
* to composite effecter count in number
* @return - Success or failure in setting the states. Returns failure in terms
* of PLDM completion codes if atleast one state fails to be set
*/
template <class DBusInterface>
int setStateEffecterStatesHandler(
const DBusInterface& dBusIntf, effecter::Id effecterId,
const std::vector<set_effecter_state_field>& stateField)
{
using namespace std::string_literals;
using DBusProperty = std::variant<std::string, bool>;
using StateSetId = uint16_t;
using StateSetNum = uint8_t;
using PropertyMap =
std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
static const PropertyMap stateNumToDbusProp = {
{PLDM_BOOT_PROGRESS_STATE,
{{PLDM_BOOT_NOT_ACTIVE,
"xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
"Standby"s},
{PLDM_BOOT_COMPLETED,
"xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
"BootComplete"s}}},
{PLDM_SYSTEM_POWER_STATE,
{{PLDM_OFF_SOFT_GRACEFUL,
"xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
using namespace phosphor::logging;
using namespace pldm::responder::pdr;
using namespace pldm::responder::effecter::dbus_mapping;
state_effecter_possible_states* states = nullptr;
pldm_state_effecter_pdr* pdr = nullptr;
uint8_t compEffecterCnt = stateField.size();
uint32_t recordHndl{};
Repo& pdrRepo = get(PDR_JSONS_DIR);
pdr::Entry pdrEntry{};
while (!pdr)
{
pdrEntry = pdrRepo.at(recordHndl);
pldm_pdr_hdr* header = reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data());
if (header->type != PLDM_STATE_EFFECTER_PDR)
{
recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
if (recordHndl)
{
continue;
}
return PLDM_PLATFORM_INVALID_EFFECTER_ID;
}
pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data());
recordHndl = pdr->hdr.record_handle;
if (pdr->effecter_id == effecterId)
{
states = reinterpret_cast<state_effecter_possible_states*>(
pdr->possible_states);
if (compEffecterCnt > pdr->composite_effecter_count)
{
log<level::ERR>("The requester sent wrong composite effecter "
"count for the effecter",
entry("EFFECTER_ID=%d", effecterId),
entry("COMP_EFF_CNT=%d", compEffecterCnt));
return PLDM_ERROR_INVALID_DATA;
}
break;
}
recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
if (!recordHndl)
{
return PLDM_PLATFORM_INVALID_EFFECTER_ID;
}
pdr = nullptr;
}
std::map<StateSetId, std::function<int(const std::string& objPath,
const uint8_t currState)>>
effecterToDbusEntries = {
{PLDM_BOOT_PROGRESS_STATE,
[&](const std::string& objPath, const uint8_t currState) {
auto stateSet =
stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
if (stateSet == stateNumToDbusProp.end())
{
log<level::ERR>("Couldn't find D-Bus mapping for "
"PLDM_BOOT_PROGRESS_STATE",
entry("EFFECTER_ID=%d", effecterId));
return PLDM_ERROR;
}
auto iter = stateSet->second.find(
stateField[currState].effecter_state);
if (iter == stateSet->second.end())
{
log<level::ERR>(
"Invalid state field passed or field not "
"found for PLDM_BOOT_PROGRESS_STATE",
entry("EFFECTER_ID=%d", effecterId),
entry("FIELD=%d",
stateField[currState].effecter_state),
entry("OBJECT_PATH=%s", objPath.c_str()));
return PLDM_ERROR_INVALID_DATA;
}
auto dbusProp = "OperatingSystemState";
std::variant<std::string> value{
std::get<std::string>(iter->second)};
auto dbusInterface =
"xyz.openbmc_project.State.OperatingSystem.Status";
try
{
dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
dbusInterface, value);
}
catch (const std::exception& e)
{
log<level::ERR>("Error setting property",
entry("ERROR=%s", e.what()),
entry("PROPERTY=%s", dbusProp),
entry("INTERFACE=%s", dbusInterface),
entry("PATH=%s", objPath.c_str()));
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}},
{PLDM_SYSTEM_POWER_STATE,
[&](const std::string& objPath, const uint8_t currState) {
auto stateSet =
stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
if (stateSet == stateNumToDbusProp.end())
{
log<level::ERR>("Couldn't find D-Bus mapping for "
"PLDM_SYSTEM_POWER_STATE",
entry("EFFECTER_ID=%d", effecterId));
return PLDM_ERROR;
}
auto iter = stateSet->second.find(
stateField[currState].effecter_state);
if (iter == stateSet->second.end())
{
log<level::ERR>(
"Invalid state field passed or field not "
"found for PLDM_SYSTEM_POWER_STATE",
entry("EFFECTER_ID=%d", effecterId),
entry("FIELD=%d",
stateField[currState].effecter_state),
entry("OBJECT_PATH=%s", objPath.c_str()));
return PLDM_ERROR_INVALID_DATA;
}
auto dbusProp = "RequestedPowerTransition";
std::variant<std::string> value{
std::get<std::string>(iter->second)};
auto dbusInterface = "xyz.openbmc_project.State.Chassis";
try
{
dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
dbusInterface, value);
}
catch (const std::exception& e)
{
log<level::ERR>("Error setting property",
entry("ERROR=%s", e.what()),
entry("PROPERTY=%s", dbusProp),
entry("INTERFACE=%s", dbusInterface),
entry("PATH=%s", objPath.c_str()));
return PLDM_ERROR;
}
return PLDM_SUCCESS;
}}};
int rc = PLDM_SUCCESS;
auto paths = get(effecterId);
for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
{
std::vector<StateSetNum> allowed{};
// computation is based on table 79 from DSP0248 v1.1.1
uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
uint8_t bit =
stateField[currState].effecter_state - (8 * bitfieldIndex);
if (states->possible_states_size < bitfieldIndex ||
!(states->states[bitfieldIndex].byte & (1 << bit)))
{
log<level::ERR>(
"Invalid state set value", entry("EFFECTER_ID=%d", effecterId),
entry("VALUE=%d", stateField[currState].effecter_state),
entry("COMPOSITE_EFFECTER_ID=%d", currState),
entry("DBUS_PATH=%c", paths[currState].c_str()));
rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
break;
}
auto iter = effecterToDbusEntries.find(states->state_set_id);
if (iter == effecterToDbusEntries.end())
{
uint16_t setId = states->state_set_id;
log<level::ERR>(
"Did not find the state set for the state effecter pdr ",
entry("STATE=%d", setId), entry("EFFECTER_ID=%d", effecterId));
rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
break;
}
if (stateField[currState].set_request == PLDM_REQUEST_SET)
{
rc = iter->second(paths[currState], currState);
if (rc != PLDM_SUCCESS)
{
break;
}
}
uint8_t* nextState =
reinterpret_cast<uint8_t*>(states) +
sizeof(state_effecter_possible_states) - sizeof(states->states) +
(states->possible_states_size * sizeof(states->states));
states = reinterpret_cast<state_effecter_possible_states*>(nextState);
}
return rc;
}
} // namespace responder
} // namespace pldm