blob: 0a46b839829826b6fdd9662ecea05beb2b7d9403 [file] [log] [blame]
Patrick Venture3a5071a2018-09-12 13:27:42 -07001#include "storagehandler.hpp"
2
3#include "fruread.hpp"
4#include "read_fru_data.hpp"
5#include "selutility.hpp"
6#include "sensorhandler.hpp"
7#include "storageaddsel.hpp"
8#include "utils.hpp"
9
Lei YU52d91242017-10-17 22:52:28 +080010#include <arpa/inet.h>
Patrick Venture3a5071a2018-09-12 13:27:42 -070011#include <host-ipmid/ipmid-api.h>
12#include <mapper.h>
13#include <systemd/sd-bus.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070014
15#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +080016#include <chrono>
17#include <cstdio>
Patrick Ventureb51bf9c2018-09-10 15:53:14 -070018#include <cstring>
Patrick Venture3a5071a2018-09-12 13:27:42 -070019#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/log.hpp>
21#include <sdbusplus/server.hpp>
22#include <string>
23#include <xyz/openbmc_project/Common/error.hpp>
24
Vernon Mauery185b9f82018-07-20 10:52:36 -070025#if __has_include(<filesystem>)
26#include <filesystem>
27#elif __has_include(<experimental/filesystem>)
Tom Josepha4953392017-06-30 19:09:47 +053028#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070029namespace std
30{
31// splice experimental::filesystem into std
32namespace filesystem = std::experimental::filesystem;
33} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070034#else
Patrick Venture0b02be92018-08-31 11:55:55 -070035#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070036#endif
Patrick Venture0b02be92018-08-31 11:55:55 -070037
Chris Austenb4f5b922015-10-13 12:44:43 -050038void register_netfn_storage_functions() __attribute__((constructor));
39
Patrick Venture0b02be92018-08-31 11:55:55 -070040unsigned int g_sel_time = 0xFFFFFFFF;
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
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700148 std::memcpy(response, outPayload.data(), outPayload.size());
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530149 *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 {
Jason M. Bills13e67c82018-09-10 14:12:16 -0700163 if (!checkSELReservation(requestData->reservationID))
Tom Josepha4953392017-06-30 19:09:47 +0530164 {
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 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700242 std::memcpy(response, &record, sizeof(record));
Tom Josepha4953392017-06-30 19:09:47 +0530243 *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
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700258 std::memcpy(response, &record.nextRecordID,
259 sizeof(record.nextRecordID));
260 std::memcpy(static_cast<uint8_t*>(response) +
261 sizeof(record.nextRecordID),
262 &record.recordID + requestData->offset, readLength);
Tom Josepha4953392017-06-30 19:09:47 +0530263 *data_len = sizeof(record.nextRecordID) + readLength;
264 }
265
266 return IPMI_CC_OK;
267}
268
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530269ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
270 ipmi_request_t request, ipmi_response_t response,
271 ipmi_data_len_t data_len, ipmi_context_t context)
272{
273 namespace fs = std::experimental::filesystem;
Patrick Venture0b02be92018-08-31 11:55:55 -0700274 auto requestData =
275 reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>(request);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530276
Jason M. Bills13e67c82018-09-10 14:12:16 -0700277 if (!checkSELReservation(requestData->reservationID))
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530278 {
279 *data_len = 0;
280 return IPMI_CC_INVALID_RESERVATION_ID;
281 }
282
Jason M. Bills13e67c82018-09-10 14:12:16 -0700283 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
284 // deleted
285 cancelSELReservation();
286
Tom Josephe59abfb2018-08-06 18:46:27 +0530287 try
288 {
289 ipmi::sel::readLoggingObjectPaths(cache::paths);
290 }
291 catch (const sdbusplus::exception::SdBusError& e)
292 {
293 // readLoggingObjectPaths will throw exception if there are no error
294 // log entries.
295 *data_len = 0;
296 return IPMI_CC_SENSOR_INVALID;
297 }
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530298
299 if (cache::paths.empty())
300 {
301 *data_len = 0;
302 return IPMI_CC_SENSOR_INVALID;
303 }
304
305 ipmi::sel::ObjectPaths::const_iterator iter;
306 uint16_t delRecordID = 0;
307
308 if (requestData->selRecordID == ipmi::sel::firstEntry)
309 {
310 iter = cache::paths.begin();
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 if (requestData->selRecordID == ipmi::sel::lastEntry)
316 {
317 iter = cache::paths.end();
318 fs::path path(*iter);
Patrick Venture0b02be92018-08-31 11:55:55 -0700319 delRecordID = static_cast<uint16_t>(
320 std::stoul(std::string(path.filename().c_str())));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530321 }
322 else
323 {
324 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
325 std::to_string(requestData->selRecordID);
326
327 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
328 if (iter == cache::paths.end())
329 {
330 *data_len = 0;
331 return IPMI_CC_SENSOR_INVALID;
332 }
333 delRecordID = requestData->selRecordID;
334 }
335
336 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
337 std::string service;
338
339 try
340 {
341 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
342 }
343 catch (const std::runtime_error& e)
344 {
345 log<level::ERR>(e.what());
346 *data_len = 0;
347 return IPMI_CC_UNSPECIFIED_ERROR;
348 }
349
Patrick Venture0b02be92018-08-31 11:55:55 -0700350 auto methodCall = bus.new_method_call(service.c_str(), (*iter).c_str(),
351 ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530352 auto reply = bus.call(methodCall);
353 if (reply.is_method_error())
354 {
355 *data_len = 0;
356 return IPMI_CC_UNSPECIFIED_ERROR;
357 }
358
359 // Invalidate the cache of dbus entry objects.
360 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700361 std::memcpy(response, &delRecordID, sizeof(delRecordID));
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530362 *data_len = sizeof(delRecordID);
363
364 return IPMI_CC_OK;
365}
366
Tom Joseph2f05bb52017-06-30 19:14:49 +0530367ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
368 ipmi_response_t response, ipmi_data_len_t data_len,
369 ipmi_context_t context)
370{
Patrick Venture0b02be92018-08-31 11:55:55 -0700371 auto requestData =
372 reinterpret_cast<const ipmi::sel::ClearSELRequest*>(request);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530373
Jason M. Bills13e67c82018-09-10 14:12:16 -0700374 if (!checkSELReservation(requestData->reservationID))
Tom Joseph2f05bb52017-06-30 19:14:49 +0530375 {
376 *data_len = 0;
377 return IPMI_CC_INVALID_RESERVATION_ID;
378 }
379
Patrick Venture0b02be92018-08-31 11:55:55 -0700380 if (requestData->charC != 'C' || requestData->charL != 'L' ||
Tom Joseph2f05bb52017-06-30 19:14:49 +0530381 requestData->charR != 'R')
382 {
383 *data_len = 0;
384 return IPMI_CC_INVALID_FIELD_REQUEST;
385 }
386
387 uint8_t eraseProgress = ipmi::sel::eraseComplete;
388
389 /*
390 * Erasure status cannot be fetched from DBUS, so always return erasure
391 * status as `erase completed`.
392 */
393 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
394 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700395 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530396 *data_len = sizeof(eraseProgress);
397 return IPMI_CC_OK;
398 }
399
Jason M. Bills13e67c82018-09-10 14:12:16 -0700400 // Per the IPMI spec, need to cancel any reservation when the SEL is cleared
401 cancelSELReservation();
402
Tom Joseph2f05bb52017-06-30 19:14:49 +0530403 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
Tom Josephe59abfb2018-08-06 18:46:27 +0530404 ipmi::sel::ObjectPaths objectPaths;
Tom Joseph2f05bb52017-06-30 19:14:49 +0530405 auto depth = 0;
406
Patrick Venture0b02be92018-08-31 11:55:55 -0700407 auto mapperCall =
408 bus.new_method_call(ipmi::sel::mapperBusName, ipmi::sel::mapperObjPath,
409 ipmi::sel::mapperIntf, "GetSubTreePaths");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530410 mapperCall.append(ipmi::sel::logBasePath);
411 mapperCall.append(depth);
412 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
413
Tom Josephe59abfb2018-08-06 18:46:27 +0530414 try
Tom Joseph2f05bb52017-06-30 19:14:49 +0530415 {
Tom Josephe59abfb2018-08-06 18:46:27 +0530416 auto reply = bus.call(mapperCall);
417 if (reply.is_method_error())
418 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700419 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530420 *data_len = sizeof(eraseProgress);
421 return IPMI_CC_OK;
422 }
Tom Joseph2f05bb52017-06-30 19:14:49 +0530423
Tom Josephe59abfb2018-08-06 18:46:27 +0530424 reply.read(objectPaths);
425 if (objectPaths.empty())
426 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700427 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Josephe59abfb2018-08-06 18:46:27 +0530428 *data_len = sizeof(eraseProgress);
429 return IPMI_CC_OK;
430 }
431 }
432 catch (const sdbusplus::exception::SdBusError& e)
Tom Joseph2f05bb52017-06-30 19:14:49 +0530433 {
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700434 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530435 *data_len = sizeof(eraseProgress);
436 return IPMI_CC_OK;
437 }
438
439 std::string service;
440
441 try
442 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700443 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf,
Tom Joseph2f05bb52017-06-30 19:14:49 +0530444 objectPaths.front());
445 }
446 catch (const std::runtime_error& e)
447 {
448 log<level::ERR>(e.what());
449 *data_len = 0;
450 return IPMI_CC_UNSPECIFIED_ERROR;
451 }
452
453 for (const auto& iter : objectPaths)
454 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700455 auto methodCall = bus.new_method_call(
456 service.c_str(), iter.c_str(), ipmi::sel::logDeleteIntf, "Delete");
Tom Joseph2f05bb52017-06-30 19:14:49 +0530457
458 auto reply = bus.call(methodCall);
459 if (reply.is_method_error())
460 {
461 *data_len = 0;
462 return IPMI_CC_UNSPECIFIED_ERROR;
463 }
464 }
465
466 // Invalidate the cache of dbus entry objects.
467 cache::paths.clear();
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700468 std::memcpy(response, &eraseProgress, sizeof(eraseProgress));
Tom Joseph2f05bb52017-06-30 19:14:49 +0530469 *data_len = sizeof(eraseProgress);
470 return IPMI_CC_OK;
471}
472
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500473ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700474 ipmi_request_t request,
475 ipmi_response_t response,
476 ipmi_data_len_t data_len,
477 ipmi_context_t context)
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500478{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530479 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530480 uint64_t host_time_usec = 0;
481 uint32_t resp = 0;
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500482 std::stringstream hostTime;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500483
Lei YUe8939392017-06-15 10:45:05 +0800484 try
485 {
486 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
487 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
488 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530489
Lei YUe8939392017-06-15 10:45:05 +0800490 // Get host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700491 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
492 DBUS_PROPERTIES, "Get");
Lei YUe8939392017-06-15 10:45:05 +0800493
494 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
495 auto reply = bus.call(method);
496 if (reply.is_method_error())
497 {
498 log<level::ERR>("Error getting time",
499 entry("SERVICE=%s", service.c_str()),
500 entry("PATH=%s", HOST_TIME_PATH));
501 return IPMI_CC_UNSPECIFIED_ERROR;
502 }
503 reply.read(value);
504 host_time_usec = value.get<uint64_t>();
505 }
506 catch (InternalFailure& e)
507 {
508 log<level::ERR>(e.what());
509 return IPMI_CC_UNSPECIFIED_ERROR;
510 }
511 catch (const std::runtime_error& e)
512 {
513 log<level::ERR>(e.what());
514 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530515 }
516
Nagaraju Goruganti8960b7c2018-04-29 22:38:40 -0500517 hostTime << "Host time:" << getTimeString(host_time_usec);
518 log<level::DEBUG>(hostTime.str().c_str());
519
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530520 // Time is really long int but IPMI wants just uint32. This works okay until
521 // the number of seconds since 1970 overflows uint32 size.. Still a whole
522 // lot of time here to even think about that.
523 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
524 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530525
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500526 // From the IPMI Spec 2.0, response should be a 32-bit value
527 *data_len = sizeof(resp);
528
529 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700530 std::memcpy(response, &resp, *data_len);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500531
Lei YUe8939392017-06-15 10:45:05 +0800532 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500533}
534
535ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700536 ipmi_request_t request,
537 ipmi_response_t response,
538 ipmi_data_len_t data_len,
539 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500540{
Lei YUe8939392017-06-15 10:45:05 +0800541 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530542 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800543 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530544 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500545
Lei YUe8939392017-06-15 10:45:05 +0800546 secs = le32toh(secs);
547 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600548
Lei YUe8939392017-06-15 10:45:05 +0800549 try
550 {
551 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
552 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
553 sdbusplus::message::variant<uint64_t> value{usec.count()};
554
555 // Set host time
Patrick Venture0b02be92018-08-31 11:55:55 -0700556 auto method = bus.new_method_call(service.c_str(), HOST_TIME_PATH,
557 DBUS_PROPERTIES, "Set");
Lei YUe8939392017-06-15 10:45:05 +0800558
559 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
560 auto reply = bus.call(method);
561 if (reply.is_method_error())
562 {
563 log<level::ERR>("Error setting time",
564 entry("SERVICE=%s", service.c_str()),
565 entry("PATH=%s", HOST_TIME_PATH));
566 rc = IPMI_CC_UNSPECIFIED_ERROR;
567 }
Norman James82330442015-11-19 16:53:26 -0600568 }
Lei YUe8939392017-06-15 10:45:05 +0800569 catch (InternalFailure& e)
570 {
571 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530572 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530573 }
Lei YUe8939392017-06-15 10:45:05 +0800574 catch (const std::runtime_error& e)
575 {
576 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600577 rc = IPMI_CC_UNSPECIFIED_ERROR;
578 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530579
Chris Austenb4f5b922015-10-13 12:44:43 -0500580 return rc;
581}
582
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500583ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700584 ipmi_request_t request,
585 ipmi_response_t response,
586 ipmi_data_len_t data_len,
587 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500588{
Chris Austenb4f5b922015-10-13 12:44:43 -0500589 ipmi_ret_t rc = IPMI_CC_OK;
Jason M. Bills13e67c82018-09-10 14:12:16 -0700590 unsigned short selResID = reserveSel();
Chris Austenb4f5b922015-10-13 12:44:43 -0500591
Jason M. Bills13e67c82018-09-10 14:12:16 -0700592 *data_len = sizeof(selResID);
Chris Austenb4f5b922015-10-13 12:44:43 -0500593
594 // Pack the actual response
Jason M. Bills13e67c82018-09-10 14:12:16 -0700595 std::memcpy(response, &selResID, *data_len);
Chris Austenb4f5b922015-10-13 12:44:43 -0500596
597 return rc;
598}
599
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500600ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700601 ipmi_request_t request,
602 ipmi_response_t response,
603 ipmi_data_len_t data_len,
604 ipmi_context_t context)
Chris Austenb4f5b922015-10-13 12:44:43 -0500605{
606
607 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -0700608 ipmi_add_sel_request_t* p = (ipmi_add_sel_request_t*)request;
Chris Austen41a4b312015-10-25 03:45:42 -0500609 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500610
Jason M. Bills13e67c82018-09-10 14:12:16 -0700611 // Per the IPMI spec, need to cancel the reservation when a SEL entry is
612 // added
613 cancelSELReservation();
614
Chris Austen313d95b2015-10-31 12:55:30 -0500615 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500616
Jason M. Bills13e67c82018-09-10 14:12:16 -0700617 *data_len = sizeof(recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500618
619 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700620 std::memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500621
Tom Josephb647d5b2017-10-31 17:25:33 +0530622 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
623 // a maintenance procedure associated with eSEL record.
624 static constexpr auto procedureType = 0xDE;
625 if (p->recordtype == procedureType)
626 {
627 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
628 // procedure number.
629 createProcedureLogEntry(p->sensortype);
630 }
631 else
632 {
633 send_esel(recordid);
634 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500635
636 return rc;
637}
638
Patrick Venture0b02be92018-08-31 11:55:55 -0700639// Read FRU info area
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500640ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
Patrick Venture0b02be92018-08-31 11:55:55 -0700641 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
642 ipmi_response_t response, ipmi_data_len_t data_len, ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500643{
644 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500645 const FruInvenAreaInfoRequest* reqptr =
646 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
Tom Joseph187f5642018-03-29 13:49:06 +0530647
648 auto iter = frus.find(reqptr->fruID);
649 if (iter == frus.end())
650 {
651 *data_len = 0;
652 return IPMI_CC_SENSOR_INVALID;
653 }
654
Marri Devender Raocac383b2017-07-03 13:24:27 -0500655 try
656 {
657 const auto& fruArea = getFruAreaData(reqptr->fruID);
658 auto size = static_cast<uint16_t>(fruArea.size());
659 FruInvenAreaInfoResponse resp;
660 resp.sizems = size >> 8;
661 resp.sizels = size;
662 resp.access = static_cast<uint8_t>(AccessMode::bytes);
663
664 *data_len = sizeof(resp);
665
666 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700667 std::memcpy(response, &resp, *data_len);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500668 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700669 catch (const InternalFailure& e)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500670 {
671 rc = IPMI_CC_UNSPECIFIED_ERROR;
672 *data_len = 0;
673 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500674 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500675 return rc;
676}
677
Patrick Venture0b02be92018-08-31 11:55:55 -0700678// Read FRU data
679ipmi_ret_t ipmi_storage_read_fru_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
680 ipmi_request_t request,
681 ipmi_response_t response,
682 ipmi_data_len_t data_len,
683 ipmi_context_t context)
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500684{
685 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500686 const ReadFruDataRequest* reqptr =
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500687 reinterpret_cast<const ReadFruDataRequest*>(request);
Patrick Venture0b02be92018-08-31 11:55:55 -0700688 auto resptr = reinterpret_cast<ReadFruDataResponse*>(response);
Tom Joseph187f5642018-03-29 13:49:06 +0530689
690 auto iter = frus.find(reqptr->fruID);
691 if (iter == frus.end())
692 {
693 *data_len = 0;
694 return IPMI_CC_SENSOR_INVALID;
695 }
696
Marri Devender Raocac383b2017-07-03 13:24:27 -0500697 auto offset =
698 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
699 try
700 {
701 const auto& fruArea = getFruAreaData(reqptr->fruID);
702 auto size = fruArea.size();
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500703
Tom Josephefcd68b2018-04-26 18:46:27 +0530704 if (offset >= size)
705 {
706 return IPMI_CC_PARM_OUT_OF_RANGE;
707 }
708
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500709 // Write the count of response data.
710 if ((offset + reqptr->count) <= size)
Marri Devender Raocac383b2017-07-03 13:24:27 -0500711 {
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500712 resptr->count = reqptr->count;
713 }
714 else
715 {
716 resptr->count = size - offset;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500717 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530718
Ratan Gupta2848d602018-01-31 20:39:20 +0530719 std::copy((fruArea.begin() + offset),
Patrick Venture0b02be92018-08-31 11:55:55 -0700720 (fruArea.begin() + offset + resptr->count), resptr->data);
Ratan Gupta2848d602018-01-31 20:39:20 +0530721
Nagaraju Goruganti7f2d7c92018-03-21 11:18:30 -0500722 *data_len = resptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500723 }
724 catch (const InternalFailure& e)
725 {
726 rc = IPMI_CC_UNSPECIFIED_ERROR;
727 *data_len = 0;
728 log<level::ERR>(e.what());
Marri Devender Raocac383b2017-07-03 13:24:27 -0500729 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500730 return rc;
731}
732
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600733ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700734 ipmi_request_t request,
735 ipmi_response_t response,
736 ipmi_data_len_t data_len,
737 ipmi_context_t context)
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600738{
739 constexpr auto sdrVersion = 0x51;
Patrick Venture0b02be92018-08-31 11:55:55 -0700740 auto responseData = reinterpret_cast<GetRepositoryInfoResponse*>(response);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600741
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700742 std::memset(responseData, 0, sizeof(GetRepositoryInfoResponse));
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600743
744 responseData->sdrVersion = sdrVersion;
745
746 uint16_t records = frus.size() + sensors.size();
747 responseData->recordCountMs = records >> 8;
748 responseData->recordCountLs = records;
749
750 responseData->freeSpace[0] = 0xFF;
751 responseData->freeSpace[1] = 0xFF;
752
753 *data_len = sizeof(GetRepositoryInfoResponse);
754
755 return IPMI_CC_OK;
756}
Chris Austenb4f5b922015-10-13 12:44:43 -0500757
Chris Austenb4f5b922015-10-13 12:44:43 -0500758void register_netfn_storage_functions()
759{
Tom05732372016-09-06 17:21:23 +0530760 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700761 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL,
762 ipmi_storage_wildcard, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500763
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530764 // <Get SEL Info>
Patrick Venture0b02be92018-08-31 11:55:55 -0700765 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL,
766 getSELInfo, PRIVILEGE_USER);
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530767
Tom05732372016-09-06 17:21:23 +0530768 // <Get SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700769 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL,
770 ipmi_storage_get_sel_time, PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500771
Tom05732372016-09-06 17:21:23 +0530772 // <Set SEL Time>
Patrick Venture0b02be92018-08-31 11:55:55 -0700773 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL,
774 ipmi_storage_set_sel_time, PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500775
Tom05732372016-09-06 17:21:23 +0530776 // <Reserve SEL>
Patrick Venture0b02be92018-08-31 11:55:55 -0700777 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL,
778 ipmi_storage_reserve_sel, PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500779
Tom Josepha4953392017-06-30 19:09:47 +0530780 // <Get SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700781 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL,
782 getSELEntry, PRIVILEGE_USER);
Tom Josepha4953392017-06-30 19:09:47 +0530783
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530784 // <Delete SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700785 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL,
786 deleteSELEntry, PRIVILEGE_OPERATOR);
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530787
Tom05732372016-09-06 17:21:23 +0530788 // <Add SEL Entry>
Patrick Venture0b02be92018-08-31 11:55:55 -0700789 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL,
790 ipmi_storage_add_sel, PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530791 // <Clear SEL>
Tom Joseph2f05bb52017-06-30 19:14:49 +0530792 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
793 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500794 // <Get FRU Inventory Area Info>
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500795 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700796 ipmi_storage_get_fru_inv_area_info,
797 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500798
799 // <Add READ FRU Data
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500800 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
Patrick Venture0b02be92018-08-31 11:55:55 -0700801 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500802
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600803 // <Get Repository Info>
804 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
Patrick Venture0b02be92018-08-31 11:55:55 -0700805 nullptr, ipmi_get_repository_info, PRIVILEGE_USER);
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600806
Tom Joseph5ca50952018-02-22 00:33:38 +0530807 // <Reserve SDR Repository>
Patrick Venture0b02be92018-08-31 11:55:55 -0700808 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR, nullptr,
809 ipmi_sen_reserve_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530810
811 // <Get SDR>
Patrick Venture0b02be92018-08-31 11:55:55 -0700812 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR, nullptr,
813 ipmi_sen_get_sdr, PRIVILEGE_USER);
Tom Joseph5ca50952018-02-22 00:33:38 +0530814
Marri Devender Rao908f7502017-07-10 01:49:54 -0500815 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500816 return;
817}