blob: df46a6e0817252c717572a8e50172fbd75f93be1 [file] [log] [blame]
Marri Devender Raocac383b2017-07-03 13:24:27 -05001#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +08002#include <arpa/inet.h>
3#include <chrono>
4#include <cstdio>
Tom Josepha4953392017-06-30 19:09:47 +05305#include <experimental/filesystem>
Lei YU52d91242017-10-17 22:52:28 +08006#include <mapper.h>
7#include <string>
8#include <systemd/sd-bus.h>
9
Tom Joseph6f7deaa2017-06-30 19:03:54 +053010#include <phosphor-logging/log.hpp>
Marri Devender Raocac383b2017-07-03 13:24:27 -050011#include <phosphor-logging/elog-errors.hpp>
Lei YU52d91242017-10-17 22:52:28 +080012#include <sdbusplus/server.hpp>
13
14#include "host-ipmid/ipmid-api.h"
15#include "read_fru_data.hpp"
16#include "selutility.hpp"
17#include "storageaddsel.h"
18#include "storagehandler.h"
19#include "utils.hpp"
20#include "xyz/openbmc_project/Common/error.hpp"
21
Chris Austen41a4b312015-10-25 03:45:42 -050022
Chris Austenb4f5b922015-10-13 12:44:43 -050023void register_netfn_storage_functions() __attribute__((constructor));
24
Chris Austenb4f5b922015-10-13 12:44:43 -050025unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080026extern unsigned short g_sel_reserve;
Chris Austenb4f5b922015-10-13 12:44:43 -050027
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053028constexpr auto time_manager_intf = "org.openbmc.TimeManager";
29constexpr auto time_manager_obj = "/org/openbmc/TimeManager";
30
Tom Joseph6f7deaa2017-06-30 19:03:54 +053031namespace cache
32{
33 /*
34 * This cache contains the object paths of the logging entries sorted in the
35 * order of the filename(numeric order). The cache is initialized by
36 * invoking readLoggingObjectPaths with the cache as the parameter. The
37 * cache is invoked in the execution of the Get SEL info and Delete SEL
38 * entry command. The Get SEL Info command is typically invoked before the
39 * Get SEL entry command, so the cache is utilized for responding to Get SEL
40 * entry command. The cache is invalidated by clearing after Delete SEL
41 * entry and Clear SEL command.
42 */
43 ipmi::sel::ObjectPaths paths;
44
45} // namespace objectPathsCache
46
47using InternalFailure =
48 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
49using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050050using namespace ipmi::fru;
51
52/**
53 * @enum Device access mode
54 */
55enum class AccessMode
56{
57 bytes, ///< Device is accessed by bytes
58 words ///< Device is accessed by words
59};
60
Tom Joseph6f7deaa2017-06-30 19:03:54 +053061
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050062ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
63 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -050064 ipmi_data_len_t data_len, ipmi_context_t context)
65{
66 printf("Handling STORAGE WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
67 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080068 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050069 *data_len = 0;
70 return rc;
71}
72
Tom Joseph6f7deaa2017-06-30 19:03:54 +053073ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
74 ipmi_request_t request, ipmi_response_t response,
75 ipmi_data_len_t data_len, ipmi_context_t context)
76{
77 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
78 auto responseData = reinterpret_cast<ipmi::sel::GetSELInfoResponse*>
79 (outPayload.data());
80
81 responseData->selVersion = ipmi::sel::selVersion;
82 // Last erase timestamp is not available from log manager.
83 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
84 responseData->operationSupport = ipmi::sel::operationSupport;
85
86 ipmi::sel::readLoggingObjectPaths(cache::paths);
87 responseData->entries = 0;
88 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
89
90 if (!cache::paths.empty())
91 {
92 responseData->entries = static_cast<uint16_t>(cache::paths.size());
93
94 try
95 {
96 responseData->addTimeStamp = static_cast<uint32_t>(
97 (ipmi::sel::getEntryTimeStamp(cache::paths.back())
98 .count()));
99 }
100 catch (InternalFailure& e)
101 {
102 }
103 catch (const std::runtime_error& e)
104 {
105 log<level::ERR>(e.what());
106 }
107 }
108
109 memcpy(response, outPayload.data(), outPayload.size());
110 *data_len = outPayload.size();
111
112 return IPMI_CC_OK;
113}
114
Tom Josepha4953392017-06-30 19:09:47 +0530115ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
116 ipmi_request_t request, ipmi_response_t response,
117 ipmi_data_len_t data_len, ipmi_context_t context)
118{
119 auto requestData = reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>
120 (request);
121
122 if (requestData->reservationID != 0)
123 {
124 if (g_sel_reserve != requestData->reservationID)
125 {
126 *data_len = 0;
127 return IPMI_CC_INVALID_RESERVATION_ID;
128 }
129 }
130
131 if (cache::paths.empty())
132 {
133 *data_len = 0;
134 return IPMI_CC_SENSOR_INVALID;
135 }
136
137 ipmi::sel::ObjectPaths::const_iterator iter;
138
139 // Check for the requested SEL Entry.
140 if (requestData->selRecordID == ipmi::sel::firstEntry)
141 {
142 iter = cache::paths.begin();
143 }
144 else if (requestData->selRecordID == ipmi::sel::lastEntry)
145 {
146 iter = cache::paths.end();
147 }
148 else
149 {
150 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
151 std::to_string(requestData->selRecordID);
152
153 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
154 if (iter == cache::paths.end())
155 {
156 *data_len = 0;
157 return IPMI_CC_SENSOR_INVALID;
158 }
159 }
160
161 ipmi::sel::GetSELEntryResponse record {};
162
163 // Convert the log entry into SEL record.
164 try
165 {
166 record = ipmi::sel::convertLogEntrytoSEL(*iter);
167 }
168 catch (InternalFailure& e)
169 {
170 *data_len = 0;
171 return IPMI_CC_UNSPECIFIED_ERROR;
172 }
173 catch (const std::runtime_error& e)
174 {
175 log<level::ERR>(e.what());
176 *data_len = 0;
177 return IPMI_CC_UNSPECIFIED_ERROR;
178 }
179
180
181 // Identify the next SEL record ID
182 if(iter != cache::paths.end())
183 {
184 ++iter;
185 if (iter == cache::paths.end())
186 {
187 record.nextRecordID = ipmi::sel::lastEntry;
188 }
189 else
190 {
191 namespace fs = std::experimental::filesystem;
192 fs::path path(*iter);
193 record.nextRecordID = static_cast<uint16_t>
194 (std::stoul(std::string(path.filename().c_str())));
195 }
196 }
197 else
198 {
199 record.nextRecordID = ipmi::sel::lastEntry;
200 }
201
202 if (requestData->readLength == ipmi::sel::entireRecord)
203 {
204 memcpy(response, &record, sizeof(record));
205 *data_len = sizeof(record);
206 }
207 else
208 {
209 if (requestData->offset >= ipmi::sel::selRecordSize ||
210 requestData->readLength > ipmi::sel::selRecordSize)
211 {
212 *data_len = 0;
213 return IPMI_CC_INVALID_FIELD_REQUEST;
214 }
215
216 auto diff = ipmi::sel::selRecordSize - requestData->offset;
217 auto readLength = std::min(diff,
218 static_cast<int>(requestData->readLength));
219
220 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
221 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
222 &record.recordID + requestData->offset, readLength);
223 *data_len = sizeof(record.nextRecordID) + readLength;
224 }
225
226 return IPMI_CC_OK;
227}
228
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530229ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
230 ipmi_request_t request, ipmi_response_t response,
231 ipmi_data_len_t data_len, ipmi_context_t context)
232{
233 namespace fs = std::experimental::filesystem;
234 auto requestData = reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>
235 (request);
236
237 if (g_sel_reserve != requestData->reservationID)
238 {
239 *data_len = 0;
240 return IPMI_CC_INVALID_RESERVATION_ID;
241 }
242
243 ipmi::sel::readLoggingObjectPaths(cache::paths);
244
245 if (cache::paths.empty())
246 {
247 *data_len = 0;
248 return IPMI_CC_SENSOR_INVALID;
249 }
250
251 ipmi::sel::ObjectPaths::const_iterator iter;
252 uint16_t delRecordID = 0;
253
254 if (requestData->selRecordID == ipmi::sel::firstEntry)
255 {
256 iter = cache::paths.begin();
257 fs::path path(*iter);
258 delRecordID = static_cast<uint16_t>
259 (std::stoul(std::string(path.filename().c_str())));
260 }
261 else if (requestData->selRecordID == ipmi::sel::lastEntry)
262 {
263 iter = cache::paths.end();
264 fs::path path(*iter);
265 delRecordID = static_cast<uint16_t>
266 (std::stoul(std::string(path.filename().c_str())));
267 }
268 else
269 {
270 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
271 std::to_string(requestData->selRecordID);
272
273 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
274 if (iter == cache::paths.end())
275 {
276 *data_len = 0;
277 return IPMI_CC_SENSOR_INVALID;
278 }
279 delRecordID = requestData->selRecordID;
280 }
281
282 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
283 std::string service;
284
285 try
286 {
287 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
288 }
289 catch (const std::runtime_error& e)
290 {
291 log<level::ERR>(e.what());
292 *data_len = 0;
293 return IPMI_CC_UNSPECIFIED_ERROR;
294 }
295
296 auto methodCall = bus.new_method_call(service.c_str(),
297 (*iter).c_str(),
298 ipmi::sel::logDeleteIntf,
299 "Delete");
300 auto reply = bus.call(methodCall);
301 if (reply.is_method_error())
302 {
303 *data_len = 0;
304 return IPMI_CC_UNSPECIFIED_ERROR;
305 }
306
307 // Invalidate the cache of dbus entry objects.
308 cache::paths.clear();
309 memcpy(response, &delRecordID, sizeof(delRecordID));
310 *data_len = sizeof(delRecordID);
311
312 return IPMI_CC_OK;
313}
314
Tom Joseph2f05bb52017-06-30 19:14:49 +0530315ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
316 ipmi_response_t response, ipmi_data_len_t data_len,
317 ipmi_context_t context)
318{
319 auto requestData = reinterpret_cast<const ipmi::sel::ClearSELRequest*>
320 (request);
321
322 if (g_sel_reserve != requestData->reservationID)
323 {
324 *data_len = 0;
325 return IPMI_CC_INVALID_RESERVATION_ID;
326 }
327
328 if (requestData->charC != 'C' ||
329 requestData->charL != 'L' ||
330 requestData->charR != 'R')
331 {
332 *data_len = 0;
333 return IPMI_CC_INVALID_FIELD_REQUEST;
334 }
335
336 uint8_t eraseProgress = ipmi::sel::eraseComplete;
337
338 /*
339 * Erasure status cannot be fetched from DBUS, so always return erasure
340 * status as `erase completed`.
341 */
342 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
343 {
344 memcpy(response, &eraseProgress, sizeof(eraseProgress));
345 *data_len = sizeof(eraseProgress);
346 return IPMI_CC_OK;
347 }
348
349 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
350 auto depth = 0;
351
352 auto mapperCall = bus.new_method_call(ipmi::sel::mapperBusName,
353 ipmi::sel::mapperObjPath,
354 ipmi::sel::mapperIntf,
355 "GetSubTreePaths");
356 mapperCall.append(ipmi::sel::logBasePath);
357 mapperCall.append(depth);
358 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
359
360 auto reply = bus.call(mapperCall);
361 if (reply.is_method_error())
362 {
363 memcpy(response, &eraseProgress, sizeof(eraseProgress));
364 *data_len = sizeof(eraseProgress);
365 return IPMI_CC_OK;
366 }
367
368 ipmi::sel::ObjectPaths objectPaths;
369 reply.read(objectPaths);
370 if (objectPaths.empty())
371 {
372 memcpy(response, &eraseProgress, sizeof(eraseProgress));
373 *data_len = sizeof(eraseProgress);
374 return IPMI_CC_OK;
375 }
376
377 std::string service;
378
379 try
380 {
381 service = ipmi::getService(bus,
382 ipmi::sel::logDeleteIntf,
383 objectPaths.front());
384 }
385 catch (const std::runtime_error& e)
386 {
387 log<level::ERR>(e.what());
388 *data_len = 0;
389 return IPMI_CC_UNSPECIFIED_ERROR;
390 }
391
392 for (const auto& iter : objectPaths)
393 {
394 auto methodCall = bus.new_method_call(service.c_str(),
395 iter.c_str(),
396 ipmi::sel::logDeleteIntf,
397 "Delete");
398
399 auto reply = bus.call(methodCall);
400 if (reply.is_method_error())
401 {
402 *data_len = 0;
403 return IPMI_CC_UNSPECIFIED_ERROR;
404 }
405 }
406
407 // Invalidate the cache of dbus entry objects.
408 cache::paths.clear();
409 memcpy(response, &eraseProgress, sizeof(eraseProgress));
410 *data_len = sizeof(eraseProgress);
411 return IPMI_CC_OK;
412}
413
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500414ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
415 ipmi_request_t request, ipmi_response_t response,
416 ipmi_data_len_t data_len, ipmi_context_t context)
417{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530418 using namespace std::chrono;
419
420 char *time_provider = nullptr;
421 const char* time_in_str = nullptr;
422 uint64_t host_time_usec = 0;
423 uint32_t resp = 0;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500424 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austenb4f5b922015-10-13 12:44:43 -0500425
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530426 sd_bus_message *reply = nullptr;
427 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500428
429 printf("IPMI Handling GET-SEL-TIME\n");
430
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530431 auto bus = ipmid_get_sd_bus_connection();
432
433 auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
434 if (rct < 0) {
435 printf("Error [%s] getting bus name for time provider\n",
436 strerror(-rct));
437 rc = IPMI_CC_UNSPECIFIED_ERROR;
438 goto finish;
439 }
440
441 rct = sd_bus_call_method(bus,
442 time_provider,
443 time_manager_obj,
444 time_manager_intf,
445 "GetTime",
446 &bus_error,
447 &reply,
448 "s",
449 "host");
450 if (rct < 0) {
451 printf("Error [%s] getting time\n", strerror(-rct));
452 rc = IPMI_CC_UNSPECIFIED_ERROR;
453 goto finish;
454 }
455
456 rct = sd_bus_message_read(reply, "sx", &time_in_str, &host_time_usec);
457 if (rct < 0) {
458 fprintf(stderr, "Error [%s] parsing get-time response\n",
459 strerror(-rct));
460 rc = IPMI_CC_UNSPECIFIED_ERROR;
461 goto finish;
462 }
463
464 // Time is really long int but IPMI wants just uint32. This works okay until
465 // the number of seconds since 1970 overflows uint32 size.. Still a whole
466 // lot of time here to even think about that.
467 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
468 resp = htole32(resp);
469 printf("Host Time read:[%s] :: [%d]\n", time_in_str, resp);
470
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500471 // From the IPMI Spec 2.0, response should be a 32-bit value
472 *data_len = sizeof(resp);
473
474 // Pack the actual response
475 memcpy(response, &resp, *data_len);
476
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530477finish:
478 sd_bus_error_free(&bus_error);
479 reply = sd_bus_message_unref(reply);
480 free(time_provider);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500481 return rc;
482}
483
484ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
485 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500486 ipmi_data_len_t data_len, ipmi_context_t context)
487{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530488 char *time_provider = nullptr;
489 int time_rc = 0;
490 ipmi_ret_t rc = IPMI_CC_OK;
491
492 sd_bus_message *reply = nullptr;
493 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
494
Norman James82330442015-11-19 16:53:26 -0600495 uint32_t* secs = (uint32_t*)request;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530496 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500497
498 printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
Norman James82330442015-11-19 16:53:26 -0600499 printf("Data: 0x%X]\n",*secs);
Chris Austenb4f5b922015-10-13 12:44:43 -0500500
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530501 auto bus = ipmid_get_sd_bus_connection();
Norman James82330442015-11-19 16:53:26 -0600502
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530503 auto rct = mapper_get_service(bus, time_manager_obj, &time_provider);
504 if (rct < 0) {
505 printf("Error [%s] getting bus name for time provider\n",
506 strerror(-rct));
507 rc = IPMI_CC_UNSPECIFIED_ERROR;
508 goto finish;
Norman James82330442015-11-19 16:53:26 -0600509 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530510
511 rct = sd_bus_call_method(bus,
512 time_provider,
513 time_manager_obj,
514 time_manager_intf,
515 "SetTime",
516 &bus_error,
517 &reply,
518 "ss",
519 "host",
520 std::to_string(le32toh(*secs)).c_str());
521
522 if (rct < 0) {
523 printf("Error [%s] setting time\n", strerror(-rct));
524 rc = IPMI_CC_UNSPECIFIED_ERROR;
525 goto finish;
526 }
527
528 rct = sd_bus_message_read(reply, "i", &time_rc);
529 if (rct < 0) {
530 fprintf(stderr, "Error [%s] parsing set-time response\n",
531 strerror(-rct));
532 rc = IPMI_CC_UNSPECIFIED_ERROR;
533 goto finish;
534 }
535
536 if (time_rc < 0) {
537 printf("Error setting time.");
Norman James82330442015-11-19 16:53:26 -0600538 rc = IPMI_CC_UNSPECIFIED_ERROR;
539 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530540
541finish:
542 sd_bus_error_free(&bus_error);
543 reply = sd_bus_message_unref(reply);
544 free(time_provider);
Chris Austenb4f5b922015-10-13 12:44:43 -0500545 return rc;
546}
547
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500548ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
549 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500550 ipmi_data_len_t data_len, ipmi_context_t context)
551{
Chris Austenb4f5b922015-10-13 12:44:43 -0500552 ipmi_ret_t rc = IPMI_CC_OK;
553
Nan Li36c0cb62016-03-31 11:16:08 +0800554 // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
555 if( ++g_sel_reserve == 0)
556 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500557
Nan Li36c0cb62016-03-31 11:16:08 +0800558 printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
Chris Austen41a4b312015-10-25 03:45:42 -0500559
Chris Austenb4f5b922015-10-13 12:44:43 -0500560 *data_len = sizeof(g_sel_reserve);
561
562 // Pack the actual response
563 memcpy(response, &g_sel_reserve, *data_len);
564
565 return rc;
566}
567
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500568ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
569 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500570 ipmi_data_len_t data_len, ipmi_context_t context)
571{
572
573 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austen41a4b312015-10-25 03:45:42 -0500574 ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
575 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500576
Chris Austen313d95b2015-10-31 12:55:30 -0500577 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500578
579 printf("IPMI Handling ADD-SEL for record 0x%04x\n", recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500580
581 *data_len = sizeof(g_sel_reserve);
582
583 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600584 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500585
Chris Austen41a4b312015-10-25 03:45:42 -0500586 send_esel(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500587
588 return rc;
589}
590
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500591//Read FRU info area
592ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
593 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
594 ipmi_response_t response, ipmi_data_len_t data_len,
595 ipmi_context_t context)
596{
597 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500598 const FruInvenAreaInfoRequest* reqptr =
599 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
600 try
601 {
602 const auto& fruArea = getFruAreaData(reqptr->fruID);
603 auto size = static_cast<uint16_t>(fruArea.size());
604 FruInvenAreaInfoResponse resp;
605 resp.sizems = size >> 8;
606 resp.sizels = size;
607 resp.access = static_cast<uint8_t>(AccessMode::bytes);
608
609 *data_len = sizeof(resp);
610
611 // Pack the actual response
612 memcpy(response, &resp, *data_len);
613 }
614 catch(const InternalFailure& e)
615 {
616 rc = IPMI_CC_UNSPECIFIED_ERROR;
617 *data_len = 0;
618 log<level::ERR>(e.what());
619 report<InternalFailure>();
620 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500621 return rc;
622}
623
624//Read FRU data
625ipmi_ret_t ipmi_storage_read_fru_data(
626 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
627 ipmi_response_t response, ipmi_data_len_t data_len,
628 ipmi_context_t context)
629{
630 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500631 const ReadFruDataRequest* reqptr =
632 reinterpret_cast<const ReadFruDataRequest*>(request);
633 auto offset =
634 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
635 try
636 {
637 const auto& fruArea = getFruAreaData(reqptr->fruID);
638 auto size = fruArea.size();
639 if ((offset + reqptr->count) > size)
640 {
641 log<level::ERR>("Invalid offset and count",
642 entry("Offset=%d Count=%d SizeOfFruArea=%d",
643 offset, reqptr->count, size));
644 return IPMI_CC_INVALID;
645 }
646 std::copy((fruArea.begin() + offset), (fruArea.begin() + reqptr->count),
647 (static_cast<uint8_t*>(response)));
648 *data_len = reqptr->count;
649 }
650 catch (const InternalFailure& e)
651 {
652 rc = IPMI_CC_UNSPECIFIED_ERROR;
653 *data_len = 0;
654 log<level::ERR>(e.what());
655 report<InternalFailure>();
656 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500657 return rc;
658}
659
Chris Austenb4f5b922015-10-13 12:44:43 -0500660
Chris Austenb4f5b922015-10-13 12:44:43 -0500661void register_netfn_storage_functions()
662{
Tom05732372016-09-06 17:21:23 +0530663 // <Wildcard Command>
Chris Austenb4f5b922015-10-13 12:44:43 -0500664 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530665 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
666 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500667
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530668 // <Get SEL Info>
669 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO);
670 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, getSELInfo,
671 PRIVILEGE_USER);
672
Tom05732372016-09-06 17:21:23 +0530673 // <Get SEL Time>
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500674 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530675 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
676 PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500677
Tom05732372016-09-06 17:21:23 +0530678 // <Set SEL Time>
Chris Austenb4f5b922015-10-13 12:44:43 -0500679 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530680 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
681 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500682
Tom05732372016-09-06 17:21:23 +0530683 // <Reserve SEL>
Chris Austenb4f5b922015-10-13 12:44:43 -0500684 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL);
Tom05732372016-09-06 17:21:23 +0530685 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
686 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500687
Tom Josepha4953392017-06-30 19:09:47 +0530688 // <Get SEL Entry>
689 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY);
690 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL, getSELEntry,
691 PRIVILEGE_USER);
692
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530693 // <Delete SEL Entry>
694 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_DELETE_SEL);
695 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL, deleteSELEntry,
696 PRIVILEGE_OPERATOR);
697
Tom05732372016-09-06 17:21:23 +0530698 // <Add SEL Entry>
Chris Austenb4f5b922015-10-13 12:44:43 -0500699 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_ADD_SEL);
Tom05732372016-09-06 17:21:23 +0530700 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
701 PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530702 // <Clear SEL>
703 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL);
704 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
705 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500706 // <Get FRU Inventory Area Info>
707 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
708 IPMI_CMD_GET_FRU_INV_AREA_INFO);
709 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
710 ipmi_storage_get_fru_inv_area_info, PRIVILEGE_OPERATOR);
711
712 // <Add READ FRU Data
713 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
714 IPMI_CMD_READ_FRU_DATA);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500715 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
716 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500717
Marri Devender Rao908f7502017-07-10 01:49:54 -0500718 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500719 return;
720}
721