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