blob: 3aecb1ca54138fe48f18514d9ad7fab43892593a [file] [log] [blame]
Patrick Venture46470a32018-09-07 19:26:25 -07001#include "config.h"
2
3#include "selutility.hpp"
4
William A. Kennington III194375f2018-12-14 02:14:33 -08005#include <ipmid/api.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -07006
Tom Joseph6b7a1432017-05-19 10:43:36 +05307#include <chrono>
Vernon Mauerybdda8002019-02-26 10:18:51 -08008#include <filesystem>
Vernon Mauery33250242019-03-12 16:49:26 -07009#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070010#include <ipmid/utils.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070011#include <phosphor-logging/elog-errors.hpp>
Tom Joseph6b7a1432017-05-19 10:43:36 +053012#include <vector>
Patrick Venture3a5071a2018-09-12 13:27:42 -070013#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070014
Tom Joseph6b7a1432017-05-19 10:43:36 +053015extern const ipmi::sensor::InvObjectIDMap invSensors;
16using namespace phosphor::logging;
17using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070018 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6b7a1432017-05-19 10:43:36 +053019
20namespace ipmi
21{
22
23namespace sel
24{
25
26namespace internal
27{
28
Patrick Venture0b02be92018-08-31 11:55:55 -070029GetSELEntryResponse
30 prepareSELEntry(const std::string& objPath,
31 ipmi::sensor::InvObjectIDMap::const_iterator iter)
Tom Joseph6b7a1432017-05-19 10:43:36 +053032{
Patrick Venture0b02be92018-08-31 11:55:55 -070033 GetSELEntryResponse record{};
Tom Joseph6b7a1432017-05-19 10:43:36 +053034
35 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
36 auto service = ipmi::getService(bus, logEntryIntf, objPath);
37
38 // Read all the log entry properties.
Patrick Venture0b02be92018-08-31 11:55:55 -070039 auto methodCall = bus.new_method_call(service.c_str(), objPath.c_str(),
40 propIntf, "GetAll");
Tom Joseph6b7a1432017-05-19 10:43:36 +053041 methodCall.append(logEntryIntf);
42
43 auto reply = bus.call(methodCall);
44 if (reply.is_method_error())
45 {
46 log<level::ERR>("Error in reading logging property entries");
47 elog<InternalFailure>();
48 }
49
Tom Joseph306878b2017-07-10 19:30:54 +053050 std::map<PropertyName, PropertyType> entryData;
Tom Joseph6b7a1432017-05-19 10:43:36 +053051 reply.read(entryData);
52
53 // Read Id from the log entry.
54 static constexpr auto propId = "Id";
55 auto iterId = entryData.find(propId);
56 if (iterId == entryData.end())
57 {
58 log<level::ERR>("Error in reading Id of logging entry");
59 elog<InternalFailure>();
60 }
61
62 record.recordID = static_cast<uint16_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -070063 sdbusplus::message::variant_ns::get<uint32_t>(iterId->second));
Tom Joseph6b7a1432017-05-19 10:43:36 +053064
65 // Read Timestamp from the log entry.
66 static constexpr auto propTimeStamp = "Timestamp";
67 auto iterTimeStamp = entryData.find(propTimeStamp);
68 if (iterTimeStamp == entryData.end())
69 {
70 log<level::ERR>("Error in reading Timestamp of logging entry");
71 elog<InternalFailure>();
72 }
73
74 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -070075 sdbusplus::message::variant_ns::get<uint64_t>(iterTimeStamp->second));
76 record.timeStamp = static_cast<uint32_t>(
77 std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp)
78 .count());
Tom Joseph6b7a1432017-05-19 10:43:36 +053079
80 static constexpr auto systemEventRecord = 0x02;
81 static constexpr auto generatorID = 0x2000;
82 static constexpr auto eventMsgRevision = 0x04;
83
84 record.recordType = systemEventRecord;
85 record.generatorID = generatorID;
86 record.eventMsgRevision = eventMsgRevision;
87
88 record.sensorType = iter->second.sensorType;
89 record.sensorNum = iter->second.sensorID;
90 record.eventData1 = iter->second.eventOffset;
91
92 // Read Resolved from the log entry.
93 static constexpr auto propResolved = "Resolved";
94 auto iterResolved = entryData.find(propResolved);
95 if (iterResolved == entryData.end())
96 {
97 log<level::ERR>("Error in reading Resolved field of logging entry");
98 elog<InternalFailure>();
99 }
100
101 static constexpr auto deassertEvent = 0x80;
102
103 // Evaluate if the event is assertion or deassertion event
104 if (sdbusplus::message::variant_ns::get<bool>(iterResolved->second))
105 {
106 record.eventType = deassertEvent | iter->second.eventReadingType;
107 }
108 else
109 {
110 record.eventType = iter->second.eventReadingType;
111 }
112
113 return record;
114}
115
116} // namespace internal
117
Tom Joseph6edc8a02017-06-30 18:52:56 +0530118GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
119{
120 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
121
122 static constexpr auto assocIntf = "org.openbmc.Associations";
123 static constexpr auto assocProp = "associations";
124
125 auto service = ipmi::getService(bus, assocIntf, objPath);
126
127 // Read the Associations interface.
Patrick Venture0b02be92018-08-31 11:55:55 -0700128 auto methodCall =
129 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph6edc8a02017-06-30 18:52:56 +0530130 methodCall.append(assocIntf);
131 methodCall.append(assocProp);
132
133 auto reply = bus.call(methodCall);
134 if (reply.is_method_error())
135 {
136 log<level::ERR>("Error in reading Associations interface");
137 elog<InternalFailure>();
138 }
139
Patrick Venture0b02be92018-08-31 11:55:55 -0700140 using AssociationList =
141 std::vector<std::tuple<std::string, std::string, std::string>>;
Tom Joseph6edc8a02017-06-30 18:52:56 +0530142
143 sdbusplus::message::variant<AssociationList> list;
144 reply.read(list);
145
Patrick Venture0b02be92018-08-31 11:55:55 -0700146 auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>(list);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530147
148 /*
149 * Check if the log entry has any callout associations, if there is a
150 * callout association try to match the inventory path to the corresponding
151 * IPMI sensor.
152 */
153 for (const auto& item : assocs)
154 {
155 if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
156 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700157 auto iter = invSensors.find(std::get<2>(item));
158 if (iter == invSensors.end())
159 {
160 iter = invSensors.find(BOARD_SENSOR);
161 if (iter == invSensors.end())
162 {
163 log<level::ERR>("Motherboard sensor not found");
164 elog<InternalFailure>();
165 }
166 }
Tom Joseph6edc8a02017-06-30 18:52:56 +0530167
Patrick Venture0b02be92018-08-31 11:55:55 -0700168 return internal::prepareSELEntry(objPath, iter);
Tom Joseph6edc8a02017-06-30 18:52:56 +0530169 }
170 }
171
172 // If there are no callout associations link the log entry to system event
173 // sensor
174 auto iter = invSensors.find(SYSTEM_SENSOR);
175 if (iter == invSensors.end())
176 {
177 log<level::ERR>("System event sensor not found");
178 elog<InternalFailure>();
179 }
180
181 return internal::prepareSELEntry(objPath, iter);
182}
183
Tom Joseph399fd922017-06-30 18:40:30 +0530184std::chrono::seconds getEntryTimeStamp(const std::string& objPath)
185{
186 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
187
188 auto service = ipmi::getService(bus, logEntryIntf, objPath);
189
190 using namespace std::string_literals;
191 static const auto propTimeStamp = "Timestamp"s;
192
Patrick Venture0b02be92018-08-31 11:55:55 -0700193 auto methodCall =
194 bus.new_method_call(service.c_str(), objPath.c_str(), propIntf, "Get");
Tom Joseph399fd922017-06-30 18:40:30 +0530195 methodCall.append(logEntryIntf);
196 methodCall.append(propTimeStamp);
197
198 auto reply = bus.call(methodCall);
199 if (reply.is_method_error())
200 {
201 log<level::ERR>("Error in reading Timestamp from Entry interface");
202 elog<InternalFailure>();
203 }
204
205 sdbusplus::message::variant<uint64_t> timeStamp;
206 reply.read(timeStamp);
207
208 std::chrono::milliseconds chronoTimeStamp(
Patrick Venture0b02be92018-08-31 11:55:55 -0700209 sdbusplus::message::variant_ns::get<uint64_t>(timeStamp));
Tom Joseph399fd922017-06-30 18:40:30 +0530210
211 return std::chrono::duration_cast<std::chrono::seconds>(chronoTimeStamp);
212}
213
Tom Joseph232f5292017-07-07 20:14:02 +0530214void readLoggingObjectPaths(ObjectPaths& paths)
215{
216 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
217 auto depth = 0;
218 paths.clear();
219
Patrick Venture0b02be92018-08-31 11:55:55 -0700220 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
221 mapperIntf, "GetSubTreePaths");
Tom Joseph232f5292017-07-07 20:14:02 +0530222 mapperCall.append(logBasePath);
223 mapperCall.append(depth);
224 mapperCall.append(ObjectPaths({logEntryIntf}));
225
226 auto reply = bus.call(mapperCall);
227 if (reply.is_method_error())
228 {
229 log<level::INFO>("Error in reading logging entry object paths");
230 }
231 else
232 {
233 reply.read(paths);
234
Patrick Venture0b02be92018-08-31 11:55:55 -0700235 std::sort(paths.begin(), paths.end(),
236 [](const std::string& a, const std::string& b) {
237 namespace fs = std::filesystem;
238 fs::path pathA(a);
239 fs::path pathB(b);
240 auto idA = std::stoul(pathA.filename().string());
241 auto idB = std::stoul(pathB.filename().string());
Tom Joseph232f5292017-07-07 20:14:02 +0530242
Patrick Venture0b02be92018-08-31 11:55:55 -0700243 return idA < idB;
244 });
Tom Joseph232f5292017-07-07 20:14:02 +0530245 }
246}
247
Tom Joseph6b7a1432017-05-19 10:43:36 +0530248} // namespace sel
249
250} // namespace ipmi