blob: 6ae2f916fbbd1b98f13a02da4dfc4766ab50e410 [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
14#include "host-ipmid/ipmid-api.h"
15#include "read_fru_data.hpp"
16#include "selutility.hpp"
17#include "storageaddsel.h"
18#include "storagehandler.h"
19#include "utils.hpp"
20#include "xyz/openbmc_project/Common/error.hpp"
21
Chris Austen41a4b312015-10-25 03:45:42 -050022
Chris Austenb4f5b922015-10-13 12:44:43 -050023void register_netfn_storage_functions() __attribute__((constructor));
24
Chris Austenb4f5b922015-10-13 12:44:43 -050025unsigned int g_sel_time = 0xFFFFFFFF;
Nan Li36c0cb62016-03-31 11:16:08 +080026extern unsigned short g_sel_reserve;
Chris Austenb4f5b922015-10-13 12:44:43 -050027
Lei YUe8939392017-06-15 10:45:05 +080028namespace {
29constexpr auto TIME_INTERFACE = "xyz.openbmc_project.Time.EpochTime";
30constexpr auto HOST_TIME_PATH = "/xyz/openbmc_project/time/host";
31constexpr auto DBUS_PROPERTIES = "org.freedesktop.DBus.Properties";
32constexpr auto PROPERTY_ELAPSED= "Elapsed";
33
34const char* getTimeString(const uint64_t& usecSinceEpoch)
35{
36 using namespace std::chrono;
37 system_clock::time_point tp{microseconds(usecSinceEpoch)};
38 auto t = system_clock::to_time_t(tp);
39 return std::ctime(&t);
40}
41}
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +053042
Tom Joseph6f7deaa2017-06-30 19:03:54 +053043namespace cache
44{
45 /*
46 * This cache contains the object paths of the logging entries sorted in the
47 * order of the filename(numeric order). The cache is initialized by
48 * invoking readLoggingObjectPaths with the cache as the parameter. The
49 * cache is invoked in the execution of the Get SEL info and Delete SEL
50 * entry command. The Get SEL Info command is typically invoked before the
51 * Get SEL entry command, so the cache is utilized for responding to Get SEL
52 * entry command. The cache is invalidated by clearing after Delete SEL
53 * entry and Clear SEL command.
54 */
55 ipmi::sel::ObjectPaths paths;
56
57} // namespace objectPathsCache
58
59using InternalFailure =
60 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
61using namespace phosphor::logging;
Marri Devender Raocac383b2017-07-03 13:24:27 -050062using namespace ipmi::fru;
63
64/**
65 * @enum Device access mode
66 */
67enum class AccessMode
68{
69 bytes, ///< Device is accessed by bytes
70 words ///< Device is accessed by words
71};
72
Tom Joseph6f7deaa2017-06-30 19:03:54 +053073
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -050074ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
75 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -050076 ipmi_data_len_t data_len, ipmi_context_t context)
77{
78 printf("Handling STORAGE WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
79 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +080080 ipmi_ret_t rc = IPMI_CC_INVALID;
Chris Austenb4f5b922015-10-13 12:44:43 -050081 *data_len = 0;
82 return rc;
83}
84
Tom Joseph6f7deaa2017-06-30 19:03:54 +053085ipmi_ret_t getSELInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
86 ipmi_request_t request, ipmi_response_t response,
87 ipmi_data_len_t data_len, ipmi_context_t context)
88{
89 std::vector<uint8_t> outPayload(sizeof(ipmi::sel::GetSELInfoResponse));
90 auto responseData = reinterpret_cast<ipmi::sel::GetSELInfoResponse*>
91 (outPayload.data());
92
93 responseData->selVersion = ipmi::sel::selVersion;
94 // Last erase timestamp is not available from log manager.
95 responseData->eraseTimeStamp = ipmi::sel::invalidTimeStamp;
96 responseData->operationSupport = ipmi::sel::operationSupport;
97
98 ipmi::sel::readLoggingObjectPaths(cache::paths);
99 responseData->entries = 0;
100 responseData->addTimeStamp = ipmi::sel::invalidTimeStamp;
101
102 if (!cache::paths.empty())
103 {
104 responseData->entries = static_cast<uint16_t>(cache::paths.size());
105
106 try
107 {
108 responseData->addTimeStamp = static_cast<uint32_t>(
109 (ipmi::sel::getEntryTimeStamp(cache::paths.back())
110 .count()));
111 }
112 catch (InternalFailure& e)
113 {
114 }
115 catch (const std::runtime_error& e)
116 {
117 log<level::ERR>(e.what());
118 }
119 }
120
121 memcpy(response, outPayload.data(), outPayload.size());
122 *data_len = outPayload.size();
123
124 return IPMI_CC_OK;
125}
126
Tom Josepha4953392017-06-30 19:09:47 +0530127ipmi_ret_t getSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
128 ipmi_request_t request, ipmi_response_t response,
129 ipmi_data_len_t data_len, ipmi_context_t context)
130{
131 auto requestData = reinterpret_cast<const ipmi::sel::GetSELEntryRequest*>
132 (request);
133
134 if (requestData->reservationID != 0)
135 {
136 if (g_sel_reserve != requestData->reservationID)
137 {
138 *data_len = 0;
139 return IPMI_CC_INVALID_RESERVATION_ID;
140 }
141 }
142
143 if (cache::paths.empty())
144 {
145 *data_len = 0;
146 return IPMI_CC_SENSOR_INVALID;
147 }
148
149 ipmi::sel::ObjectPaths::const_iterator iter;
150
151 // Check for the requested SEL Entry.
152 if (requestData->selRecordID == ipmi::sel::firstEntry)
153 {
154 iter = cache::paths.begin();
155 }
156 else if (requestData->selRecordID == ipmi::sel::lastEntry)
157 {
158 iter = cache::paths.end();
159 }
160 else
161 {
162 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
163 std::to_string(requestData->selRecordID);
164
165 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
166 if (iter == cache::paths.end())
167 {
168 *data_len = 0;
169 return IPMI_CC_SENSOR_INVALID;
170 }
171 }
172
173 ipmi::sel::GetSELEntryResponse record {};
174
175 // Convert the log entry into SEL record.
176 try
177 {
178 record = ipmi::sel::convertLogEntrytoSEL(*iter);
179 }
180 catch (InternalFailure& e)
181 {
182 *data_len = 0;
183 return IPMI_CC_UNSPECIFIED_ERROR;
184 }
185 catch (const std::runtime_error& e)
186 {
187 log<level::ERR>(e.what());
188 *data_len = 0;
189 return IPMI_CC_UNSPECIFIED_ERROR;
190 }
191
192
193 // Identify the next SEL record ID
194 if(iter != cache::paths.end())
195 {
196 ++iter;
197 if (iter == cache::paths.end())
198 {
199 record.nextRecordID = ipmi::sel::lastEntry;
200 }
201 else
202 {
203 namespace fs = std::experimental::filesystem;
204 fs::path path(*iter);
205 record.nextRecordID = static_cast<uint16_t>
206 (std::stoul(std::string(path.filename().c_str())));
207 }
208 }
209 else
210 {
211 record.nextRecordID = ipmi::sel::lastEntry;
212 }
213
214 if (requestData->readLength == ipmi::sel::entireRecord)
215 {
216 memcpy(response, &record, sizeof(record));
217 *data_len = sizeof(record);
218 }
219 else
220 {
221 if (requestData->offset >= ipmi::sel::selRecordSize ||
222 requestData->readLength > ipmi::sel::selRecordSize)
223 {
224 *data_len = 0;
225 return IPMI_CC_INVALID_FIELD_REQUEST;
226 }
227
228 auto diff = ipmi::sel::selRecordSize - requestData->offset;
229 auto readLength = std::min(diff,
230 static_cast<int>(requestData->readLength));
231
232 memcpy(response, &record.nextRecordID, sizeof(record.nextRecordID));
233 memcpy(static_cast<uint8_t*>(response) + sizeof(record.nextRecordID),
234 &record.recordID + requestData->offset, readLength);
235 *data_len = sizeof(record.nextRecordID) + readLength;
236 }
237
238 return IPMI_CC_OK;
239}
240
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530241ipmi_ret_t deleteSELEntry(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
242 ipmi_request_t request, ipmi_response_t response,
243 ipmi_data_len_t data_len, ipmi_context_t context)
244{
245 namespace fs = std::experimental::filesystem;
246 auto requestData = reinterpret_cast<const ipmi::sel::DeleteSELEntryRequest*>
247 (request);
248
249 if (g_sel_reserve != requestData->reservationID)
250 {
251 *data_len = 0;
252 return IPMI_CC_INVALID_RESERVATION_ID;
253 }
254
255 ipmi::sel::readLoggingObjectPaths(cache::paths);
256
257 if (cache::paths.empty())
258 {
259 *data_len = 0;
260 return IPMI_CC_SENSOR_INVALID;
261 }
262
263 ipmi::sel::ObjectPaths::const_iterator iter;
264 uint16_t delRecordID = 0;
265
266 if (requestData->selRecordID == ipmi::sel::firstEntry)
267 {
268 iter = cache::paths.begin();
269 fs::path path(*iter);
270 delRecordID = static_cast<uint16_t>
271 (std::stoul(std::string(path.filename().c_str())));
272 }
273 else if (requestData->selRecordID == ipmi::sel::lastEntry)
274 {
275 iter = cache::paths.end();
276 fs::path path(*iter);
277 delRecordID = static_cast<uint16_t>
278 (std::stoul(std::string(path.filename().c_str())));
279 }
280 else
281 {
282 std::string objPath = std::string(ipmi::sel::logBasePath) + "/" +
283 std::to_string(requestData->selRecordID);
284
285 iter = std::find(cache::paths.begin(), cache::paths.end(), objPath);
286 if (iter == cache::paths.end())
287 {
288 *data_len = 0;
289 return IPMI_CC_SENSOR_INVALID;
290 }
291 delRecordID = requestData->selRecordID;
292 }
293
294 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
295 std::string service;
296
297 try
298 {
299 service = ipmi::getService(bus, ipmi::sel::logDeleteIntf, *iter);
300 }
301 catch (const std::runtime_error& e)
302 {
303 log<level::ERR>(e.what());
304 *data_len = 0;
305 return IPMI_CC_UNSPECIFIED_ERROR;
306 }
307
308 auto methodCall = bus.new_method_call(service.c_str(),
309 (*iter).c_str(),
310 ipmi::sel::logDeleteIntf,
311 "Delete");
312 auto reply = bus.call(methodCall);
313 if (reply.is_method_error())
314 {
315 *data_len = 0;
316 return IPMI_CC_UNSPECIFIED_ERROR;
317 }
318
319 // Invalidate the cache of dbus entry objects.
320 cache::paths.clear();
321 memcpy(response, &delRecordID, sizeof(delRecordID));
322 *data_len = sizeof(delRecordID);
323
324 return IPMI_CC_OK;
325}
326
Tom Joseph2f05bb52017-06-30 19:14:49 +0530327ipmi_ret_t clearSEL(ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
328 ipmi_response_t response, ipmi_data_len_t data_len,
329 ipmi_context_t context)
330{
331 auto requestData = reinterpret_cast<const ipmi::sel::ClearSELRequest*>
332 (request);
333
334 if (g_sel_reserve != requestData->reservationID)
335 {
336 *data_len = 0;
337 return IPMI_CC_INVALID_RESERVATION_ID;
338 }
339
340 if (requestData->charC != 'C' ||
341 requestData->charL != 'L' ||
342 requestData->charR != 'R')
343 {
344 *data_len = 0;
345 return IPMI_CC_INVALID_FIELD_REQUEST;
346 }
347
348 uint8_t eraseProgress = ipmi::sel::eraseComplete;
349
350 /*
351 * Erasure status cannot be fetched from DBUS, so always return erasure
352 * status as `erase completed`.
353 */
354 if (requestData->eraseOperation == ipmi::sel::getEraseStatus)
355 {
356 memcpy(response, &eraseProgress, sizeof(eraseProgress));
357 *data_len = sizeof(eraseProgress);
358 return IPMI_CC_OK;
359 }
360
361 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
362 auto depth = 0;
363
364 auto mapperCall = bus.new_method_call(ipmi::sel::mapperBusName,
365 ipmi::sel::mapperObjPath,
366 ipmi::sel::mapperIntf,
367 "GetSubTreePaths");
368 mapperCall.append(ipmi::sel::logBasePath);
369 mapperCall.append(depth);
370 mapperCall.append(ipmi::sel::ObjectPaths({ipmi::sel::logEntryIntf}));
371
372 auto reply = bus.call(mapperCall);
373 if (reply.is_method_error())
374 {
375 memcpy(response, &eraseProgress, sizeof(eraseProgress));
376 *data_len = sizeof(eraseProgress);
377 return IPMI_CC_OK;
378 }
379
380 ipmi::sel::ObjectPaths objectPaths;
381 reply.read(objectPaths);
382 if (objectPaths.empty())
383 {
384 memcpy(response, &eraseProgress, sizeof(eraseProgress));
385 *data_len = sizeof(eraseProgress);
386 return IPMI_CC_OK;
387 }
388
389 std::string service;
390
391 try
392 {
393 service = ipmi::getService(bus,
394 ipmi::sel::logDeleteIntf,
395 objectPaths.front());
396 }
397 catch (const std::runtime_error& e)
398 {
399 log<level::ERR>(e.what());
400 *data_len = 0;
401 return IPMI_CC_UNSPECIFIED_ERROR;
402 }
403
404 for (const auto& iter : objectPaths)
405 {
406 auto methodCall = bus.new_method_call(service.c_str(),
407 iter.c_str(),
408 ipmi::sel::logDeleteIntf,
409 "Delete");
410
411 auto reply = bus.call(methodCall);
412 if (reply.is_method_error())
413 {
414 *data_len = 0;
415 return IPMI_CC_UNSPECIFIED_ERROR;
416 }
417 }
418
419 // Invalidate the cache of dbus entry objects.
420 cache::paths.clear();
421 memcpy(response, &eraseProgress, sizeof(eraseProgress));
422 *data_len = sizeof(eraseProgress);
423 return IPMI_CC_OK;
424}
425
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500426ipmi_ret_t ipmi_storage_get_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
427 ipmi_request_t request, ipmi_response_t response,
428 ipmi_data_len_t data_len, ipmi_context_t context)
429{
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530430 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530431 uint64_t host_time_usec = 0;
432 uint32_t resp = 0;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500433
434 printf("IPMI Handling GET-SEL-TIME\n");
435
Lei YUe8939392017-06-15 10:45:05 +0800436 try
437 {
438 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
439 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
440 sdbusplus::message::variant<uint64_t> value;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530441
Lei YUe8939392017-06-15 10:45:05 +0800442 // Get host time
443 auto method = bus.new_method_call(service.c_str(),
444 HOST_TIME_PATH,
445 DBUS_PROPERTIES,
446 "Get");
447
448 method.append(TIME_INTERFACE, PROPERTY_ELAPSED);
449 auto reply = bus.call(method);
450 if (reply.is_method_error())
451 {
452 log<level::ERR>("Error getting time",
453 entry("SERVICE=%s", service.c_str()),
454 entry("PATH=%s", HOST_TIME_PATH));
455 return IPMI_CC_UNSPECIFIED_ERROR;
456 }
457 reply.read(value);
458 host_time_usec = value.get<uint64_t>();
459 }
460 catch (InternalFailure& e)
461 {
462 log<level::ERR>(e.what());
463 return IPMI_CC_UNSPECIFIED_ERROR;
464 }
465 catch (const std::runtime_error& e)
466 {
467 log<level::ERR>(e.what());
468 return IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530469 }
470
Lei YUe8939392017-06-15 10:45:05 +0800471 printf("Host time: %" PRIu64 ", %s",
472 host_time_usec, getTimeString(host_time_usec));
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530473
474 // Time is really long int but IPMI wants just uint32. This works okay until
475 // the number of seconds since 1970 overflows uint32 size.. Still a whole
476 // lot of time here to even think about that.
477 resp = duration_cast<seconds>(microseconds(host_time_usec)).count();
478 resp = htole32(resp);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530479
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500480 // From the IPMI Spec 2.0, response should be a 32-bit value
481 *data_len = sizeof(resp);
482
483 // Pack the actual response
484 memcpy(response, &resp, *data_len);
485
Lei YUe8939392017-06-15 10:45:05 +0800486 return IPMI_CC_OK;
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500487}
488
489ipmi_ret_t ipmi_storage_set_sel_time(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
490 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500491 ipmi_data_len_t data_len, ipmi_context_t context)
492{
Lei YUe8939392017-06-15 10:45:05 +0800493 using namespace std::chrono;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530494 ipmi_ret_t rc = IPMI_CC_OK;
Lei YUe8939392017-06-15 10:45:05 +0800495 uint32_t secs = *static_cast<uint32_t*>(request);
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530496 *data_len = 0;
Chris Austenb4f5b922015-10-13 12:44:43 -0500497
Lei YUe8939392017-06-15 10:45:05 +0800498 printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X], Data:[0x%X]\n",
499 netfn, cmd, secs);
Chris Austenb4f5b922015-10-13 12:44:43 -0500500
Lei YUe8939392017-06-15 10:45:05 +0800501 secs = le32toh(secs);
502 microseconds usec{seconds(secs)};
Norman James82330442015-11-19 16:53:26 -0600503
Lei YUe8939392017-06-15 10:45:05 +0800504 printf("To Set host time: %" PRIu64 ", %s",
505 usec.count(), getTimeString(usec.count()));
506
507 try
508 {
509 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
510 auto service = ipmi::getService(bus, TIME_INTERFACE, HOST_TIME_PATH);
511 sdbusplus::message::variant<uint64_t> value{usec.count()};
512
513 // Set host time
514 auto method = bus.new_method_call(service.c_str(),
515 HOST_TIME_PATH,
516 DBUS_PROPERTIES,
517 "Set");
518
519 method.append(TIME_INTERFACE, PROPERTY_ELAPSED, value);
520 auto reply = bus.call(method);
521 if (reply.is_method_error())
522 {
523 log<level::ERR>("Error setting time",
524 entry("SERVICE=%s", service.c_str()),
525 entry("PATH=%s", HOST_TIME_PATH));
526 rc = IPMI_CC_UNSPECIFIED_ERROR;
527 }
Norman James82330442015-11-19 16:53:26 -0600528 }
Lei YUe8939392017-06-15 10:45:05 +0800529 catch (InternalFailure& e)
530 {
531 log<level::ERR>(e.what());
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530532 rc = IPMI_CC_UNSPECIFIED_ERROR;
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530533 }
Lei YUe8939392017-06-15 10:45:05 +0800534 catch (const std::runtime_error& e)
535 {
536 log<level::ERR>(e.what());
Norman James82330442015-11-19 16:53:26 -0600537 rc = IPMI_CC_UNSPECIFIED_ERROR;
538 }
Vishwanatha Subbanna5fba7a62016-09-01 14:06:07 +0530539
Chris Austenb4f5b922015-10-13 12:44:43 -0500540 return rc;
541}
542
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500543ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
544 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500545 ipmi_data_len_t data_len, ipmi_context_t context)
546{
Chris Austenb4f5b922015-10-13 12:44:43 -0500547 ipmi_ret_t rc = IPMI_CC_OK;
548
Nan Li36c0cb62016-03-31 11:16:08 +0800549 // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
550 if( ++g_sel_reserve == 0)
551 g_sel_reserve = 1;
Chris Austenb4f5b922015-10-13 12:44:43 -0500552
Nan Li36c0cb62016-03-31 11:16:08 +0800553 printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
Chris Austen41a4b312015-10-25 03:45:42 -0500554
Chris Austenb4f5b922015-10-13 12:44:43 -0500555 *data_len = sizeof(g_sel_reserve);
556
557 // Pack the actual response
558 memcpy(response, &g_sel_reserve, *data_len);
559
560 return rc;
561}
562
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500563ipmi_ret_t ipmi_storage_add_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
564 ipmi_request_t request, ipmi_response_t response,
Chris Austenb4f5b922015-10-13 12:44:43 -0500565 ipmi_data_len_t data_len, ipmi_context_t context)
566{
567
568 ipmi_ret_t rc = IPMI_CC_OK;
Chris Austen41a4b312015-10-25 03:45:42 -0500569 ipmi_add_sel_request_t *p = (ipmi_add_sel_request_t*) request;
570 uint16_t recordid;
Chris Austenb4f5b922015-10-13 12:44:43 -0500571
Chris Austen313d95b2015-10-31 12:55:30 -0500572 recordid = ((uint16_t)p->eventdata[1] << 8) | p->eventdata[2];
Chris Austen41a4b312015-10-25 03:45:42 -0500573
574 printf("IPMI Handling ADD-SEL for record 0x%04x\n", recordid);
Chris Austenb4f5b922015-10-13 12:44:43 -0500575
576 *data_len = sizeof(g_sel_reserve);
577
578 // Pack the actual response
Chris Austen7cc33322015-11-11 00:20:22 -0600579 memcpy(response, &p->eventdata[1], 2);
Chris Austenb4f5b922015-10-13 12:44:43 -0500580
Tom Josephb647d5b2017-10-31 17:25:33 +0530581 // Hostboot sends SEL with OEM record type 0xDE to indicate that there is
582 // a maintenance procedure associated with eSEL record.
583 static constexpr auto procedureType = 0xDE;
584 if (p->recordtype == procedureType)
585 {
586 // In the OEM record type 0xDE, byte 11 in the SEL record indicate the
587 // procedure number.
588 createProcedureLogEntry(p->sensortype);
589 }
590 else
591 {
592 send_esel(recordid);
593 }
Chris Austenb4f5b922015-10-13 12:44:43 -0500594
595 return rc;
596}
597
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500598//Read FRU info area
599ipmi_ret_t ipmi_storage_get_fru_inv_area_info(
600 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
601 ipmi_response_t response, ipmi_data_len_t data_len,
602 ipmi_context_t context)
603{
604 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500605 const FruInvenAreaInfoRequest* reqptr =
606 reinterpret_cast<const FruInvenAreaInfoRequest*>(request);
607 try
608 {
609 const auto& fruArea = getFruAreaData(reqptr->fruID);
610 auto size = static_cast<uint16_t>(fruArea.size());
611 FruInvenAreaInfoResponse resp;
612 resp.sizems = size >> 8;
613 resp.sizels = size;
614 resp.access = static_cast<uint8_t>(AccessMode::bytes);
615
616 *data_len = sizeof(resp);
617
618 // Pack the actual response
619 memcpy(response, &resp, *data_len);
620 }
621 catch(const InternalFailure& e)
622 {
623 rc = IPMI_CC_UNSPECIFIED_ERROR;
624 *data_len = 0;
625 log<level::ERR>(e.what());
626 report<InternalFailure>();
627 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500628 return rc;
629}
630
631//Read FRU data
632ipmi_ret_t ipmi_storage_read_fru_data(
633 ipmi_netfn_t netfn, ipmi_cmd_t cmd, ipmi_request_t request,
634 ipmi_response_t response, ipmi_data_len_t data_len,
635 ipmi_context_t context)
636{
637 ipmi_ret_t rc = IPMI_CC_OK;
Marri Devender Raocac383b2017-07-03 13:24:27 -0500638 const ReadFruDataRequest* reqptr =
639 reinterpret_cast<const ReadFruDataRequest*>(request);
640 auto offset =
641 static_cast<uint16_t>(reqptr->offsetMS << 8 | reqptr->offsetLS);
642 try
643 {
644 const auto& fruArea = getFruAreaData(reqptr->fruID);
645 auto size = fruArea.size();
646 if ((offset + reqptr->count) > size)
647 {
648 log<level::ERR>("Invalid offset and count",
Gunnar Millse4050f22017-10-19 16:36:45 -0500649 entry("OFFSET=%s", offset),
650 entry("COUNT=%s", reqptr->count),
651 entry("SIZE_OF_FRU_AREA=%s", size));
Marri Devender Raocac383b2017-07-03 13:24:27 -0500652 return IPMI_CC_INVALID;
653 }
Ratan Gupta2848d602018-01-31 20:39:20 +0530654
655 // Write the count of requested data.
656 auto buff = static_cast<uint8_t *>(response);
657 *buff = reqptr->count;
658 buff++;
659
660 std::copy((fruArea.begin() + offset),
661 (fruArea.begin() + offset + reqptr->count),
662 buff);
663
664 *data_len = reqptr->count + 1; // additional one byte for count
Marri Devender Raocac383b2017-07-03 13:24:27 -0500665 }
666 catch (const InternalFailure& e)
667 {
668 rc = IPMI_CC_UNSPECIFIED_ERROR;
669 *data_len = 0;
670 log<level::ERR>(e.what());
671 report<InternalFailure>();
672 }
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500673 return rc;
674}
675
Chris Austenb4f5b922015-10-13 12:44:43 -0500676
Chris Austenb4f5b922015-10-13 12:44:43 -0500677void register_netfn_storage_functions()
678{
Tom05732372016-09-06 17:21:23 +0530679 // <Wildcard Command>
Chris Austenb4f5b922015-10-13 12:44:43 -0500680 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +0530681 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_WILDCARD, NULL, ipmi_storage_wildcard,
682 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500683
Tom Joseph6f7deaa2017-06-30 19:03:54 +0530684 // <Get SEL Info>
685 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO);
686 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_INFO, NULL, getSELInfo,
687 PRIVILEGE_USER);
688
Tom05732372016-09-06 17:21:23 +0530689 // <Get SEL Time>
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500690 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530691 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_TIME, NULL, ipmi_storage_get_sel_time,
692 PRIVILEGE_USER);
Adriana Kobylak8e30f2a2015-10-20 10:23:51 -0500693
Tom05732372016-09-06 17:21:23 +0530694 // <Set SEL Time>
Chris Austenb4f5b922015-10-13 12:44:43 -0500695 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME);
Tom05732372016-09-06 17:21:23 +0530696 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_SET_SEL_TIME, NULL, ipmi_storage_set_sel_time,
697 PRIVILEGE_OPERATOR);
Chris Austenb4f5b922015-10-13 12:44:43 -0500698
Tom05732372016-09-06 17:21:23 +0530699 // <Reserve SEL>
Chris Austenb4f5b922015-10-13 12:44:43 -0500700 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL);
Tom05732372016-09-06 17:21:23 +0530701 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_RESERVE_SEL, NULL, ipmi_storage_reserve_sel,
702 PRIVILEGE_USER);
Chris Austenb4f5b922015-10-13 12:44:43 -0500703
Tom Josepha4953392017-06-30 19:09:47 +0530704 // <Get SEL Entry>
705 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY);
706 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_SEL_ENTRY, NULL, getSELEntry,
707 PRIVILEGE_USER);
708
Tom Joseph8f4a2aa2017-06-30 19:12:49 +0530709 // <Delete SEL Entry>
710 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_DELETE_SEL);
711 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_DELETE_SEL, NULL, deleteSELEntry,
712 PRIVILEGE_OPERATOR);
713
Tom05732372016-09-06 17:21:23 +0530714 // <Add SEL Entry>
Chris Austenb4f5b922015-10-13 12:44:43 -0500715 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_ADD_SEL);
Tom05732372016-09-06 17:21:23 +0530716 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_ADD_SEL, NULL, ipmi_storage_add_sel,
717 PRIVILEGE_OPERATOR);
Tom Joseph2f05bb52017-06-30 19:14:49 +0530718 // <Clear SEL>
719 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL);
720 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_CLEAR_SEL, NULL, clearSEL,
721 PRIVILEGE_OPERATOR);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500722 // <Get FRU Inventory Area Info>
723 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
724 IPMI_CMD_GET_FRU_INV_AREA_INFO);
725 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_GET_FRU_INV_AREA_INFO, NULL,
726 ipmi_storage_get_fru_inv_area_info, PRIVILEGE_OPERATOR);
727
728 // <Add READ FRU Data
729 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_STORAGE,
730 IPMI_CMD_READ_FRU_DATA);
Marri Devender Raofa7b4e22017-07-03 00:52:20 -0500731 ipmi_register_callback(NETFUN_STORAGE, IPMI_CMD_READ_FRU_DATA, NULL,
732 ipmi_storage_read_fru_data, PRIVILEGE_OPERATOR);
Marri Devender Raocac383b2017-07-03 13:24:27 -0500733
Marri Devender Rao908f7502017-07-10 01:49:54 -0500734 ipmi::fru::registerCallbackHandler();
Chris Austenb4f5b922015-10-13 12:44:43 -0500735 return;
736}
737