blob: b23498e05bc3b4281e598baa90f678991b6e7479 [file] [log] [blame]
Marri Devender Rao0acf0572017-07-03 12:25:47 -05001#include <map>
2#include <phosphor-logging/elog-errors.hpp>
3#include "xyz/openbmc_project/Common/error.hpp"
4#include "read_fru_data.hpp"
5#include "fruread.hpp"
6#include "host-ipmid/ipmid-api.h"
7#include "utils.hpp"
8
9extern const FruMap frus;
Marri Devender Rao0acf0572017-07-03 12:25:47 -050010namespace ipmi
11{
12namespace fru
13{
14using namespace phosphor::logging;
15using InternalFailure =
16 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Marri Devender Rao908f7502017-07-10 01:49:54 -050017std::unique_ptr<sdbusplus::bus::match_t> matchPtr(nullptr);
Marri Devender Rao0acf0572017-07-03 12:25:47 -050018
19static constexpr auto INV_INTF = "xyz.openbmc_project.Inventory.Manager";
20static constexpr auto OBJ_PATH = "/xyz/openbmc_project/inventory";
21static constexpr auto PROP_INTF = "org.freedesktop.DBus.Properties";
22
23namespace cache
24{
25 //User initiate read FRU info area command followed by
26 //FRU read command. Also data is read in small chunks of
27 //the specified offset and count.
28 //Caching the data which will be invalidated when ever there
29 //is a change in FRU properties.
30 FRUAreaMap fruMap;
31}
32/**
33 * @brief Read the property value from Inventory
34 *
35 * @param[in] bus dbus
36 * @param[in] intf Interface
37 * @param[in] propertyName Name of the property
38 * @param[in] path Object path
39 * @return property value
40 */
41std::string readProperty(const std::string& intf,
42 const std::string& propertyName,
43 const std::string& path)
44{
45 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
46 auto service = ipmi::getService(bus, INV_INTF, OBJ_PATH);
47 std::string objPath = OBJ_PATH + path;
48 auto method = bus.new_method_call(service.c_str(),
49 objPath.c_str(),
50 PROP_INTF,
51 "Get");
52 method.append(intf, propertyName);
53 auto reply = bus.call(method);
54 if (reply.is_method_error())
55 {
56 //If property is not found simply return empty value
57 log<level::INFO>("Property value not set",
58 entry("Property=%s", propertyName),
59 entry("Path=%s", objPath));
60 return {};
61 }
62 sdbusplus::message::variant<std::string> property;
63 reply.read(property);
64 std::string value =
65 sdbusplus::message::variant_ns::get<std::string>(property);
66 return value;
67}
68
Marri Devender Rao908f7502017-07-10 01:49:54 -050069void processFruPropChange(sdbusplus::message::message& msg)
70{
71 if(cache::fruMap.empty())
72 {
73 return;
74 }
75 std::string path = msg.get_path();
76 //trim the object base path, if found at the beginning
77 if (path.compare(0, strlen(OBJ_PATH), OBJ_PATH) == 0)
78 {
79 path.erase(0, strlen(OBJ_PATH));
80 }
81 for (auto& fru : frus)
82 {
83 bool found = false;
84 auto& fruId = fru.first;
85 auto& instanceList = fru.second;
86 for (auto& instance : instanceList)
87 {
88 if(instance.first == path)
89 {
90 found = true;
91 break;
92 }
93 }
94 if (found)
95 {
96 cache::fruMap.erase(fruId);
97 break;
98 }
99 }
100}
101
102//register for fru property change
103int registerCallbackHandler()
104{
105 if(matchPtr == nullptr)
106 {
107 using namespace sdbusplus::bus::match::rules;
108 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
109 matchPtr = std::make_unique<sdbusplus::bus::match_t>(
110 bus,
111 path_namespace(OBJ_PATH) +
112 type::signal() +
113 member("PropertiesChanged") +
114 interface(PROP_INTF),
115 std::bind(processFruPropChange, std::placeholders::_1));
116 }
117 return 0;
118}
119
Marri Devender Rao0acf0572017-07-03 12:25:47 -0500120/**
121 * @brief Read FRU property values from Inventory
122 *
123 * @param[in] fruNum FRU id
124 * @return populate FRU Inventory data
125 */
126FruInventoryData readDataFromInventory(const FRUId& fruNum)
127{
128 auto iter = frus.find(fruNum);
129 if (iter == frus.end())
130 {
131 log<level::ERR>("Unsupported FRU ID ",entry("FRUID=%d", fruNum));
132 elog<InternalFailure>();
133 }
134
135 FruInventoryData data;
136 auto& instanceList = iter->second;
137 for (auto& instance : instanceList)
138 {
139 for (auto& interfaceList : instance.second)
140 {
141 for (auto& properties : interfaceList.second)
142 {
143 decltype(auto) pdata = properties.second;
144 auto value = readProperty(
145 interfaceList.first, properties.first,
146 instance.first);
147 data[pdata.section].emplace(properties.first, value);
148 }
149 }
150 }
151 return data;
152}
153
154const FruAreaData& getFruAreaData(const FRUId& fruNum)
155{
156 auto iter = cache::fruMap.find(fruNum);
157 if (iter != cache::fruMap.end())
158 {
159 return iter->second;
160 }
161 auto invData = readDataFromInventory(fruNum);
162
163 //Build area info based on inventory data
164 FruAreaData newdata = buildFruAreaData(std::move(invData));
165 cache::fruMap.emplace(fruNum, std::move(newdata));
166 return cache::fruMap.at(fruNum);
167}
168} //fru
169} //ipmi