blob: 0107515a2caa9b585ae1dbdd69bb26dc206d0906 [file] [log] [blame]
Tom Joseph6b7a1432017-05-19 10:43:36 +05301#include <chrono>
2#include <vector>
3#include <phosphor-logging/elog-errors.hpp>
4#include "host-ipmid/ipmid-api.h"
5#include "xyz/openbmc_project/Common/error.hpp"
Tom Joseph6edc8a02017-06-30 18:52:56 +05306#include "config.h"
Tom Joseph6b7a1432017-05-19 10:43:36 +05307#include "selutility.hpp"
8#include "types.hpp"
9#include "utils.hpp"
10
11extern const ipmi::sensor::InvObjectIDMap invSensors;
12using namespace phosphor::logging;
13using InternalFailure =
14 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
15
16namespace ipmi
17{
18
19namespace sel
20{
21
22namespace internal
23{
24
25GetSELEntryResponse prepareSELEntry(
26 const std::string& objPath,
27 ipmi::sensor::InvObjectIDMap::const_iterator iter)
28{
29 ipmi::sel::GetSELEntryResponse record {};
30
31 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
32 auto service = ipmi::getService(bus, logEntryIntf, objPath);
33
34 // Read all the log entry properties.
35 auto methodCall = bus.new_method_call(service.c_str(),
36 objPath.c_str(),
37 propIntf,
38 "GetAll");
39 methodCall.append(logEntryIntf);
40
41 auto reply = bus.call(methodCall);
42 if (reply.is_method_error())
43 {
44 log<level::ERR>("Error in reading logging property entries");
45 elog<InternalFailure>();
46 }
47
48 std::map<std::string, PropertyType> entryData;
49 reply.read(entryData);
50
51 // Read Id from the log entry.
52 static constexpr auto propId = "Id";
53 auto iterId = entryData.find(propId);
54 if (iterId == entryData.end())
55 {
56 log<level::ERR>("Error in reading Id of logging entry");
57 elog<InternalFailure>();
58 }
59
60 record.recordID = static_cast<uint16_t>(
61 sdbusplus::message::variant_ns::get<uint32_t>(iterId->second));
62
63 // Read Timestamp from the log entry.
64 static constexpr auto propTimeStamp = "Timestamp";
65 auto iterTimeStamp = entryData.find(propTimeStamp);
66 if (iterTimeStamp == entryData.end())
67 {
68 log<level::ERR>("Error in reading Timestamp of logging entry");
69 elog<InternalFailure>();
70 }
71
72 std::chrono::milliseconds chronoTimeStamp(
73 sdbusplus::message::variant_ns::get<uint64_t>
74 (iterTimeStamp->second));
75 record.timeStamp = static_cast<uint32_t>(std::chrono::duration_cast<
76 std::chrono::seconds>(chronoTimeStamp).count());
77
78 static constexpr auto systemEventRecord = 0x02;
79 static constexpr auto generatorID = 0x2000;
80 static constexpr auto eventMsgRevision = 0x04;
81
82 record.recordType = systemEventRecord;
83 record.generatorID = generatorID;
84 record.eventMsgRevision = eventMsgRevision;
85
86 record.sensorType = iter->second.sensorType;
87 record.sensorNum = iter->second.sensorID;
88 record.eventData1 = iter->second.eventOffset;
89
90 // Read Resolved from the log entry.
91 static constexpr auto propResolved = "Resolved";
92 auto iterResolved = entryData.find(propResolved);
93 if (iterResolved == entryData.end())
94 {
95 log<level::ERR>("Error in reading Resolved field of logging entry");
96 elog<InternalFailure>();
97 }
98
99 static constexpr auto deassertEvent = 0x80;
100
101 // Evaluate if the event is assertion or deassertion event
102 if (sdbusplus::message::variant_ns::get<bool>(iterResolved->second))
103 {
104 record.eventType = deassertEvent | iter->second.eventReadingType;
105 }
106 else
107 {
108 record.eventType = iter->second.eventReadingType;
109 }
110
111 return record;
112}
113
114} // namespace internal
115
Tom Joseph6edc8a02017-06-30 18:52:56 +0530116GetSELEntryResponse convertLogEntrytoSEL(const std::string& objPath)
117{
118 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
119
120 static constexpr auto assocIntf = "org.openbmc.Associations";
121 static constexpr auto assocProp = "associations";
122
123 auto service = ipmi::getService(bus, assocIntf, objPath);
124
125 // Read the Associations interface.
126 auto methodCall = bus.new_method_call(service.c_str(),
127 objPath.c_str(),
128 propIntf,
129 "Get");
130 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
140 using AssociationList = std::vector<std::tuple<
141 std::string, std::string, std::string>>;
142
143 sdbusplus::message::variant<AssociationList> list;
144 reply.read(list);
145
146 auto& assocs = sdbusplus::message::variant_ns::get<AssociationList>
147 (list);
148
149 /*
150 * Check if the log entry has any callout associations, if there is a
151 * callout association try to match the inventory path to the corresponding
152 * IPMI sensor.
153 */
154 for (const auto& item : assocs)
155 {
156 if (std::get<0>(item).compare(CALLOUT_FWD_ASSOCIATION) == 0)
157 {
158 auto iter = invSensors.find(std::get<2>(item));
159 if (iter == invSensors.end())
160 {
161 iter = invSensors.find(BOARD_SENSOR);
162 if (iter == invSensors.end())
163 {
164 log<level::ERR>("Motherboard sensor not found");
165 elog<InternalFailure>();
166 }
167 }
168
169 return internal::prepareSELEntry(objPath, iter);
170 }
171 }
172
173 // If there are no callout associations link the log entry to system event
174 // sensor
175 auto iter = invSensors.find(SYSTEM_SENSOR);
176 if (iter == invSensors.end())
177 {
178 log<level::ERR>("System event sensor not found");
179 elog<InternalFailure>();
180 }
181
182 return internal::prepareSELEntry(objPath, iter);
183}
184
Tom Joseph6b7a1432017-05-19 10:43:36 +0530185} // namespace sel
186
187} // namespace ipmi