blob: 929f3b6692d8ec48022ec24ccf7f274f4dddeb29 [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 Venture3a5071a2018-09-12 13:27:42 -070018#include <phosphor-logging/elog-errors.hpp>
19#include <phosphor-logging/log.hpp>
20#include <sdbusplus/server.hpp>
21#include <string>
22#include <xyz/openbmc_project/Common/error.hpp>
23
Vernon Mauery185b9f82018-07-20 10:52:36 -070024#if __has_include(<filesystem>)
25#include <filesystem>
26#elif __has_include(<experimental/filesystem>)
Tom Josepha4953392017-06-30 19:09:47 +053027#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070028namespace std
29{
30// splice experimental::filesystem into std
31namespace filesystem = std::experimental::filesystem;
32} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070033#else
Patrick Venture0b02be92018-08-31 11:55:55 -070034#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070035#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070036
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
Tom Josephe59abfb2018-08-06 18:46:27 +0530115 try
116 {
117 ipmi::sel::readLoggingObjectPaths(cache::paths);
118 }
119 catch (const sdbusplus::exception::SdBusError& e)
120 {
121 // No action if reading log objects have failed for this command.
122 // readLoggingObjectPaths will throw exception if there are no log
123 // entries. The command will be responded with number of SEL entries
124 // as 0.
125 }
126
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530127 responseData->entries = 0;
128 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
129
130 if (!cache::paths.empty())
131 {
132 responseData->entries = static_cast<uint16_t>(cache::paths.size());
133
134 try
135 {
136 responseData->addTimeStamp = static_cast<uint32_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700137 (ipmi::sel::getEntryTimeStamp(cache::paths.back()).count()));
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530138 }
139 catch (InternalFailure& e)
140 {
141 }
142 catch (const std::runtime_error& e)
143 {
144 log<level::ERR>(e.what());
145 }
146 }
147
148 memcpy(response, outPayload.data(), outPayload.size());
149 *data_len = outPayload.size();
150
151 return IPMI_CC_OK;
152}
153
Tom Josepha4953392017-06-30 19:09:47 +0530154ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
155 ipmi_request_t request, ipmi_response_t response,
156 ipmi_data_len_t data_len, ipmi_context_t context)
157{
Patrick Venture0b02be92018-08-31 11:55:55 -0700158 auto requestData =
159 reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>(request);
Tom Josepha4953392017-06-30 19:09:47 +0530160
161 if (requestData->reservationID != 0)
162 {
163 if (g_sel_reserve != requestData->reservationID)
164 {
165 *data_len = 0;
166 return IPMI_CC_INVALID_RESERVATION_ID;
167 }
168 }
169
170 if (cache::paths.empty())
171 {
172 *data_len = 0;
173 return IPMI_CC_SENSOR_INVALID;
174 }
175
176 ipmi::sel::ObjectPaths::const_iterator iter;
177
178 // Check for the requested SEL Entry.
179 if (requestData->selRecordID == ipmi::sel::firstEntry)
180 {
181 iter = cache::paths.begin();
182 }
183 else if (requestData->selRecordID == ipmi::sel::lastEntry)
184 {
185 iter = cache::paths.end();
186 }
187 else
188 {
189 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
190 std::to_string(requestData->selRecordID);
191
192 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
193 if (iter == cache::paths.end())
194 {
195 *data_len = 0;
196 return IPMI_CC_SENSOR_INVALID;
197 }
198 }
199
Patrick Venture0b02be92018-08-31 11:55:55 -0700200 ipmi::sel::GetSELEntryResponse record{};
Tom Josepha4953392017-06-30 19:09:47 +0530201
202 // Convert the log entry into SEL record.
203 try
204 {
205 record = ipmi::sel::convertLogEntrytoSEL(*iter);
206 }
207 catch (InternalFailure& e)
208 {
209 *data_len = 0;
210 return IPMI_CC_UNSPECIFIED_ERROR;
211 }
212 catch (const std::runtime_error& e)
213 {
214 log<level::ERR>(e.what());
215 *data_len = 0;
216 return IPMI_CC_UNSPECIFIED_ERROR;
217 }
218
Tom Josepha4953392017-06-30 19:09:47 +0530219 // Identify the next SEL record ID
Patrick Venture0b02be92018-08-31 11:55:55 -0700220 if (iter != cache::paths.end())
Tom Josepha4953392017-06-30 19:09:47 +0530221 {
222 ++iter;
223 if (iter == cache::paths.end())
224 {
225 record.nextRecordID = ipmi::sel::lastEntry;
226 }
227 else
228 {
Vernon Mauery185b9f82018-07-20 10:52:36 -0700229 namespace fs = std::filesystem;
Tom Josepha4953392017-06-30 19:09:47 +0530230 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700231 record.nextRecordID = static_cast<uint16_t>(
232 std::stoul(std::string(path.filename().c_str())));
Tom Josepha4953392017-06-30 19:09:47 +0530233 }
234 }
235 else
236 {
237 record.nextRecordID = ipmi::sel::lastEntry;
238 }
239
240 if (requestData->readLength == ipmi::sel::entireRecord)
241 {
242 memcpy(response, &record, sizeof(record));
243 *data_len = sizeof(record);
244 }
245 else
246 {
247 if (requestData->offset >= ipmi::sel::selRecordSize ||
248 requestData->readLength > ipmi::sel::selRecordSize)
249 {
250 *data_len = 0;
251 return IPMI_CC_INVALID_FIELD_REQUEST;
252 }
253
254 auto diff = ipmi::sel::selRecordSize - requestData->offset;
Patrick Venture0b02be92018-08-31 11:55:55 -0700255 auto readLength =
256 std::min(diff, static_cast<int>(requestData->readLength));
Tom Josepha4953392017-06-30 19:09:47 +0530257
258 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
259 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
260 &record.recordID + requestData->offset, readLength);
261 *data_len = sizeof(record.nextRecordID) + readLength;
262 }
263
264 return IPMI_CC_OK;
265}
266
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530267ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
268 ipmi_request_t request, ipmi_response_t response,
269 ipmi_data_len_t data_len, ipmi_context_t context)
270{
271 namespace fs = std::experimental::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700272 auto requestData =
273 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530274
275 if (g_sel_reserve != requestData->reservationID)
276 {
277 *data_len = 0;
278 return IPMI_CC_INVALID_RESERVATION_ID;
279 }
280
Tom Josephe59abfb2018-08-06 18:46:27 +0530281 try
282 {
283 ipmi::sel::readLoggingObjectPaths(cache::paths);
284 }
285 catch (const sdbusplus::exception::SdBusError& e)
286 {
287 // readLoggingObjectPaths will throw exception if there are no error
288 // log entries.
289 *data_len = 0;
290 return IPMI_CC_SENSOR_INVALID;
291 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530292
293 if (cache::paths.empty())
294 {
295 *data_len = 0;
296 return IPMI_CC_SENSOR_INVALID;
297 }
298
299 ipmi::sel::ObjectPaths::const_iterator iter;
300 uint16_t delRecordID = 0;
301
302 if (requestData->selRecordID == ipmi::sel::firstEntry)
303 {
304 iter = cache::paths.begin();
305 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700306 delRecordID = static_cast<uint16_t>(
307 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530308 }
309 else if (requestData->selRecordID == ipmi::sel::lastEntry)
310 {
311 iter = cache::paths.end();
312 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700313 delRecordID = static_cast<uint16_t>(
314 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530315 }
316 else
317 {
318 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
319 std::to_string(requestData->selRecordID);
320
321 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
322 if (iter == cache::paths.end())
323 {
324 *data_len = 0;
325 return IPMI_CC_SENSOR_INVALID;
326 }
327 delRecordID = requestData->selRecordID;
328 }
329
330 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
331 std::string service;
332
333 try
334 {
335 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
336 }
337 catch (const std::runtime_error& e)
338 {
339 log<level::ERR>(e.what());
340 *data_len = 0;
341 return IPMI_CC_UNSPECIFIED_ERROR;
342 }
343
Patrick Venture0b02be92018-08-31 11:55:55 -0700344 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
345 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530346 auto reply = bus.call(methodCall);
347 if (reply.is_method_error())
348 {
349 *data_len = 0;
350 return IPMI_CC_UNSPECIFIED_ERROR;
351 }
352
353 // Invalidate the cache of dbus entry objects.
354 cache::paths.clear();
355 memcpy(response, &delRecordID, sizeof(delRecordID));
356 *data_len = sizeof(delRecordID);
357
358 return IPMI_CC_OK;
359}
360
Tom Joseph2f05bb52017-06-30 19:14:49 +0530361ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
362 ipmi_response_t response, ipmi_data_len_t data_len,
363 ipmi_context_t context)
364{
Patrick Venture0b02be92018-08-31 11:55:55 -0700365 auto requestData =
366 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530367
368 if (g_sel_reserve != requestData->reservationID)
369 {
370 *data_len = 0;
371 return IPMI_CC_INVALID_RESERVATION_ID;
372 }
373
Patrick Venture0b02be92018-08-31 11:55:55 -0700374 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530375 requestData->charR != 'R')
376 {
377 *data_len = 0;
378 return IPMI_CC_INVALID_FIELD_REQUEST;
379 }
380
381 uint8_t eraseProgress = ipmi::sel::eraseComplete;
382
383 /*
384 * Erasure status cannot be fetched from DBUS, so always return erasure
385 * status as `erase completed`.
386 */
387 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
388 {
389 memcpy(response, &eraseProgress, sizeof(eraseProgress));
390 *data_len = sizeof(eraseProgress);
391 return IPMI_CC_OK;
392 }
393
394 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530395 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530396 auto depth = 0;
397
Patrick Venture0b02be92018-08-31 11:55:55 -0700398 auto mapperCall =
399 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
400 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530401 mapperCall.append(ipmi::sel::logBasePath);
402 mapperCall.append(depth);
403 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
404
Tom Josephe59abfb2018-08-06 18:46:27 +0530405 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530406 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530407 auto reply = bus.call(mapperCall);
408 if (reply.is_method_error())
409 {
410 memcpy(response, &eraseProgress, sizeof(eraseProgress));
411 *data_len = sizeof(eraseProgress);
412 return IPMI_CC_OK;
413 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530414
Tom Josephe59abfb2018-08-06 18:46:27 +0530415 reply.read(objectPaths);
416 if (objectPaths.empty())
417 {
418 memcpy(response, &eraseProgress, sizeof(eraseProgress));
419 *data_len = sizeof(eraseProgress);
420 return IPMI_CC_OK;
421 }
422 }
423 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530424 {
425 memcpy(response, &eraseProgress, sizeof(eraseProgress));
426 *data_len = sizeof(eraseProgress);
427 return IPMI_CC_OK;
428 }
429
430 std::string service;
431
432 try
433 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700434 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530435 objectPaths.front());
436 }
437 catch (const std::runtime_error& e)
438 {
439 log<level::ERR>(e.what());
440 *data_len = 0;
441 return IPMI_CC_UNSPECIFIED_ERROR;
442 }
443
444 for (const auto& iter : objectPaths)
445 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700446 auto methodCall = bus.new_method_call(
447 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530448
449 auto reply = bus.call(methodCall);
450 if (reply.is_method_error())
451 {
452 *data_len = 0;
453 return IPMI_CC_UNSPECIFIED_ERROR;
454 }
455 }
456
457 // Invalidate the cache of dbus entry objects.
458 cache::paths.clear();
459 memcpy(response, &eraseProgress, sizeof(eraseProgress));
460 *data_len = sizeof(eraseProgress);
461 return IPMI_CC_OK;
462}
463
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500464ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700465 ipmi_request_t request,
466 ipmi_response_t response,
467 ipmi_data_len_t data_len,
468 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500469{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530470 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530471 uint64_t host_time_usec = 0;
472 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500473 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500474
Lei YUe8939392017-06-15 10:45:05 +0800475 try
476 {
477 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
478 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
479 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530480
Lei YUe8939392017-06-15 10:45:05 +0800481 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700482 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
483 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800484
485 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
486 auto reply = bus.call(method);
487 if (reply.is_method_error())
488 {
489 log<level::ERR>("Error getting time",
490 entry("SERVICE=%s", service.c_str()),
491 entry("PATH=%s", HOST_TIME_PATH));
492 return IPMI_CC_UNSPECIFIED_ERROR;
493 }
494 reply.read(value);
495 host_time_usec = value.get<uint64_t>();
496 }
497 catch (InternalFailure& e)
498 {
499 log<level::ERR>(e.what());
500 return IPMI_CC_UNSPECIFIED_ERROR;
501 }
502 catch (const std::runtime_error& e)
503 {
504 log<level::ERR>(e.what());
505 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530506 }
507
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500508 hostTime << "Host time:" << getTimeString(host_time_usec);
509 log<level::DEBUG>(hostTime.str().c_str());
510
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530511 // Time is really long int but IPMI wants just uint32. This works okay until
512 // the number of seconds since 1970 overflows uint32 size.. Still a whole
513 // lot of time here to even think about that.
514 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
515 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530516
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500517 // From the IPMI Spec 2.0, response should be a 32-bit value
518 *data_len = sizeof(resp);
519
520 // Pack the actual response
521 memcpy(response, &resp, *data_len);
522
Lei YUe8939392017-06-15 10:45:05 +0800523 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500524}
525
526ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700527 ipmi_request_t request,
528 ipmi_response_t response,
529 ipmi_data_len_t data_len,
530 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500531{
Lei YUe8939392017-06-15 10:45:05 +0800532 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530533 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800534 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530535 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500536
Lei YUe8939392017-06-15 10:45:05 +0800537 secs = le32toh(secs);
538 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600539
Lei YUe8939392017-06-15 10:45:05 +0800540 try
541 {
542 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
543 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
544 sdbusplus::message::variant<uint64_t> value{usec.count()};
545
546 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700547 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
548 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800549
550 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
551 auto reply = bus.call(method);
552 if (reply.is_method_error())
553 {
554 log<level::ERR>("Error setting time",
555 entry("SERVICE=%s", service.c_str()),
556 entry("PATH=%s", HOST_TIME_PATH));
557 rc = IPMI_CC_UNSPECIFIED_ERROR;
558 }
Norman James82330442015-11-19 16:53:26 -0600559 }
Lei YUe8939392017-06-15 10:45:05 +0800560 catch (InternalFailure& e)
561 {
562 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530563 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530564 }
Lei YUe8939392017-06-15 10:45:05 +0800565 catch (const std::runtime_error& e)
566 {
567 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600568 rc = IPMI_CC_UNSPECIFIED_ERROR;
569 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530570
Chris Austenb4f5b922015-10-13 12:44:43 -0500571 return rc;
572}
573
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500574ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700575 ipmi_request_t request,
576 ipmi_response_t response,
577 ipmi_data_len_t data_len,
578 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500579{
Chris Austenb4f5b922015-10-13 12:44:43 -0500580 ipmi_ret_t rc = IPMI_CC_OK;
581
Patrick Venture0b02be92018-08-31 11:55:55 -0700582 // IPMI spec, Reservation ID, the value simply increases against each
583 // execution of reserve_sel command.
584 if (++g_sel_reserve == 0)
Nan Li36c0cb62016-03-31 11:16:08 +0800585 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500586
587 *data_len = sizeof(g_sel_reserve);
588
589 // Pack the actual response
590 memcpy(response, &g_sel_reserve, *data_len);
591
592 return rc;
593}
594
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500595ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700596 ipmi_request_t request,
597 ipmi_response_t response,
598 ipmi_data_len_t data_len,
599 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500600{
601
602 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700603 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500604 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500605
Chris Austen313d95b2015-10-31 12:55:30 -0500606 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500607
Chris Austenb4f5b922015-10-13 12:44:43 -0500608 *data_len = sizeof(g_sel_reserve);
609
610 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600611 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500612
Tom Josephb647d5b2017-10-31 17:25:33 +0530613 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
614 // a maintenance procedure associated with eSEL record.
615 static constexpr auto procedureType = 0xDE;
616 if (p->recordtype == procedureType)
617 {
618 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
619 // procedure number.
620 createProcedureLogEntry(p->sensortype);
621 }
622 else
623 {
624 send_esel(recordid);
625 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500626
627 return rc;
628}
629
Patrick Venture0b02be92018-08-31 11:55:55 -0700630// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500631ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700632 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
633 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500634{
635 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500636 const FruInvenAreaInfoRequest* reqptr =
637 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530638
639 auto iter = frus.find(reqptr->fruID);
640 if (iter == frus.end())
641 {
642 *data_len = 0;
643 return IPMI_CC_SENSOR_INVALID;
644 }
645
Marri Devender Raocac383b2017-07-03 13:24:27 -0500646 try
647 {
648 const auto& fruArea = getFruAreaData(reqptr->fruID);
649 auto size = static_cast<uint16_t>(fruArea.size());
650 FruInvenAreaInfoResponse resp;
651 resp.sizems = size >> 8;
652 resp.sizels = size;
653 resp.access = static_cast<uint8_t>(AccessMode::bytes);
654
655 *data_len = sizeof(resp);
656
657 // Pack the actual response
658 memcpy(response, &resp, *data_len);
659 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700660 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500661 {
662 rc = IPMI_CC_UNSPECIFIED_ERROR;
663 *data_len = 0;
664 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500665 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500666 return rc;
667}
668
Patrick Venture0b02be92018-08-31 11:55:55 -0700669// Read FRU data
670ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
671 ipmi_request_t request,
672 ipmi_response_t response,
673 ipmi_data_len_t data_len,
674 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500675{
676 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500677 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500678 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700679 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530680
681 auto iter = frus.find(reqptr->fruID);
682 if (iter == frus.end())
683 {
684 *data_len = 0;
685 return IPMI_CC_SENSOR_INVALID;
686 }
687
Marri Devender Raocac383b2017-07-03 13:24:27 -0500688 auto offset =
689 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
690 try
691 {
692 const auto& fruArea = getFruAreaData(reqptr->fruID);
693 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500694
Tom Josephefcd68b2018-04-26 18:46:27 +0530695 if (offset >= size)
696 {
697 return IPMI_CC_PARM_OUT_OF_RANGE;
698 }
699
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500700 // Write the count of response data.
701 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500702 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500703 resptr->count = reqptr->count;
704 }
705 else
706 {
707 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500708 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530709
Ratan Gupta2848d602018-01-31 20:39:20 +0530710 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700711 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530712
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500713 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500714 }
715 catch (const InternalFailure& e)
716 {
717 rc = IPMI_CC_UNSPECIFIED_ERROR;
718 *data_len = 0;
719 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500720 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500721 return rc;
722}
723
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600724ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700725 ipmi_request_t request,
726 ipmi_response_t response,
727 ipmi_data_len_t data_len,
728 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600729{
730 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700731 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600732
Patrick Venture0b02be92018-08-31 11:55:55 -0700733 memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600734
735 responseData->sdrVersion = sdrVersion;
736
737 uint16_t records = frus.size() + sensors.size();
738 responseData->recordCountMs = records >> 8;
739 responseData->recordCountLs = records;
740
741 responseData->freeSpace[0] = 0xFF;
742 responseData->freeSpace[1] = 0xFF;
743
744 *data_len = sizeof(GetRepositoryInfoResponse);
745
746 return IPMI_CC_OK;
747}
Chris Austenb4f5b922015-10-13 12:44:43 -0500748
Chris Austenb4f5b922015-10-13 12:44:43 -0500749void register_netfn_storage_functions()
750{
Tom05732372016-09-06 17:21:23 +0530751 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700752 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
753 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500754
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530755 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700756 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
757 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530758
Tom05732372016-09-06 17:21:23 +0530759 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700760 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
761 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500762
Tom05732372016-09-06 17:21:23 +0530763 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700764 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
765 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500766
Tom05732372016-09-06 17:21:23 +0530767 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700768 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
769 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500770
Tom Josepha4953392017-06-30 19:09:47 +0530771 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700772 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
773 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530774
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530775 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700776 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
777 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530778
Tom05732372016-09-06 17:21:23 +0530779 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700780 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
781 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530782 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530783 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
784 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500785 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500786 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700787 ipmi_storage_get_fru_inv_area_info,
788 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500789
790 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500791 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700792 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500793
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600794 // <Get Repository Info>
795 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700796 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600797
Tom Joseph5ca50952018-02-22 00:33:38 +0530798 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700799 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
800 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530801
802 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700803 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
804 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530805
Marri Devender Rao908f7502017-07-10 01:49:54 -0500806 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500807 return;
808}