blob: 72a0c086aea7d34d0759b3c033cdf26e817d1c55 [file] [log] [blame]
Lei YU52d91242017-10-17 22:52:28 +08001#include <arpa/inet.h>
Patrick Venture0b02be92018-08-31 11:55:55 -07002
3#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +08004#include <chrono>
5#include <cstdio>
Vernon Mauery185b9f82018-07-20 10:52:36 -07006#if __has_include(<filesystem>)
7#include <filesystem>
8#elif __has_include(<experimental/filesystem>)
Tom Josepha4953392017-06-30 19:09:47 +05309#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070010namespace std
11{
12// splice experimental::filesystem into std
13namespace filesystem = std::experimental::filesystem;
14} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070015#else
Patrick Venture0b02be92018-08-31 11:55:55 -070016#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070017#endif
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060018#include "fruread.hpp"
Lei YU52d91242017-10-17 22:52:28 +080019#include "read_fru_data.hpp"
20#include "selutility.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -070021#include "utils.hpp"
22
23#include <mapper.h>
24#include <systemd/sd-bus.h>
25
26#include <phosphor-logging/elog-errors.hpp>
27#include <phosphor-logging/log.hpp>
28#include <sdbusplus/server.hpp>
29#include <string>
30#include <xyz/openbmc_project/Common/error.hpp>
31
32#include "host-ipmid/ipmid-api.h"
33#include "sensorhandler.h"
Lei YU52d91242017-10-17 22:52:28 +080034#include "storageaddsel.h"
35#include "storagehandler.h"
Chris Austen41a4b312015-10-25 03:45:42 -050036
Chris Austenb4f5b922015-10-13 12:44:43 -050037void register_netfn_storage_functions() __attribute__((constructor));
38
Patrick Venture0b02be92018-08-31 11:55:55 -070039unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080040extern unsigned short g_sel_reserve;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060041extern const ipmi::sensor::IdInfoMap sensors;
42extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050043
Patrick Venture0b02be92018-08-31 11:55:55 -070044namespace
45{
Lei YUe8939392017-06-15 10:45:05 +080046constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
47constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
48constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
Patrick Venture0b02be92018-08-31 11:55:55 -070049constexpr auto PROPERTY_ELAPSED = "Elapsed";
Lei YUe8939392017-06-15 10:45:05 +080050
51const char* getTimeString(const uint64_t& usecSinceEpoch)
52{
53 using namespace std::chrono;
54 system_clock::time_point tp{microseconds(usecSinceEpoch)};
55 auto t = system_clock::to_time_t(tp);
56 return std::ctime(&t);
57}
Patrick Venture0b02be92018-08-31 11:55:55 -070058} // namespace
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053059
Tom Joseph6f7deaa2017-06-30 19:03:54 +053060namespace cache
61{
Patrick Venture0b02be92018-08-31 11:55:55 -070062/*
63 * This cache contains the object paths of the logging entries sorted in the
64 * order of the filename(numeric order). The cache is initialized by
65 * invoking readLoggingObjectPaths with the cache as the parameter. The
66 * cache is invoked in the execution of the Get SEL info and Delete SEL
67 * entry command. The Get SEL Info command is typically invoked before the
68 * Get SEL entry command, so the cache is utilized for responding to Get SEL
69 * entry command. The cache is invalidated by clearing after Delete SEL
70 * entry and Clear SEL command.
71 */
72ipmi::sel::ObjectPaths paths;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053073
Patrick Venture0b02be92018-08-31 11:55:55 -070074} // namespace cache
Tom Joseph6f7deaa2017-06-30 19:03:54 +053075
76using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070077 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053078using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050079using namespace ipmi::fru;
80
81/**
82 * @enum Device access mode
83 */
84enum class AccessMode
85{
86 bytes, ///< Device is accessed by bytes
87 words ///< Device is accessed by words
88};
89
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050090ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070091 ipmi_request_t request,
92 ipmi_response_t response,
93 ipmi_data_len_t data_len,
94 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050095{
Chris Austenb4f5b922015-10-13 12:44:43 -050096 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080097 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050098 *data_len = 0;
99 return rc;
100}
101
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530102ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
103 ipmi_request_t request, ipmi_response_t response,
104 ipmi_data_len_t data_len, ipmi_context_t context)
105{
106 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700107 auto responseData =
108 reinterpret_cast<ipmi::sel::GetSELInfoResponse*>(outPayload.data());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530109
110 responseData->selVersion = ipmi::sel::selVersion;
111 // Last erase timestamp is not available from log manager.
112 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
113 responseData->operationSupport = ipmi::sel::operationSupport;
114
115 ipmi::sel::readLoggingObjectPaths(cache::paths);
116 responseData->entries = 0;
117 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
118
119 if (!cache::paths.empty())
120 {
121 responseData->entries = static_cast<uint16_t>(cache::paths.size());
122
123 try
124 {
125 responseData->addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700126 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530127 }
128 catch (InternalFailure& e)
129 {
130 }
131 catch (const std::runtime_error& e)
132 {
133 log<level::ERR>(e.what());
134 }
135 }
136
137 memcpy(response, outPayload.data(), outPayload.size());
138 *data_len = outPayload.size();
139
140 return IPMI_CC_OK;
141}
142
Tom Josepha4953392017-06-30 19:09:47 +0530143ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
144 ipmi_request_t request, ipmi_response_t response,
145 ipmi_data_len_t data_len, ipmi_context_t context)
146{
Patrick Venture0b02be92018-08-31 11:55:55 -0700147 auto requestData =
148 reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>(request);
Tom Josepha4953392017-06-30 19:09:47 +0530149
150 if (requestData->reservationID != 0)
151 {
152 if (g_sel_reserve != requestData->reservationID)
153 {
154 *data_len = 0;
155 return IPMI_CC_INVALID_RESERVATION_ID;
156 }
157 }
158
159 if (cache::paths.empty())
160 {
161 *data_len = 0;
162 return IPMI_CC_SENSOR_INVALID;
163 }
164
165 ipmi::sel::ObjectPaths::const_iterator iter;
166
167 // Check for the requested SEL Entry.
168 if (requestData->selRecordID == ipmi::sel::firstEntry)
169 {
170 iter = cache::paths.begin();
171 }
172 else if (requestData->selRecordID == ipmi::sel::lastEntry)
173 {
174 iter = cache::paths.end();
175 }
176 else
177 {
178 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
179 std::to_string(requestData->selRecordID);
180
181 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
182 if (iter == cache::paths.end())
183 {
184 *data_len = 0;
185 return IPMI_CC_SENSOR_INVALID;
186 }
187 }
188
Patrick Venture0b02be92018-08-31 11:55:55 -0700189 ipmi::sel::GetSELEntryResponse record{};
Tom Josepha4953392017-06-30 19:09:47 +0530190
191 // Convert the log entry into SEL record.
192 try
193 {
194 record = ipmi::sel::convertLogEntrytoSEL(*iter);
195 }
196 catch (InternalFailure& e)
197 {
198 *data_len = 0;
199 return IPMI_CC_UNSPECIFIED_ERROR;
200 }
201 catch (const std::runtime_error& e)
202 {
203 log<level::ERR>(e.what());
204 *data_len = 0;
205 return IPMI_CC_UNSPECIFIED_ERROR;
206 }
207
Tom Josepha4953392017-06-30 19:09:47 +0530208 // Identify the next SEL record ID
Patrick Venture0b02be92018-08-31 11:55:55 -0700209 if (iter != cache::paths.end())
Tom Josepha4953392017-06-30 19:09:47 +0530210 {
211 ++iter;
212 if (iter == cache::paths.end())
213 {
214 record.nextRecordID = ipmi::sel::lastEntry;
215 }
216 else
217 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700218 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530219 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700220 record.nextRecordID = static_cast<uint16_t>(
221 std::stoul(std::string(path.filename().c_str())));
Tom Josepha4953392017-06-30 19:09:47 +0530222 }
223 }
224 else
225 {
226 record.nextRecordID = ipmi::sel::lastEntry;
227 }
228
229 if (requestData->readLength == ipmi::sel::entireRecord)
230 {
231 memcpy(response, &record, sizeof(record));
232 *data_len = sizeof(record);
233 }
234 else
235 {
236 if (requestData->offset >= ipmi::sel::selRecordSize ||
237 requestData->readLength > ipmi::sel::selRecordSize)
238 {
239 *data_len = 0;
240 return IPMI_CC_INVALID_FIELD_REQUEST;
241 }
242
243 auto diff = ipmi::sel::selRecordSize - requestData->offset;
Patrick Venture0b02be92018-08-31 11:55:55 -0700244 auto readLength =
245 std::min(diff, static_cast<int>(requestData->readLength));
Tom Josepha4953392017-06-30 19:09:47 +0530246
247 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
248 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
249 &record.recordID + requestData->offset, readLength);
250 *data_len = sizeof(record.nextRecordID) + readLength;
251 }
252
253 return IPMI_CC_OK;
254}
255
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530256ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
257 ipmi_request_t request, ipmi_response_t response,
258 ipmi_data_len_t data_len, ipmi_context_t context)
259{
260 namespace fs = std::experimental::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700261 auto requestData =
262 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530263
264 if (g_sel_reserve != requestData->reservationID)
265 {
266 *data_len = 0;
267 return IPMI_CC_INVALID_RESERVATION_ID;
268 }
269
270 ipmi::sel::readLoggingObjectPaths(cache::paths);
271
272 if (cache::paths.empty())
273 {
274 *data_len = 0;
275 return IPMI_CC_SENSOR_INVALID;
276 }
277
278 ipmi::sel::ObjectPaths::const_iterator iter;
279 uint16_t delRecordID = 0;
280
281 if (requestData->selRecordID == ipmi::sel::firstEntry)
282 {
283 iter = cache::paths.begin();
284 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700285 delRecordID = static_cast<uint16_t>(
286 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530287 }
288 else if (requestData->selRecordID == ipmi::sel::lastEntry)
289 {
290 iter = cache::paths.end();
291 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700292 delRecordID = static_cast<uint16_t>(
293 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530294 }
295 else
296 {
297 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
298 std::to_string(requestData->selRecordID);
299
300 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
301 if (iter == cache::paths.end())
302 {
303 *data_len = 0;
304 return IPMI_CC_SENSOR_INVALID;
305 }
306 delRecordID = requestData->selRecordID;
307 }
308
309 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
310 std::string service;
311
312 try
313 {
314 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
315 }
316 catch (const std::runtime_error& e)
317 {
318 log<level::ERR>(e.what());
319 *data_len = 0;
320 return IPMI_CC_UNSPECIFIED_ERROR;
321 }
322
Patrick Venture0b02be92018-08-31 11:55:55 -0700323 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
324 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530325 auto reply = bus.call(methodCall);
326 if (reply.is_method_error())
327 {
328 *data_len = 0;
329 return IPMI_CC_UNSPECIFIED_ERROR;
330 }
331
332 // Invalidate the cache of dbus entry objects.
333 cache::paths.clear();
334 memcpy(response, &delRecordID, sizeof(delRecordID));
335 *data_len = sizeof(delRecordID);
336
337 return IPMI_CC_OK;
338}
339
Tom Joseph2f05bb52017-06-30 19:14:49 +0530340ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
341 ipmi_response_t response, ipmi_data_len_t data_len,
342 ipmi_context_t context)
343{
Patrick Venture0b02be92018-08-31 11:55:55 -0700344 auto requestData =
345 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530346
347 if (g_sel_reserve != requestData->reservationID)
348 {
349 *data_len = 0;
350 return IPMI_CC_INVALID_RESERVATION_ID;
351 }
352
Patrick Venture0b02be92018-08-31 11:55:55 -0700353 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530354 requestData->charR != 'R')
355 {
356 *data_len = 0;
357 return IPMI_CC_INVALID_FIELD_REQUEST;
358 }
359
360 uint8_t eraseProgress = ipmi::sel::eraseComplete;
361
362 /*
363 * Erasure status cannot be fetched from DBUS, so always return erasure
364 * status as `erase completed`.
365 */
366 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
367 {
368 memcpy(response, &eraseProgress, sizeof(eraseProgress));
369 *data_len = sizeof(eraseProgress);
370 return IPMI_CC_OK;
371 }
372
373 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
374 auto depth = 0;
375
Patrick Venture0b02be92018-08-31 11:55:55 -0700376 auto mapperCall =
377 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
378 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530379 mapperCall.append(ipmi::sel::logBasePath);
380 mapperCall.append(depth);
381 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
382
383 auto reply = bus.call(mapperCall);
384 if (reply.is_method_error())
385 {
386 memcpy(response, &eraseProgress, sizeof(eraseProgress));
387 *data_len = sizeof(eraseProgress);
388 return IPMI_CC_OK;
389 }
390
391 ipmi::sel::ObjectPaths objectPaths;
392 reply.read(objectPaths);
393 if (objectPaths.empty())
394 {
395 memcpy(response, &eraseProgress, sizeof(eraseProgress));
396 *data_len = sizeof(eraseProgress);
397 return IPMI_CC_OK;
398 }
399
400 std::string service;
401
402 try
403 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700404 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530405 objectPaths.front());
406 }
407 catch (const std::runtime_error& e)
408 {
409 log<level::ERR>(e.what());
410 *data_len = 0;
411 return IPMI_CC_UNSPECIFIED_ERROR;
412 }
413
414 for (const auto& iter : objectPaths)
415 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700416 auto methodCall = bus.new_method_call(
417 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530418
419 auto reply = bus.call(methodCall);
420 if (reply.is_method_error())
421 {
422 *data_len = 0;
423 return IPMI_CC_UNSPECIFIED_ERROR;
424 }
425 }
426
427 // Invalidate the cache of dbus entry objects.
428 cache::paths.clear();
429 memcpy(response, &eraseProgress, sizeof(eraseProgress));
430 *data_len = sizeof(eraseProgress);
431 return IPMI_CC_OK;
432}
433
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500434ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700435 ipmi_request_t request,
436 ipmi_response_t response,
437 ipmi_data_len_t data_len,
438 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500439{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530440 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530441 uint64_t host_time_usec = 0;
442 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500443 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500444
Lei YUe8939392017-06-15 10:45:05 +0800445 try
446 {
447 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
448 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
449 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530450
Lei YUe8939392017-06-15 10:45:05 +0800451 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700452 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
453 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800454
455 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
456 auto reply = bus.call(method);
457 if (reply.is_method_error())
458 {
459 log<level::ERR>("Error getting time",
460 entry("SERVICE=%s", service.c_str()),
461 entry("PATH=%s", HOST_TIME_PATH));
462 return IPMI_CC_UNSPECIFIED_ERROR;
463 }
464 reply.read(value);
465 host_time_usec = value.get<uint64_t>();
466 }
467 catch (InternalFailure& e)
468 {
469 log<level::ERR>(e.what());
470 return IPMI_CC_UNSPECIFIED_ERROR;
471 }
472 catch (const std::runtime_error& e)
473 {
474 log<level::ERR>(e.what());
475 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530476 }
477
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500478 hostTime << "Host time:" << getTimeString(host_time_usec);
479 log<level::DEBUG>(hostTime.str().c_str());
480
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530481 // Time is really long int but IPMI wants just uint32. This works okay until
482 // the number of seconds since 1970 overflows uint32 size.. Still a whole
483 // lot of time here to even think about that.
484 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
485 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530486
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500487 // From the IPMI Spec 2.0, response should be a 32-bit value
488 *data_len = sizeof(resp);
489
490 // Pack the actual response
491 memcpy(response, &resp, *data_len);
492
Lei YUe8939392017-06-15 10:45:05 +0800493 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500494}
495
496ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700497 ipmi_request_t request,
498 ipmi_response_t response,
499 ipmi_data_len_t data_len,
500 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500501{
Lei YUe8939392017-06-15 10:45:05 +0800502 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530503 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800504 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530505 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500506
Lei YUe8939392017-06-15 10:45:05 +0800507 secs = le32toh(secs);
508 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600509
Lei YUe8939392017-06-15 10:45:05 +0800510 try
511 {
512 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
513 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
514 sdbusplus::message::variant<uint64_t> value{usec.count()};
515
516 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700517 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
518 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800519
520 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
521 auto reply = bus.call(method);
522 if (reply.is_method_error())
523 {
524 log<level::ERR>("Error setting time",
525 entry("SERVICE=%s", service.c_str()),
526 entry("PATH=%s", HOST_TIME_PATH));
527 rc = IPMI_CC_UNSPECIFIED_ERROR;
528 }
Norman James82330442015-11-19 16:53:26 -0600529 }
Lei YUe8939392017-06-15 10:45:05 +0800530 catch (InternalFailure& e)
531 {
532 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530533 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530534 }
Lei YUe8939392017-06-15 10:45:05 +0800535 catch (const std::runtime_error& e)
536 {
537 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600538 rc = IPMI_CC_UNSPECIFIED_ERROR;
539 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530540
Chris Austenb4f5b922015-10-13 12:44:43 -0500541 return rc;
542}
543
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500544ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700545 ipmi_request_t request,
546 ipmi_response_t response,
547 ipmi_data_len_t data_len,
548 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500549{
Chris Austenb4f5b922015-10-13 12:44:43 -0500550 ipmi_ret_t rc = IPMI_CC_OK;
551
Patrick Venture0b02be92018-08-31 11:55:55 -0700552 // IPMI spec, Reservation ID, the value simply increases against each
553 // execution of reserve_sel command.
554 if (++g_sel_reserve == 0)
Nan Li36c0cb62016-03-31 11:16:08 +0800555 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500556
557 *data_len = sizeof(g_sel_reserve);
558
559 // Pack the actual response
560 memcpy(response, &g_sel_reserve, *data_len);
561
562 return rc;
563}
564
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500565ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700566 ipmi_request_t request,
567 ipmi_response_t response,
568 ipmi_data_len_t data_len,
569 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500570{
571
572 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700573 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500574 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500575
Chris Austen313d95b2015-10-31 12:55:30 -0500576 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500577
Chris Austenb4f5b922015-10-13 12:44:43 -0500578 *data_len = sizeof(g_sel_reserve);
579
580 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600581 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500582
Tom Josephb647d5b2017-10-31 17:25:33 +0530583 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
584 // a maintenance procedure associated with eSEL record.
585 static constexpr auto procedureType = 0xDE;
586 if (p->recordtype == procedureType)
587 {
588 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
589 // procedure number.
590 createProcedureLogEntry(p->sensortype);
591 }
592 else
593 {
594 send_esel(recordid);
595 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500596
597 return rc;
598}
599
Patrick Venture0b02be92018-08-31 11:55:55 -0700600// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500601ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700602 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
603 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500604{
605 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500606 const FruInvenAreaInfoRequest* reqptr =
607 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530608
609 auto iter = frus.find(reqptr->fruID);
610 if (iter == frus.end())
611 {
612 *data_len = 0;
613 return IPMI_CC_SENSOR_INVALID;
614 }
615
Marri Devender Raocac383b2017-07-03 13:24:27 -0500616 try
617 {
618 const auto& fruArea = getFruAreaData(reqptr->fruID);
619 auto size = static_cast<uint16_t>(fruArea.size());
620 FruInvenAreaInfoResponse resp;
621 resp.sizems = size >> 8;
622 resp.sizels = size;
623 resp.access = static_cast<uint8_t>(AccessMode::bytes);
624
625 *data_len = sizeof(resp);
626
627 // Pack the actual response
628 memcpy(response, &resp, *data_len);
629 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700630 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500631 {
632 rc = IPMI_CC_UNSPECIFIED_ERROR;
633 *data_len = 0;
634 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500635 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500636 return rc;
637}
638
Patrick Venture0b02be92018-08-31 11:55:55 -0700639// Read FRU data
640ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
641 ipmi_request_t request,
642 ipmi_response_t response,
643 ipmi_data_len_t data_len,
644 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500645{
646 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500647 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500648 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700649 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530650
651 auto iter = frus.find(reqptr->fruID);
652 if (iter == frus.end())
653 {
654 *data_len = 0;
655 return IPMI_CC_SENSOR_INVALID;
656 }
657
Marri Devender Raocac383b2017-07-03 13:24:27 -0500658 auto offset =
659 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
660 try
661 {
662 const auto& fruArea = getFruAreaData(reqptr->fruID);
663 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500664
Tom Josephefcd68b2018-04-26 18:46:27 +0530665 if (offset >= size)
666 {
667 return IPMI_CC_PARM_OUT_OF_RANGE;
668 }
669
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500670 // Write the count of response data.
671 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500672 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500673 resptr->count = reqptr->count;
674 }
675 else
676 {
677 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500678 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530679
Ratan Gupta2848d602018-01-31 20:39:20 +0530680 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700681 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530682
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500683 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500684 }
685 catch (const InternalFailure& e)
686 {
687 rc = IPMI_CC_UNSPECIFIED_ERROR;
688 *data_len = 0;
689 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500690 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500691 return rc;
692}
693
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600694ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700695 ipmi_request_t request,
696 ipmi_response_t response,
697 ipmi_data_len_t data_len,
698 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600699{
700 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700701 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600702
Patrick Venture0b02be92018-08-31 11:55:55 -0700703 memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600704
705 responseData->sdrVersion = sdrVersion;
706
707 uint16_t records = frus.size() + sensors.size();
708 responseData->recordCountMs = records >> 8;
709 responseData->recordCountLs = records;
710
711 responseData->freeSpace[0] = 0xFF;
712 responseData->freeSpace[1] = 0xFF;
713
714 *data_len = sizeof(GetRepositoryInfoResponse);
715
716 return IPMI_CC_OK;
717}
Chris Austenb4f5b922015-10-13 12:44:43 -0500718
Chris Austenb4f5b922015-10-13 12:44:43 -0500719void register_netfn_storage_functions()
720{
Tom05732372016-09-06 17:21:23 +0530721 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700722 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
723 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500724
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530725 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700726 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
727 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530728
Tom05732372016-09-06 17:21:23 +0530729 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700730 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
731 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500732
Tom05732372016-09-06 17:21:23 +0530733 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700734 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
735 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500736
Tom05732372016-09-06 17:21:23 +0530737 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700738 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
739 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500740
Tom Josepha4953392017-06-30 19:09:47 +0530741 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700742 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
743 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530744
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530745 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700746 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
747 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530748
Tom05732372016-09-06 17:21:23 +0530749 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700750 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
751 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530752 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530753 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
754 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500755 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500756 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700757 ipmi_storage_get_fru_inv_area_info,
758 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500759
760 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500761 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700762 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500763
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600764 // <Get Repository Info>
765 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700766 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600767
Tom Joseph5ca50952018-02-22 00:33:38 +0530768 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700769 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
770 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530771
772 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700773 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
774 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530775
Marri Devender Rao908f7502017-07-10 01:49:54 -0500776 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500777 return;
778}