blob: 4ed22fccf5b463929188a3086160101b897aa84e [file] [log] [blame]
Patrick Venture0b02be92018-08-31 11:55:55 -07001#include "elog-errors.hpp"
2#include "error-HostEvent.hpp"
Patrick Venture46470a32018-09-07 19:26:25 -07003#include "sensorhandler.hpp"
4#include "storagehandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07005#include "types.hpp"
6
Patrick Venture46470a32018-09-07 19:26:25 -07007#include <host-ipmid/ipmid-api.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07008#include <mapper.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <systemd/sd-bus.h>
10
11#include <algorithm>
Chris Austen41a4b312015-10-25 03:45:42 -050012#include <cstdlib>
13#include <cstring>
14#include <fstream>
15#include <iostream>
Chris Austen41a4b312015-10-25 03:45:42 -050016#include <memory>
Saqib Khand33a4af2017-02-20 15:23:27 -060017#include <phosphor-logging/elog.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070018#include <vector>
19#include <xyz/openbmc_project/Logging/Entry/server.hpp>
20
Chris Austen41a4b312015-10-25 03:45:42 -050021using namespace std;
Adriana Kobylak2efb3e72017-02-06 21:43:59 -060022using namespace phosphor::logging;
Deepak Kodihalli3d230482018-04-03 07:00:45 -050023using namespace sdbusplus::xyz::openbmc_project::Logging::server;
Tom Joseph448e74e2017-07-24 23:08:56 +053024extern const ipmi::sensor::InvObjectIDMap invSensors;
Chris Austen41a4b312015-10-25 03:45:42 -050025
Chris Austen41a4b312015-10-25 03:45:42 -050026//////////////////////////
Patrick Venture0b02be92018-08-31 11:55:55 -070027struct esel_section_headers_t
28{
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050029 uint8_t sectionid[2];
30 uint8_t sectionlength[2];
31 uint8_t version;
32 uint8_t subsectiontype;
33 uint8_t compid;
Chris Austen41a4b312015-10-25 03:45:42 -050034};
35
Patrick Venture0b02be92018-08-31 11:55:55 -070036struct severity_values_t
37{
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050038 uint8_t type;
39 Entry::Level level;
Chris Austen41a4b312015-10-25 03:45:42 -050040};
41
Chris Austen41a4b312015-10-25 03:45:42 -050042const std::vector<severity_values_t> g_sev_desc = {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050043 {0x10, Entry::Level::Warning}, // recoverable error
44 {0x20, Entry::Level::Warning}, // predictive error
Patrick Venture0b02be92018-08-31 11:55:55 -070045 // TODO via github issue 3066 : map level
46 // below to Level::Unrecoverable
47 {0x40, Entry::Level::Error}, // unrecoverable error
48 // TODO via github issue 3066 : map level below
49 // to Level::Critical
50 {0x50, Entry::Level::Error}, // critical error
51 {0x60, Entry::Level::Error}, // error from a diagnostic test
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050052 {0x70, Entry::Level::Warning}, // recoverable symptom
Patrick Venture0b02be92018-08-31 11:55:55 -070053 {0xFF, Entry::Level::Error}, // unknown error
Chris Austen41a4b312015-10-25 03:45:42 -050054};
55
Patrick Venture0b02be92018-08-31 11:55:55 -070056Entry::Level sev_lookup(uint8_t n)
57{
58 auto i =
59 std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc),
60 [n](auto p) { return p.type == n || p.type == 0xFF; });
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050061 return i->level;
Chris Austen41a4b312015-10-25 03:45:42 -050062}
63
Patrick Venture0b02be92018-08-31 11:55:55 -070064int find_sensor_type_string(uint8_t sensor_number, char** s)
65{
Chris Austen41a4b312015-10-25 03:45:42 -050066
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050067 dbus_interface_t a;
Patrick Venture0b02be92018-08-31 11:55:55 -070068 const char* p;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050069 int r;
Chris Austen41a4b312015-10-25 03:45:42 -050070
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050071 r = find_openbmc_path(sensor_number, &a);
Chris Austen41a4b312015-10-25 03:45:42 -050072
Patrick Venture0b02be92018-08-31 11:55:55 -070073 if ((r < 0) || (a.bus[0] == 0))
74 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050075 // Just make a generic message for errors that
76 // occur on sensors that don't exist
77 r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number);
Patrick Venture0b02be92018-08-31 11:55:55 -070078 }
79 else
80 {
Chris Austen41a4b312015-10-25 03:45:42 -050081
Patrick Venture0b02be92018-08-31 11:55:55 -070082 if ((p = strrchr(a.path, '/')) == NULL)
83 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050084 p = "/Unknown Sensor";
85 }
Chris Austen41a4b312015-10-25 03:45:42 -050086
Patrick Venture0b02be92018-08-31 11:55:55 -070087 *s = strdup(p + 1);
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050088 }
Chris Austen41a4b312015-10-25 03:45:42 -050089
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050090 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -050091}
92
Patrick Venture0b02be92018-08-31 11:55:55 -070093size_t getfilestream(const char* fn, uint8_t** buffer)
94{
Chris Austen41a4b312015-10-25 03:45:42 -050095
Patrick Venture0b02be92018-08-31 11:55:55 -070096 FILE* fp;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -050097 ssize_t size = 0;
98 int r;
Chris Austen41a4b312015-10-25 03:45:42 -050099
Patrick Venture0b02be92018-08-31 11:55:55 -0700100 if ((fp = fopen(fn, "rb")) != NULL)
101 {
Chris Austen41a4b312015-10-25 03:45:42 -0500102
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500103 r = fseek(fp, 0, SEEK_END);
Patrick Venture0b02be92018-08-31 11:55:55 -0700104 if (r)
105 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500106 log<level::ERR>("Fseek failed");
107 goto fclose_fp;
108 }
Nan Lidfe6e422016-05-13 21:46:26 +0800109
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500110 size = ftell(fp);
Patrick Venture0b02be92018-08-31 11:55:55 -0700111 if (size == -1L)
112 {
113 log<level::ERR>("Ftell failed", entry("ERROR=%s", strerror(errno)));
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500114 size = 0;
115 goto fclose_fp;
116 }
Nan Lidfe6e422016-05-13 21:46:26 +0800117
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500118 r = fseek(fp, 0, SEEK_SET);
Patrick Venture0b02be92018-08-31 11:55:55 -0700119 if (r)
120 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500121 log<level::ERR>("Fseek failed");
122 size = 0;
123 goto fclose_fp;
124 }
Chris Austen41a4b312015-10-25 03:45:42 -0500125
Patrick Venture0b02be92018-08-31 11:55:55 -0700126 *buffer = new uint8_t[size];
Chris Austen41a4b312015-10-25 03:45:42 -0500127
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500128 r = fread(*buffer, 1, size, fp);
Patrick Venture0b02be92018-08-31 11:55:55 -0700129 if (r != size)
130 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500131 size = 0;
132 log<level::ERR>("Fread failed\n");
133 }
Nan Lidfe6e422016-05-13 21:46:26 +0800134
Patrick Venture0b02be92018-08-31 11:55:55 -0700135 fclose_fp:
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500136 fclose(fp);
137 }
Chris Austen41a4b312015-10-25 03:45:42 -0500138
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500139 return static_cast<size_t>(size);
Chris Austen41a4b312015-10-25 03:45:42 -0500140}
141
Patrick Venture0b02be92018-08-31 11:55:55 -0700142Entry::Level create_esel_severity(const uint8_t* buffer)
143{
Chris Austen41a4b312015-10-25 03:45:42 -0500144
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500145 uint8_t severity;
146 // Dive in to the IBM log to find the severity
Patrick Venture0b02be92018-08-31 11:55:55 -0700147 severity = (0xF0 & buffer[0x4A]);
Chris Austen41a4b312015-10-25 03:45:42 -0500148
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500149 return sev_lookup(severity);
Chris Austen41a4b312015-10-25 03:45:42 -0500150}
151
Patrick Venture0b02be92018-08-31 11:55:55 -0700152int create_esel_association(const uint8_t* buffer, std::string& inventoryPath)
Tom Joseph448e74e2017-07-24 23:08:56 +0530153{
Patrick Ventured99148b2018-10-13 10:06:13 -0700154 auto p = reinterpret_cast<const ipmi_add_sel_request_t*>(buffer);
Chris Austen41a4b312015-10-25 03:45:42 -0500155
Patrick Venture2e633522018-10-13 13:51:06 -0700156 uint8_t sensor = p->sensornumber;
Chris Austen41a4b312015-10-25 03:45:42 -0500157
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500158 inventoryPath = {};
Chris Austen41a4b312015-10-25 03:45:42 -0500159
Tom Joseph448e74e2017-07-24 23:08:56 +0530160 /*
161 * Search the sensor number to inventory path mapping to figure out the
162 * inventory associated with the ESEL.
163 */
Patrick Venture2e633522018-10-13 13:51:06 -0700164 auto found = std::find_if(invSensors.begin(), invSensors.end(),
165 [&sensor](const auto& iter) {
166 return (iter.second.sensorID == sensor);
167 });
168 if (found != invSensors.end())
Tom Joseph448e74e2017-07-24 23:08:56 +0530169 {
Patrick Venture2e633522018-10-13 13:51:06 -0700170 inventoryPath = found->first;
Tom Joseph448e74e2017-07-24 23:08:56 +0530171 }
Chris Austen41a4b312015-10-25 03:45:42 -0500172
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500173 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500174}
175
Patrick Venture0b02be92018-08-31 11:55:55 -0700176int create_esel_description(const uint8_t* buffer, Entry::Level level,
177 char** message)
178{
Patrick Venture0b02be92018-08-31 11:55:55 -0700179 char* m;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500180 int r;
Chris Austen41a4b312015-10-25 03:45:42 -0500181
Patrick Ventured99148b2018-10-13 10:06:13 -0700182 auto p = reinterpret_cast<const ipmi_add_sel_request_t*>(buffer);
Chris Austen41a4b312015-10-25 03:45:42 -0500183
Patrick Venture0b02be92018-08-31 11:55:55 -0700184 find_sensor_type_string(p->sensornumber, &m);
Chris Austen41a4b312015-10-25 03:45:42 -0500185
Patrick Venture0b02be92018-08-31 11:55:55 -0700186 r = asprintf(message, "A %s has experienced an error of level %d", m,
187 static_cast<uint32_t>(level));
188 if (r == -1)
189 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500190 log<level::ERR>("Failed to allocate memory for ESEL description");
191 }
Chris Austen41a4b312015-10-25 03:45:42 -0500192
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500193 free(m);
Chris Austen41a4b312015-10-25 03:45:42 -0500194
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500195 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500196}
197
Patrick Venture0b02be92018-08-31 11:55:55 -0700198int send_esel_to_dbus(const char* desc, Entry::Level level,
199 const std::string& inventoryPath, uint8_t* debug,
Tom Joseph448e74e2017-07-24 23:08:56 +0530200 size_t debuglen)
201{
Chris Austen41a4b312015-10-25 03:45:42 -0500202
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600203 // Allocate enough space to represent the data in hex separated by spaces,
204 // to mimic how IPMI would display the data.
Patrick Venture0b02be92018-08-31 11:55:55 -0700205 unique_ptr<char[]> selData(new char[(debuglen * 3) + 1]());
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600206 uint32_t i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700207 for (i = 0; i < debuglen; i++)
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600208 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700209 sprintf(&selData[i * 3], "%02x ", 0xFF & ((char*)debug)[i]);
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600210 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700211 selData[debuglen * 3] = '\0';
Tom Josephb9ac6a42017-02-28 19:56:33 +0530212
Patrick Venture0b02be92018-08-31 11:55:55 -0700213 using error = sdbusplus::org::open_power::Host::Error::Event;
Marri Devender Raob0b395b2017-10-24 10:14:14 -0500214 using metadata = org::open_power::Host::Event;
Tom Joseph448e74e2017-07-24 23:08:56 +0530215
Patrick Venture0b02be92018-08-31 11:55:55 -0700216 report<error>(level, metadata::ESEL(selData.get()),
Tom Joseph448e74e2017-07-24 23:08:56 +0530217 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600218
Adriana Kobylak513d68e2017-02-15 11:36:28 -0600219 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500220}
221
Patrick Venture0b02be92018-08-31 11:55:55 -0700222void send_esel(uint16_t recordid)
223{
224 char* desc;
225 uint8_t* buffer = NULL;
226 const char* path = "/tmp/esel";
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500227 ssize_t sz;
228 int r;
229 std::string inventoryPath;
Chris Austen41a4b312015-10-25 03:45:42 -0500230
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500231 sz = getfilestream(path, &buffer);
Patrick Venture0b02be92018-08-31 11:55:55 -0700232 if (sz == 0)
233 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500234 log<level::ERR>("Error file does not exist",
235 entry("FILENAME=%s", path));
236 return;
237 }
Chris Austen41a4b312015-10-25 03:45:42 -0500238
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500239 auto sev = create_esel_severity(buffer);
240 create_esel_association(buffer, inventoryPath);
241 create_esel_description(buffer, sev, &desc);
Chris Austen41a4b312015-10-25 03:45:42 -0500242
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500243 r = send_esel_to_dbus(desc, sev, inventoryPath, buffer, sz);
Patrick Venture0b02be92018-08-31 11:55:55 -0700244 if (r < 0)
245 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500246 log<level::ERR>("Failed to send esel to dbus");
247 }
Chris Austen41a4b312015-10-25 03:45:42 -0500248
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500249 free(desc);
250 delete[] buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500251
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500252 return;
Chris Austen41a4b312015-10-25 03:45:42 -0500253}
Tom Josephb647d5b2017-10-31 17:25:33 +0530254
255std::string readESEL(const char* fileName)
256{
257 std::string content;
258 std::ifstream handle(fileName);
259
260 if (handle.fail())
261 {
262 log<level::ERR>("Failed to open eSEL", entry("FILENAME=%s", fileName));
263 return content;
264 }
265
266 handle.seekg(0, std::ios::end);
267 content.resize(handle.tellg());
268 handle.seekg(0, std::ios::beg);
269 handle.read(&content[0], content.size());
270 handle.close();
271
272 return content;
273}
274
275void createProcedureLogEntry(uint8_t procedureNum)
276{
277 // Read the eSEL data from the file.
278 static constexpr auto eSELFile = "/tmp/esel";
279 auto eSELData = readESEL(eSELFile);
280
281 // Each byte in eSEL is formatted as %02x with a space between bytes and
282 // insert '/0' at the end of the character array.
283 static constexpr auto byteSeparator = 3;
Patrick Venture0b02be92018-08-31 11:55:55 -0700284 std::unique_ptr<char[]> data(
285 new char[(eSELData.size() * byteSeparator) + 1]());
Tom Josephb647d5b2017-10-31 17:25:33 +0530286
287 for (size_t i = 0; i < eSELData.size(); i++)
288 {
289 sprintf(&data[i * byteSeparator], "%02x ", eSELData[i]);
290 }
291 data[eSELData.size() * byteSeparator] = '\0';
292
Patrick Venture0b02be92018-08-31 11:55:55 -0700293 using error = sdbusplus::org::open_power::Host::Error::MaintenanceProcedure;
Tom Josephb647d5b2017-10-31 17:25:33 +0530294 using metadata = org::open_power::Host::MaintenanceProcedure;
295
296 report<error>(metadata::ESEL(data.get()),
297 metadata::PROCEDURE(static_cast<uint32_t>(procedureNum)));
298}