summaryrefslogtreecommitdiff
path: root/hsbp-manager/src/hsbp_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hsbp-manager/src/hsbp_manager.cpp')
-rw-r--r--hsbp-manager/src/hsbp_manager.cpp212
1 files changed, 133 insertions, 79 deletions
diff --git a/hsbp-manager/src/hsbp_manager.cpp b/hsbp-manager/src/hsbp_manager.cpp
index 83ebdf3..f25f266 100644
--- a/hsbp-manager/src/hsbp_manager.cpp
+++ b/hsbp-manager/src/hsbp_manager.cpp
@@ -18,7 +18,9 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/asio/steady_timer.hpp>
+#include <boost/container/flat_set.hpp>
#include <filesystem>
+#include <fstream>
#include <iostream>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
@@ -51,11 +53,20 @@ static std::string zeroPad(const uint8_t val)
struct Mux
{
- Mux(size_t busIn, size_t addressIn) : bus(busIn), address(addressIn)
+ Mux(size_t busIn, size_t addressIn, size_t channelsIn, size_t indexIn) :
+ bus(busIn), address(addressIn), channels(channelsIn), index(indexIn)
{
}
size_t bus;
size_t address;
+ size_t channels;
+ size_t index;
+
+ // to sort in the flat set
+ bool operator<(const Mux& rhs) const
+ {
+ return index < rhs.index;
+ }
};
enum class BlinkPattern : uint8_t
@@ -155,58 +166,41 @@ struct Drive
itemIface->get_object_path(), "xyz.openbmc_project.State.Drive");
rebuildingIface->register_property("Rebuilding", rebuilding);
rebuildingIface->initialize();
+ driveIface =
+ objServer.add_interface(itemIface->get_object_path(),
+ "xyz.openbmc_project.Inventory.Item.Drive");
+ driveIface->initialize();
}
virtual ~Drive()
{
objServer.remove_interface(itemIface);
objServer.remove_interface(operationalIface);
objServer.remove_interface(rebuildingIface);
- objServer.remove_interface(associationIface);
+ objServer.remove_interface(assetIface);
objServer.remove_interface(driveIface);
}
- void createAssociation(const std::string& path)
+ void createAsset(
+ const boost::container::flat_map<std::string, std::string>& data)
{
- if (associationIface != nullptr)
+ if (assetIface != nullptr)
{
return;
}
- associationIface = objServer.add_interface(
+ assetIface = objServer.add_interface(
itemIface->get_object_path(),
- "xyz.openbmc_project.Association.Definitions");
- std::vector<Association> associations;
- associations.emplace_back("inventory", "drive", path);
- associationIface->register_property("Associations", associations);
- associationIface->initialize();
- }
-
- void removeDriveIface()
- {
- objServer.remove_interface(driveIface);
- }
-
- void createDriveIface()
- {
- if (associationIface != nullptr || driveIface != nullptr)
+ "xyz.openbmc_project.Inventory.Decorator.Asset");
+ for (const auto& [key, value] : data)
{
- // this shouldn't be used if we found another provider of the drive
- // interface, or if we already created one
- return;
+ assetIface->register_property(key, value);
}
- driveIface =
- objServer.add_interface(itemIface->get_object_path(),
- "xyz.openbmc_project.Inventory.Item.Drive");
- driveIface->initialize();
- createAssociation(itemIface->get_object_path());
+ assetIface->initialize();
}
std::shared_ptr<sdbusplus::asio::dbus_interface> itemIface;
std::shared_ptr<sdbusplus::asio::dbus_interface> operationalIface;
std::shared_ptr<sdbusplus::asio::dbus_interface> rebuildingIface;
- std::shared_ptr<sdbusplus::asio::dbus_interface> associationIface;
-
- // if something else doesn't expose a driveInterface for this, we need to
- // export it ourselves
+ std::shared_ptr<sdbusplus::asio::dbus_interface> assetIface;
std::shared_ptr<sdbusplus::asio::dbus_interface> driveIface;
bool isNvme;
@@ -220,7 +214,7 @@ struct Backplane
bus(busIn),
address(addressIn), backplaneIndex(backplaneIndexIn - 1), name(nameIn),
timer(std::make_shared<boost::asio::steady_timer>(io)),
- muxes(std::make_shared<std::vector<Mux>>())
+ muxes(std::make_shared<boost::container::flat_set<Mux>>())
{
}
void run()
@@ -516,30 +510,28 @@ struct Backplane
std::vector<Drive> drives;
std::vector<std::shared_ptr<Led>> leds;
- std::shared_ptr<std::vector<Mux>> muxes;
+ std::shared_ptr<boost::container::flat_set<Mux>> muxes;
};
std::unordered_map<std::string, Backplane> backplanes;
+std::vector<Drive> ownerlessDrives; // drives without a backplane
-void createDriveInterfaces(size_t referenceCount)
+static size_t getDriveCount()
{
- if (referenceCount != 1)
- {
- return;
- }
- for (auto& [name, backplane] : backplanes)
+ size_t count = 0;
+ for (const auto& [key, backplane] : backplanes)
{
- for (Drive& drive : backplane.drives)
- {
- drive.createDriveIface();
- }
+ count += backplane.drives.size();
}
+ return count + ownerlessDrives.size();
}
-void updateAssociations()
+void updateAssets()
{
- constexpr const char* driveType =
- "xyz.openbmc_project.Inventory.Item.Drive";
+ static constexpr const char* nvmeType =
+ "xyz.openbmc_project.Inventory.Item.NVMe";
+ static const std::string assetTag =
+ "xyz.openbmc_project.Inventory.Decorator.Asset";
conn->async_method_call(
[](const boost::system::error_code ec, const GetSubTreeType& subtree) {
@@ -548,6 +540,10 @@ void updateAssociations()
std::cerr << "Error contacting mapper " << ec.message() << "\n";
return;
}
+
+ // drives may get an owner during this, or we might disover more
+ // drives
+ ownerlessDrives.clear();
for (const auto& [path, objDict] : subtree)
{
if (objDict.empty())
@@ -561,48 +557,49 @@ void updateAssociations()
{
continue;
}
- std::shared_ptr<bool> referenceCount = std::make_shared<bool>();
+ if (std::find(objDict.begin()->second.begin(),
+ objDict.begin()->second.end(),
+ assetTag) == objDict.begin()->second.end())
+ {
+ // no asset tag to associate to
+ continue;
+ }
+
conn->async_method_call(
- [path, referenceCount](
- const boost::system::error_code ec2,
- const boost::container::flat_map<
- std::string, std::variant<uint64_t>>& values) {
+ [path](const boost::system::error_code ec2,
+ const boost::container::flat_map<
+ std::string,
+ std::variant<uint64_t, std::string>>& values) {
if (ec2)
{
std::cerr << "Error Getting Config "
<< ec2.message() << " " << __FUNCTION__
<< "\n";
- createDriveInterfaces(referenceCount.use_count());
return;
}
auto findBus = values.find("Bus");
- auto findIndex = values.find("Index");
- if (findBus == values.end() ||
- findIndex == values.end())
+ if (findBus == values.end())
{
std::cerr << "Illegal interface at " << path
<< "\n";
- createDriveInterfaces(referenceCount.use_count());
return;
}
+ // find the mux bus and addr
size_t muxBus = static_cast<size_t>(
std::get<uint64_t>(findBus->second));
- size_t driveIndex = static_cast<size_t>(
- std::get<uint64_t>(findIndex->second));
std::filesystem::path muxPath =
"/sys/bus/i2c/devices/i2c-" +
std::to_string(muxBus) + "/mux_device";
if (!std::filesystem::is_symlink(muxPath))
{
std::cerr << path << " mux does not exist\n";
- createDriveInterfaces(referenceCount.use_count());
return;
}
- // we should be getting something of the form 7-0052 for
- // bus 7 addr 52
+ // we should be getting something of the form 7-0052
+ // for bus 7 addr 52
std::string fname =
std::filesystem::read_symlink(muxPath).filename();
auto findDash = fname.find('-');
@@ -611,7 +608,6 @@ void updateAssociations()
findDash + 1 >= fname.size())
{
std::cerr << path << " mux path invalid\n";
- createDriveInterfaces(referenceCount.use_count());
return;
}
@@ -621,9 +617,42 @@ void updateAssociations()
size_t bus = static_cast<size_t>(std::stoi(busStr));
size_t addr =
static_cast<size_t>(std::stoi(muxStr, nullptr, 16));
+ size_t muxIndex = 0;
+
+ // find the channel of the mux the drive is on
+ std::ifstream nameFile("/sys/bus/i2c/devices/i2c-" +
+ std::to_string(muxBus) +
+ "/name");
+ if (!nameFile)
+ {
+ std::cerr << "Unable to open name file of bus "
+ << muxBus << "\n";
+ return;
+ }
+
+ std::string nameStr;
+ std::getline(nameFile, nameStr);
+
+ // file is of the form "i2c-4-mux (chan_id 1)", get chan
+ // assume single digit chan
+ const std::string prefix = "chan_id ";
+ size_t findId = nameStr.find(prefix);
+ if (findId == std::string::npos ||
+ findId + 1 >= nameStr.size())
+ {
+ std::cerr << "Illegal name file on bus " << muxBus
+ << "\n";
+ }
+
+ std::string indexStr =
+ nameStr.substr(findId + prefix.size(), 1);
+
+ size_t driveIndex = std::stoi(indexStr);
+
Backplane* parent = nullptr;
for (auto& [name, backplane] : backplanes)
{
+ muxIndex = 0;
for (const Mux& mux : *(backplane.muxes))
{
if (bus == mux.bus && addr == mux.address)
@@ -631,37 +660,54 @@ void updateAssociations()
parent = &backplane;
break;
}
+ muxIndex += mux.channels;
}
}
+ boost::container::flat_map<std::string, std::string>
+ assetInventory;
+ const std::array<const char*, 4> assetKeys = {
+ "PartNumber", "SerialNumber", "Manufacturer",
+ "Model"};
+ for (const auto& [key, value] : values)
+ {
+ if (std::find(assetKeys.begin(), assetKeys.end(),
+ key) == assetKeys.end())
+ {
+ continue;
+ }
+ assetInventory[key] = std::get<std::string>(value);
+ }
+
+ // assume its a M.2 or something without a hsbp
if (parent == nullptr)
{
- std::cerr << "Failed to find mux at bus " << bus
- << ", addr " << addr << "\n";
- createDriveInterfaces(referenceCount.use_count());
+ auto& drive = ownerlessDrives.emplace_back(
+ getDriveCount() + 1, true, true, true, false);
+ drive.createAsset(assetInventory);
return;
}
+
+ driveIndex += muxIndex;
+
if (parent->drives.size() <= driveIndex)
{
-
std::cerr << "Illegal drive index at " << path
<< " " << driveIndex << "\n";
- createDriveInterfaces(referenceCount.use_count());
return;
}
+
Drive& drive = parent->drives[driveIndex];
- drive.removeDriveIface();
- drive.createAssociation(path);
- createDriveInterfaces(referenceCount.use_count());
+ drive.createAsset(assetInventory);
},
owner, path, "org.freedesktop.DBus.Properties", "GetAll",
- "xyz.openbmc_project.Inventory.Item.Drive");
+ "" /*all interface items*/);
}
},
mapper::busName, mapper::path, mapper::interface, mapper::subtree, "/",
- 0, std::array<const char*, 1>{driveType});
+ 0, std::array<const char*, 1>{nvmeType});
}
-void populateMuxes(std::shared_ptr<std::vector<Mux>> muxes,
+void populateMuxes(std::shared_ptr<boost::container::flat_set<Mux>> muxes,
std::string& rootPath)
{
const static std::array<const std::string, 4> muxTypes = {
@@ -679,7 +725,8 @@ void populateMuxes(std::shared_ptr<std::vector<Mux>> muxes,
}
std::shared_ptr<std::function<void()>> callback =
std::make_shared<std::function<void()>>(
- []() { updateAssociations(); });
+ []() { updateAssets(); });
+ size_t index = 0; // as we use a flat map, these are sorted
for (const auto& [path, objDict] : subtree)
{
if (objDict.empty() || objDict.begin()->second.empty())
@@ -708,10 +755,12 @@ void populateMuxes(std::shared_ptr<std::vector<Mux>> muxes,
}
conn->async_method_call(
- [path, muxes, callback](
+ [path, muxes, callback, index](
const boost::system::error_code ec2,
const boost::container::flat_map<
- std::string, std::variant<uint64_t>>& values) {
+ std::string,
+ std::variant<uint64_t, std::vector<std::string>>>&
+ values) {
if (ec2)
{
std::cerr << "Error Getting Config "
@@ -721,6 +770,7 @@ void populateMuxes(std::shared_ptr<std::vector<Mux>> muxes,
}
auto findBus = values.find("Bus");
auto findAddress = values.find("Address");
+ auto findChannelNames = values.find("ChannelNames");
if (findBus == values.end() ||
findAddress == values.end())
{
@@ -732,7 +782,10 @@ void populateMuxes(std::shared_ptr<std::vector<Mux>> muxes,
std::get<uint64_t>(findBus->second));
size_t address = static_cast<size_t>(
std::get<uint64_t>(findAddress->second));
- muxes->emplace_back(bus, address);
+ std::vector<std::string> channels =
+ std::get<std::vector<std::string>>(
+ findChannelNames->second);
+ muxes->emplace(bus, address, channels.size(), index);
if (callback.use_count() == 1)
{
(*callback)();
@@ -740,6 +793,7 @@ void populateMuxes(std::shared_ptr<std::vector<Mux>> muxes,
},
owner, path, "org.freedesktop.DBus.Properties", "GetAll",
*interface);
+ index++;
}
},
mapper::busName, mapper::path, mapper::interface, mapper::subtree,
@@ -849,7 +903,7 @@ int main()
sdbusplus::bus::match::match drive(
*conn,
"type='signal',member='PropertiesChanged',arg0='xyz.openbmc_project."
- "Inventory.Item.Drive'",
+ "Inventory.Item.NVMe'",
[&callbackTimer](sdbusplus::message::message& message) {
callbackTimer.expires_after(std::chrono::seconds(2));
if (message.get_sender() == conn->get_unique_name())