1 #include <stdint.h> 2 #include <cstdlib> 3 #include <cstring> 4 #include <fstream> 5 #include <iostream> 6 #include <algorithm> 7 #include <vector> 8 #include <memory> 9 #include <systemd/sd-bus.h> 10 #include <mapper.h> 11 #include <phosphor-logging/elog.hpp> 12 #include "host-ipmid/ipmid-api.h" 13 #include "elog-errors.hpp" 14 #include "error-HostEvent.hpp" 15 #include "sensorhandler.h" 16 #include "storagehandler.h" 17 #include "types.hpp" 18 19 20 using namespace std; 21 using namespace phosphor::logging; 22 extern const ipmi::sensor::InvObjectIDMap invSensors; 23 24 ////////////////////////// 25 struct esel_section_headers_t { 26 uint8_t sectionid[2]; 27 uint8_t sectionlength[2]; 28 uint8_t version; 29 uint8_t subsectiontype; 30 uint8_t compid; 31 }; 32 33 struct severity_values_t { 34 uint8_t type; 35 const char *description; 36 }; 37 38 39 const std::vector<severity_values_t> g_sev_desc = { 40 {0x10, "recoverable error"}, 41 {0x20, "predictive error"}, 42 {0x40, "unrecoverable error"}, 43 {0x50, "critical error"}, 44 {0x60, "error from a diagnostic test"}, 45 {0x70, "recovered symptom "}, 46 {0xFF, "Unknown"}, 47 }; 48 49 const char* sev_lookup(uint8_t n) { 50 auto i = std::find_if(std::begin(g_sev_desc), std::end(g_sev_desc), 51 [n](auto p){ return p.type == n || p.type == 0xFF; }); 52 return i->description; 53 } 54 55 56 57 58 int find_sensor_type_string(uint8_t sensor_number, char **s) { 59 60 dbus_interface_t a; 61 const char *p; 62 int r; 63 64 r = find_openbmc_path(sensor_number, &a); 65 66 if ((r < 0) || (a.bus[0] == 0)) { 67 // Just make a generic message for errors that 68 // occur on sensors that don't exist 69 r = asprintf(s, "Unknown Sensor (0x%02x)", sensor_number); 70 } else { 71 72 if ((p = strrchr (a.path, '/')) == NULL) { 73 p = "/Unknown Sensor"; 74 } 75 76 *s = strdup(p+1); 77 } 78 79 return 0; 80 } 81 82 83 size_t getfilestream(const char *fn, uint8_t **buffer) { 84 85 FILE *fp; 86 ssize_t size = 0; 87 int r; 88 89 if ((fp = fopen(fn, "rb")) != NULL) { 90 91 r = fseek(fp, 0, SEEK_END); 92 if (r) { 93 fprintf(stderr,"Fseek failed\n"); 94 goto fclose_fp; 95 } 96 97 size = ftell(fp); 98 if (size == -1L) { 99 fprintf(stderr,"Ftell failed for %s\n", strerror(errno)); 100 size = 0; 101 goto fclose_fp; 102 } 103 104 r = fseek(fp, 0, SEEK_SET); 105 if (r) { 106 fprintf(stderr,"Fseek failed\n"); 107 size = 0; 108 goto fclose_fp; 109 } 110 111 *buffer = new uint8_t [size]; 112 113 r = fread(*buffer, 1, size, fp); 114 if ( r != size) { 115 size = 0; 116 fprintf(stderr,"Fread failed\n"); 117 } 118 119 fclose_fp: 120 fclose(fp); 121 } 122 123 return static_cast<size_t>(size); 124 } 125 126 127 const char *create_esel_severity(const uint8_t *buffer) { 128 129 uint8_t severity; 130 // Dive in to the IBM log to find the severity 131 severity = (0xF0 & buffer[0x4A]); 132 133 return sev_lookup(severity); 134 } 135 136 int create_esel_association(const uint8_t *buffer, std::string& inventoryPath) 137 { 138 ipmi_add_sel_request_t *p; 139 uint8_t sensor; 140 141 p = ( ipmi_add_sel_request_t *) buffer; 142 143 sensor = p->sensornumber; 144 145 inventoryPath = {}; 146 147 /* 148 * Search the sensor number to inventory path mapping to figure out the 149 * inventory associated with the ESEL. 150 */ 151 for (auto const &iter : invSensors) 152 { 153 if (iter.second.sensorID == sensor) 154 { 155 inventoryPath = iter.first; 156 break; 157 } 158 } 159 160 return 0; 161 } 162 163 164 165 int create_esel_description(const uint8_t *buffer, const char *sev, char **message) { 166 167 168 ipmi_add_sel_request_t *p; 169 char *m; 170 int r; 171 172 p = ( ipmi_add_sel_request_t *) buffer; 173 174 find_sensor_type_string(p->sensornumber,&m); 175 176 r = asprintf(message, "A %s has experienced a %s", m, sev ); 177 if (r == -1) { 178 fprintf(stderr, 179 "Failed to allocate memory for ESEL description\n"); 180 } 181 182 free(m); 183 184 return 0; 185 } 186 187 188 int send_esel_to_dbus(const char *desc, 189 const char *sev, 190 const std::string& inventoryPath, 191 uint8_t *debug, 192 size_t debuglen) 193 { 194 195 // Allocate enough space to represent the data in hex separated by spaces, 196 // to mimic how IPMI would display the data. 197 unique_ptr<char[]> selData(new char[(debuglen*3) + 1]()); 198 uint32_t i = 0; 199 for(i = 0; i < debuglen; i++) 200 { 201 sprintf(&selData[i*3], "%02x ", 0xFF & ((char*)debug)[i]); 202 } 203 selData[debuglen*3] = '\0'; 204 205 using error = sdbusplus::org::open_power::Host::Event::Error::Event; 206 using metadata = org::open_power::Host::Event::Event; 207 208 report<error>(metadata::ESEL(selData.get()), 209 metadata::CALLOUT_INVENTORY_PATH(inventoryPath.c_str())); 210 211 return 0; 212 } 213 214 215 void send_esel(uint16_t recordid) { 216 char *desc; 217 const char *sev; 218 uint8_t *buffer = NULL; 219 const char *path = "/tmp/esel"; 220 ssize_t sz; 221 int r; 222 std::string inventoryPath; 223 224 sz = getfilestream(path, &buffer); 225 if (sz == 0) { 226 printf("Error file does not exist %d\n",__LINE__); 227 return; 228 } 229 230 sev = create_esel_severity(buffer); 231 create_esel_association(buffer, inventoryPath); 232 create_esel_description(buffer, sev, &desc); 233 234 r = send_esel_to_dbus(desc, sev, inventoryPath, buffer, sz); 235 if (r < 0) { 236 fprintf(stderr, "Failed to send esel to dbus\n"); 237 } 238 239 free(desc); 240 delete[] buffer; 241 242 return; 243 } 244