blob: 66db77b8ca1cc7e5128ed7dc04762f49db36f812 [file] [log] [blame]
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +05301#include <cstdio>
2#include <string>
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -05003#include <arpa/inet.h>
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +05304#include <systemd/sd-bus.h>
5#include <mapper.h>
6#include <chrono>
Tom Joseph6f7deaa2017-06-30 19:03:54 +05307#include "selutility.hpp"
Chris Austen41a4b312015-10-25 03:45:42 -05008#include "storagehandler.h"
9#include "storageaddsel.h"
Patrick Williams37af7332016-09-02 21:21:42 -050010#include "host-ipmid/ipmid-api.h"
Tom Josepha4953392017-06-30 19:09:47 +053011#include <experimental/filesystem>
Tom Joseph6f7deaa2017-06-30 19:03:54 +053012#include <phosphor-logging/log.hpp>
13#include <sdbusplus/server.hpp>
14#include "xyz/openbmc_project/Common/error.hpp"
Chris Austen41a4b312015-10-25 03:45:42 -050015
Chris Austenb4f5b922015-10-13 12:44:43 -050016void register_netfn_storage_functions() __attribute__((constructor));
17
18
19unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080020extern unsigned short g_sel_reserve;
Chris Austenb4f5b922015-10-13 12:44:43 -050021
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053022constexpr auto time_manager_intf = "org.openbmc.TimeManager";
23constexpr auto time_manager_obj = "/org/openbmc/TimeManager";
24
Tom Joseph6f7deaa2017-06-30 19:03:54 +053025namespace cache
26{
27 /*
28 * This cache contains the object paths of the logging entries sorted in the
29 * order of the filename(numeric order). The cache is initialized by
30 * invoking readLoggingObjectPaths with the cache as the parameter. The
31 * cache is invoked in the execution of the Get SEL info and Delete SEL
32 * entry command. The Get SEL Info command is typically invoked before the
33 * Get SEL entry command, so the cache is utilized for responding to Get SEL
34 * entry command. The cache is invalidated by clearing after Delete SEL
35 * entry and Clear SEL command.
36 */
37 ipmi::sel::ObjectPaths paths;
38
39} // namespace objectPathsCache
40
41using InternalFailure =
42 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
43using namespace phosphor::logging;
44
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050045ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
46 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -050047 ipmi_data_len_t data_len, ipmi_context_t context)
48{
49 printf("Handling STORAGE WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
50 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080051 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050052 *data_len = 0;
53 return rc;
54}
55
Tom Joseph6f7deaa2017-06-30 19:03:54 +053056ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
57 ipmi_request_t request, ipmi_response_t response,
58 ipmi_data_len_t data_len, ipmi_context_t context)
59{
60 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
61 auto responseData = reinterpret_cast<ipmi::sel::GetSELInfoResponse*>
62 (outPayload.data());
63
64 responseData->selVersion = ipmi::sel::selVersion;
65 // Last erase timestamp is not available from log manager.
66 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
67 responseData->operationSupport = ipmi::sel::operationSupport;
68
69 ipmi::sel::readLoggingObjectPaths(cache::paths);
70 responseData->entries = 0;
71 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
72
73 if (!cache::paths.empty())
74 {
75 responseData->entries = static_cast<uint16_t>(cache::paths.size());
76
77 try
78 {
79 responseData->addTimeStamp = static_cast<uint32_t>(
80 (ipmi::sel::getEntryTimeStamp(cache::paths.back())
81 .count()));
82 }
83 catch (InternalFailure& e)
84 {
85 }
86 catch (const std::runtime_error& e)
87 {
88 log<level::ERR>(e.what());
89 }
90 }
91
92 memcpy(response, outPayload.data(), outPayload.size());
93 *data_len = outPayload.size();
94
95 return IPMI_CC_OK;
96}
97
Tom Josepha4953392017-06-30 19:09:47 +053098ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
99 ipmi_request_t request, ipmi_response_t response,
100 ipmi_data_len_t data_len, ipmi_context_t context)
101{
102 auto requestData = reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>
103 (request);
104
105 if (requestData->reservationID != 0)
106 {
107 if (g_sel_reserve != requestData->reservationID)
108 {
109 *data_len = 0;
110 return IPMI_CC_INVALID_RESERVATION_ID;
111 }
112 }
113
114 if (cache::paths.empty())
115 {
116 *data_len = 0;
117 return IPMI_CC_SENSOR_INVALID;
118 }
119
120 ipmi::sel::ObjectPaths::const_iterator iter;
121
122 // Check for the requested SEL Entry.
123 if (requestData->selRecordID == ipmi::sel::firstEntry)
124 {
125 iter = cache::paths.begin();
126 }
127 else if (requestData->selRecordID == ipmi::sel::lastEntry)
128 {
129 iter = cache::paths.end();
130 }
131 else
132 {
133 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
134 std::to_string(requestData->selRecordID);
135
136 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
137 if (iter == cache::paths.end())
138 {
139 *data_len = 0;
140 return IPMI_CC_SENSOR_INVALID;
141 }
142 }
143
144 ipmi::sel::GetSELEntryResponse record {};
145
146 // Convert the log entry into SEL record.
147 try
148 {
149 record = ipmi::sel::convertLogEntrytoSEL(*iter);
150 }
151 catch (InternalFailure& e)
152 {
153 *data_len = 0;
154 return IPMI_CC_UNSPECIFIED_ERROR;
155 }
156 catch (const std::runtime_error& e)
157 {
158 log<level::ERR>(e.what());
159 *data_len = 0;
160 return IPMI_CC_UNSPECIFIED_ERROR;
161 }
162
163
164 // Identify the next SEL record ID
165 if(iter != cache::paths.end())
166 {
167 ++iter;
168 if (iter == cache::paths.end())
169 {
170 record.nextRecordID = ipmi::sel::lastEntry;
171 }
172 else
173 {
174 namespace fs = std::experimental::filesystem;
175 fs::path path(*iter);
176 record.nextRecordID = static_cast<uint16_t>
177 (std::stoul(std::string(path.filename().c_str())));
178 }
179 }
180 else
181 {
182 record.nextRecordID = ipmi::sel::lastEntry;
183 }
184
185 if (requestData->readLength == ipmi::sel::entireRecord)
186 {
187 memcpy(response, &record, sizeof(record));
188 *data_len = sizeof(record);
189 }
190 else
191 {
192 if (requestData->offset >= ipmi::sel::selRecordSize ||
193 requestData->readLength > ipmi::sel::selRecordSize)
194 {
195 *data_len = 0;
196 return IPMI_CC_INVALID_FIELD_REQUEST;
197 }
198
199 auto diff = ipmi::sel::selRecordSize - requestData->offset;
200 auto readLength = std::min(diff,
201 static_cast<int>(requestData->readLength));
202
203 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
204 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
205 &record.recordID + requestData->offset, readLength);
206 *data_len = sizeof(record.nextRecordID) + readLength;
207 }
208
209 return IPMI_CC_OK;
210}
211
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500212ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
213 ipmi_request_t request, ipmi_response_t response,
214 ipmi_data_len_t data_len, ipmi_context_t context)
215{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530216 using namespace std::chrono;
217
218 char *time_provider = nullptr;
219 const char* time_in_str = nullptr;
220 uint64_t host_time_usec = 0;
221 uint32_t resp = 0;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500222 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austenb4f5b922015-10-13 12:44:43 -0500223
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530224 sd_bus_message *reply = nullptr;
225 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500226
227 printf("IPMI Handling GET-SEL-TIME\n");
228
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530229 auto bus = ipmid_get_sd_bus_connection();
230
231 auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
232 if (rct < 0) {
233 printf("Error [%s] getting bus name for time provider\n",
234 strerror(-rct));
235 rc = IPMI_CC_UNSPECIFIED_ERROR;
236 goto finish;
237 }
238
239 rct = sd_bus_call_method(bus,
240 time_provider,
241 time_manager_obj,
242 time_manager_intf,
243 "GetTime",
244 &bus_error,
245 &reply,
246 "s",
247 "host");
248 if (rct < 0) {
249 printf("Error [%s] getting time\n", strerror(-rct));
250 rc = IPMI_CC_UNSPECIFIED_ERROR;
251 goto finish;
252 }
253
254 rct = sd_bus_message_read(reply, "sx", &time_in_str, &host_time_usec);
255 if (rct < 0) {
256 fprintf(stderr, "Error [%s] parsing get-time response\n",
257 strerror(-rct));
258 rc = IPMI_CC_UNSPECIFIED_ERROR;
259 goto finish;
260 }
261
262 // Time is really long int but IPMI wants just uint32. This works okay until
263 // the number of seconds since 1970 overflows uint32 size.. Still a whole
264 // lot of time here to even think about that.
265 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
266 resp = htole32(resp);
267 printf("Host Time read:[%s] :: [%d]\n", time_in_str, resp);
268
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500269 // From the IPMI Spec 2.0, response should be a 32-bit value
270 *data_len = sizeof(resp);
271
272 // Pack the actual response
273 memcpy(response, &resp, *data_len);
274
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530275finish:
276 sd_bus_error_free(&bus_error);
277 reply = sd_bus_message_unref(reply);
278 free(time_provider);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500279 return rc;
280}
281
282ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
283 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500284 ipmi_data_len_t data_len, ipmi_context_t context)
285{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530286 char *time_provider = nullptr;
287 int time_rc = 0;
288 ipmi_ret_t rc = IPMI_CC_OK;
289
290 sd_bus_message *reply = nullptr;
291 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
292
Norman James82330442015-11-19 16:53:26 -0600293 uint32_t* secs = (uint32_t*)request;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530294 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500295
296 printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
Norman James82330442015-11-19 16:53:26 -0600297 printf("Data: 0x%X]\n",*secs);
Chris Austenb4f5b922015-10-13 12:44:43 -0500298
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530299 auto bus = ipmid_get_sd_bus_connection();
Norman James82330442015-11-19 16:53:26 -0600300
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530301 auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
302 if (rct < 0) {
303 printf("Error [%s] getting bus name for time provider\n",
304 strerror(-rct));
305 rc = IPMI_CC_UNSPECIFIED_ERROR;
306 goto finish;
Norman James82330442015-11-19 16:53:26 -0600307 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530308
309 rct = sd_bus_call_method(bus,
310 time_provider,
311 time_manager_obj,
312 time_manager_intf,
313 "SetTime",
314 &bus_error,
315 &reply,
316 "ss",
317 "host",
318 std::to_string(le32toh(*secs)).c_str());
319
320 if (rct < 0) {
321 printf("Error [%s] setting time\n", strerror(-rct));
322 rc = IPMI_CC_UNSPECIFIED_ERROR;
323 goto finish;
324 }
325
326 rct = sd_bus_message_read(reply, "i", &time_rc);
327 if (rct < 0) {
328 fprintf(stderr, "Error [%s] parsing set-time response\n",
329 strerror(-rct));
330 rc = IPMI_CC_UNSPECIFIED_ERROR;
331 goto finish;
332 }
333
334 if (time_rc < 0) {
335 printf("Error setting time.");
Norman James82330442015-11-19 16:53:26 -0600336 rc = IPMI_CC_UNSPECIFIED_ERROR;
337 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530338
339finish:
340 sd_bus_error_free(&bus_error);
341 reply = sd_bus_message_unref(reply);
342 free(time_provider);
Chris Austenb4f5b922015-10-13 12:44:43 -0500343 return rc;
344}
345
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500346ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
347 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500348 ipmi_data_len_t data_len, ipmi_context_t context)
349{
Chris Austenb4f5b922015-10-13 12:44:43 -0500350 ipmi_ret_t rc = IPMI_CC_OK;
351
Nan Li36c0cb62016-03-31 11:16:08 +0800352 // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
353 if( ++g_sel_reserve == 0)
354 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500355
Nan Li36c0cb62016-03-31 11:16:08 +0800356 printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
Chris Austen41a4b312015-10-25 03:45:42 -0500357
Chris Austenb4f5b922015-10-13 12:44:43 -0500358 *data_len = sizeof(g_sel_reserve);
359
360 // Pack the actual response
361 memcpy(response, &g_sel_reserve, *data_len);
362
363 return rc;
364}
365
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500366ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
367 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500368 ipmi_data_len_t data_len, ipmi_context_t context)
369{
370
371 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austen41a4b312015-10-25 03:45:42 -0500372 ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
373 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500374
Chris Austen313d95b2015-10-31 12:55:30 -0500375 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500376
377 printf("IPMI Handling ADD-SEL for record 0x%04x\n", recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500378
379 *data_len = sizeof(g_sel_reserve);
380
381 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600382 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500383
Chris Austen41a4b312015-10-25 03:45:42 -0500384 send_esel(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500385
386 return rc;
387}
388
389
390
391void register_netfn_storage_functions()
392{
Tom05732372016-09-06 17:21:23 +0530393 // <Wildcard Command>
Chris Austenb4f5b922015-10-13 12:44:43 -0500394 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530395 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
396 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500397
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530398 // <Get SEL Info>
399 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO);
400 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, getSELInfo,
401 PRIVILEGE_USER);
402
Tom05732372016-09-06 17:21:23 +0530403 // <Get SEL Time>
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500404 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530405 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
406 PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500407
Tom05732372016-09-06 17:21:23 +0530408 // <Set SEL Time>
Chris Austenb4f5b922015-10-13 12:44:43 -0500409 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530410 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
411 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500412
Tom05732372016-09-06 17:21:23 +0530413 // <Reserve SEL>
Chris Austenb4f5b922015-10-13 12:44:43 -0500414 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL);
Tom05732372016-09-06 17:21:23 +0530415 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
416 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500417
Tom Josepha4953392017-06-30 19:09:47 +0530418 // <Get SEL Entry>
419 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY);
420 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL, getSELEntry,
421 PRIVILEGE_USER);
422
Tom05732372016-09-06 17:21:23 +0530423 // <Add SEL Entry>
Chris Austenb4f5b922015-10-13 12:44:43 -0500424 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_ADD_SEL);
Tom05732372016-09-06 17:21:23 +0530425 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
426 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500427 return;
428}
429