blob: 65497b25e9202a362404d1e7c925d7f21754dfd4 [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"
8#include "utils.hpp"
9
Lei YU52d91242017-10-17 22:52:28 +080010#include <arpa/inet.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -070011#include <host-ipmid/ipmid-api.h>
12#include <mapper.h>
13#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070014
15#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +080016#include <chrono>
17#include <cstdio>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070018#include <cstring>
Patrick Venture3a5071a2018-09-12 13:27:42 -070019#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/log.hpp>
21#include <sdbusplus/server.hpp>
22#include <string>
23#include <xyz/openbmc_project/Common/error.hpp>
24
Vernon Mauery185b9f82018-07-20 10:52:36 -070025#if __has_include(<filesystem>)
26#include <filesystem>
27#elif __has_include(<experimental/filesystem>)
Tom Josepha4953392017-06-30 19:09:47 +053028#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070029namespace std
30{
31// splice experimental::filesystem into std
32namespace filesystem = std::experimental::filesystem;
33} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070034#else
Patrick Venture0b02be92018-08-31 11:55:55 -070035#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070036#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070037
Chris Austenb4f5b922015-10-13 12:44:43 -050038void register_netfn_storage_functions() __attribute__((constructor));
39
Patrick Venture0b02be92018-08-31 11:55:55 -070040unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080041extern unsigned short g_sel_reserve;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060042extern const ipmi::sensor::IdInfoMap sensors;
43extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050044
Patrick Venture0b02be92018-08-31 11:55:55 -070045namespace
46{
Lei YUe8939392017-06-15 10:45:05 +080047constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
48constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
49constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
Patrick Venture0b02be92018-08-31 11:55:55 -070050constexpr auto PROPERTY_ELAPSED = "Elapsed";
Lei YUe8939392017-06-15 10:45:05 +080051
52const char* getTimeString(const uint64_t& usecSinceEpoch)
53{
54 using namespace std::chrono;
55 system_clock::time_point tp{microseconds(usecSinceEpoch)};
56 auto t = system_clock::to_time_t(tp);
57 return std::ctime(&t);
58}
Patrick Venture0b02be92018-08-31 11:55:55 -070059} // namespace
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053060
Tom Joseph6f7deaa2017-06-30 19:03:54 +053061namespace cache
62{
Patrick Venture0b02be92018-08-31 11:55:55 -070063/*
64 * This cache contains the object paths of the logging entries sorted in the
65 * order of the filename(numeric order). The cache is initialized by
66 * invoking readLoggingObjectPaths with the cache as the parameter. The
67 * cache is invoked in the execution of the Get SEL info and Delete SEL
68 * entry command. The Get SEL Info command is typically invoked before the
69 * Get SEL entry command, so the cache is utilized for responding to Get SEL
70 * entry command. The cache is invalidated by clearing after Delete SEL
71 * entry and Clear SEL command.
72 */
73ipmi::sel::ObjectPaths paths;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053074
Patrick Venture0b02be92018-08-31 11:55:55 -070075} // namespace cache
Tom Joseph6f7deaa2017-06-30 19:03:54 +053076
77using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070078 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053079using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050080using namespace ipmi::fru;
81
82/**
83 * @enum Device access mode
84 */
85enum class AccessMode
86{
87 bytes, ///< Device is accessed by bytes
88 words ///< Device is accessed by words
89};
90
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050091ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070092 ipmi_request_t request,
93 ipmi_response_t response,
94 ipmi_data_len_t data_len,
95 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050096{
Chris Austenb4f5b922015-10-13 12:44:43 -050097 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080098 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050099 *data_len = 0;
100 return rc;
101}
102
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530103ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
104 ipmi_request_t request, ipmi_response_t response,
105 ipmi_data_len_t data_len, ipmi_context_t context)
106{
107 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700108 auto responseData =
109 reinterpret_cast<ipmi::sel::GetSELInfoResponse*>(outPayload.data());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530110
111 responseData->selVersion = ipmi::sel::selVersion;
112 // Last erase timestamp is not available from log manager.
113 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
114 responseData->operationSupport = ipmi::sel::operationSupport;
115
Tom Josephe59abfb2018-08-06 18:46:27 +0530116 try
117 {
118 ipmi::sel::readLoggingObjectPaths(cache::paths);
119 }
120 catch (const sdbusplus::exception::SdBusError& e)
121 {
122 // No action if reading log objects have failed for this command.
123 // readLoggingObjectPaths will throw exception if there are no log
124 // entries. The command will be responded with number of SEL entries
125 // as 0.
126 }
127
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530128 responseData->entries = 0;
129 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
130
131 if (!cache::paths.empty())
132 {
133 responseData->entries = static_cast<uint16_t>(cache::paths.size());
134
135 try
136 {
137 responseData->addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700138 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530139 }
140 catch (InternalFailure& e)
141 {
142 }
143 catch (const std::runtime_error& e)
144 {
145 log<level::ERR>(e.what());
146 }
147 }
148
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700149 std::memcpy(response, outPayload.data(), outPayload.size());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530150 *data_len = outPayload.size();
151
152 return IPMI_CC_OK;
153}
154
Tom Josepha4953392017-06-30 19:09:47 +0530155ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
156 ipmi_request_t request, ipmi_response_t response,
157 ipmi_data_len_t data_len, ipmi_context_t context)
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 {
164 if (g_sel_reserve != requestData->reservationID)
165 {
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
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530270ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
271 ipmi_request_t request, ipmi_response_t response,
272 ipmi_data_len_t data_len, ipmi_context_t context)
273{
274 namespace fs = std::experimental::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700275 auto requestData =
276 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530277
278 if (g_sel_reserve != requestData->reservationID)
279 {
280 *data_len = 0;
281 return IPMI_CC_INVALID_RESERVATION_ID;
282 }
283
Tom Josephe59abfb2018-08-06 18:46:27 +0530284 try
285 {
286 ipmi::sel::readLoggingObjectPaths(cache::paths);
287 }
288 catch (const sdbusplus::exception::SdBusError& e)
289 {
290 // readLoggingObjectPaths will throw exception if there are no error
291 // log entries.
292 *data_len = 0;
293 return IPMI_CC_SENSOR_INVALID;
294 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530295
296 if (cache::paths.empty())
297 {
298 *data_len = 0;
299 return IPMI_CC_SENSOR_INVALID;
300 }
301
302 ipmi::sel::ObjectPaths::const_iterator iter;
303 uint16_t delRecordID = 0;
304
305 if (requestData->selRecordID == ipmi::sel::firstEntry)
306 {
307 iter = cache::paths.begin();
308 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700309 delRecordID = static_cast<uint16_t>(
310 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530311 }
312 else if (requestData->selRecordID == ipmi::sel::lastEntry)
313 {
314 iter = cache::paths.end();
315 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700316 delRecordID = static_cast<uint16_t>(
317 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530318 }
319 else
320 {
321 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
322 std::to_string(requestData->selRecordID);
323
324 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
325 if (iter == cache::paths.end())
326 {
327 *data_len = 0;
328 return IPMI_CC_SENSOR_INVALID;
329 }
330 delRecordID = requestData->selRecordID;
331 }
332
333 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
334 std::string service;
335
336 try
337 {
338 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
339 }
340 catch (const std::runtime_error& e)
341 {
342 log<level::ERR>(e.what());
343 *data_len = 0;
344 return IPMI_CC_UNSPECIFIED_ERROR;
345 }
346
Patrick Venture0b02be92018-08-31 11:55:55 -0700347 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
348 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530349 auto reply = bus.call(methodCall);
350 if (reply.is_method_error())
351 {
352 *data_len = 0;
353 return IPMI_CC_UNSPECIFIED_ERROR;
354 }
355
356 // Invalidate the cache of dbus entry objects.
357 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700358 std::memcpy(response, &delRecordID, sizeof(delRecordID));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530359 *data_len = sizeof(delRecordID);
360
361 return IPMI_CC_OK;
362}
363
Tom Joseph2f05bb52017-06-30 19:14:49 +0530364ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
365 ipmi_response_t response, ipmi_data_len_t data_len,
366 ipmi_context_t context)
367{
Patrick Venture0b02be92018-08-31 11:55:55 -0700368 auto requestData =
369 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530370
371 if (g_sel_reserve != requestData->reservationID)
372 {
373 *data_len = 0;
374 return IPMI_CC_INVALID_RESERVATION_ID;
375 }
376
Patrick Venture0b02be92018-08-31 11:55:55 -0700377 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530378 requestData->charR != 'R')
379 {
380 *data_len = 0;
381 return IPMI_CC_INVALID_FIELD_REQUEST;
382 }
383
384 uint8_t eraseProgress = ipmi::sel::eraseComplete;
385
386 /*
387 * Erasure status cannot be fetched from DBUS, so always return erasure
388 * status as `erase completed`.
389 */
390 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
391 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700392 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530393 *data_len = sizeof(eraseProgress);
394 return IPMI_CC_OK;
395 }
396
397 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530398 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530399 auto depth = 0;
400
Patrick Venture0b02be92018-08-31 11:55:55 -0700401 auto mapperCall =
402 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
403 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530404 mapperCall.append(ipmi::sel::logBasePath);
405 mapperCall.append(depth);
406 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
407
Tom Josephe59abfb2018-08-06 18:46:27 +0530408 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530409 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530410 auto reply = bus.call(mapperCall);
411 if (reply.is_method_error())
412 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700413 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530414 *data_len = sizeof(eraseProgress);
415 return IPMI_CC_OK;
416 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530417
Tom Josephe59abfb2018-08-06 18:46:27 +0530418 reply.read(objectPaths);
419 if (objectPaths.empty())
420 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700421 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530422 *data_len = sizeof(eraseProgress);
423 return IPMI_CC_OK;
424 }
425 }
426 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530427 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700428 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530429 *data_len = sizeof(eraseProgress);
430 return IPMI_CC_OK;
431 }
432
433 std::string service;
434
435 try
436 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700437 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530438 objectPaths.front());
439 }
440 catch (const std::runtime_error& e)
441 {
442 log<level::ERR>(e.what());
443 *data_len = 0;
444 return IPMI_CC_UNSPECIFIED_ERROR;
445 }
446
447 for (const auto& iter : objectPaths)
448 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700449 auto methodCall = bus.new_method_call(
450 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530451
452 auto reply = bus.call(methodCall);
453 if (reply.is_method_error())
454 {
455 *data_len = 0;
456 return IPMI_CC_UNSPECIFIED_ERROR;
457 }
458 }
459
460 // Invalidate the cache of dbus entry objects.
461 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700462 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530463 *data_len = sizeof(eraseProgress);
464 return IPMI_CC_OK;
465}
466
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500467ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700468 ipmi_request_t request,
469 ipmi_response_t response,
470 ipmi_data_len_t data_len,
471 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500472{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530473 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530474 uint64_t host_time_usec = 0;
475 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500476 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500477
Lei YUe8939392017-06-15 10:45:05 +0800478 try
479 {
480 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
481 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
482 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530483
Lei YUe8939392017-06-15 10:45:05 +0800484 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700485 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
486 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800487
488 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
489 auto reply = bus.call(method);
490 if (reply.is_method_error())
491 {
492 log<level::ERR>("Error getting time",
493 entry("SERVICE=%s", service.c_str()),
494 entry("PATH=%s", HOST_TIME_PATH));
495 return IPMI_CC_UNSPECIFIED_ERROR;
496 }
497 reply.read(value);
498 host_time_usec = value.get<uint64_t>();
499 }
500 catch (InternalFailure& e)
501 {
502 log<level::ERR>(e.what());
503 return IPMI_CC_UNSPECIFIED_ERROR;
504 }
505 catch (const std::runtime_error& e)
506 {
507 log<level::ERR>(e.what());
508 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530509 }
510
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500511 hostTime << "Host time:" << getTimeString(host_time_usec);
512 log<level::DEBUG>(hostTime.str().c_str());
513
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530514 // Time is really long int but IPMI wants just uint32. This works okay until
515 // the number of seconds since 1970 overflows uint32 size.. Still a whole
516 // lot of time here to even think about that.
517 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
518 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530519
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500520 // From the IPMI Spec 2.0, response should be a 32-bit value
521 *data_len = sizeof(resp);
522
523 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700524 std::memcpy(response, &resp, *data_len);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500525
Lei YUe8939392017-06-15 10:45:05 +0800526 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500527}
528
529ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700530 ipmi_request_t request,
531 ipmi_response_t response,
532 ipmi_data_len_t data_len,
533 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500534{
Lei YUe8939392017-06-15 10:45:05 +0800535 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530536 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800537 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530538 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500539
Lei YUe8939392017-06-15 10:45:05 +0800540 secs = le32toh(secs);
541 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600542
Lei YUe8939392017-06-15 10:45:05 +0800543 try
544 {
545 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
546 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
547 sdbusplus::message::variant<uint64_t> value{usec.count()};
548
549 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700550 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
551 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800552
553 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
554 auto reply = bus.call(method);
555 if (reply.is_method_error())
556 {
557 log<level::ERR>("Error setting time",
558 entry("SERVICE=%s", service.c_str()),
559 entry("PATH=%s", HOST_TIME_PATH));
560 rc = IPMI_CC_UNSPECIFIED_ERROR;
561 }
Norman James82330442015-11-19 16:53:26 -0600562 }
Lei YUe8939392017-06-15 10:45:05 +0800563 catch (InternalFailure& e)
564 {
565 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530566 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530567 }
Lei YUe8939392017-06-15 10:45:05 +0800568 catch (const std::runtime_error& e)
569 {
570 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600571 rc = IPMI_CC_UNSPECIFIED_ERROR;
572 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530573
Chris Austenb4f5b922015-10-13 12:44:43 -0500574 return rc;
575}
576
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500577ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700578 ipmi_request_t request,
579 ipmi_response_t response,
580 ipmi_data_len_t data_len,
581 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500582{
Chris Austenb4f5b922015-10-13 12:44:43 -0500583 ipmi_ret_t rc = IPMI_CC_OK;
584
Patrick Venture0b02be92018-08-31 11:55:55 -0700585 // IPMI spec, Reservation ID, the value simply increases against each
586 // execution of reserve_sel command.
587 if (++g_sel_reserve == 0)
Nan Li36c0cb62016-03-31 11:16:08 +0800588 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500589
590 *data_len = sizeof(g_sel_reserve);
591
592 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700593 std::memcpy(response, &g_sel_reserve, *data_len);
Chris Austenb4f5b922015-10-13 12:44:43 -0500594
595 return rc;
596}
597
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500598ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700599 ipmi_request_t request,
600 ipmi_response_t response,
601 ipmi_data_len_t data_len,
602 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500603{
604
605 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700606 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500607 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500608
Chris Austen313d95b2015-10-31 12:55:30 -0500609 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500610
Chris Austenb4f5b922015-10-13 12:44:43 -0500611 *data_len = sizeof(g_sel_reserve);
612
613 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700614 std::memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500615
Tom Josephb647d5b2017-10-31 17:25:33 +0530616 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
617 // a maintenance procedure associated with eSEL record.
618 static constexpr auto procedureType = 0xDE;
619 if (p->recordtype == procedureType)
620 {
621 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
622 // procedure number.
623 createProcedureLogEntry(p->sensortype);
624 }
625 else
626 {
627 send_esel(recordid);
628 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500629
630 return rc;
631}
632
Patrick Venture0b02be92018-08-31 11:55:55 -0700633// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500634ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700635 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
636 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500637{
638 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500639 const FruInvenAreaInfoRequest* reqptr =
640 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530641
642 auto iter = frus.find(reqptr->fruID);
643 if (iter == frus.end())
644 {
645 *data_len = 0;
646 return IPMI_CC_SENSOR_INVALID;
647 }
648
Marri Devender Raocac383b2017-07-03 13:24:27 -0500649 try
650 {
651 const auto& fruArea = getFruAreaData(reqptr->fruID);
652 auto size = static_cast<uint16_t>(fruArea.size());
653 FruInvenAreaInfoResponse resp;
654 resp.sizems = size >> 8;
655 resp.sizels = size;
656 resp.access = static_cast<uint8_t>(AccessMode::bytes);
657
658 *data_len = sizeof(resp);
659
660 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700661 std::memcpy(response, &resp, *data_len);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500662 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700663 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500664 {
665 rc = IPMI_CC_UNSPECIFIED_ERROR;
666 *data_len = 0;
667 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500668 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500669 return rc;
670}
671
Patrick Venture0b02be92018-08-31 11:55:55 -0700672// Read FRU data
673ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
674 ipmi_request_t request,
675 ipmi_response_t response,
676 ipmi_data_len_t data_len,
677 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500678{
679 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500680 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500681 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700682 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530683
684 auto iter = frus.find(reqptr->fruID);
685 if (iter == frus.end())
686 {
687 *data_len = 0;
688 return IPMI_CC_SENSOR_INVALID;
689 }
690
Marri Devender Raocac383b2017-07-03 13:24:27 -0500691 auto offset =
692 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
693 try
694 {
695 const auto& fruArea = getFruAreaData(reqptr->fruID);
696 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500697
Tom Josephefcd68b2018-04-26 18:46:27 +0530698 if (offset >= size)
699 {
700 return IPMI_CC_PARM_OUT_OF_RANGE;
701 }
702
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500703 // Write the count of response data.
704 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500705 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500706 resptr->count = reqptr->count;
707 }
708 else
709 {
710 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500711 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530712
Ratan Gupta2848d602018-01-31 20:39:20 +0530713 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700714 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530715
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500716 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500717 }
718 catch (const InternalFailure& e)
719 {
720 rc = IPMI_CC_UNSPECIFIED_ERROR;
721 *data_len = 0;
722 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500723 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500724 return rc;
725}
726
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600727ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700728 ipmi_request_t request,
729 ipmi_response_t response,
730 ipmi_data_len_t data_len,
731 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600732{
733 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700734 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600735
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700736 std::memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600737
738 responseData->sdrVersion = sdrVersion;
739
740 uint16_t records = frus.size() + sensors.size();
741 responseData->recordCountMs = records >> 8;
742 responseData->recordCountLs = records;
743
744 responseData->freeSpace[0] = 0xFF;
745 responseData->freeSpace[1] = 0xFF;
746
747 *data_len = sizeof(GetRepositoryInfoResponse);
748
749 return IPMI_CC_OK;
750}
Chris Austenb4f5b922015-10-13 12:44:43 -0500751
Chris Austenb4f5b922015-10-13 12:44:43 -0500752void register_netfn_storage_functions()
753{
Tom05732372016-09-06 17:21:23 +0530754 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700755 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
756 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500757
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530758 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700759 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
760 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530761
Tom05732372016-09-06 17:21:23 +0530762 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700763 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
764 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500765
Tom05732372016-09-06 17:21:23 +0530766 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700767 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
768 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500769
Tom05732372016-09-06 17:21:23 +0530770 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700771 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
772 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500773
Tom Josepha4953392017-06-30 19:09:47 +0530774 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700775 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
776 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530777
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530778 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700779 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
780 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530781
Tom05732372016-09-06 17:21:23 +0530782 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700783 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
784 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530785 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530786 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
787 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500788 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500789 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700790 ipmi_storage_get_fru_inv_area_info,
791 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500792
793 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500794 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700795 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500796
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600797 // <Get Repository Info>
798 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700799 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600800
Tom Joseph5ca50952018-02-22 00:33:38 +0530801 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700802 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
803 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530804
805 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700806 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
807 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530808
Marri Devender Rao908f7502017-07-10 01:49:54 -0500809 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500810 return;
811}