blob: 8a0dce594e117aba51914d8edca8f9edd1a30e0d [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 Venture0b02be92018-08-31 11:55:55 -0700154 ipmi_add_sel_request_t* p;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500155 uint8_t sensor;
Chris Austen41a4b312015-10-25 03:45:42 -0500156
Patrick Venture0b02be92018-08-31 11:55:55 -0700157 p = (ipmi_add_sel_request_t*)buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500158
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500159 sensor = p->sensornumber;
Chris Austen41a4b312015-10-25 03:45:42 -0500160
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500161 inventoryPath = {};
Chris Austen41a4b312015-10-25 03:45:42 -0500162
Tom Joseph448e74e2017-07-24 23:08:56 +0530163 /*
164 * Search the sensor number to inventory path mapping to figure out the
165 * inventory associated with the ESEL.
166 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700167 for (auto const& iter : invSensors)
Tom Joseph448e74e2017-07-24 23:08:56 +0530168 {
169 if (iter.second.sensorID == sensor)
170 {
171 inventoryPath = iter.first;
172 break;
173 }
174 }
Chris Austen41a4b312015-10-25 03:45:42 -0500175
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500176 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500177}
178
Patrick Venture0b02be92018-08-31 11:55:55 -0700179int create_esel_description(const uint8_t* buffer, Entry::Level level,
180 char** message)
181{
Chris Austen41a4b312015-10-25 03:45:42 -0500182
Patrick Venture0b02be92018-08-31 11:55:55 -0700183 ipmi_add_sel_request_t* p;
184 char* m;
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500185 int r;
Chris Austen41a4b312015-10-25 03:45:42 -0500186
Patrick Venture0b02be92018-08-31 11:55:55 -0700187 p = (ipmi_add_sel_request_t*)buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500188
Patrick Venture0b02be92018-08-31 11:55:55 -0700189 find_sensor_type_string(p->sensornumber, &m);
Chris Austen41a4b312015-10-25 03:45:42 -0500190
Patrick Venture0b02be92018-08-31 11:55:55 -0700191 r = asprintf(message, "A %s has experienced an error of level %d", m,
192 static_cast<uint32_t>(level));
193 if (r == -1)
194 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500195 log<level::ERR>("Failed to allocate memory for ESEL description");
196 }
Chris Austen41a4b312015-10-25 03:45:42 -0500197
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500198 free(m);
Chris Austen41a4b312015-10-25 03:45:42 -0500199
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500200 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500201}
202
Patrick Venture0b02be92018-08-31 11:55:55 -0700203int send_esel_to_dbus(const char* desc, Entry::Level level,
204 const std::string& inventoryPath, uint8_t* debug,
Tom Joseph448e74e2017-07-24 23:08:56 +0530205 size_t debuglen)
206{
Chris Austen41a4b312015-10-25 03:45:42 -0500207
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600208 // Allocate enough space to represent the data in hex separated by spaces,
209 // to mimic how IPMI would display the data.
Patrick Venture0b02be92018-08-31 11:55:55 -0700210 unique_ptr<char[]> selData(new char[(debuglen * 3) + 1]());
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600211 uint32_t i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700212 for (i = 0; i < debuglen; i++)
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600213 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700214 sprintf(&selData[i * 3], "%02x ", 0xFF & ((char*)debug)[i]);
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600215 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700216 selData[debuglen * 3] = '\0';
Tom Josephb9ac6a42017-02-28 19:56:33 +0530217
Patrick Venture0b02be92018-08-31 11:55:55 -0700218 using error = sdbusplus::org::open_power::Host::Error::Event;
Marri Devender Raob0b395b2017-10-24 10:14:14 -0500219 using metadata = org::open_power::Host::Event;
Tom Joseph448e74e2017-07-24 23:08:56 +0530220
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 report<error>(level, metadata::ESEL(selData.get()),
Tom Joseph448e74e2017-07-24 23:08:56 +0530222 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
Adriana Kobylak2efb3e72017-02-06 21:43:59 -0600223
Adriana Kobylak513d68e2017-02-15 11:36:28 -0600224 return 0;
Chris Austen41a4b312015-10-25 03:45:42 -0500225}
226
Patrick Venture0b02be92018-08-31 11:55:55 -0700227void send_esel(uint16_t recordid)
228{
229 char* desc;
230 uint8_t* buffer = NULL;
231 const char* path = "/tmp/esel";
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500232 ssize_t sz;
233 int r;
234 std::string inventoryPath;
Chris Austen41a4b312015-10-25 03:45:42 -0500235
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500236 sz = getfilestream(path, &buffer);
Patrick Venture0b02be92018-08-31 11:55:55 -0700237 if (sz == 0)
238 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500239 log<level::ERR>("Error file does not exist",
240 entry("FILENAME=%s", path));
241 return;
242 }
Chris Austen41a4b312015-10-25 03:45:42 -0500243
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500244 auto sev = create_esel_severity(buffer);
245 create_esel_association(buffer, inventoryPath);
246 create_esel_description(buffer, sev, &desc);
Chris Austen41a4b312015-10-25 03:45:42 -0500247
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500248 r = send_esel_to_dbus(desc, sev, inventoryPath, buffer, sz);
Patrick Venture0b02be92018-08-31 11:55:55 -0700249 if (r < 0)
250 {
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500251 log<level::ERR>("Failed to send esel to dbus");
252 }
Chris Austen41a4b312015-10-25 03:45:42 -0500253
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500254 free(desc);
255 delete[] buffer;
Chris Austen41a4b312015-10-25 03:45:42 -0500256
Nagaraju Goruganti2fa0e702018-04-16 05:25:21 -0500257 return;
Chris Austen41a4b312015-10-25 03:45:42 -0500258}
Tom Josephb647d5b2017-10-31 17:25:33 +0530259
260std::string readESEL(const char* fileName)
261{
262 std::string content;
263 std::ifstream handle(fileName);
264
265 if (handle.fail())
266 {
267 log<level::ERR>("Failed to open eSEL", entry("FILENAME=%s", fileName));
268 return content;
269 }
270
271 handle.seekg(0, std::ios::end);
272 content.resize(handle.tellg());
273 handle.seekg(0, std::ios::beg);
274 handle.read(&content[0], content.size());
275 handle.close();
276
277 return content;
278}
279
280void createProcedureLogEntry(uint8_t procedureNum)
281{
282 // Read the eSEL data from the file.
283 static constexpr auto eSELFile = "/tmp/esel";
284 auto eSELData = readESEL(eSELFile);
285
286 // Each byte in eSEL is formatted as %02x with a space between bytes and
287 // insert '/0' at the end of the character array.
288 static constexpr auto byteSeparator = 3;
Patrick Venture0b02be92018-08-31 11:55:55 -0700289 std::unique_ptr<char[]> data(
290 new char[(eSELData.size() * byteSeparator) + 1]());
Tom Josephb647d5b2017-10-31 17:25:33 +0530291
292 for (size_t i = 0; i < eSELData.size(); i++)
293 {
294 sprintf(&data[i * byteSeparator], "%02x ", eSELData[i]);
295 }
296 data[eSELData.size() * byteSeparator] = '\0';
297
Patrick Venture0b02be92018-08-31 11:55:55 -0700298 using error = sdbusplus::org::open_power::Host::Error::MaintenanceProcedure;
Tom Josephb647d5b2017-10-31 17:25:33 +0530299 using metadata = org::open_power::Host::MaintenanceProcedure;
300
301 report<error>(metadata::ESEL(data.get()),
302 metadata::PROCEDURE(static_cast<uint32_t>(procedureNum)));
303}