summaryrefslogtreecommitdiffstats
path: root/storageaddsel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storageaddsel.cpp')
-rw-r--r--storageaddsel.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/storageaddsel.cpp b/storageaddsel.cpp
index 5cdf535..1dde2a4 100644
--- a/storageaddsel.cpp
+++ b/storageaddsel.cpp
@@ -21,6 +21,7 @@
using namespace std;
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Logging::server;
+extern const ipmi::sensor::InvObjectIDMap invSensors;
//////////////////////////
struct esel_section_headers_t
@@ -32,6 +33,225 @@ struct esel_section_headers_t
uint8_t compid;
};
+struct severity_values_t
+{
+ uint8_t type;
+ Entry::Level level;
+};
+
+const std::vector<severity_values_t> g_sev_desc = {
+ {0x10, Entry::Level::Warning}, // recoverable error
+ {0x20, Entry::Level::Warning}, // predictive error
+ // TODO via github issue 3066 : map level
+ // below to Level::Unrecoverable
+ {0x40, Entry::Level::Error}, // unrecoverable error
+ // TODO via github issue 3066 : map level below
+ // to Level::Critical
+ {0x50, Entry::Level::Error}, // critical error
+ {0x60, Entry::Level::Error}, // error from a diagnostic test
+ {0x70, Entry::Level::Warning}, // recoverable symptom
+ {0xFF, Entry::Level::Error}, // unknown error
+};
+
+Entry::Level sev_lookup(uint8_t n)
+{
+ auto i =
+ std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc),
+ [n](auto p) { return p.type == n || p.type == 0xFF; });
+ return i->level;
+}
+
+int find_sensor_type_string(uint8_t sensor_number, char** s)
+{
+
+ dbus_interface_t a;
+ int r;
+
+ r = find_openbmc_path(sensor_number, &a);
+
+ if ((r < 0) || (a.bus[0] == 0))
+ {
+ // Just make a generic message for errors that
+ // occur on sensors that don't exist
+ r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number);
+ }
+ else
+ {
+ const char* p;
+
+ if ((p = strrchr(a.path, '/')) == NULL)
+ {
+ p = "/Unknown Sensor";
+ }
+
+ *s = strdup(p + 1);
+ }
+
+ return 0;
+}
+
+size_t getfilestream(const char* fn, uint8_t** buffer)
+{
+
+ FILE* fp;
+ ssize_t size = 0;
+ int r;
+
+ if ((fp = fopen(fn, "rb")) != NULL)
+ {
+
+ r = fseek(fp, 0, SEEK_END);
+ if (r)
+ {
+ log<level::ERR>("Fseek failed");
+ goto fclose_fp;
+ }
+
+ size = ftell(fp);
+ if (size == -1L)
+ {
+ log<level::ERR>("Ftell failed", entry("ERROR=%s", strerror(errno)));
+ size = 0;
+ goto fclose_fp;
+ }
+
+ r = fseek(fp, 0, SEEK_SET);
+ if (r)
+ {
+ log<level::ERR>("Fseek failed");
+ size = 0;
+ goto fclose_fp;
+ }
+
+ *buffer = new uint8_t[size];
+
+ r = fread(*buffer, 1, size, fp);
+ if (r != size)
+ {
+ size = 0;
+ log<level::ERR>("Fread failed\n");
+ }
+
+ fclose_fp:
+ fclose(fp);
+ }
+
+ return static_cast<size_t>(size);
+}
+
+Entry::Level create_esel_severity(const uint8_t* buffer)
+{
+
+ uint8_t severity;
+ // Dive in to the IBM log to find the severity
+ severity = (0xF0 & buffer[0x4A]);
+
+ return sev_lookup(severity);
+}
+
+int create_esel_association(const uint8_t* buffer, std::string& inventoryPath)
+{
+ auto p = reinterpret_cast<const ipmi_add_sel_request_t*>(buffer);
+
+ uint8_t sensor = p->sensornumber;
+
+ inventoryPath = {};
+
+ /*
+ * Search the sensor number to inventory path mapping to figure out the
+ * inventory associated with the ESEL.
+ */
+ auto found = std::find_if(invSensors.begin(), invSensors.end(),
+ [&sensor](const auto& iter) {
+ return (iter.second.sensorID == sensor);
+ });
+ if (found != invSensors.end())
+ {
+ inventoryPath = found->first;
+ }
+
+ return 0;
+}
+
+int create_esel_description(const uint8_t* buffer, Entry::Level level,
+ char** message)
+{
+ char* m;
+ int r;
+
+ auto p = reinterpret_cast<const ipmi_add_sel_request_t*>(buffer);
+
+ find_sensor_type_string(p->sensornumber, &m);
+
+ r = asprintf(message, "A %s has experienced an error of level %d", m,
+ static_cast<uint32_t>(level));
+ if (r == -1)
+ {
+ log<level::ERR>("Failed to allocate memory for ESEL description");
+ }
+
+ free(m);
+
+ return 0;
+}
+
+int send_esel_to_dbus(const char* desc, Entry::Level level,
+ const std::string& inventoryPath, uint8_t* debug,
+ size_t debuglen)
+{
+
+ // Allocate enough space to represent the data in hex separated by spaces,
+ // to mimic how IPMI would display the data.
+ unique_ptr<char[]> selData(new char[(debuglen * 3) + 1]());
+ uint32_t i = 0;
+ for (i = 0; i < debuglen; i++)
+ {
+ sprintf(&selData[i * 3], "%02x ", 0xFF & ((char*)debug)[i]);
+ }
+ selData[debuglen * 3] = '\0';
+
+ using error = sdbusplus::org::open_power::Host::Error::Event;
+ using metadata = org::open_power::Host::Event;
+
+ report<error>(level, metadata::ESEL(selData.get()),
+ metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str()));
+
+ return 0;
+}
+
+void send_esel(uint16_t recordid)
+{
+ char* desc;
+ uint8_t* buffer = NULL;
+ const char* path = "/tmp/esel";
+ ssize_t sz;
+ int r;
+ std::string inventoryPath;
+
+ sz = getfilestream(path, &buffer);
+ if (sz == 0)
+ {
+ log<level::ERR>("Error file does not exist",
+ entry("FILENAME=%s", path));
+ return;
+ }
+
+ auto sev = create_esel_severity(buffer);
+ create_esel_association(buffer, inventoryPath);
+ create_esel_description(buffer, sev, &desc);
+
+ r = send_esel_to_dbus(desc, sev, inventoryPath, buffer, sz);
+ if (r < 0)
+ {
+ log<level::ERR>("Failed to send esel to dbus");
+ }
+
+ free(desc);
+ delete[] buffer;
+
+ return;
+}
+
std::string readESEL(const char* fileName)
{
std::string content;
OpenPOWER on IntegriCloud