blob: 2e89de7ad966434ec8248211260d042f905cb865 [file] [log] [blame]
Patrick Venture3a5071a2018-09-12 13:27:42 -07001#include "storagehandler.hpp"
2
3#include "fruread.hpp"
4#include "read_fru_data.hpp"
5#include "selutility.hpp"
6#include "sensorhandler.hpp"
7#include "storageaddsel.hpp"
Patrick Venture3a5071a2018-09-12 13:27:42 -07008
Lei YU52d91242017-10-17 22:52:28 +08009#include <arpa/inet.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -070010#include <mapper.h>
11#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070012
13#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +080014#include <chrono>
15#include <cstdio>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070016#include <cstring>
Vernon Mauerybdda8002019-02-26 10:18:51 -080017#include <filesystem>
Vernon Mauerye08fbff2019-04-03 09:19:34 -070018#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070019#include <ipmid/utils.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070020#include <phosphor-logging/elog-errors.hpp>
21#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070022#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070023#include <sdbusplus/server.hpp>
24#include <string>
25#include <xyz/openbmc_project/Common/error.hpp>
26
Chris Austenb4f5b922015-10-13 12:44:43 -050027void register_netfn_storage_functions() __attribute__((constructor));
28
Patrick Venture0b02be92018-08-31 11:55:55 -070029unsigned int g_sel_time = 0xFFFFFFFF;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060030extern const ipmi::sensor::IdInfoMap sensors;
31extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050032
Patrick Venture0b02be92018-08-31 11:55:55 -070033namespace
34{
Lei YUe8939392017-06-15 10:45:05 +080035constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
36constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
37constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
Patrick Venture0b02be92018-08-31 11:55:55 -070038constexpr auto PROPERTY_ELAPSED = "Elapsed";
Lei YUe8939392017-06-15 10:45:05 +080039
40const char* getTimeString(const uint64_t& usecSinceEpoch)
41{
42 using namespace std::chrono;
43 system_clock::time_point tp{microseconds(usecSinceEpoch)};
44 auto t = system_clock::to_time_t(tp);
45 return std::ctime(&t);
46}
Patrick Venture0b02be92018-08-31 11:55:55 -070047} // namespace
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053048
Tom Joseph6f7deaa2017-06-30 19:03:54 +053049namespace cache
50{
Patrick Venture0b02be92018-08-31 11:55:55 -070051/*
52 * This cache contains the object paths of the logging entries sorted in the
53 * order of the filename(numeric order). The cache is initialized by
54 * invoking readLoggingObjectPaths with the cache as the parameter. The
55 * cache is invoked in the execution of the Get SEL info and Delete SEL
56 * entry command. The Get SEL Info command is typically invoked before the
57 * Get SEL entry command, so the cache is utilized for responding to Get SEL
58 * entry command. The cache is invalidated by clearing after Delete SEL
59 * entry and Clear SEL command.
60 */
61ipmi::sel::ObjectPaths paths;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053062
Patrick Venture0b02be92018-08-31 11:55:55 -070063} // namespace cache
Tom Joseph6f7deaa2017-06-30 19:03:54 +053064
65using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070066 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053067using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050068using namespace ipmi::fru;
69
70/**
71 * @enum Device access mode
72 */
73enum class AccessMode
74{
75 bytes, ///< Device is accessed by bytes
76 words ///< Device is accessed by words
77};
78
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050079ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070080 ipmi_request_t request,
81 ipmi_response_t response,
82 ipmi_data_len_t data_len,
83 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050084{
Chris Austenb4f5b922015-10-13 12:44:43 -050085 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080086 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050087 *data_len = 0;
88 return rc;
89}
90
Tom Joseph6f7deaa2017-06-30 19:03:54 +053091ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
92 ipmi_request_t request, ipmi_response_t response,
93 ipmi_data_len_t data_len, ipmi_context_t context)
94{
Jason M. Bills851acb12019-02-04 14:06:57 -080095 if (*data_len != 0)
96 {
97 *data_len = 0;
98 return IPMI_CC_REQ_DATA_LEN_INVALID;
99 }
100
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530101 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700102 auto responseData =
103 reinterpret_cast<ipmi::sel::GetSELInfoResponse*>(outPayload.data());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530104
105 responseData->selVersion = ipmi::sel::selVersion;
106 // Last erase timestamp is not available from log manager.
107 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
108 responseData->operationSupport = ipmi::sel::operationSupport;
109
Tom Josephe59abfb2018-08-06 18:46:27 +0530110 try
111 {
112 ipmi::sel::readLoggingObjectPaths(cache::paths);
113 }
114 catch (const sdbusplus::exception::SdBusError& e)
115 {
116 // No action if reading log objects have failed for this command.
117 // readLoggingObjectPaths will throw exception if there are no log
118 // entries. The command will be responded with number of SEL entries
119 // as 0.
120 }
121
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530122 responseData->entries = 0;
123 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
124
125 if (!cache::paths.empty())
126 {
127 responseData->entries = static_cast<uint16_t>(cache::paths.size());
128
129 try
130 {
131 responseData->addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700132 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530133 }
134 catch (InternalFailure& e)
135 {
136 }
137 catch (const std::runtime_error& e)
138 {
139 log<level::ERR>(e.what());
140 }
141 }
142
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700143 std::memcpy(response, outPayload.data(), outPayload.size());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530144 *data_len = outPayload.size();
145
146 return IPMI_CC_OK;
147}
148
Tom Josepha4953392017-06-30 19:09:47 +0530149ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
150 ipmi_request_t request, ipmi_response_t response,
151 ipmi_data_len_t data_len, ipmi_context_t context)
152{
Jason M. Bills851acb12019-02-04 14:06:57 -0800153 if (*data_len != sizeof(ipmi::sel::GetSELEntryRequest))
154 {
155 *data_len = 0;
156 return IPMI_CC_REQ_DATA_LEN_INVALID;
157 }
158
Patrick Venture0b02be92018-08-31 11:55:55 -0700159 auto requestData =
160 reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>(request);
Tom Josepha4953392017-06-30 19:09:47 +0530161
162 if (requestData->reservationID != 0)
163 {
Jason M. Bills13e67c82018-09-10 14:12:16 -0700164 if (!checkSELReservation(requestData->reservationID))
Tom Josepha4953392017-06-30 19:09:47 +0530165 {
166 *data_len = 0;
167 return IPMI_CC_INVALID_RESERVATION_ID;
168 }
169 }
170
171 if (cache::paths.empty())
172 {
173 *data_len = 0;
174 return IPMI_CC_SENSOR_INVALID;
175 }
176
177 ipmi::sel::ObjectPaths::const_iterator iter;
178
179 // Check for the requested SEL Entry.
180 if (requestData->selRecordID == ipmi::sel::firstEntry)
181 {
182 iter = cache::paths.begin();
183 }
184 else if (requestData->selRecordID == ipmi::sel::lastEntry)
185 {
186 iter = cache::paths.end();
187 }
188 else
189 {
190 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
191 std::to_string(requestData->selRecordID);
192
193 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
194 if (iter == cache::paths.end())
195 {
196 *data_len = 0;
197 return IPMI_CC_SENSOR_INVALID;
198 }
199 }
200
Patrick Venture0b02be92018-08-31 11:55:55 -0700201 ipmi::sel::GetSELEntryResponse record{};
Tom Josepha4953392017-06-30 19:09:47 +0530202
203 // Convert the log entry into SEL record.
204 try
205 {
206 record = ipmi::sel::convertLogEntrytoSEL(*iter);
207 }
208 catch (InternalFailure& e)
209 {
210 *data_len = 0;
211 return IPMI_CC_UNSPECIFIED_ERROR;
212 }
213 catch (const std::runtime_error& e)
214 {
215 log<level::ERR>(e.what());
216 *data_len = 0;
217 return IPMI_CC_UNSPECIFIED_ERROR;
218 }
219
Tom Josepha4953392017-06-30 19:09:47 +0530220 // Identify the next SEL record ID
Patrick Venture0b02be92018-08-31 11:55:55 -0700221 if (iter != cache::paths.end())
Tom Josepha4953392017-06-30 19:09:47 +0530222 {
223 ++iter;
224 if (iter == cache::paths.end())
225 {
226 record.nextRecordID = ipmi::sel::lastEntry;
227 }
228 else
229 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700230 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530231 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700232 record.nextRecordID = static_cast<uint16_t>(
233 std::stoul(std::string(path.filename().c_str())));
Tom Josepha4953392017-06-30 19:09:47 +0530234 }
235 }
236 else
237 {
238 record.nextRecordID = ipmi::sel::lastEntry;
239 }
240
241 if (requestData->readLength == ipmi::sel::entireRecord)
242 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700243 std::memcpy(response, &record, sizeof(record));
Tom Josepha4953392017-06-30 19:09:47 +0530244 *data_len = sizeof(record);
245 }
246 else
247 {
248 if (requestData->offset >= ipmi::sel::selRecordSize ||
249 requestData->readLength > ipmi::sel::selRecordSize)
250 {
251 *data_len = 0;
252 return IPMI_CC_INVALID_FIELD_REQUEST;
253 }
254
255 auto diff = ipmi::sel::selRecordSize - requestData->offset;
Patrick Venture0b02be92018-08-31 11:55:55 -0700256 auto readLength =
257 std::min(diff, static_cast<int>(requestData->readLength));
Tom Josepha4953392017-06-30 19:09:47 +0530258
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700259 std::memcpy(response, &record.nextRecordID,
260 sizeof(record.nextRecordID));
261 std::memcpy(static_cast<uint8_t*>(response) +
262 sizeof(record.nextRecordID),
263 &record.recordID + requestData->offset, readLength);
Tom Josepha4953392017-06-30 19:09:47 +0530264 *data_len = sizeof(record.nextRecordID) + readLength;
265 }
266
267 return IPMI_CC_OK;
268}
269
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000270/** @brief implements the delete SEL entry command
271 * @request
272 * - reservationID; // reservation ID.
273 * - selRecordID; // SEL record ID.
274 *
275 * @returns ipmi completion code plus response data
276 * - Record ID of the deleted record
277 */
278ipmi::RspType<uint16_t // deleted record ID
279 >
280 deleteSELEntry(uint16_t reservationID, uint16_t selRecordID)
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530281{
Jason M. Bills851acb12019-02-04 14:06:57 -0800282
Brad Bishop1a4117b2018-11-21 15:48:18 -0500283 namespace fs = std::filesystem;
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530284
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000285 if (!checkSELReservation(reservationID))
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530286 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000287 return ipmi::responseInvalidReservationId();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530288 }
289
Jason M. Bills13e67c82018-09-10 14:12:16 -0700290 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
291 // deleted
292 cancelSELReservation();
293
Tom Josephe59abfb2018-08-06 18:46:27 +0530294 try
295 {
296 ipmi::sel::readLoggingObjectPaths(cache::paths);
297 }
298 catch (const sdbusplus::exception::SdBusError& e)
299 {
300 // readLoggingObjectPaths will throw exception if there are no error
301 // log entries.
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000302 return ipmi::responseSensorInvalid();
Tom Josephe59abfb2018-08-06 18:46:27 +0530303 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530304
305 if (cache::paths.empty())
306 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000307 return ipmi::responseSensorInvalid();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530308 }
309
310 ipmi::sel::ObjectPaths::const_iterator iter;
311 uint16_t delRecordID = 0;
312
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000313 if (selRecordID == ipmi::sel::firstEntry)
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530314 {
315 iter = cache::paths.begin();
316 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700317 delRecordID = static_cast<uint16_t>(
318 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530319 }
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000320 else if (selRecordID == ipmi::sel::lastEntry)
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530321 {
322 iter = cache::paths.end();
323 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700324 delRecordID = static_cast<uint16_t>(
325 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530326 }
327 else
328 {
329 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000330 std::to_string(selRecordID);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530331
332 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
333 if (iter == cache::paths.end())
334 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000335 return ipmi::responseSensorInvalid();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530336 }
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000337 delRecordID = selRecordID;
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530338 }
339
340 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
341 std::string service;
342
343 try
344 {
345 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
346 }
347 catch (const std::runtime_error& e)
348 {
349 log<level::ERR>(e.what());
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000350 return ipmi::responseUnspecifiedError();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530351 }
352
Patrick Venture0b02be92018-08-31 11:55:55 -0700353 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
354 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530355 auto reply = bus.call(methodCall);
356 if (reply.is_method_error())
357 {
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000358 return ipmi::responseUnspecifiedError();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530359 }
360
361 // Invalidate the cache of dbus entry objects.
362 cache::paths.clear();
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530363
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000364 return ipmi::responseSuccess(delRecordID);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530365}
366
Tom Joseph2f05bb52017-06-30 19:14:49 +0530367ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
368 ipmi_response_t response, ipmi_data_len_t data_len,
369 ipmi_context_t context)
370{
Jason M. Bills851acb12019-02-04 14:06:57 -0800371 if (*data_len != sizeof(ipmi::sel::ClearSELRequest))
372 {
373 *data_len = 0;
374 return IPMI_CC_REQ_DATA_LEN_INVALID;
375 }
376
Patrick Venture0b02be92018-08-31 11:55:55 -0700377 auto requestData =
378 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530379
Jason M. Bills13e67c82018-09-10 14:12:16 -0700380 if (!checkSELReservation(requestData->reservationID))
Tom Joseph2f05bb52017-06-30 19:14:49 +0530381 {
382 *data_len = 0;
383 return IPMI_CC_INVALID_RESERVATION_ID;
384 }
385
Patrick Venture0b02be92018-08-31 11:55:55 -0700386 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530387 requestData->charR != 'R')
388 {
389 *data_len = 0;
390 return IPMI_CC_INVALID_FIELD_REQUEST;
391 }
392
393 uint8_t eraseProgress = ipmi::sel::eraseComplete;
394
395 /*
396 * Erasure status cannot be fetched from DBUS, so always return erasure
397 * status as `erase completed`.
398 */
399 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
400 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700401 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530402 *data_len = sizeof(eraseProgress);
403 return IPMI_CC_OK;
404 }
405
Jason M. Bills13e67c82018-09-10 14:12:16 -0700406 // Per the IPMI spec, need to cancel any reservation when the SEL is cleared
407 cancelSELReservation();
408
Tom Joseph2f05bb52017-06-30 19:14:49 +0530409 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530410 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530411 auto depth = 0;
412
Patrick Venture0b02be92018-08-31 11:55:55 -0700413 auto mapperCall =
414 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
415 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530416 mapperCall.append(ipmi::sel::logBasePath);
417 mapperCall.append(depth);
418 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
419
Tom Josephe59abfb2018-08-06 18:46:27 +0530420 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530421 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530422 auto reply = bus.call(mapperCall);
423 if (reply.is_method_error())
424 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700425 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530426 *data_len = sizeof(eraseProgress);
427 return IPMI_CC_OK;
428 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530429
Tom Josephe59abfb2018-08-06 18:46:27 +0530430 reply.read(objectPaths);
431 if (objectPaths.empty())
432 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700433 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530434 *data_len = sizeof(eraseProgress);
435 return IPMI_CC_OK;
436 }
437 }
438 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530439 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700440 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530441 *data_len = sizeof(eraseProgress);
442 return IPMI_CC_OK;
443 }
444
445 std::string service;
446
447 try
448 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700449 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530450 objectPaths.front());
451 }
452 catch (const std::runtime_error& e)
453 {
454 log<level::ERR>(e.what());
455 *data_len = 0;
456 return IPMI_CC_UNSPECIFIED_ERROR;
457 }
458
459 for (const auto& iter : objectPaths)
460 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700461 auto methodCall = bus.new_method_call(
462 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530463
464 auto reply = bus.call(methodCall);
465 if (reply.is_method_error())
466 {
467 *data_len = 0;
468 return IPMI_CC_UNSPECIFIED_ERROR;
469 }
470 }
471
472 // Invalidate the cache of dbus entry objects.
473 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700474 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530475 *data_len = sizeof(eraseProgress);
476 return IPMI_CC_OK;
477}
478
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500479ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700480 ipmi_request_t request,
481 ipmi_response_t response,
482 ipmi_data_len_t data_len,
483 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500484{
Jason M. Bills851acb12019-02-04 14:06:57 -0800485 if (*data_len != 0)
486 {
487 *data_len = 0;
488 return IPMI_CC_REQ_DATA_LEN_INVALID;
489 }
490
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530491 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530492 uint64_t host_time_usec = 0;
493 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500494 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500495
Lei YUe8939392017-06-15 10:45:05 +0800496 try
497 {
498 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
499 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
500 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530501
Lei YUe8939392017-06-15 10:45:05 +0800502 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700503 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
504 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800505
506 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
507 auto reply = bus.call(method);
508 if (reply.is_method_error())
509 {
510 log<level::ERR>("Error getting time",
511 entry("SERVICE=%s", service.c_str()),
512 entry("PATH=%s", HOST_TIME_PATH));
513 return IPMI_CC_UNSPECIFIED_ERROR;
514 }
515 reply.read(value);
Vernon Maueryf442e112019-04-09 11:44:36 -0700516 host_time_usec = std::get<uint64_t>(value);
Lei YUe8939392017-06-15 10:45:05 +0800517 }
518 catch (InternalFailure& e)
519 {
520 log<level::ERR>(e.what());
521 return IPMI_CC_UNSPECIFIED_ERROR;
522 }
523 catch (const std::runtime_error& e)
524 {
525 log<level::ERR>(e.what());
526 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530527 }
528
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500529 hostTime << "Host time:" << getTimeString(host_time_usec);
530 log<level::DEBUG>(hostTime.str().c_str());
531
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530532 // Time is really long int but IPMI wants just uint32. This works okay until
533 // the number of seconds since 1970 overflows uint32 size.. Still a whole
534 // lot of time here to even think about that.
535 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
536 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530537
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500538 // From the IPMI Spec 2.0, response should be a 32-bit value
539 *data_len = sizeof(resp);
540
541 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700542 std::memcpy(response, &resp, *data_len);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500543
Lei YUe8939392017-06-15 10:45:05 +0800544 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500545}
546
547ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700548 ipmi_request_t request,
549 ipmi_response_t response,
550 ipmi_data_len_t data_len,
551 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500552{
Jason M. Bills851acb12019-02-04 14:06:57 -0800553 if (*data_len != sizeof(uint32_t))
554 {
555 *data_len = 0;
556 return IPMI_CC_REQ_DATA_LEN_INVALID;
557 }
Lei YUe8939392017-06-15 10:45:05 +0800558 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530559 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800560 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530561 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500562
Lei YUe8939392017-06-15 10:45:05 +0800563 secs = le32toh(secs);
564 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600565
Lei YUe8939392017-06-15 10:45:05 +0800566 try
567 {
568 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
569 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
570 sdbusplus::message::variant<uint64_t> value{usec.count()};
571
572 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700573 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
574 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800575
576 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
577 auto reply = bus.call(method);
578 if (reply.is_method_error())
579 {
580 log<level::ERR>("Error setting time",
581 entry("SERVICE=%s", service.c_str()),
582 entry("PATH=%s", HOST_TIME_PATH));
583 rc = IPMI_CC_UNSPECIFIED_ERROR;
584 }
Norman James82330442015-11-19 16:53:26 -0600585 }
Lei YUe8939392017-06-15 10:45:05 +0800586 catch (InternalFailure& e)
587 {
588 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530589 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530590 }
Lei YUe8939392017-06-15 10:45:05 +0800591 catch (const std::runtime_error& e)
592 {
593 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600594 rc = IPMI_CC_UNSPECIFIED_ERROR;
595 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530596
Chris Austenb4f5b922015-10-13 12:44:43 -0500597 return rc;
598}
599
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500600ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700601 ipmi_request_t request,
602 ipmi_response_t response,
603 ipmi_data_len_t data_len,
604 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500605{
Jason M. Bills851acb12019-02-04 14:06:57 -0800606 if (*data_len != 0)
607 {
608 *data_len = 0;
609 return IPMI_CC_REQ_DATA_LEN_INVALID;
610 }
611
Chris Austenb4f5b922015-10-13 12:44:43 -0500612 ipmi_ret_t rc = IPMI_CC_OK;
Jason M. Bills13e67c82018-09-10 14:12:16 -0700613 unsigned short selResID = reserveSel();
Chris Austenb4f5b922015-10-13 12:44:43 -0500614
Jason M. Bills13e67c82018-09-10 14:12:16 -0700615 *data_len = sizeof(selResID);
Chris Austenb4f5b922015-10-13 12:44:43 -0500616
617 // Pack the actual response
Jason M. Bills13e67c82018-09-10 14:12:16 -0700618 std::memcpy(response, &selResID, *data_len);
Chris Austenb4f5b922015-10-13 12:44:43 -0500619
620 return rc;
621}
622
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500623ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700624 ipmi_request_t request,
625 ipmi_response_t response,
626 ipmi_data_len_t data_len,
627 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500628{
Jason M. Bills851acb12019-02-04 14:06:57 -0800629 if (*data_len != sizeof(ipmi_add_sel_request_t))
630 {
631 *data_len = 0;
632 return IPMI_CC_REQ_DATA_LEN_INVALID;
633 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500634
635 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700636 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500637 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500638
Jason M. Bills13e67c82018-09-10 14:12:16 -0700639 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
640 // added
641 cancelSELReservation();
642
Chris Austen313d95b2015-10-31 12:55:30 -0500643 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500644
Jason M. Bills13e67c82018-09-10 14:12:16 -0700645 *data_len = sizeof(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500646
647 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700648 std::memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500649
Tom Josephb647d5b2017-10-31 17:25:33 +0530650 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
651 // a maintenance procedure associated with eSEL record.
652 static constexpr auto procedureType = 0xDE;
653 if (p->recordtype == procedureType)
654 {
655 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
656 // procedure number.
657 createProcedureLogEntry(p->sensortype);
658 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500659
660 return rc;
661}
662
Patrick Venture0b02be92018-08-31 11:55:55 -0700663// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500664ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700665 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
666 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500667{
668 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500669 const FruInvenAreaInfoRequest* reqptr =
670 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530671
672 auto iter = frus.find(reqptr->fruID);
673 if (iter == frus.end())
674 {
675 *data_len = 0;
676 return IPMI_CC_SENSOR_INVALID;
677 }
678
Marri Devender Raocac383b2017-07-03 13:24:27 -0500679 try
680 {
681 const auto& fruArea = getFruAreaData(reqptr->fruID);
682 auto size = static_cast<uint16_t>(fruArea.size());
683 FruInvenAreaInfoResponse resp;
684 resp.sizems = size >> 8;
685 resp.sizels = size;
686 resp.access = static_cast<uint8_t>(AccessMode::bytes);
687
688 *data_len = sizeof(resp);
689
690 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700691 std::memcpy(response, &resp, *data_len);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500692 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700693 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500694 {
695 rc = IPMI_CC_UNSPECIFIED_ERROR;
696 *data_len = 0;
697 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500698 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500699 return rc;
700}
701
Patrick Venture0b02be92018-08-31 11:55:55 -0700702// Read FRU data
703ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
704 ipmi_request_t request,
705 ipmi_response_t response,
706 ipmi_data_len_t data_len,
707 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500708{
709 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500710 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500711 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700712 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530713
714 auto iter = frus.find(reqptr->fruID);
715 if (iter == frus.end())
716 {
717 *data_len = 0;
718 return IPMI_CC_SENSOR_INVALID;
719 }
720
Marri Devender Raocac383b2017-07-03 13:24:27 -0500721 auto offset =
722 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
723 try
724 {
725 const auto& fruArea = getFruAreaData(reqptr->fruID);
726 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500727
Tom Josephefcd68b2018-04-26 18:46:27 +0530728 if (offset >= size)
729 {
730 return IPMI_CC_PARM_OUT_OF_RANGE;
731 }
732
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500733 // Write the count of response data.
734 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500735 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500736 resptr->count = reqptr->count;
737 }
738 else
739 {
740 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500741 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530742
Ratan Gupta2848d602018-01-31 20:39:20 +0530743 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700744 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530745
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500746 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500747 }
748 catch (const InternalFailure& e)
749 {
750 rc = IPMI_CC_UNSPECIFIED_ERROR;
751 *data_len = 0;
752 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500753 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500754 return rc;
755}
756
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600757ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700758 ipmi_request_t request,
759 ipmi_response_t response,
760 ipmi_data_len_t data_len,
761 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600762{
763 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700764 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600765
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700766 std::memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600767
768 responseData->sdrVersion = sdrVersion;
769
770 uint16_t records = frus.size() + sensors.size();
771 responseData->recordCountMs = records >> 8;
772 responseData->recordCountLs = records;
773
774 responseData->freeSpace[0] = 0xFF;
775 responseData->freeSpace[1] = 0xFF;
776
777 *data_len = sizeof(GetRepositoryInfoResponse);
778
779 return IPMI_CC_OK;
780}
Chris Austenb4f5b922015-10-13 12:44:43 -0500781
Chris Austenb4f5b922015-10-13 12:44:43 -0500782void register_netfn_storage_functions()
783{
Tom05732372016-09-06 17:21:23 +0530784 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700785 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
786 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500787
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530788 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700789 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
790 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530791
Tom05732372016-09-06 17:21:23 +0530792 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700793 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
794 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500795
Tom05732372016-09-06 17:21:23 +0530796 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700797 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
798 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500799
Tom05732372016-09-06 17:21:23 +0530800 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700801 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
802 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500803
Tom Josepha4953392017-06-30 19:09:47 +0530804 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700805 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
806 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530807
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530808 // <Delete SEL Entry>
Pradeep Kumar00a18d02019-04-26 17:04:28 +0000809 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,
810 ipmi::storage::cmdDeleteSelEntry,
811 ipmi::Privilege::Operator, deleteSELEntry);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530812
Tom05732372016-09-06 17:21:23 +0530813 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700814 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
815 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530816 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530817 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
818 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500819 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500820 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700821 ipmi_storage_get_fru_inv_area_info,
822 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500823
824 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500825 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700826 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500827
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600828 // <Get Repository Info>
829 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700830 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600831
Tom Joseph5ca50952018-02-22 00:33:38 +0530832 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700833 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
834 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530835
836 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700837 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
838 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530839
Marri Devender Rao908f7502017-07-10 01:49:54 -0500840 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500841 return;
842}