blob: b38e06c68f44c91ad9613ccef9834d86f715f14d [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"
Marri Devender Raocac383b2017-07-03 13:24:27 -05008#include <algorithm>
Chris Austen41a4b312015-10-25 03:45:42 -05009#include "storagehandler.h"
10#include "storageaddsel.h"
Tom Joseph8f4a2aa2017-06-30 19:12:49 +053011#include "utils.hpp"
Patrick Williams37af7332016-09-02 21:21:42 -050012#include "host-ipmid/ipmid-api.h"
Tom Josepha4953392017-06-30 19:09:47 +053013#include <experimental/filesystem>
Tom Joseph6f7deaa2017-06-30 19:03:54 +053014#include <phosphor-logging/log.hpp>
15#include <sdbusplus/server.hpp>
16#include "xyz/openbmc_project/Common/error.hpp"
Marri Devender Raocac383b2017-07-03 13:24:27 -050017#include "read_fru_data.hpp"
18#include <phosphor-logging/elog-errors.hpp>
Chris Austen41a4b312015-10-25 03:45:42 -050019
Chris Austenb4f5b922015-10-13 12:44:43 -050020void register_netfn_storage_functions() __attribute__((constructor));
21
Chris Austenb4f5b922015-10-13 12:44:43 -050022unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080023extern unsigned short g_sel_reserve;
Chris Austenb4f5b922015-10-13 12:44:43 -050024
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053025constexpr auto time_manager_intf = "org.openbmc.TimeManager";
26constexpr auto time_manager_obj = "/org/openbmc/TimeManager";
27
Tom Joseph6f7deaa2017-06-30 19:03:54 +053028namespace cache
29{
30 /*
31 * This cache contains the object paths of the logging entries sorted in the
32 * order of the filename(numeric order). The cache is initialized by
33 * invoking readLoggingObjectPaths with the cache as the parameter. The
34 * cache is invoked in the execution of the Get SEL info and Delete SEL
35 * entry command. The Get SEL Info command is typically invoked before the
36 * Get SEL entry command, so the cache is utilized for responding to Get SEL
37 * entry command. The cache is invalidated by clearing after Delete SEL
38 * entry and Clear SEL command.
39 */
40 ipmi::sel::ObjectPaths paths;
41
42} // namespace objectPathsCache
43
44using InternalFailure =
45 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
46using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050047using namespace ipmi::fru;
48
49/**
50 * @enum Device access mode
51 */
52enum class AccessMode
53{
54 bytes, ///< Device is accessed by bytes
55 words ///< Device is accessed by words
56};
57
Tom Joseph6f7deaa2017-06-30 19:03:54 +053058
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050059ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
60 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -050061 ipmi_data_len_t data_len, ipmi_context_t context)
62{
63 printf("Handling STORAGE WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
64 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080065 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050066 *data_len = 0;
67 return rc;
68}
69
Tom Joseph6f7deaa2017-06-30 19:03:54 +053070ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
71 ipmi_request_t request, ipmi_response_t response,
72 ipmi_data_len_t data_len, ipmi_context_t context)
73{
74 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
75 auto responseData = reinterpret_cast<ipmi::sel::GetSELInfoResponse*>
76 (outPayload.data());
77
78 responseData->selVersion = ipmi::sel::selVersion;
79 // Last erase timestamp is not available from log manager.
80 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
81 responseData->operationSupport = ipmi::sel::operationSupport;
82
83 ipmi::sel::readLoggingObjectPaths(cache::paths);
84 responseData->entries = 0;
85 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
86
87 if (!cache::paths.empty())
88 {
89 responseData->entries = static_cast<uint16_t>(cache::paths.size());
90
91 try
92 {
93 responseData->addTimeStamp = static_cast<uint32_t>(
94 (ipmi::sel::getEntryTimeStamp(cache::paths.back())
95 .count()));
96 }
97 catch (InternalFailure& e)
98 {
99 }
100 catch (const std::runtime_error& e)
101 {
102 log<level::ERR>(e.what());
103 }
104 }
105
106 memcpy(response, outPayload.data(), outPayload.size());
107 *data_len = outPayload.size();
108
109 return IPMI_CC_OK;
110}
111
Tom Josepha4953392017-06-30 19:09:47 +0530112ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
113 ipmi_request_t request, ipmi_response_t response,
114 ipmi_data_len_t data_len, ipmi_context_t context)
115{
116 auto requestData = reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>
117 (request);
118
119 if (requestData->reservationID != 0)
120 {
121 if (g_sel_reserve != requestData->reservationID)
122 {
123 *data_len = 0;
124 return IPMI_CC_INVALID_RESERVATION_ID;
125 }
126 }
127
128 if (cache::paths.empty())
129 {
130 *data_len = 0;
131 return IPMI_CC_SENSOR_INVALID;
132 }
133
134 ipmi::sel::ObjectPaths::const_iterator iter;
135
136 // Check for the requested SEL Entry.
137 if (requestData->selRecordID == ipmi::sel::firstEntry)
138 {
139 iter = cache::paths.begin();
140 }
141 else if (requestData->selRecordID == ipmi::sel::lastEntry)
142 {
143 iter = cache::paths.end();
144 }
145 else
146 {
147 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
148 std::to_string(requestData->selRecordID);
149
150 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
151 if (iter == cache::paths.end())
152 {
153 *data_len = 0;
154 return IPMI_CC_SENSOR_INVALID;
155 }
156 }
157
158 ipmi::sel::GetSELEntryResponse record {};
159
160 // Convert the log entry into SEL record.
161 try
162 {
163 record = ipmi::sel::convertLogEntrytoSEL(*iter);
164 }
165 catch (InternalFailure& e)
166 {
167 *data_len = 0;
168 return IPMI_CC_UNSPECIFIED_ERROR;
169 }
170 catch (const std::runtime_error& e)
171 {
172 log<level::ERR>(e.what());
173 *data_len = 0;
174 return IPMI_CC_UNSPECIFIED_ERROR;
175 }
176
177
178 // Identify the next SEL record ID
179 if(iter != cache::paths.end())
180 {
181 ++iter;
182 if (iter == cache::paths.end())
183 {
184 record.nextRecordID = ipmi::sel::lastEntry;
185 }
186 else
187 {
188 namespace fs = std::experimental::filesystem;
189 fs::path path(*iter);
190 record.nextRecordID = static_cast<uint16_t>
191 (std::stoul(std::string(path.filename().c_str())));
192 }
193 }
194 else
195 {
196 record.nextRecordID = ipmi::sel::lastEntry;
197 }
198
199 if (requestData->readLength == ipmi::sel::entireRecord)
200 {
201 memcpy(response, &record, sizeof(record));
202 *data_len = sizeof(record);
203 }
204 else
205 {
206 if (requestData->offset >= ipmi::sel::selRecordSize ||
207 requestData->readLength > ipmi::sel::selRecordSize)
208 {
209 *data_len = 0;
210 return IPMI_CC_INVALID_FIELD_REQUEST;
211 }
212
213 auto diff = ipmi::sel::selRecordSize - requestData->offset;
214 auto readLength = std::min(diff,
215 static_cast<int>(requestData->readLength));
216
217 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
218 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
219 &record.recordID + requestData->offset, readLength);
220 *data_len = sizeof(record.nextRecordID) + readLength;
221 }
222
223 return IPMI_CC_OK;
224}
225
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530226ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
227 ipmi_request_t request, ipmi_response_t response,
228 ipmi_data_len_t data_len, ipmi_context_t context)
229{
230 namespace fs = std::experimental::filesystem;
231 auto requestData = reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>
232 (request);
233
234 if (g_sel_reserve != requestData->reservationID)
235 {
236 *data_len = 0;
237 return IPMI_CC_INVALID_RESERVATION_ID;
238 }
239
240 ipmi::sel::readLoggingObjectPaths(cache::paths);
241
242 if (cache::paths.empty())
243 {
244 *data_len = 0;
245 return IPMI_CC_SENSOR_INVALID;
246 }
247
248 ipmi::sel::ObjectPaths::const_iterator iter;
249 uint16_t delRecordID = 0;
250
251 if (requestData->selRecordID == ipmi::sel::firstEntry)
252 {
253 iter = cache::paths.begin();
254 fs::path path(*iter);
255 delRecordID = static_cast<uint16_t>
256 (std::stoul(std::string(path.filename().c_str())));
257 }
258 else if (requestData->selRecordID == ipmi::sel::lastEntry)
259 {
260 iter = cache::paths.end();
261 fs::path path(*iter);
262 delRecordID = static_cast<uint16_t>
263 (std::stoul(std::string(path.filename().c_str())));
264 }
265 else
266 {
267 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
268 std::to_string(requestData->selRecordID);
269
270 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
271 if (iter == cache::paths.end())
272 {
273 *data_len = 0;
274 return IPMI_CC_SENSOR_INVALID;
275 }
276 delRecordID = requestData->selRecordID;
277 }
278
279 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
280 std::string service;
281
282 try
283 {
284 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
285 }
286 catch (const std::runtime_error& e)
287 {
288 log<level::ERR>(e.what());
289 *data_len = 0;
290 return IPMI_CC_UNSPECIFIED_ERROR;
291 }
292
293 auto methodCall = bus.new_method_call(service.c_str(),
294 (*iter).c_str(),
295 ipmi::sel::logDeleteIntf,
296 "Delete");
297 auto reply = bus.call(methodCall);
298 if (reply.is_method_error())
299 {
300 *data_len = 0;
301 return IPMI_CC_UNSPECIFIED_ERROR;
302 }
303
304 // Invalidate the cache of dbus entry objects.
305 cache::paths.clear();
306 memcpy(response, &delRecordID, sizeof(delRecordID));
307 *data_len = sizeof(delRecordID);
308
309 return IPMI_CC_OK;
310}
311
Tom Joseph2f05bb52017-06-30 19:14:49 +0530312ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
313 ipmi_response_t response, ipmi_data_len_t data_len,
314 ipmi_context_t context)
315{
316 auto requestData = reinterpret_cast<const ipmi::sel::ClearSELRequest*>
317 (request);
318
319 if (g_sel_reserve != requestData->reservationID)
320 {
321 *data_len = 0;
322 return IPMI_CC_INVALID_RESERVATION_ID;
323 }
324
325 if (requestData->charC != 'C' ||
326 requestData->charL != 'L' ||
327 requestData->charR != 'R')
328 {
329 *data_len = 0;
330 return IPMI_CC_INVALID_FIELD_REQUEST;
331 }
332
333 uint8_t eraseProgress = ipmi::sel::eraseComplete;
334
335 /*
336 * Erasure status cannot be fetched from DBUS, so always return erasure
337 * status as `erase completed`.
338 */
339 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
340 {
341 memcpy(response, &eraseProgress, sizeof(eraseProgress));
342 *data_len = sizeof(eraseProgress);
343 return IPMI_CC_OK;
344 }
345
346 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
347 auto depth = 0;
348
349 auto mapperCall = bus.new_method_call(ipmi::sel::mapperBusName,
350 ipmi::sel::mapperObjPath,
351 ipmi::sel::mapperIntf,
352 "GetSubTreePaths");
353 mapperCall.append(ipmi::sel::logBasePath);
354 mapperCall.append(depth);
355 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
356
357 auto reply = bus.call(mapperCall);
358 if (reply.is_method_error())
359 {
360 memcpy(response, &eraseProgress, sizeof(eraseProgress));
361 *data_len = sizeof(eraseProgress);
362 return IPMI_CC_OK;
363 }
364
365 ipmi::sel::ObjectPaths objectPaths;
366 reply.read(objectPaths);
367 if (objectPaths.empty())
368 {
369 memcpy(response, &eraseProgress, sizeof(eraseProgress));
370 *data_len = sizeof(eraseProgress);
371 return IPMI_CC_OK;
372 }
373
374 std::string service;
375
376 try
377 {
378 service = ipmi::getService(bus,
379 ipmi::sel::logDeleteIntf,
380 objectPaths.front());
381 }
382 catch (const std::runtime_error& e)
383 {
384 log<level::ERR>(e.what());
385 *data_len = 0;
386 return IPMI_CC_UNSPECIFIED_ERROR;
387 }
388
389 for (const auto& iter : objectPaths)
390 {
391 auto methodCall = bus.new_method_call(service.c_str(),
392 iter.c_str(),
393 ipmi::sel::logDeleteIntf,
394 "Delete");
395
396 auto reply = bus.call(methodCall);
397 if (reply.is_method_error())
398 {
399 *data_len = 0;
400 return IPMI_CC_UNSPECIFIED_ERROR;
401 }
402 }
403
404 // Invalidate the cache of dbus entry objects.
405 cache::paths.clear();
406 memcpy(response, &eraseProgress, sizeof(eraseProgress));
407 *data_len = sizeof(eraseProgress);
408 return IPMI_CC_OK;
409}
410
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500411ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
412 ipmi_request_t request, ipmi_response_t response,
413 ipmi_data_len_t data_len, ipmi_context_t context)
414{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530415 using namespace std::chrono;
416
417 char *time_provider = nullptr;
418 const char* time_in_str = nullptr;
419 uint64_t host_time_usec = 0;
420 uint32_t resp = 0;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500421 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austenb4f5b922015-10-13 12:44:43 -0500422
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530423 sd_bus_message *reply = nullptr;
424 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500425
426 printf("IPMI Handling GET-SEL-TIME\n");
427
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530428 auto bus = ipmid_get_sd_bus_connection();
429
430 auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
431 if (rct < 0) {
432 printf("Error [%s] getting bus name for time provider\n",
433 strerror(-rct));
434 rc = IPMI_CC_UNSPECIFIED_ERROR;
435 goto finish;
436 }
437
438 rct = sd_bus_call_method(bus,
439 time_provider,
440 time_manager_obj,
441 time_manager_intf,
442 "GetTime",
443 &bus_error,
444 &reply,
445 "s",
446 "host");
447 if (rct < 0) {
448 printf("Error [%s] getting time\n", strerror(-rct));
449 rc = IPMI_CC_UNSPECIFIED_ERROR;
450 goto finish;
451 }
452
453 rct = sd_bus_message_read(reply, "sx", &time_in_str, &host_time_usec);
454 if (rct < 0) {
455 fprintf(stderr, "Error [%s] parsing get-time response\n",
456 strerror(-rct));
457 rc = IPMI_CC_UNSPECIFIED_ERROR;
458 goto finish;
459 }
460
461 // Time is really long int but IPMI wants just uint32. This works okay until
462 // the number of seconds since 1970 overflows uint32 size.. Still a whole
463 // lot of time here to even think about that.
464 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
465 resp = htole32(resp);
466 printf("Host Time read:[%s] :: [%d]\n", time_in_str, resp);
467
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500468 // From the IPMI Spec 2.0, response should be a 32-bit value
469 *data_len = sizeof(resp);
470
471 // Pack the actual response
472 memcpy(response, &resp, *data_len);
473
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530474finish:
475 sd_bus_error_free(&bus_error);
476 reply = sd_bus_message_unref(reply);
477 free(time_provider);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500478 return rc;
479}
480
481ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
482 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500483 ipmi_data_len_t data_len, ipmi_context_t context)
484{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530485 char *time_provider = nullptr;
486 int time_rc = 0;
487 ipmi_ret_t rc = IPMI_CC_OK;
488
489 sd_bus_message *reply = nullptr;
490 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
491
Norman James82330442015-11-19 16:53:26 -0600492 uint32_t* secs = (uint32_t*)request;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530493 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500494
495 printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
Norman James82330442015-11-19 16:53:26 -0600496 printf("Data: 0x%X]\n",*secs);
Chris Austenb4f5b922015-10-13 12:44:43 -0500497
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530498 auto bus = ipmid_get_sd_bus_connection();
Norman James82330442015-11-19 16:53:26 -0600499
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530500 auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
501 if (rct < 0) {
502 printf("Error [%s] getting bus name for time provider\n",
503 strerror(-rct));
504 rc = IPMI_CC_UNSPECIFIED_ERROR;
505 goto finish;
Norman James82330442015-11-19 16:53:26 -0600506 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530507
508 rct = sd_bus_call_method(bus,
509 time_provider,
510 time_manager_obj,
511 time_manager_intf,
512 "SetTime",
513 &bus_error,
514 &reply,
515 "ss",
516 "host",
517 std::to_string(le32toh(*secs)).c_str());
518
519 if (rct < 0) {
520 printf("Error [%s] setting time\n", strerror(-rct));
521 rc = IPMI_CC_UNSPECIFIED_ERROR;
522 goto finish;
523 }
524
525 rct = sd_bus_message_read(reply, "i", &time_rc);
526 if (rct < 0) {
527 fprintf(stderr, "Error [%s] parsing set-time response\n",
528 strerror(-rct));
529 rc = IPMI_CC_UNSPECIFIED_ERROR;
530 goto finish;
531 }
532
533 if (time_rc < 0) {
534 printf("Error setting time.");
Norman James82330442015-11-19 16:53:26 -0600535 rc = IPMI_CC_UNSPECIFIED_ERROR;
536 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530537
538finish:
539 sd_bus_error_free(&bus_error);
540 reply = sd_bus_message_unref(reply);
541 free(time_provider);
Chris Austenb4f5b922015-10-13 12:44:43 -0500542 return rc;
543}
544
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500545ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
546 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500547 ipmi_data_len_t data_len, ipmi_context_t context)
548{
Chris Austenb4f5b922015-10-13 12:44:43 -0500549 ipmi_ret_t rc = IPMI_CC_OK;
550
Nan Li36c0cb62016-03-31 11:16:08 +0800551 // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
552 if( ++g_sel_reserve == 0)
553 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500554
Nan Li36c0cb62016-03-31 11:16:08 +0800555 printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
Chris Austen41a4b312015-10-25 03:45:42 -0500556
Chris Austenb4f5b922015-10-13 12:44:43 -0500557 *data_len = sizeof(g_sel_reserve);
558
559 // Pack the actual response
560 memcpy(response, &g_sel_reserve, *data_len);
561
562 return rc;
563}
564
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500565ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
566 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500567 ipmi_data_len_t data_len, ipmi_context_t context)
568{
569
570 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austen41a4b312015-10-25 03:45:42 -0500571 ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
572 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500573
Chris Austen313d95b2015-10-31 12:55:30 -0500574 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500575
576 printf("IPMI Handling ADD-SEL for record 0x%04x\n", recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500577
578 *data_len = sizeof(g_sel_reserve);
579
580 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600581 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500582
Chris Austen41a4b312015-10-25 03:45:42 -0500583 send_esel(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500584
585 return rc;
586}
587
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500588//Read FRU info area
589ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
590 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
591 ipmi_response_t response, ipmi_data_len_t data_len,
592 ipmi_context_t context)
593{
594 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500595 const FruInvenAreaInfoRequest* reqptr =
596 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
597 try
598 {
599 const auto& fruArea = getFruAreaData(reqptr->fruID);
600 auto size = static_cast<uint16_t>(fruArea.size());
601 FruInvenAreaInfoResponse resp;
602 resp.sizems = size >> 8;
603 resp.sizels = size;
604 resp.access = static_cast<uint8_t>(AccessMode::bytes);
605
606 *data_len = sizeof(resp);
607
608 // Pack the actual response
609 memcpy(response, &resp, *data_len);
610 }
611 catch(const InternalFailure& e)
612 {
613 rc = IPMI_CC_UNSPECIFIED_ERROR;
614 *data_len = 0;
615 log<level::ERR>(e.what());
616 report<InternalFailure>();
617 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500618 return rc;
619}
620
621//Read FRU data
622ipmi_ret_t ipmi_storage_read_fru_data(
623 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
624 ipmi_response_t response, ipmi_data_len_t data_len,
625 ipmi_context_t context)
626{
627 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500628 const ReadFruDataRequest* reqptr =
629 reinterpret_cast<const ReadFruDataRequest*>(request);
630 auto offset =
631 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
632 try
633 {
634 const auto& fruArea = getFruAreaData(reqptr->fruID);
635 auto size = fruArea.size();
636 if ((offset + reqptr->count) > size)
637 {
638 log<level::ERR>("Invalid offset and count",
639 entry("Offset=%d Count=%d SizeOfFruArea=%d",
640 offset, reqptr->count, size));
641 return IPMI_CC_INVALID;
642 }
643 std::copy((fruArea.begin() + offset), (fruArea.begin() + reqptr->count),
644 (static_cast<uint8_t*>(response)));
645 *data_len = reqptr->count;
646 }
647 catch (const InternalFailure& e)
648 {
649 rc = IPMI_CC_UNSPECIFIED_ERROR;
650 *data_len = 0;
651 log<level::ERR>(e.what());
652 report<InternalFailure>();
653 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500654 return rc;
655}
656
Chris Austenb4f5b922015-10-13 12:44:43 -0500657
Chris Austenb4f5b922015-10-13 12:44:43 -0500658void register_netfn_storage_functions()
659{
Tom05732372016-09-06 17:21:23 +0530660 // <Wildcard Command>
Chris Austenb4f5b922015-10-13 12:44:43 -0500661 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530662 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
663 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500664
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530665 // <Get SEL Info>
666 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO);
667 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, getSELInfo,
668 PRIVILEGE_USER);
669
Tom05732372016-09-06 17:21:23 +0530670 // <Get SEL Time>
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500671 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530672 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
673 PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500674
Tom05732372016-09-06 17:21:23 +0530675 // <Set SEL Time>
Chris Austenb4f5b922015-10-13 12:44:43 -0500676 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530677 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
678 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500679
Tom05732372016-09-06 17:21:23 +0530680 // <Reserve SEL>
Chris Austenb4f5b922015-10-13 12:44:43 -0500681 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL);
Tom05732372016-09-06 17:21:23 +0530682 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
683 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500684
Tom Josepha4953392017-06-30 19:09:47 +0530685 // <Get SEL Entry>
686 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY);
687 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL, getSELEntry,
688 PRIVILEGE_USER);
689
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530690 // <Delete SEL Entry>
691 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_DELETE_SEL);
692 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL, deleteSELEntry,
693 PRIVILEGE_OPERATOR);
694
Tom05732372016-09-06 17:21:23 +0530695 // <Add SEL Entry>
Chris Austenb4f5b922015-10-13 12:44:43 -0500696 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_ADD_SEL);
Tom05732372016-09-06 17:21:23 +0530697 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
698 PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530699 // <Clear SEL>
700 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL);
701 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
702 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500703 // <Get FRU Inventory Area Info>
704 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
705 IPMI_CMD_GET_FRU_INV_AREA_INFO);
706 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
707 ipmi_storage_get_fru_inv_area_info, PRIVILEGE_OPERATOR);
708
709 // <Add READ FRU Data
710 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
711 IPMI_CMD_READ_FRU_DATA);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500712 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
713 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500714
Marri Devender Rao908f7502017-07-10 01:49:54 -0500715 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500716 return;
717}
718