Skip to content

CFAM: Support FailoverImminent field in CFAM #29

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion rbmc-cfam-daemon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ The `rbmc-cfam-daemon` meson option will enable building this code.
| Provisioned | 1 | 13 | 1 |
| BMC State | 1 | 14 | 3 |
| Sibling Comms OK | 1 | 17 | 1 |
| Reserved | 1 | 18 | 6 |
| Failover Imminent | 1 | 18 | 1 |
| Reserved | 1 | 19 | 5 |
| Heartbeat | 1 | 24 | 8 |
| FW Version | 2 | 0 | 32 |
| Reserved | 3 | 0 | 32 |
Expand Down Expand Up @@ -58,6 +59,9 @@ property from the BMC state daemon.

**Sibling Comms OK**: If this BMC can read the sibling BMC's CFAM.

**Failover Imminent**: If the sibling will start a failover soon. Only the
passive BMC will set this, soon before it starts a failover to become active.

**Heartbeat**: This field is incremented by one every time the CFAM application
receives the Heartbeat signal from the RBMC state manager application. This can
be used by the sibling to know the management daemon is alive.
Expand All @@ -80,6 +84,7 @@ Failovers Allowed true
Provisioned true
BMC State xyz.openbmc_project.State.BMC.BMCState.Ready
Sibling Communication OK true
Failover Imminent false
Heartbeat 0x25
FW Version 0x1c9c4045

Expand All @@ -92,6 +97,7 @@ Failovers Allowed true
Provisioned true
BMC State xyz.openbmc_project.State.BMC.BMCState.Ready
Sibling Communication OK true
Failover Imminent false
Heartbeat 0x24
FW Version 0x1c9c4045
```
3 changes: 3 additions & 0 deletions rbmc-cfam-daemon/src/bmc_cfam.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class BMCCFAM
provisioned,
bmcState,
siblingCommsOK,
failoverImminent,
heartbeat,
fwVersion
};
Expand All @@ -53,6 +54,8 @@ class BMCCFAM
{Field::bmcState, {cfam::ScratchPadReg::one, 14, 3, "BMC State"}},
{Field::siblingCommsOK,
{cfam::ScratchPadReg::one, 17, 1, "Sibling Communication OK"}},
{Field::failoverImminent,
{cfam::ScratchPadReg::one, 18, 1, "Failover Imminent"}},
{Field::heartbeat, {cfam::ScratchPadReg::one, 24, 8, "Heartbeat"}},
{Field::fwVersion, {cfam::ScratchPadReg::two, 0, 32, "FW Version"}}};

Expand Down
1 change: 1 addition & 0 deletions rbmc-cfam-daemon/src/cfams_tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ std::string formatValue(BMCCFAM::Field field, uint32_t value)
case failoversAllowed:
case provisioned:
case siblingCommsOK:
case failoverImminent:
result = std::format("{}", value ? "true" : "false");
break;
case role:
Expand Down
19 changes: 15 additions & 4 deletions rbmc-cfam-daemon/src/local_bmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ sdbusplus::async::task<> LocalBMC::start()
ctx, [this](auto state) { bmcStateChanged(state); },
[this](auto role) { roleChanged(role); },
[this](auto enabled) { redEnabledChanged(enabled); },
[this](auto allowed) { failoversAllowedChanged(allowed); });
[this](auto allowed) { failoversAllowedChanged(allowed); },
[this](auto imminent) { failoverImminentChanged(imminent); });

co_await writeRedundancyProps();
co_await writeBMCState();
Expand Down Expand Up @@ -122,18 +123,28 @@ void LocalBMC::failoversAllowedChanged(bool allowed)
cfam.writeFailoversAllowed(allowed);
}

void LocalBMC::failoverImminentChanged(bool imminent)
{
lg2::info("Local Failover Imminent changed to {IMMINENT}", "IMMINENT",
imminent);
cfam.writeFailoverImminent(imminent);
}

sdbusplus::async::task<> LocalBMC::writeRedundancyProps()
{
try
{
auto [role, enabled, allowed] = co_await services->getRedundancyProps();
auto [role, enabled, allowed,
imminent] = co_await services->getRedundancyProps();
lg2::info(
"Initial values of local role, redEnabled, fo allowed: {ROLE} {ENABLED} {ALLOWED}",
"ROLE", role, "ENABLED", enabled, "ALLOWED", allowed);
"Initial values of local role, redEnabled, fo allowed, fo imminent: {ROLE} {ENABLED} {ALLOWED} {IMMINENT}",
"ROLE", role, "ENABLED", enabled, "ALLOWED", allowed, "IMMINENT",
imminent);

cfam.writeRole(role);
cfam.writeRedundancyEnabled(enabled);
cfam.writeFailoversAllowed(allowed);
cfam.writeFailoverImminent(imminent);
}
catch (const sdbusplus::exception_t& e)
{
Expand Down
11 changes: 11 additions & 0 deletions rbmc-cfam-daemon/src/local_bmc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ class LocalBMC
*/
void failoversAllowedChanged(bool allowed);

/**
* @brief Callback function for when the failover
* imminent D-Bus property changes.
*
* Writes the new value into the CFAM in the
* FailoverImminent field.
*
* @param[in] imminent - the value to write
*/
void failoverImminentChanged(bool imminent);

/**
* @brief The context object
*/
Expand Down
11 changes: 11 additions & 0 deletions rbmc-cfam-daemon/src/local_cfam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,17 @@ void LocalCFAM::writeSiblingCommsOK(bool ok)
}
}

void LocalCFAM::writeFailoverImminent(bool imminent)
{
auto rc = writeField(Field::failoverImminent, imminent);
if (rc != 0)
{
lg2::error("Failed writing Failover Imminent field {IMM} in local CFAM",
"IMM", imminent);
throw std::system_error(rc, std::generic_category());
}
}

std::expected<uint32_t, int> LocalCFAM::readField(Field field)
{
auto data = cfamAccess.readScratchReg(cfamFields.at(field).reg);
Expand Down
7 changes: 7 additions & 0 deletions rbmc-cfam-daemon/src/local_cfam.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,13 @@ class LocalCFAM : public BMCCFAM
*/
void writeSiblingCommsOK(bool ok);

/**
* @brief Writes the failover imminent field into the CFAM
*
* @param[in] imminent - If a failover is imminent
*/
void writeFailoverImminent(bool imminent);

/**
* @brief Increments the heartbeat field in the CFAM
*/
Expand Down
27 changes: 20 additions & 7 deletions rbmc-cfam-daemon/src/services.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,16 @@ sdbusplus::async::task<std::string> getService(sdbusplus::async::context& ctx,

} // namespace util

Services::Services(sdbusplus::async::context& ctx,
BMCStateCallback&& stateCallback,
RoleCallback&& roleCallback,
RedEnabledCallback&& redEnabledCallback,
FailoversAllowedCallback&& failoversAllowedCallback) :
Services::Services(
sdbusplus::async::context& ctx, BMCStateCallback&& stateCallback,
RoleCallback&& roleCallback, RedEnabledCallback&& redEnabledCallback,
FailoversAllowedCallback&& failoversAllowedCallback,
FailoverImminentCallback&& failoverImminentCallback) :
ctx(ctx), bmcStateCallback(std::move(stateCallback)),
roleCallback(std::move(roleCallback)),
redEnabledCallback(std::move(redEnabledCallback)),
failoversAllowedCallback(std::move(failoversAllowedCallback)),
failoverImminentCallback(std::move(failoverImminentCallback)),
localBMCPath(
sdbusplus::message::object_path{RedNSPath::value} / RedNSPath::bmc)
{
Expand Down Expand Up @@ -147,7 +148,7 @@ sdbusplus::async::task<Services::BMCState> Services::getBMCState()
.current_bmc_state();
}

sdbusplus::async::task<std::tuple<Services::Role, bool, bool>>
sdbusplus::async::task<std::tuple<Services::Role, bool, bool, bool>>
Services::getRedundancyProps()
{
auto service = co_await util::getService(ctx, localBMCPath,
Expand All @@ -162,7 +163,7 @@ sdbusplus::async::task<std::tuple<Services::Role, bool, bool>>
.properties();

co_return std::make_tuple(props.role, props.redundancy_enabled,
props.failovers_allowed);
props.failovers_allowed, props.failover_imminent);
}

sdbusplus::async::task<> Services::watchBMCStateProp()
Expand Down Expand Up @@ -216,6 +217,12 @@ sdbusplus::async::task<> Services::watchRedundancyProps()
{
failoversAllowedCallback(std::get<bool>(it->second));
}

it = propertyMap.find("FailoverImminent");
if (it != propertyMap.end())
{
failoverImminentCallback(std::get<bool>(it->second));
}
}
}

Expand Down Expand Up @@ -269,6 +276,12 @@ sdbusplus::async::task<> Services::watchBMCInterfaceAdded()
{
failoversAllowedCallback(std::get<bool>(propIt->second));
}

propIt = props.find("FailoverImminent");
if (propIt != props.end())
{
failoverImminentCallback(std::get<bool>(propIt->second));
}
}
}
}
16 changes: 13 additions & 3 deletions rbmc-cfam-daemon/src/services.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class Services
using RoleCallback = std::function<void(Role)>;
using RedEnabledCallback = std::function<void(bool)>;
using FailoversAllowedCallback = std::function<void(bool)>;
using FailoverImminentCallback = std::function<void(bool)>;

Services() = delete;
~Services() = default;
Expand All @@ -44,11 +45,14 @@ class Services
* redundancyEnabled prop changes
* @param[in] failoversAllowedCallback - Function to run when this prop
* changes
* @param[in] failoverImminentCallback - Function to run when this
* prop changes
*/
Services(sdbusplus::async::context& ctx, BMCStateCallback&& stateCallback,
RoleCallback&& roleCallback,
RedEnabledCallback&& redEnabledCallback,
FailoversAllowedCallback&& failoversAllowedCallback);
FailoversAllowedCallback&& failoversAllowedCallback,
FailoverImminentCallback&& failoverImminentCallback);

/**
* @brief Reads the CurrentBMCState property
Expand All @@ -60,9 +64,10 @@ class Services
/**
* @brief Reads the role and redundancyEnabled properties
*
* @return - A tuple of the role and redundancyEnabled property
* @return - A tuple of role, redundancyEnabled, FailoversAllowed
* FailoverImminent
*/
sdbusplus::async::task<std::tuple<Services::Role, bool, bool>>
sdbusplus::async::task<std::tuple<Services::Role, bool, bool, bool>>
getRedundancyProps();

/**
Expand Down Expand Up @@ -139,6 +144,11 @@ class Services
*/
FailoversAllowedCallback failoversAllowedCallback;

/**
* @brief The callback function for FailoverImminent
*/
FailoverImminentCallback failoverImminentCallback;

/**
* @brief Object path for this BMC's redundancy and state interfaces.
*/
Expand Down
1 change: 1 addition & 0 deletions rbmc-cfam-daemon/src/sibling_bmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ void SiblingBMC::read()
createdObject);
siblingObject->failoversAllowed(cfam.getFailoversAllowed(), createdObject);
siblingObject->currentBMCState(cfam.getBMCState(), createdObject);
siblingObject->failoverImminent(cfam.getFailoverImminent(), createdObject);

auto version = std::format("{:08X}", cfam.getFWVersion());
siblingObject->version(version, createdObject);
Expand Down
12 changes: 12 additions & 0 deletions rbmc-cfam-daemon/src/sibling_cfam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ void SiblingCFAM::readAll()

siblingCommsOK =
cfam::getFieldValue(*regs, cfamFields.at(Field::siblingCommsOK));

failoverImminent =
cfam::getFieldValue(*regs, cfamFields.at(Field::failoverImminent));
}

uint8_t SiblingCFAM::getApiVersion() const
Expand Down Expand Up @@ -122,6 +125,15 @@ bool SiblingCFAM::getSiblingCommsOK() const
return siblingCommsOK;
}

bool SiblingCFAM::getFailoverImminent() const
{
if (error)
{
throw std::runtime_error{"CFAM fields not available"};
}
return failoverImminent;
}

uint32_t SiblingCFAM::getHeartbeat() const
{
if (error)
Expand Down
10 changes: 10 additions & 0 deletions rbmc-cfam-daemon/src/sibling_cfam.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ class SiblingCFAM : public BMCCFAM
*/
bool getSiblingCommsOK() const;

/**
* @brief Returns the failover imminent field
*
* Will throw if there is a hardware error
*/
bool getFailoverImminent() const;

/**
* @brief Returns the heartbeat field
*
Expand Down Expand Up @@ -158,6 +165,9 @@ class SiblingCFAM : public BMCCFAM
/** @brief Latest sibling comms OK value */
bool siblingCommsOK{};

/** @brief Latest failover imminent value */
bool failoverImminent{};

/** @brief The set of scratchpad regs that contain field */
std::set<cfam::ScratchPadReg> usedRegs;

Expand Down
4 changes: 3 additions & 1 deletion rbmc-cfam-daemon/test/sibling_cfam_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ TEST_F(SiblingCFAMTest, TestReads)
SiblingCFAM sibling{1, driver};

EXPECT_CALL(driver, read(link1Device, 0))
.WillOnce(Return(Expected(0x01DDFFFF)));
.WillOnce(Return(Expected(0x01DDEFFF)));
EXPECT_CALL(driver, read(link1Device, 1))
.WillOnce(Return(Expected(0x12345678)));

Expand All @@ -40,6 +40,7 @@ TEST_F(SiblingCFAMTest, TestReads)
EXPECT_EQ(sibling.getSiblingCommsOK(), true);
EXPECT_EQ(sibling.getHeartbeat(), 0xFF);
EXPECT_EQ(sibling.getFWVersion(), 0x12345678);
EXPECT_EQ(sibling.getFailoverImminent(), true);
}

TEST_F(SiblingCFAMTest, TestReadFail)
Expand All @@ -65,4 +66,5 @@ TEST_F(SiblingCFAMTest, TestReadFail)
EXPECT_THROW(sibling.getRole(), std::runtime_error);
EXPECT_THROW(sibling.getSiblingCommsOK(), std::runtime_error);
EXPECT_THROW(sibling.getHeartbeat(), std::runtime_error);
EXPECT_THROW(sibling.getFailoverImminent(), std::runtime_error);
}