blob: 24c9d30e16e7c3e77bc4abdb221075aced5eec2d [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 Venture46470a32018-09-07 19:26:25 -070021#include "sensorhandler.hpp"
22#include "storageaddsel.hpp"
23#include "storagehandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -070024#include "utils.hpp"
25
Patrick Venture46470a32018-09-07 19:26:25 -070026#include <host-ipmid/ipmid-api.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070027#include <mapper.h>
28#include <systemd/sd-bus.h>
29
30#include <phosphor-logging/elog-errors.hpp>
31#include <phosphor-logging/log.hpp>
32#include <sdbusplus/server.hpp>
33#include <string>
34#include <xyz/openbmc_project/Common/error.hpp>
35
Chris Austenb4f5b922015-10-13 12:44:43 -050036void register_netfn_storage_functions() __attribute__((constructor));
37
Patrick Venture0b02be92018-08-31 11:55:55 -070038unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080039extern unsigned short g_sel_reserve;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060040extern const ipmi::sensor::IdInfoMap sensors;
41extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050042
Patrick Venture0b02be92018-08-31 11:55:55 -070043namespace
44{
Lei YUe8939392017-06-15 10:45:05 +080045constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
46constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
47constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
Patrick Venture0b02be92018-08-31 11:55:55 -070048constexpr auto PROPERTY_ELAPSED = "Elapsed";
Lei YUe8939392017-06-15 10:45:05 +080049
50const char* getTimeString(const uint64_t& usecSinceEpoch)
51{
52 using namespace std::chrono;
53 system_clock::time_point tp{microseconds(usecSinceEpoch)};
54 auto t = system_clock::to_time_t(tp);
55 return std::ctime(&t);
56}
Patrick Venture0b02be92018-08-31 11:55:55 -070057} // namespace
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053058
Tom Joseph6f7deaa2017-06-30 19:03:54 +053059namespace cache
60{
Patrick Venture0b02be92018-08-31 11:55:55 -070061/*
62 * This cache contains the object paths of the logging entries sorted in the
63 * order of the filename(numeric order). The cache is initialized by
64 * invoking readLoggingObjectPaths with the cache as the parameter. The
65 * cache is invoked in the execution of the Get SEL info and Delete SEL
66 * entry command. The Get SEL Info command is typically invoked before the
67 * Get SEL entry command, so the cache is utilized for responding to Get SEL
68 * entry command. The cache is invalidated by clearing after Delete SEL
69 * entry and Clear SEL command.
70 */
71ipmi::sel::ObjectPaths paths;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053072
Patrick Venture0b02be92018-08-31 11:55:55 -070073} // namespace cache
Tom Joseph6f7deaa2017-06-30 19:03:54 +053074
75using InternalFailure =
Patrick Venture0b02be92018-08-31 11:55:55 -070076 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Tom Joseph6f7deaa2017-06-30 19:03:54 +053077using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050078using namespace ipmi::fru;
79
80/**
81 * @enum Device access mode
82 */
83enum class AccessMode
84{
85 bytes, ///< Device is accessed by bytes
86 words ///< Device is accessed by words
87};
88
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050089ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -070090 ipmi_request_t request,
91 ipmi_response_t response,
92 ipmi_data_len_t data_len,
93 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -050094{
Chris Austenb4f5b922015-10-13 12:44:43 -050095 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080096 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050097 *data_len = 0;
98 return rc;
99}
100
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530101ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
102 ipmi_request_t request, ipmi_response_t response,
103 ipmi_data_len_t data_len, ipmi_context_t context)
104{
105 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700106 auto responseData =
107 reinterpret_cast<ipmi::sel::GetSELInfoResponse*>(outPayload.data());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530108
109 responseData->selVersion = ipmi::sel::selVersion;
110 // Last erase timestamp is not available from log manager.
111 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
112 responseData->operationSupport = ipmi::sel::operationSupport;
113
Tom Josephe59abfb2018-08-06 18:46:27 +0530114 try
115 {
116 ipmi::sel::readLoggingObjectPaths(cache::paths);
117 }
118 catch (const sdbusplus::exception::SdBusError& e)
119 {
120 // No action if reading log objects have failed for this command.
121 // readLoggingObjectPaths will throw exception if there are no log
122 // entries. The command will be responded with number of SEL entries
123 // as 0.
124 }
125
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530126 responseData->entries = 0;
127 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
128
129 if (!cache::paths.empty())
130 {
131 responseData->entries = static_cast<uint16_t>(cache::paths.size());
132
133 try
134 {
135 responseData->addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700136 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530137 }
138 catch (InternalFailure& e)
139 {
140 }
141 catch (const std::runtime_error& e)
142 {
143 log<level::ERR>(e.what());
144 }
145 }
146
147 memcpy(response, outPayload.data(), outPayload.size());
148 *data_len = outPayload.size();
149
150 return IPMI_CC_OK;
151}
152
Tom Josepha4953392017-06-30 19:09:47 +0530153ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
154 ipmi_request_t request, ipmi_response_t response,
155 ipmi_data_len_t data_len, ipmi_context_t context)
156{
Patrick Venture0b02be92018-08-31 11:55:55 -0700157 auto requestData =
158 reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>(request);
Tom Josepha4953392017-06-30 19:09:47 +0530159
160 if (requestData->reservationID != 0)
161 {
162 if (g_sel_reserve != requestData->reservationID)
163 {
164 *data_len = 0;
165 return IPMI_CC_INVALID_RESERVATION_ID;
166 }
167 }
168
169 if (cache::paths.empty())
170 {
171 *data_len = 0;
172 return IPMI_CC_SENSOR_INVALID;
173 }
174
175 ipmi::sel::ObjectPaths::const_iterator iter;
176
177 // Check for the requested SEL Entry.
178 if (requestData->selRecordID == ipmi::sel::firstEntry)
179 {
180 iter = cache::paths.begin();
181 }
182 else if (requestData->selRecordID == ipmi::sel::lastEntry)
183 {
184 iter = cache::paths.end();
185 }
186 else
187 {
188 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
189 std::to_string(requestData->selRecordID);
190
191 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
192 if (iter == cache::paths.end())
193 {
194 *data_len = 0;
195 return IPMI_CC_SENSOR_INVALID;
196 }
197 }
198
Patrick Venture0b02be92018-08-31 11:55:55 -0700199 ipmi::sel::GetSELEntryResponse record{};
Tom Josepha4953392017-06-30 19:09:47 +0530200
201 // Convert the log entry into SEL record.
202 try
203 {
204 record = ipmi::sel::convertLogEntrytoSEL(*iter);
205 }
206 catch (InternalFailure& e)
207 {
208 *data_len = 0;
209 return IPMI_CC_UNSPECIFIED_ERROR;
210 }
211 catch (const std::runtime_error& e)
212 {
213 log<level::ERR>(e.what());
214 *data_len = 0;
215 return IPMI_CC_UNSPECIFIED_ERROR;
216 }
217
Tom Josepha4953392017-06-30 19:09:47 +0530218 // Identify the next SEL record ID
Patrick Venture0b02be92018-08-31 11:55:55 -0700219 if (iter != cache::paths.end())
Tom Josepha4953392017-06-30 19:09:47 +0530220 {
221 ++iter;
222 if (iter == cache::paths.end())
223 {
224 record.nextRecordID = ipmi::sel::lastEntry;
225 }
226 else
227 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700228 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530229 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700230 record.nextRecordID = static_cast<uint16_t>(
231 std::stoul(std::string(path.filename().c_str())));
Tom Josepha4953392017-06-30 19:09:47 +0530232 }
233 }
234 else
235 {
236 record.nextRecordID = ipmi::sel::lastEntry;
237 }
238
239 if (requestData->readLength == ipmi::sel::entireRecord)
240 {
241 memcpy(response, &record, sizeof(record));
242 *data_len = sizeof(record);
243 }
244 else
245 {
246 if (requestData->offset >= ipmi::sel::selRecordSize ||
247 requestData->readLength > ipmi::sel::selRecordSize)
248 {
249 *data_len = 0;
250 return IPMI_CC_INVALID_FIELD_REQUEST;
251 }
252
253 auto diff = ipmi::sel::selRecordSize - requestData->offset;
Patrick Venture0b02be92018-08-31 11:55:55 -0700254 auto readLength =
255 std::min(diff, static_cast<int>(requestData->readLength));
Tom Josepha4953392017-06-30 19:09:47 +0530256
257 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
258 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
259 &record.recordID + requestData->offset, readLength);
260 *data_len = sizeof(record.nextRecordID) + readLength;
261 }
262
263 return IPMI_CC_OK;
264}
265
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530266ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
267 ipmi_request_t request, ipmi_response_t response,
268 ipmi_data_len_t data_len, ipmi_context_t context)
269{
270 namespace fs = std::experimental::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700271 auto requestData =
272 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530273
274 if (g_sel_reserve != requestData->reservationID)
275 {
276 *data_len = 0;
277 return IPMI_CC_INVALID_RESERVATION_ID;
278 }
279
Tom Josephe59abfb2018-08-06 18:46:27 +0530280 try
281 {
282 ipmi::sel::readLoggingObjectPaths(cache::paths);
283 }
284 catch (const sdbusplus::exception::SdBusError& e)
285 {
286 // readLoggingObjectPaths will throw exception if there are no error
287 // log entries.
288 *data_len = 0;
289 return IPMI_CC_SENSOR_INVALID;
290 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530291
292 if (cache::paths.empty())
293 {
294 *data_len = 0;
295 return IPMI_CC_SENSOR_INVALID;
296 }
297
298 ipmi::sel::ObjectPaths::const_iterator iter;
299 uint16_t delRecordID = 0;
300
301 if (requestData->selRecordID == ipmi::sel::firstEntry)
302 {
303 iter = cache::paths.begin();
304 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700305 delRecordID = static_cast<uint16_t>(
306 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530307 }
308 else if (requestData->selRecordID == ipmi::sel::lastEntry)
309 {
310 iter = cache::paths.end();
311 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700312 delRecordID = static_cast<uint16_t>(
313 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530314 }
315 else
316 {
317 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
318 std::to_string(requestData->selRecordID);
319
320 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
321 if (iter == cache::paths.end())
322 {
323 *data_len = 0;
324 return IPMI_CC_SENSOR_INVALID;
325 }
326 delRecordID = requestData->selRecordID;
327 }
328
329 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
330 std::string service;
331
332 try
333 {
334 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
335 }
336 catch (const std::runtime_error& e)
337 {
338 log<level::ERR>(e.what());
339 *data_len = 0;
340 return IPMI_CC_UNSPECIFIED_ERROR;
341 }
342
Patrick Venture0b02be92018-08-31 11:55:55 -0700343 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
344 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530345 auto reply = bus.call(methodCall);
346 if (reply.is_method_error())
347 {
348 *data_len = 0;
349 return IPMI_CC_UNSPECIFIED_ERROR;
350 }
351
352 // Invalidate the cache of dbus entry objects.
353 cache::paths.clear();
354 memcpy(response, &delRecordID, sizeof(delRecordID));
355 *data_len = sizeof(delRecordID);
356
357 return IPMI_CC_OK;
358}
359
Tom Joseph2f05bb52017-06-30 19:14:49 +0530360ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
361 ipmi_response_t response, ipmi_data_len_t data_len,
362 ipmi_context_t context)
363{
Patrick Venture0b02be92018-08-31 11:55:55 -0700364 auto requestData =
365 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530366
367 if (g_sel_reserve != requestData->reservationID)
368 {
369 *data_len = 0;
370 return IPMI_CC_INVALID_RESERVATION_ID;
371 }
372
Patrick Venture0b02be92018-08-31 11:55:55 -0700373 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530374 requestData->charR != 'R')
375 {
376 *data_len = 0;
377 return IPMI_CC_INVALID_FIELD_REQUEST;
378 }
379
380 uint8_t eraseProgress = ipmi::sel::eraseComplete;
381
382 /*
383 * Erasure status cannot be fetched from DBUS, so always return erasure
384 * status as `erase completed`.
385 */
386 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
387 {
388 memcpy(response, &eraseProgress, sizeof(eraseProgress));
389 *data_len = sizeof(eraseProgress);
390 return IPMI_CC_OK;
391 }
392
393 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530394 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530395 auto depth = 0;
396
Patrick Venture0b02be92018-08-31 11:55:55 -0700397 auto mapperCall =
398 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
399 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530400 mapperCall.append(ipmi::sel::logBasePath);
401 mapperCall.append(depth);
402 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
403
Tom Josephe59abfb2018-08-06 18:46:27 +0530404 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530405 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530406 auto reply = bus.call(mapperCall);
407 if (reply.is_method_error())
408 {
409 memcpy(response, &eraseProgress, sizeof(eraseProgress));
410 *data_len = sizeof(eraseProgress);
411 return IPMI_CC_OK;
412 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530413
Tom Josephe59abfb2018-08-06 18:46:27 +0530414 reply.read(objectPaths);
415 if (objectPaths.empty())
416 {
417 memcpy(response, &eraseProgress, sizeof(eraseProgress));
418 *data_len = sizeof(eraseProgress);
419 return IPMI_CC_OK;
420 }
421 }
422 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530423 {
424 memcpy(response, &eraseProgress, sizeof(eraseProgress));
425 *data_len = sizeof(eraseProgress);
426 return IPMI_CC_OK;
427 }
428
429 std::string service;
430
431 try
432 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700433 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530434 objectPaths.front());
435 }
436 catch (const std::runtime_error& e)
437 {
438 log<level::ERR>(e.what());
439 *data_len = 0;
440 return IPMI_CC_UNSPECIFIED_ERROR;
441 }
442
443 for (const auto& iter : objectPaths)
444 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700445 auto methodCall = bus.new_method_call(
446 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530447
448 auto reply = bus.call(methodCall);
449 if (reply.is_method_error())
450 {
451 *data_len = 0;
452 return IPMI_CC_UNSPECIFIED_ERROR;
453 }
454 }
455
456 // Invalidate the cache of dbus entry objects.
457 cache::paths.clear();
458 memcpy(response, &eraseProgress, sizeof(eraseProgress));
459 *data_len = sizeof(eraseProgress);
460 return IPMI_CC_OK;
461}
462
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500463ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700464 ipmi_request_t request,
465 ipmi_response_t response,
466 ipmi_data_len_t data_len,
467 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500468{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530469 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530470 uint64_t host_time_usec = 0;
471 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500472 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500473
Lei YUe8939392017-06-15 10:45:05 +0800474 try
475 {
476 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
477 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
478 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530479
Lei YUe8939392017-06-15 10:45:05 +0800480 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700481 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
482 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800483
484 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
485 auto reply = bus.call(method);
486 if (reply.is_method_error())
487 {
488 log<level::ERR>("Error getting time",
489 entry("SERVICE=%s", service.c_str()),
490 entry("PATH=%s", HOST_TIME_PATH));
491 return IPMI_CC_UNSPECIFIED_ERROR;
492 }
493 reply.read(value);
494 host_time_usec = value.get<uint64_t>();
495 }
496 catch (InternalFailure& e)
497 {
498 log<level::ERR>(e.what());
499 return IPMI_CC_UNSPECIFIED_ERROR;
500 }
501 catch (const std::runtime_error& e)
502 {
503 log<level::ERR>(e.what());
504 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530505 }
506
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500507 hostTime << "Host time:" << getTimeString(host_time_usec);
508 log<level::DEBUG>(hostTime.str().c_str());
509
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530510 // Time is really long int but IPMI wants just uint32. This works okay until
511 // the number of seconds since 1970 overflows uint32 size.. Still a whole
512 // lot of time here to even think about that.
513 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
514 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530515
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500516 // From the IPMI Spec 2.0, response should be a 32-bit value
517 *data_len = sizeof(resp);
518
519 // Pack the actual response
520 memcpy(response, &resp, *data_len);
521
Lei YUe8939392017-06-15 10:45:05 +0800522 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500523}
524
525ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700526 ipmi_request_t request,
527 ipmi_response_t response,
528 ipmi_data_len_t data_len,
529 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500530{
Lei YUe8939392017-06-15 10:45:05 +0800531 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530532 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800533 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530534 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500535
Lei YUe8939392017-06-15 10:45:05 +0800536 secs = le32toh(secs);
537 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600538
Lei YUe8939392017-06-15 10:45:05 +0800539 try
540 {
541 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
542 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
543 sdbusplus::message::variant<uint64_t> value{usec.count()};
544
545 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700546 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
547 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800548
549 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
550 auto reply = bus.call(method);
551 if (reply.is_method_error())
552 {
553 log<level::ERR>("Error setting time",
554 entry("SERVICE=%s", service.c_str()),
555 entry("PATH=%s", HOST_TIME_PATH));
556 rc = IPMI_CC_UNSPECIFIED_ERROR;
557 }
Norman James82330442015-11-19 16:53:26 -0600558 }
Lei YUe8939392017-06-15 10:45:05 +0800559 catch (InternalFailure& e)
560 {
561 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530562 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530563 }
Lei YUe8939392017-06-15 10:45:05 +0800564 catch (const std::runtime_error& e)
565 {
566 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600567 rc = IPMI_CC_UNSPECIFIED_ERROR;
568 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530569
Chris Austenb4f5b922015-10-13 12:44:43 -0500570 return rc;
571}
572
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500573ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700574 ipmi_request_t request,
575 ipmi_response_t response,
576 ipmi_data_len_t data_len,
577 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500578{
Chris Austenb4f5b922015-10-13 12:44:43 -0500579 ipmi_ret_t rc = IPMI_CC_OK;
580
Patrick Venture0b02be92018-08-31 11:55:55 -0700581 // IPMI spec, Reservation ID, the value simply increases against each
582 // execution of reserve_sel command.
583 if (++g_sel_reserve == 0)
Nan Li36c0cb62016-03-31 11:16:08 +0800584 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500585
586 *data_len = sizeof(g_sel_reserve);
587
588 // Pack the actual response
589 memcpy(response, &g_sel_reserve, *data_len);
590
591 return rc;
592}
593
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500594ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700595 ipmi_request_t request,
596 ipmi_response_t response,
597 ipmi_data_len_t data_len,
598 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500599{
600
601 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700602 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500603 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500604
Chris Austen313d95b2015-10-31 12:55:30 -0500605 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500606
Chris Austenb4f5b922015-10-13 12:44:43 -0500607 *data_len = sizeof(g_sel_reserve);
608
609 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600610 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500611
Tom Josephb647d5b2017-10-31 17:25:33 +0530612 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
613 // a maintenance procedure associated with eSEL record.
614 static constexpr auto procedureType = 0xDE;
615 if (p->recordtype == procedureType)
616 {
617 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
618 // procedure number.
619 createProcedureLogEntry(p->sensortype);
620 }
621 else
622 {
623 send_esel(recordid);
624 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500625
626 return rc;
627}
628
Patrick Venture0b02be92018-08-31 11:55:55 -0700629// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500630ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700631 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
632 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500633{
634 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500635 const FruInvenAreaInfoRequest* reqptr =
636 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530637
638 auto iter = frus.find(reqptr->fruID);
639 if (iter == frus.end())
640 {
641 *data_len = 0;
642 return IPMI_CC_SENSOR_INVALID;
643 }
644
Marri Devender Raocac383b2017-07-03 13:24:27 -0500645 try
646 {
647 const auto& fruArea = getFruAreaData(reqptr->fruID);
648 auto size = static_cast<uint16_t>(fruArea.size());
649 FruInvenAreaInfoResponse resp;
650 resp.sizems = size >> 8;
651 resp.sizels = size;
652 resp.access = static_cast<uint8_t>(AccessMode::bytes);
653
654 *data_len = sizeof(resp);
655
656 // Pack the actual response
657 memcpy(response, &resp, *data_len);
658 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700659 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500660 {
661 rc = IPMI_CC_UNSPECIFIED_ERROR;
662 *data_len = 0;
663 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500664 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500665 return rc;
666}
667
Patrick Venture0b02be92018-08-31 11:55:55 -0700668// Read FRU data
669ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
670 ipmi_request_t request,
671 ipmi_response_t response,
672 ipmi_data_len_t data_len,
673 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500674{
675 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500676 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500677 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700678 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530679
680 auto iter = frus.find(reqptr->fruID);
681 if (iter == frus.end())
682 {
683 *data_len = 0;
684 return IPMI_CC_SENSOR_INVALID;
685 }
686
Marri Devender Raocac383b2017-07-03 13:24:27 -0500687 auto offset =
688 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
689 try
690 {
691 const auto& fruArea = getFruAreaData(reqptr->fruID);
692 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500693
Tom Josephefcd68b2018-04-26 18:46:27 +0530694 if (offset >= size)
695 {
696 return IPMI_CC_PARM_OUT_OF_RANGE;
697 }
698
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500699 // Write the count of response data.
700 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500701 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500702 resptr->count = reqptr->count;
703 }
704 else
705 {
706 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500707 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530708
Ratan Gupta2848d602018-01-31 20:39:20 +0530709 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700710 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530711
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500712 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500713 }
714 catch (const InternalFailure& e)
715 {
716 rc = IPMI_CC_UNSPECIFIED_ERROR;
717 *data_len = 0;
718 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500719 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500720 return rc;
721}
722
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600723ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700724 ipmi_request_t request,
725 ipmi_response_t response,
726 ipmi_data_len_t data_len,
727 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600728{
729 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700730 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600731
Patrick Venture0b02be92018-08-31 11:55:55 -0700732 memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600733
734 responseData->sdrVersion = sdrVersion;
735
736 uint16_t records = frus.size() + sensors.size();
737 responseData->recordCountMs = records >> 8;
738 responseData->recordCountLs = records;
739
740 responseData->freeSpace[0] = 0xFF;
741 responseData->freeSpace[1] = 0xFF;
742
743 *data_len = sizeof(GetRepositoryInfoResponse);
744
745 return IPMI_CC_OK;
746}
Chris Austenb4f5b922015-10-13 12:44:43 -0500747
Chris Austenb4f5b922015-10-13 12:44:43 -0500748void register_netfn_storage_functions()
749{
Tom05732372016-09-06 17:21:23 +0530750 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700751 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
752 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500753
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530754 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700755 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
756 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530757
Tom05732372016-09-06 17:21:23 +0530758 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700759 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
760 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500761
Tom05732372016-09-06 17:21:23 +0530762 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700763 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
764 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500765
Tom05732372016-09-06 17:21:23 +0530766 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700767 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
768 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500769
Tom Josepha4953392017-06-30 19:09:47 +0530770 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700771 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
772 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530773
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530774 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700775 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
776 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530777
Tom05732372016-09-06 17:21:23 +0530778 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700779 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
780 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530781 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530782 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
783 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500784 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500785 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700786 ipmi_storage_get_fru_inv_area_info,
787 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500788
789 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500790 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700791 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500792
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600793 // <Get Repository Info>
794 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700795 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600796
Tom Joseph5ca50952018-02-22 00:33:38 +0530797 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700798 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
799 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530800
801 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700802 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
803 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530804
Marri Devender Rao908f7502017-07-10 01:49:54 -0500805 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500806 return;
807}