blob: fa630e3a956ea237241e2573067c715ee0fc37c3 [file] [log] [blame]
Marri Devender Raocac383b2017-07-03 13:24:27 -05001#include <algorithm>
Lei YU52d91242017-10-17 22:52:28 +08002#include <arpa/inet.h>
3#include <chrono>
4#include <cstdio>
Tom Josepha4953392017-06-30 19:09:47 +05305#include <experimental/filesystem>
Lei YU52d91242017-10-17 22:52:28 +08006#include <mapper.h>
7#include <string>
8#include <systemd/sd-bus.h>
9
Tom Joseph6f7deaa2017-06-30 19:03:54 +053010#include <phosphor-logging/log.hpp>
Marri Devender Raocac383b2017-07-03 13:24:27 -050011#include <phosphor-logging/elog-errors.hpp>
Lei YU52d91242017-10-17 22:52:28 +080012#include <sdbusplus/server.hpp>
13
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060014#include "fruread.hpp"
Lei YU52d91242017-10-17 22:52:28 +080015#include "host-ipmid/ipmid-api.h"
16#include "read_fru_data.hpp"
17#include "selutility.hpp"
18#include "storageaddsel.h"
19#include "storagehandler.h"
20#include "utils.hpp"
21#include "xyz/openbmc_project/Common/error.hpp"
Tom Joseph5ca50952018-02-22 00:33:38 +053022#include "sensorhandler.h"
Lei YU52d91242017-10-17 22:52:28 +080023
Chris Austen41a4b312015-10-25 03:45:42 -050024
Chris Austenb4f5b922015-10-13 12:44:43 -050025void register_netfn_storage_functions() __attribute__((constructor));
26
Chris Austenb4f5b922015-10-13 12:44:43 -050027unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080028extern unsigned short g_sel_reserve;
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -060029extern const ipmi::sensor::IdInfoMap sensors;
30extern const FruMap frus;
Chris Austenb4f5b922015-10-13 12:44:43 -050031
Lei YUe8939392017-06-15 10:45:05 +080032namespace {
33constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
34constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
35constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
36constexpr auto PROPERTY_ELAPSED= "Elapsed";
37
38const char* getTimeString(const uint64_t& usecSinceEpoch)
39{
40 using namespace std::chrono;
41 system_clock::time_point tp{microseconds(usecSinceEpoch)};
42 auto t = system_clock::to_time_t(tp);
43 return std::ctime(&t);
44}
45}
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053046
Tom Joseph6f7deaa2017-06-30 19:03:54 +053047namespace cache
48{
49 /*
50 * This cache contains the object paths of the logging entries sorted in the
51 * order of the filename(numeric order). The cache is initialized by
52 * invoking readLoggingObjectPaths with the cache as the parameter. The
53 * cache is invoked in the execution of the Get SEL info and Delete SEL
54 * entry command. The Get SEL Info command is typically invoked before the
55 * Get SEL entry command, so the cache is utilized for responding to Get SEL
56 * entry command. The cache is invalidated by clearing after Delete SEL
57 * entry and Clear SEL command.
58 */
59 ipmi::sel::ObjectPaths paths;
60
61} // namespace objectPathsCache
62
63using InternalFailure =
64 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
65using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050066using namespace ipmi::fru;
67
68/**
69 * @enum Device access mode
70 */
71enum class AccessMode
72{
73 bytes, ///< Device is accessed by bytes
74 words ///< Device is accessed by words
75};
76
Tom Joseph6f7deaa2017-06-30 19:03:54 +053077
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050078ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
79 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -050080 ipmi_data_len_t data_len, ipmi_context_t context)
81{
82 printf("Handling STORAGE WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
83 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080084 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050085 *data_len = 0;
86 return rc;
87}
88
Tom Joseph6f7deaa2017-06-30 19:03:54 +053089ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
90 ipmi_request_t request, ipmi_response_t response,
91 ipmi_data_len_t data_len, ipmi_context_t context)
92{
93 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
94 auto responseData = reinterpret_cast<ipmi::sel::GetSELInfoResponse*>
95 (outPayload.data());
96
97 responseData->selVersion = ipmi::sel::selVersion;
98 // Last erase timestamp is not available from log manager.
99 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
100 responseData->operationSupport = ipmi::sel::operationSupport;
101
102 ipmi::sel::readLoggingObjectPaths(cache::paths);
103 responseData->entries = 0;
104 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
105
106 if (!cache::paths.empty())
107 {
108 responseData->entries = static_cast<uint16_t>(cache::paths.size());
109
110 try
111 {
112 responseData->addTimeStamp = static_cast<uint32_t>(
113 (ipmi::sel::getEntryTimeStamp(cache::paths.back())
114 .count()));
115 }
116 catch (InternalFailure& e)
117 {
118 }
119 catch (const std::runtime_error& e)
120 {
121 log<level::ERR>(e.what());
122 }
123 }
124
125 memcpy(response, outPayload.data(), outPayload.size());
126 *data_len = outPayload.size();
127
128 return IPMI_CC_OK;
129}
130
Tom Josepha4953392017-06-30 19:09:47 +0530131ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
132 ipmi_request_t request, ipmi_response_t response,
133 ipmi_data_len_t data_len, ipmi_context_t context)
134{
135 auto requestData = reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>
136 (request);
137
138 if (requestData->reservationID != 0)
139 {
140 if (g_sel_reserve != requestData->reservationID)
141 {
142 *data_len = 0;
143 return IPMI_CC_INVALID_RESERVATION_ID;
144 }
145 }
146
147 if (cache::paths.empty())
148 {
149 *data_len = 0;
150 return IPMI_CC_SENSOR_INVALID;
151 }
152
153 ipmi::sel::ObjectPaths::const_iterator iter;
154
155 // Check for the requested SEL Entry.
156 if (requestData->selRecordID == ipmi::sel::firstEntry)
157 {
158 iter = cache::paths.begin();
159 }
160 else if (requestData->selRecordID == ipmi::sel::lastEntry)
161 {
162 iter = cache::paths.end();
163 }
164 else
165 {
166 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
167 std::to_string(requestData->selRecordID);
168
169 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
170 if (iter == cache::paths.end())
171 {
172 *data_len = 0;
173 return IPMI_CC_SENSOR_INVALID;
174 }
175 }
176
177 ipmi::sel::GetSELEntryResponse record {};
178
179 // Convert the log entry into SEL record.
180 try
181 {
182 record = ipmi::sel::convertLogEntrytoSEL(*iter);
183 }
184 catch (InternalFailure& e)
185 {
186 *data_len = 0;
187 return IPMI_CC_UNSPECIFIED_ERROR;
188 }
189 catch (const std::runtime_error& e)
190 {
191 log<level::ERR>(e.what());
192 *data_len = 0;
193 return IPMI_CC_UNSPECIFIED_ERROR;
194 }
195
196
197 // Identify the next SEL record ID
198 if(iter != cache::paths.end())
199 {
200 ++iter;
201 if (iter == cache::paths.end())
202 {
203 record.nextRecordID = ipmi::sel::lastEntry;
204 }
205 else
206 {
207 namespace fs = std::experimental::filesystem;
208 fs::path path(*iter);
209 record.nextRecordID = static_cast<uint16_t>
210 (std::stoul(std::string(path.filename().c_str())));
211 }
212 }
213 else
214 {
215 record.nextRecordID = ipmi::sel::lastEntry;
216 }
217
218 if (requestData->readLength == ipmi::sel::entireRecord)
219 {
220 memcpy(response, &record, sizeof(record));
221 *data_len = sizeof(record);
222 }
223 else
224 {
225 if (requestData->offset >= ipmi::sel::selRecordSize ||
226 requestData->readLength > ipmi::sel::selRecordSize)
227 {
228 *data_len = 0;
229 return IPMI_CC_INVALID_FIELD_REQUEST;
230 }
231
232 auto diff = ipmi::sel::selRecordSize - requestData->offset;
233 auto readLength = std::min(diff,
234 static_cast<int>(requestData->readLength));
235
236 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
237 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
238 &record.recordID + requestData->offset, readLength);
239 *data_len = sizeof(record.nextRecordID) + readLength;
240 }
241
242 return IPMI_CC_OK;
243}
244
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530245ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
246 ipmi_request_t request, ipmi_response_t response,
247 ipmi_data_len_t data_len, ipmi_context_t context)
248{
249 namespace fs = std::experimental::filesystem;
250 auto requestData = reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>
251 (request);
252
253 if (g_sel_reserve != requestData->reservationID)
254 {
255 *data_len = 0;
256 return IPMI_CC_INVALID_RESERVATION_ID;
257 }
258
259 ipmi::sel::readLoggingObjectPaths(cache::paths);
260
261 if (cache::paths.empty())
262 {
263 *data_len = 0;
264 return IPMI_CC_SENSOR_INVALID;
265 }
266
267 ipmi::sel::ObjectPaths::const_iterator iter;
268 uint16_t delRecordID = 0;
269
270 if (requestData->selRecordID == ipmi::sel::firstEntry)
271 {
272 iter = cache::paths.begin();
273 fs::path path(*iter);
274 delRecordID = static_cast<uint16_t>
275 (std::stoul(std::string(path.filename().c_str())));
276 }
277 else if (requestData->selRecordID == ipmi::sel::lastEntry)
278 {
279 iter = cache::paths.end();
280 fs::path path(*iter);
281 delRecordID = static_cast<uint16_t>
282 (std::stoul(std::string(path.filename().c_str())));
283 }
284 else
285 {
286 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
287 std::to_string(requestData->selRecordID);
288
289 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
290 if (iter == cache::paths.end())
291 {
292 *data_len = 0;
293 return IPMI_CC_SENSOR_INVALID;
294 }
295 delRecordID = requestData->selRecordID;
296 }
297
298 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
299 std::string service;
300
301 try
302 {
303 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
304 }
305 catch (const std::runtime_error& e)
306 {
307 log<level::ERR>(e.what());
308 *data_len = 0;
309 return IPMI_CC_UNSPECIFIED_ERROR;
310 }
311
312 auto methodCall = bus.new_method_call(service.c_str(),
313 (*iter).c_str(),
314 ipmi::sel::logDeleteIntf,
315 "Delete");
316 auto reply = bus.call(methodCall);
317 if (reply.is_method_error())
318 {
319 *data_len = 0;
320 return IPMI_CC_UNSPECIFIED_ERROR;
321 }
322
323 // Invalidate the cache of dbus entry objects.
324 cache::paths.clear();
325 memcpy(response, &delRecordID, sizeof(delRecordID));
326 *data_len = sizeof(delRecordID);
327
328 return IPMI_CC_OK;
329}
330
Tom Joseph2f05bb52017-06-30 19:14:49 +0530331ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
332 ipmi_response_t response, ipmi_data_len_t data_len,
333 ipmi_context_t context)
334{
335 auto requestData = reinterpret_cast<const ipmi::sel::ClearSELRequest*>
336 (request);
337
338 if (g_sel_reserve != requestData->reservationID)
339 {
340 *data_len = 0;
341 return IPMI_CC_INVALID_RESERVATION_ID;
342 }
343
344 if (requestData->charC != 'C' ||
345 requestData->charL != 'L' ||
346 requestData->charR != 'R')
347 {
348 *data_len = 0;
349 return IPMI_CC_INVALID_FIELD_REQUEST;
350 }
351
352 uint8_t eraseProgress = ipmi::sel::eraseComplete;
353
354 /*
355 * Erasure status cannot be fetched from DBUS, so always return erasure
356 * status as `erase completed`.
357 */
358 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
359 {
360 memcpy(response, &eraseProgress, sizeof(eraseProgress));
361 *data_len = sizeof(eraseProgress);
362 return IPMI_CC_OK;
363 }
364
365 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
366 auto depth = 0;
367
368 auto mapperCall = bus.new_method_call(ipmi::sel::mapperBusName,
369 ipmi::sel::mapperObjPath,
370 ipmi::sel::mapperIntf,
371 "GetSubTreePaths");
372 mapperCall.append(ipmi::sel::logBasePath);
373 mapperCall.append(depth);
374 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
375
376 auto reply = bus.call(mapperCall);
377 if (reply.is_method_error())
378 {
379 memcpy(response, &eraseProgress, sizeof(eraseProgress));
380 *data_len = sizeof(eraseProgress);
381 return IPMI_CC_OK;
382 }
383
384 ipmi::sel::ObjectPaths objectPaths;
385 reply.read(objectPaths);
386 if (objectPaths.empty())
387 {
388 memcpy(response, &eraseProgress, sizeof(eraseProgress));
389 *data_len = sizeof(eraseProgress);
390 return IPMI_CC_OK;
391 }
392
393 std::string service;
394
395 try
396 {
397 service = ipmi::getService(bus,
398 ipmi::sel::logDeleteIntf,
399 objectPaths.front());
400 }
401 catch (const std::runtime_error& e)
402 {
403 log<level::ERR>(e.what());
404 *data_len = 0;
405 return IPMI_CC_UNSPECIFIED_ERROR;
406 }
407
408 for (const auto& iter : objectPaths)
409 {
410 auto methodCall = bus.new_method_call(service.c_str(),
411 iter.c_str(),
412 ipmi::sel::logDeleteIntf,
413 "Delete");
414
415 auto reply = bus.call(methodCall);
416 if (reply.is_method_error())
417 {
418 *data_len = 0;
419 return IPMI_CC_UNSPECIFIED_ERROR;
420 }
421 }
422
423 // Invalidate the cache of dbus entry objects.
424 cache::paths.clear();
425 memcpy(response, &eraseProgress, sizeof(eraseProgress));
426 *data_len = sizeof(eraseProgress);
427 return IPMI_CC_OK;
428}
429
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500430ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
431 ipmi_request_t request, ipmi_response_t response,
432 ipmi_data_len_t data_len, ipmi_context_t context)
433{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530434 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530435 uint64_t host_time_usec = 0;
436 uint32_t resp = 0;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500437
438 printf("IPMI Handling GET-SEL-TIME\n");
439
Lei YUe8939392017-06-15 10:45:05 +0800440 try
441 {
442 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
443 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
444 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530445
Lei YUe8939392017-06-15 10:45:05 +0800446 // Get host time
447 auto method = bus.new_method_call(service.c_str(),
448 HOST_TIME_PATH,
449 DBUS_PROPERTIES,
450 "Get");
451
452 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
453 auto reply = bus.call(method);
454 if (reply.is_method_error())
455 {
456 log<level::ERR>("Error getting time",
457 entry("SERVICE=%s", service.c_str()),
458 entry("PATH=%s", HOST_TIME_PATH));
459 return IPMI_CC_UNSPECIFIED_ERROR;
460 }
461 reply.read(value);
462 host_time_usec = value.get<uint64_t>();
463 }
464 catch (InternalFailure& e)
465 {
466 log<level::ERR>(e.what());
467 return IPMI_CC_UNSPECIFIED_ERROR;
468 }
469 catch (const std::runtime_error& e)
470 {
471 log<level::ERR>(e.what());
472 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530473 }
474
Lei YUe8939392017-06-15 10:45:05 +0800475 printf("Host time: %" PRIu64 ", %s",
476 host_time_usec, getTimeString(host_time_usec));
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530477
478 // Time is really long int but IPMI wants just uint32. This works okay until
479 // the number of seconds since 1970 overflows uint32 size.. Still a whole
480 // lot of time here to even think about that.
481 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
482 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530483
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500484 // From the IPMI Spec 2.0, response should be a 32-bit value
485 *data_len = sizeof(resp);
486
487 // Pack the actual response
488 memcpy(response, &resp, *data_len);
489
Lei YUe8939392017-06-15 10:45:05 +0800490 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500491}
492
493ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
494 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500495 ipmi_data_len_t data_len, ipmi_context_t context)
496{
Lei YUe8939392017-06-15 10:45:05 +0800497 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530498 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800499 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530500 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500501
Lei YUe8939392017-06-15 10:45:05 +0800502 printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X], Data:[0x%X]\n",
503 netfn, cmd, secs);
Chris Austenb4f5b922015-10-13 12:44:43 -0500504
Lei YUe8939392017-06-15 10:45:05 +0800505 secs = le32toh(secs);
506 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600507
Lei YUe8939392017-06-15 10:45:05 +0800508 printf("To Set host time: %" PRIu64 ", %s",
509 usec.count(), getTimeString(usec.count()));
510
511 try
512 {
513 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
514 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
515 sdbusplus::message::variant<uint64_t> value{usec.count()};
516
517 // Set host time
518 auto method = bus.new_method_call(service.c_str(),
519 HOST_TIME_PATH,
520 DBUS_PROPERTIES,
521 "Set");
522
523 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
524 auto reply = bus.call(method);
525 if (reply.is_method_error())
526 {
527 log<level::ERR>("Error setting time",
528 entry("SERVICE=%s", service.c_str()),
529 entry("PATH=%s", HOST_TIME_PATH));
530 rc = IPMI_CC_UNSPECIFIED_ERROR;
531 }
Norman James82330442015-11-19 16:53:26 -0600532 }
Lei YUe8939392017-06-15 10:45:05 +0800533 catch (InternalFailure& e)
534 {
535 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530536 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530537 }
Lei YUe8939392017-06-15 10:45:05 +0800538 catch (const std::runtime_error& e)
539 {
540 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600541 rc = IPMI_CC_UNSPECIFIED_ERROR;
542 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530543
Chris Austenb4f5b922015-10-13 12:44:43 -0500544 return rc;
545}
546
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500547ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
548 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500549 ipmi_data_len_t data_len, ipmi_context_t context)
550{
Chris Austenb4f5b922015-10-13 12:44:43 -0500551 ipmi_ret_t rc = IPMI_CC_OK;
552
Nan Li36c0cb62016-03-31 11:16:08 +0800553 // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
554 if( ++g_sel_reserve == 0)
555 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500556
Nan Li36c0cb62016-03-31 11:16:08 +0800557 printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
Chris Austen41a4b312015-10-25 03:45:42 -0500558
Chris Austenb4f5b922015-10-13 12:44:43 -0500559 *data_len = sizeof(g_sel_reserve);
560
561 // Pack the actual response
562 memcpy(response, &g_sel_reserve, *data_len);
563
564 return rc;
565}
566
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500567ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
568 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500569 ipmi_data_len_t data_len, ipmi_context_t context)
570{
571
572 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austen41a4b312015-10-25 03:45:42 -0500573 ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
574 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500575
Chris Austen313d95b2015-10-31 12:55:30 -0500576 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500577
578 printf("IPMI Handling ADD-SEL for record 0x%04x\n", recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500579
580 *data_len = sizeof(g_sel_reserve);
581
582 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600583 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500584
Tom Josephb647d5b2017-10-31 17:25:33 +0530585 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
586 // a maintenance procedure associated with eSEL record.
587 static constexpr auto procedureType = 0xDE;
588 if (p->recordtype == procedureType)
589 {
590 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
591 // procedure number.
592 createProcedureLogEntry(p->sensortype);
593 }
594 else
595 {
596 send_esel(recordid);
597 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500598
599 return rc;
600}
601
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500602//Read FRU info area
603ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
604 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
605 ipmi_response_t response, ipmi_data_len_t data_len,
606 ipmi_context_t context)
607{
608 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500609 const FruInvenAreaInfoRequest* reqptr =
610 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
611 try
612 {
613 const auto& fruArea = getFruAreaData(reqptr->fruID);
614 auto size = static_cast<uint16_t>(fruArea.size());
615 FruInvenAreaInfoResponse resp;
616 resp.sizems = size >> 8;
617 resp.sizels = size;
618 resp.access = static_cast<uint8_t>(AccessMode::bytes);
619
620 *data_len = sizeof(resp);
621
622 // Pack the actual response
623 memcpy(response, &resp, *data_len);
624 }
625 catch(const InternalFailure& e)
626 {
627 rc = IPMI_CC_UNSPECIFIED_ERROR;
628 *data_len = 0;
629 log<level::ERR>(e.what());
630 report<InternalFailure>();
631 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500632 return rc;
633}
634
635//Read FRU data
636ipmi_ret_t ipmi_storage_read_fru_data(
637 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
638 ipmi_response_t response, ipmi_data_len_t data_len,
639 ipmi_context_t context)
640{
641 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500642 const ReadFruDataRequest* reqptr =
643 reinterpret_cast<const ReadFruDataRequest*>(request);
644 auto offset =
645 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
646 try
647 {
648 const auto& fruArea = getFruAreaData(reqptr->fruID);
649 auto size = fruArea.size();
650 if ((offset + reqptr->count) > size)
651 {
652 log<level::ERR>("Invalid offset and count",
Gunnar Millse4050f22017-10-19 16:36:45 -0500653 entry("OFFSET=%s", offset),
654 entry("COUNT=%s", reqptr->count),
655 entry("SIZE_OF_FRU_AREA=%s", size));
Marri Devender Raocac383b2017-07-03 13:24:27 -0500656 return IPMI_CC_INVALID;
657 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530658
659 // Write the count of requested data.
660 auto buff = static_cast<uint8_t *>(response);
661 *buff = reqptr->count;
662 buff++;
663
664 std::copy((fruArea.begin() + offset),
665 (fruArea.begin() + offset + reqptr->count),
666 buff);
667
668 *data_len = reqptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500669 }
670 catch (const InternalFailure& e)
671 {
672 rc = IPMI_CC_UNSPECIFIED_ERROR;
673 *data_len = 0;
674 log<level::ERR>(e.what());
675 report<InternalFailure>();
676 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500677 return rc;
678}
679
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600680ipmi_ret_t ipmi_get_repository_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
681 ipmi_request_t request, ipmi_response_t response,
682 ipmi_data_len_t data_len, ipmi_context_t context)
683{
684 constexpr auto sdrVersion = 0x51;
685 auto responseData =
686 reinterpret_cast<GetRepositoryInfoResponse*>(response);
687
688 memset(responseData, 0 , sizeof(GetRepositoryInfoResponse));
689
690 responseData->sdrVersion = sdrVersion;
691
692 uint16_t records = frus.size() + sensors.size();
693 responseData->recordCountMs = records >> 8;
694 responseData->recordCountLs = records;
695
696 responseData->freeSpace[0] = 0xFF;
697 responseData->freeSpace[1] = 0xFF;
698
699 *data_len = sizeof(GetRepositoryInfoResponse);
700
701 return IPMI_CC_OK;
702}
Chris Austenb4f5b922015-10-13 12:44:43 -0500703
Chris Austenb4f5b922015-10-13 12:44:43 -0500704void register_netfn_storage_functions()
705{
Tom05732372016-09-06 17:21:23 +0530706 // <Wildcard Command>
Chris Austenb4f5b922015-10-13 12:44:43 -0500707 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530708 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
709 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500710
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530711 // <Get SEL Info>
712 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO);
713 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, getSELInfo,
714 PRIVILEGE_USER);
715
Tom05732372016-09-06 17:21:23 +0530716 // <Get SEL Time>
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500717 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530718 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
719 PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500720
Tom05732372016-09-06 17:21:23 +0530721 // <Set SEL Time>
Chris Austenb4f5b922015-10-13 12:44:43 -0500722 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530723 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
724 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500725
Tom05732372016-09-06 17:21:23 +0530726 // <Reserve SEL>
Chris Austenb4f5b922015-10-13 12:44:43 -0500727 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL);
Tom05732372016-09-06 17:21:23 +0530728 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
729 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500730
Tom Josepha4953392017-06-30 19:09:47 +0530731 // <Get SEL Entry>
732 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY);
733 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL, getSELEntry,
734 PRIVILEGE_USER);
735
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530736 // <Delete SEL Entry>
737 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_DELETE_SEL);
738 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL, deleteSELEntry,
739 PRIVILEGE_OPERATOR);
740
Tom05732372016-09-06 17:21:23 +0530741 // <Add SEL Entry>
Chris Austenb4f5b922015-10-13 12:44:43 -0500742 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_ADD_SEL);
Tom05732372016-09-06 17:21:23 +0530743 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
744 PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530745 // <Clear SEL>
746 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL);
747 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
748 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500749 // <Get FRU Inventory Area Info>
750 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
751 IPMI_CMD_GET_FRU_INV_AREA_INFO);
752 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
753 ipmi_storage_get_fru_inv_area_info, PRIVILEGE_OPERATOR);
754
755 // <Add READ FRU Data
756 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
757 IPMI_CMD_READ_FRU_DATA);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500758 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
759 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500760
Dhruvaraj Subhashchandrane66c3b02018-02-07 01:21:56 -0600761 // <Get Repository Info>
762 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_REPOSITORY_INFO,
763 nullptr, ipmi_get_repository_info,
764 PRIVILEGE_USER);
765
Tom Joseph5ca50952018-02-22 00:33:38 +0530766 // <Reserve SDR Repository>
767 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SDR,
768 nullptr, ipmi_sen_reserve_sdr,
769 PRIVILEGE_USER);
770
771 // <Get SDR>
772 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SDR,
773 nullptr, ipmi_sen_get_sdr,
774 PRIVILEGE_USER);
775
Marri Devender Rao908f7502017-07-10 01:49:54 -0500776 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500777 return;
778}
779