xref: /openbmc/fb-ipmi-oem/src/oemcommands.cpp (revision 778147da)
1 /*
2  * Copyright (c)  2018 Intel Corporation.
3  * Copyright (c)  2018-present Facebook.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "xyz/openbmc_project/Common/error.hpp"
19 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
20 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
21 #include <xyz/openbmc_project/Control/Boot/Type/server.hpp>
22 
23 #include <ipmid/api.hpp>
24 #include <ipmid/utils.hpp>
25 #include <commandutils.hpp>
26 #include <nlohmann/json.hpp>
27 #include <oemcommands.hpp>
28 #include <phosphor-logging/log.hpp>
29 #include <sdbusplus/bus.hpp>
30 
31 #include <ipmid/api.hpp>
32 #include <ipmid/api-types.hpp>
33 
34 #include <array>
35 #include <cstring>
36 #include <fstream>
37 #include <iomanip>
38 #include <iostream>
39 #include <sstream>
40 #include <string>
41 #include <vector>
42 
43 #define SIZE_IANA_ID 3
44 
45 namespace ipmi
46 {
47 
48 using namespace phosphor::logging;
49 
50 static void registerOEMFunctions() __attribute__((constructor));
51 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
52 static constexpr size_t maxFRUStringLength = 0x3F;
53 constexpr uint8_t cmdSetSystemGuid = 0xEF;
54 
55 int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*,
56                             uint8_t*);
57 int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*,
58                             uint8_t*);
59 ipmi_ret_t plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*,
60                                     uint8_t*);
61 ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*,
62                                    uint8_t*);
63 int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&);
64 
65 int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
66                std::vector<uint8_t>&);
67 
68 nlohmann::json oemData __attribute__((init_priority(101)));
69 
70 static constexpr size_t GUID_SIZE = 16;
71 // TODO Make offset and location runtime configurable to ensure we
72 // can make each define their own locations.
73 static constexpr off_t OFFSET_SYS_GUID = 0x17F0;
74 static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom";
75 
76 enum class LanParam : uint8_t
77 {
78     INPROGRESS = 0,
79     AUTHSUPPORT = 1,
80     AUTHENABLES = 2,
81     IP = 3,
82     IPSRC = 4,
83     MAC = 5,
84     SUBNET = 6,
85     GATEWAY = 12,
86     VLAN = 20,
87     CIPHER_SUITE_COUNT = 22,
88     CIPHER_SUITE_ENTRIES = 23,
89     IPV6 = 59,
90 };
91 
92 namespace network
93 {
94 
95 constexpr auto ROOT = "/xyz/openbmc_project/network";
96 constexpr auto SERVICE = "xyz.openbmc_project.Network";
97 constexpr auto IPV4_TYPE = "ipv4";
98 constexpr auto IPV6_TYPE = "ipv6";
99 constexpr auto IPV4_PREFIX = "169.254";
100 constexpr auto IPV6_PREFIX = "fe80";
101 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
102 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
103 
104 bool isLinkLocalIP(const std::string& address)
105 {
106     return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
107 }
108 
109 DbusObjectInfo getIPObject(sdbusplus::bus::bus& bus,
110                            const std::string& interface,
111                            const std::string& serviceRoot,
112                            const std::string& match)
113 {
114     auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, match);
115 
116     if (objectTree.empty())
117     {
118         log<level::ERR>("No Object has implemented the IP interface",
119                         entry("INTERFACE=%s", interface.c_str()));
120     }
121 
122     DbusObjectInfo objectInfo;
123 
124     for (auto& object : objectTree)
125     {
126         auto variant =
127             ipmi::getDbusProperty(bus, object.second.begin()->first,
128                                   object.first, IP_INTERFACE, "Address");
129 
130         objectInfo = std::make_pair(object.first, object.second.begin()->first);
131 
132         // if LinkLocalIP found look for Non-LinkLocalIP
133         if (isLinkLocalIP(std::get<std::string>(variant)))
134         {
135             continue;
136         }
137         else
138         {
139             break;
140         }
141     }
142     return objectInfo;
143 }
144 
145 } // namespace network
146 
147 namespace boot
148 {
149 
150 using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
151 using IpmiValue = uint8_t;
152 
153 std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
154     {0x0f, Source::Sources::Default},
155     {0x00, Source::Sources::RemovableMedia},
156     {0x01, Source::Sources::Network},
157     {0x02, Source::Sources::Disk},
158     {0x03, Source::Sources::ExternalMedia},
159     {0x09, Source::Sources::Network}};
160 
161 std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
162     {0x06, Mode::Modes::Setup}, {0x00, Mode::Modes::Regular}};
163 
164 std::map<IpmiValue, Type::Types> typeIpmiToDbus = {{0x00, Type::Types::Legacy},
165                                                    {0x01, Type::Types::EFI}};
166 
167 std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
168     {Source::Sources::Default, 0x0f},
169     {Source::Sources::RemovableMedia, 0x00},
170     {Source::Sources::Network, 0x01},
171     {Source::Sources::Disk, 0x02},
172     {Source::Sources::ExternalMedia, 0x03}};
173 
174 std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
175     {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, 0x00}};
176 
177 std::map<Type::Types, IpmiValue> typeDbusToIpmi = {{Type::Types::Legacy, 0x00},
178                                                    {Type::Types::EFI, 0x01}};
179 
180 static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
181 static constexpr auto bootSourceIntf =
182     "xyz.openbmc_project.Control.Boot.Source";
183 static constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type";
184 static constexpr auto bootSourceProp = "BootSource";
185 static constexpr auto bootModeProp = "BootMode";
186 static constexpr auto bootTypeProp = "BootType";
187 
188 auto instances(std::string s)
189 {
190     std::string delimiter = " ";
191     size_t pos = 0;
192     std::string token;
193     std::vector<std::string> host;
194 
195     while ((pos = s.find(delimiter)) != std::string::npos)
196     {
197         token = s.substr(0, pos);
198         host.push_back(token);
199         s.erase(0, pos + delimiter.length());
200     }
201     host.push_back(s);
202 
203     return host;
204 }
205 
206 std::optional<size_t> findHost(size_t id)
207 {
208     std::string str = INSTANCES;
209     size_t hostId;
210 
211     if (INSTANCES == "0")
212     {
213         hostId = id;
214     }
215     else
216     {
217         static const auto hosts = instances(str);
218         std::string num = std::to_string(id + 1);
219         auto instance = std::lower_bound(hosts.begin(), hosts.end(), num);
220 
221         if ((instance == hosts.end()) || (*instance != num))
222         {
223             return std::nullopt;
224         }
225         hostId = id + 1;
226     }
227 
228     return hostId;
229 }
230 
231 std::tuple<std::string, std::string> objPath(size_t id)
232 {
233     std::string hostName = "host" + std::to_string(id);
234     std::string bootObjPath =
235         "/xyz/openbmc_project/control/" + hostName + "/boot";
236     return std::make_tuple(std::move(bootObjPath), std::move(hostName));
237 }
238 
239 } // namespace boot
240 
241 //----------------------------------------------------------------------
242 // Helper functions for storing oem data
243 //----------------------------------------------------------------------
244 
245 void flushOemData()
246 {
247     std::ofstream file(JSON_OEM_DATA_FILE);
248     file << oemData;
249     file.close();
250     return;
251 }
252 
253 std::string bytesToStr(uint8_t* byte, int len)
254 {
255     std::stringstream ss;
256     int i;
257 
258     ss << std::hex;
259     for (i = 0; i < len; i++)
260     {
261         ss << std::setw(2) << std::setfill('0') << (int)byte[i];
262     }
263 
264     return ss.str();
265 }
266 
267 int strToBytes(std::string& str, uint8_t* data)
268 {
269     std::string sstr;
270     int i;
271 
272     for (i = 0; i < (str.length()) / 2; i++)
273     {
274         sstr = str.substr(i * 2, 2);
275         data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16);
276     }
277     return i;
278 }
279 
280 ipmi_ret_t getNetworkData(uint8_t lan_param, char* data)
281 {
282     ipmi_ret_t rc = IPMI_CC_OK;
283     sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
284 
285     const std::string ethdevice = "eth0";
286 
287     switch (static_cast<LanParam>(lan_param))
288     {
289         case LanParam::IP:
290         {
291             auto ethIP = ethdevice + "/" + ipmi::network::IPV4_TYPE;
292             std::string ipaddress;
293             auto ipObjectInfo = ipmi::network::getIPObject(
294                 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT, ethIP);
295 
296             auto properties = ipmi::getAllDbusProperties(
297                 bus, ipObjectInfo.second, ipObjectInfo.first,
298                 ipmi::network::IP_INTERFACE);
299 
300             ipaddress = std::get<std::string>(properties["Address"]);
301 
302             std::strcpy(data, ipaddress.c_str());
303         }
304         break;
305 
306         case LanParam::IPV6:
307         {
308             auto ethIP = ethdevice + "/" + ipmi::network::IPV6_TYPE;
309             std::string ipaddress;
310             auto ipObjectInfo = ipmi::network::getIPObject(
311                 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT, ethIP);
312 
313             auto properties = ipmi::getAllDbusProperties(
314                 bus, ipObjectInfo.second, ipObjectInfo.first,
315                 ipmi::network::IP_INTERFACE);
316 
317             ipaddress = std::get<std::string>(properties["Address"]);
318 
319             std::strcpy(data, ipaddress.c_str());
320         }
321         break;
322 
323         case LanParam::MAC:
324         {
325             std::string macAddress;
326             auto macObjectInfo =
327                 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
328                                     ipmi::network::ROOT, ethdevice);
329 
330             auto variant = ipmi::getDbusProperty(
331                 bus, macObjectInfo.second, macObjectInfo.first,
332                 ipmi::network::MAC_INTERFACE, "MACAddress");
333 
334             macAddress = std::get<std::string>(variant);
335 
336             sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
337                    (data), (data + 1), (data + 2), (data + 3), (data + 4),
338                    (data + 5));
339             std::strcpy(data, macAddress.c_str());
340         }
341         break;
342 
343         default:
344             rc = IPMI_CC_PARM_OUT_OF_RANGE;
345     }
346     return rc;
347 }
348 
349 bool isMultiHostPlatform()
350 {
351     bool platform;
352     if (INSTANCES == "0")
353     {
354         platform = false;
355     }
356     else
357     {
358         platform = true;
359     }
360     return platform;
361 }
362 
363 // return code: 0 successful
364 int8_t getFruData(std::string& data, std::string& name)
365 {
366     std::string objpath = "/xyz/openbmc_project/FruDevice";
367     std::string intf = "xyz.openbmc_project.FruDeviceManager";
368     std::string service = getService(dbus, intf, objpath);
369     ObjectValueTree valueTree = getManagedObjects(dbus, service, "/");
370     if (valueTree.empty())
371     {
372         phosphor::logging::log<phosphor::logging::level::ERR>(
373             "No object implements interface",
374             phosphor::logging::entry("INTF=%s", intf.c_str()));
375         return -1;
376     }
377 
378     for (const auto& item : valueTree)
379     {
380         auto interface = item.second.find("xyz.openbmc_project.FruDevice");
381         if (interface == item.second.end())
382         {
383             continue;
384         }
385 
386         auto property = interface->second.find(name.c_str());
387         if (property == interface->second.end())
388         {
389             continue;
390         }
391 
392         try
393         {
394             Value variant = property->second;
395             std::string& result = std::get<std::string>(variant);
396             if (result.size() > maxFRUStringLength)
397             {
398                 phosphor::logging::log<phosphor::logging::level::ERR>(
399                     "FRU serial number exceed maximum length");
400                 return -1;
401             }
402             data = result;
403             return 0;
404         }
405         catch (const std::bad_variant_access& e)
406         {
407             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
408             return -1;
409         }
410     }
411     return -1;
412 }
413 
414 typedef struct
415 {
416     uint8_t cur_power_state;
417     uint8_t last_power_event;
418     uint8_t misc_power_state;
419     uint8_t front_panel_button_cap_status;
420 } ipmi_get_chassis_status_t;
421 
422 //----------------------------------------------------------------------
423 // Get Debug Frame Info
424 //----------------------------------------------------------------------
425 ipmi_ret_t ipmiOemDbgGetFrameInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
426                                   ipmi_request_t request,
427                                   ipmi_response_t response,
428                                   ipmi_data_len_t data_len,
429                                   ipmi_context_t context)
430 {
431     uint8_t* req = reinterpret_cast<uint8_t*>(request);
432     uint8_t* res = reinterpret_cast<uint8_t*>(response);
433     uint8_t num_frames = 3;
434 
435     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
436     res[SIZE_IANA_ID] = num_frames;
437     *data_len = SIZE_IANA_ID + 1;
438 
439     return IPMI_CC_OK;
440 }
441 
442 //----------------------------------------------------------------------
443 // Get Debug Updated Frames
444 //----------------------------------------------------------------------
445 ipmi_ret_t ipmiOemDbgGetUpdFrames(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
446                                   ipmi_request_t request,
447                                   ipmi_response_t response,
448                                   ipmi_data_len_t data_len,
449                                   ipmi_context_t context)
450 {
451     uint8_t* req = reinterpret_cast<uint8_t*>(request);
452     uint8_t* res = reinterpret_cast<uint8_t*>(response);
453     uint8_t num_updates = 3;
454     *data_len = 4;
455 
456     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
457     res[SIZE_IANA_ID] = num_updates;
458     *data_len = SIZE_IANA_ID + num_updates + 1;
459     res[SIZE_IANA_ID + 1] = 1; // info page update
460     res[SIZE_IANA_ID + 2] = 2; // cri sel update
461     res[SIZE_IANA_ID + 3] = 3; // cri sensor update
462 
463     return IPMI_CC_OK;
464 }
465 
466 //----------------------------------------------------------------------
467 // Get Debug POST Description
468 //----------------------------------------------------------------------
469 ipmi_ret_t ipmiOemDbgGetPostDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
470                                  ipmi_request_t request,
471                                  ipmi_response_t response,
472                                  ipmi_data_len_t data_len,
473                                  ipmi_context_t context)
474 {
475     uint8_t* req = reinterpret_cast<uint8_t*>(request);
476     uint8_t* res = reinterpret_cast<uint8_t*>(response);
477     uint8_t index = 0;
478     uint8_t next = 0;
479     uint8_t end = 0;
480     uint8_t phase = 0;
481     uint8_t descLen = 0;
482     int ret;
483 
484     index = req[3];
485     phase = req[4];
486 
487     ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]);
488     if (ret)
489     {
490         memcpy(res, req, SIZE_IANA_ID); // IANA ID
491         *data_len = SIZE_IANA_ID;
492         return IPMI_CC_UNSPECIFIED_ERROR;
493     }
494 
495     memcpy(res, req, SIZE_IANA_ID); // IANA ID
496     res[3] = index;
497     res[4] = next;
498     res[5] = phase;
499     res[6] = end;
500     res[7] = descLen;
501     *data_len = SIZE_IANA_ID + 5 + descLen;
502 
503     return IPMI_CC_OK;
504 }
505 
506 //----------------------------------------------------------------------
507 // Get Debug GPIO Description
508 //----------------------------------------------------------------------
509 ipmi_ret_t ipmiOemDbgGetGpioDesc(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
510                                  ipmi_request_t request,
511                                  ipmi_response_t response,
512                                  ipmi_data_len_t data_len,
513                                  ipmi_context_t context)
514 {
515     uint8_t* req = reinterpret_cast<uint8_t*>(request);
516     uint8_t* res = reinterpret_cast<uint8_t*>(response);
517 
518     uint8_t index = 0;
519     uint8_t next = 0;
520     uint8_t level = 0;
521     uint8_t pinDef = 0;
522     uint8_t descLen = 0;
523     int ret;
524 
525     index = req[3];
526 
527     ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen,
528                                   &res[8]);
529     if (ret)
530     {
531         memcpy(res, req, SIZE_IANA_ID); // IANA ID
532         *data_len = SIZE_IANA_ID;
533         return IPMI_CC_UNSPECIFIED_ERROR;
534     }
535 
536     memcpy(res, req, SIZE_IANA_ID); // IANA ID
537     res[3] = index;
538     res[4] = next;
539     res[5] = level;
540     res[6] = pinDef;
541     res[7] = descLen;
542     *data_len = SIZE_IANA_ID + 5 + descLen;
543 
544     return IPMI_CC_OK;
545 }
546 
547 //----------------------------------------------------------------------
548 // Get Debug Frame Data
549 //----------------------------------------------------------------------
550 ipmi_ret_t ipmiOemDbgGetFrameData(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
551                                   ipmi_request_t request,
552                                   ipmi_response_t response,
553                                   ipmi_data_len_t data_len,
554                                   ipmi_context_t context)
555 {
556     uint8_t* req = reinterpret_cast<uint8_t*>(request);
557     uint8_t* res = reinterpret_cast<uint8_t*>(response);
558     uint8_t frame;
559     uint8_t page;
560     uint8_t next;
561     uint8_t count;
562     int ret;
563 
564     frame = req[3];
565     page = req[4];
566     int fr = frame;
567     int pg = page;
568 
569     ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
570     if (ret)
571     {
572         memcpy(res, req, SIZE_IANA_ID); // IANA ID
573         *data_len = SIZE_IANA_ID;
574         return IPMI_CC_UNSPECIFIED_ERROR;
575     }
576 
577     memcpy(res, req, SIZE_IANA_ID); // IANA ID
578     res[3] = frame;
579     res[4] = page;
580     res[5] = next;
581     res[6] = count;
582     *data_len = SIZE_IANA_ID + 4 + count;
583 
584     return IPMI_CC_OK;
585 }
586 
587 //----------------------------------------------------------------------
588 // Get Debug Control Panel
589 //----------------------------------------------------------------------
590 ipmi_ret_t ipmiOemDbgGetCtrlPanel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
591                                   ipmi_request_t request,
592                                   ipmi_response_t response,
593                                   ipmi_data_len_t data_len,
594                                   ipmi_context_t context)
595 {
596     uint8_t* req = reinterpret_cast<uint8_t*>(request);
597     uint8_t* res = reinterpret_cast<uint8_t*>(response);
598 
599     uint8_t panel;
600     uint8_t operation;
601     uint8_t item;
602     uint8_t count;
603     ipmi_ret_t ret;
604 
605     panel = req[3];
606     operation = req[4];
607     item = req[5];
608 
609     ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
610 
611     std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
612     *data_len = SIZE_IANA_ID + count;
613 
614     return ret;
615 }
616 
617 //----------------------------------------------------------------------
618 // Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
619 //----------------------------------------------------------------------
620 ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
621                               ipmi_request_t request, ipmi_response_t response,
622                               ipmi_data_len_t data_len, ipmi_context_t context)
623 {
624     uint8_t* req = reinterpret_cast<uint8_t*>(request);
625 
626     uint8_t index = req[0];
627     uint8_t type = req[1];
628     uint16_t speed;
629     uint32_t size;
630 
631     memcpy(&speed, &req[2], 2);
632     memcpy(&size, &req[4], 4);
633 
634     std::stringstream ss;
635     ss << std::hex;
636     ss << std::setw(2) << std::setfill('0') << (int)index;
637 
638     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
639     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
640     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
641     oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
642 
643     flushOemData();
644 
645     *data_len = 0;
646 
647     return IPMI_CC_OK;
648 }
649 
650 //----------------------------------------------------------------------
651 // Get Board ID (CMD_OEM_GET_BOARD_ID)
652 //----------------------------------------------------------------------
653 ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
654                              ipmi_request_t request, ipmi_response_t response,
655                              ipmi_data_len_t data_len, ipmi_context_t context)
656 {
657     uint8_t* req = reinterpret_cast<uint8_t*>(request);
658     uint8_t* res = reinterpret_cast<uint8_t*>(response);
659 
660     /* TODO: Needs to implement this after GPIO implementation */
661     *data_len = 0;
662 
663     return IPMI_CC_OK;
664 }
665 
666 /* Helper functions to set boot order */
667 void setBootOrder(std::string bootObjPath, uint8_t* data,
668                   std::string bootOrderKey)
669 {
670 
671     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
672 
673     // SETTING BOOT MODE PROPERTY
674     uint8_t bootModeBit = data[0] & 0x06;
675     auto bootValue = ipmi::boot::modeIpmiToDbus.find(bootModeBit);
676 
677     std::string bootOption =
678         ipmi::boot::Mode::convertModesToString((bootValue->second));
679 
680     std::string service =
681         getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
682     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
683                     ipmi::boot::bootModeProp, bootOption);
684 
685     // SETTING BOOT SOURCE PROPERTY
686     auto bootOrder = ipmi::boot::sourceIpmiToDbus.find((data[1]));
687     std::string bootSource =
688         ipmi::boot::Source::convertSourcesToString((bootOrder->second));
689 
690     service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
691     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
692                     ipmi::boot::bootSourceProp, bootSource);
693 
694     // SETTING BOOT TYPE PROPERTY
695 
696     uint8_t bootTypeBit = data[0] & 0x01;
697     auto bootTypeVal = ipmi::boot::typeIpmiToDbus.find(bootTypeBit);
698     std::string bootType =
699         ipmi::boot::Type::convertTypesToString((bootTypeVal->second));
700 
701     service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
702 
703     setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
704                     ipmi::boot::bootTypeProp, bootType);
705 
706     nlohmann::json bootMode;
707     uint8_t mode = data[0];
708     int i;
709 
710     bootMode["UEFI"] = (mode & BOOT_MODE_UEFI ? true : false);
711     bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR ? true : false);
712     bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT ? true : false);
713     bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG ? true : false);
714     oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode;
715 
716     /* Initialize boot sequence array */
717     oemData[bootOrderKey][KEY_BOOT_SEQ] = {};
718     for (i = 1; i < SIZE_BOOT_ORDER; i++)
719     {
720         if (data[i] >= BOOT_SEQ_ARRAY_SIZE)
721             oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA";
722         else
723             oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = bootSeq[data[i]];
724     }
725 
726     flushOemData();
727 }
728 
729 //----------------------------------------------------------------------
730 // Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
731 //----------------------------------------------------------------------
732 ipmi::RspType<std::vector<uint8_t>>
733     ipmiOemSetBootOrder(ipmi::Context::ptr ctx, std::vector<uint8_t> data)
734 {
735 
736     uint8_t bootSeq[SIZE_BOOT_ORDER];
737     size_t len = data.size();
738 
739     if (len != SIZE_BOOT_ORDER)
740     {
741         phosphor::logging::log<phosphor::logging::level::ERR>(
742             "Invalid Boot order length received");
743         return ipmi::responseReqDataLenInvalid();
744     }
745 
746     std::copy(std::begin(data), std::end(data), bootSeq);
747     std::optional<size_t> hostId = ipmi::boot::findHost(ctx->hostIdx);
748 
749     if (!hostId)
750     {
751         phosphor::logging::log<phosphor::logging::level::ERR>(
752             "Invalid Host Id received");
753         return ipmi::responseInvalidCommand();
754     }
755     auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
756 
757     setBootOrder(bootObjPath, bootSeq, hostName);
758 
759     return ipmi::responseSuccess(data);
760 }
761 
762 //----------------------------------------------------------------------
763 // Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
764 //----------------------------------------------------------------------
765 ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t>
766     ipmiOemGetBootOrder(ipmi::Context::ptr ctx)
767 {
768     uint8_t bootSeq[SIZE_BOOT_ORDER];
769     uint8_t mode = 0;
770 
771     std::optional<size_t> hostId = ipmi::boot::findHost(ctx->hostIdx);
772 
773     if (!hostId)
774     {
775         phosphor::logging::log<phosphor::logging::level::ERR>(
776             "Invalid Host Id received");
777         return ipmi::responseInvalidCommand();
778     }
779     auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
780 
781     // GETTING PROPERTY OF MODE INTERFACE
782 
783     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
784 
785     std::string service =
786         getService(*dbus, ipmi::boot::bootModeIntf, bootObjPath);
787     Value variant =
788         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
789                         ipmi::boot::bootModeProp);
790 
791     auto bootMode = ipmi::boot::Mode::convertModesFromString(
792         std::get<std::string>(variant));
793 
794     uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode);
795 
796     // GETTING PROPERTY OF SOURCE INTERFACE
797 
798     service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
799     variant =
800         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
801                         ipmi::boot::bootSourceProp);
802     auto bootSource = ipmi::boot::Source::convertSourcesFromString(
803         std::get<std::string>(variant));
804 
805     uint8_t bootOrder = ipmi::boot::sourceDbusToIpmi.at(bootSource);
806 
807     // GETTING PROPERTY OF TYPE INTERFACE
808 
809     service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
810     variant =
811         getDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
812                         ipmi::boot::bootTypeProp);
813     auto bootType = ipmi::boot::Type::convertTypesFromString(
814         std::get<std::string>(variant));
815 
816     uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType);
817 
818     uint8_t bootVal = bootOption | bootTypeVal;
819 
820     if (oemData.find(hostName) == oemData.end())
821     {
822         /* Return default boot order 0100090203ff */
823         uint8_t defaultBoot[SIZE_BOOT_ORDER] = {
824             BOOT_MODE_UEFI,      bootMap["USB_DEV"], bootMap["NET_IPV6"],
825             bootMap["SATA_HDD"], bootMap["SATA_CD"], 0xff};
826 
827         memcpy(bootSeq, defaultBoot, SIZE_BOOT_ORDER);
828         phosphor::logging::log<phosphor::logging::level::INFO>(
829             "Set default boot order");
830         setBootOrder(bootObjPath, defaultBoot, hostName);
831     }
832     else
833     {
834         nlohmann::json bootMode = oemData[hostName][KEY_BOOT_MODE];
835         if (bootMode["UEFI"])
836             mode |= BOOT_MODE_UEFI;
837         if (bootMode["CMOS_CLR"])
838             mode |= BOOT_MODE_CMOS_CLR;
839         if (bootMode["BOOT_FLAG"])
840             mode |= BOOT_MODE_BOOT_FLAG;
841 
842         bootSeq[0] = mode;
843 
844         for (int i = 1; i < SIZE_BOOT_ORDER; i++)
845         {
846             std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1];
847             if (bootMap.find(seqStr) != bootMap.end())
848                 bootSeq[i] = bootMap[seqStr];
849             else
850                 bootSeq[i] = 0xff;
851         }
852     }
853 
854     return ipmi::responseSuccess(bootVal, bootOrder, bootSeq[2], bootSeq[3],
855                                  bootSeq[4], bootSeq[5]);
856 }
857 // Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
858 //----------------------------------------------------------------------
859 ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
860                                     ipmi_request_t request,
861                                     ipmi_response_t response,
862                                     ipmi_data_len_t data_len,
863                                     ipmi_context_t context)
864 {
865     machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request);
866     uint8_t len = *data_len;
867 
868     *data_len = 0;
869 
870     if (len < sizeof(machineConfigInfo_t))
871     {
872         phosphor::logging::log<phosphor::logging::level::ERR>(
873             "Invalid machine configuration length received");
874         return IPMI_CC_REQ_DATA_LEN_INVALID;
875     }
876 
877     if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*))
878         oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
879     else
880         oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
881             chassisType[req->chassis_type];
882 
883     if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*))
884         oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
885     else
886         oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
887 
888     oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
889     oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
890     oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
891     oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
892 
893     if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*))
894         oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
895     else
896         oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
897 
898     oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
899     int i = 0;
900     if (req->pcie_card_loc & BIT_0)
901         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
902     if (req->pcie_card_loc & BIT_1)
903         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
904     if (req->pcie_card_loc & BIT_2)
905         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
906     if (req->pcie_card_loc & BIT_3)
907         oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
908 
909     if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
910         oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
911     else
912         oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
913             pcieType[req->slot1_pcie_type];
914 
915     if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
916         oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
917     else
918         oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
919             pcieType[req->slot2_pcie_type];
920 
921     if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
922         oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
923     else
924         oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
925             pcieType[req->slot3_pcie_type];
926 
927     if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
928         oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
929     else
930         oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
931             pcieType[req->slot4_pcie_type];
932 
933     oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
934 
935     flushOemData();
936 
937     return IPMI_CC_OK;
938 }
939 
940 //----------------------------------------------------------------------
941 // Set POST start (CMD_OEM_SET_POST_START)
942 //----------------------------------------------------------------------
943 ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
944                                ipmi_request_t request, ipmi_response_t response,
945                                ipmi_data_len_t data_len, ipmi_context_t context)
946 {
947     phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
948 
949     /* Do nothing, return success */
950     *data_len = 0;
951     return IPMI_CC_OK;
952 }
953 
954 //----------------------------------------------------------------------
955 // Set POST End (CMD_OEM_SET_POST_END)
956 //----------------------------------------------------------------------
957 ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
958                              ipmi_request_t request, ipmi_response_t response,
959                              ipmi_data_len_t data_len, ipmi_context_t context)
960 {
961     struct timespec ts;
962 
963     phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
964 
965     *data_len = 0;
966 
967     // Timestamp post end time.
968     clock_gettime(CLOCK_REALTIME, &ts);
969     oemData[KEY_TS_SLED] = ts.tv_sec;
970     flushOemData();
971 
972     // Sync time with system
973     // TODO: Add code for syncing time
974 
975     return IPMI_CC_OK;
976 }
977 
978 //----------------------------------------------------------------------
979 // Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
980 //----------------------------------------------------------------------
981 // Inform BMC about PPIN data of 8 bytes for each CPU
982 //
983 // Request:
984 // Byte 1:8 – CPU0 PPIN data
985 // Optional:
986 // Byte 9:16 – CPU1 PPIN data
987 //
988 // Response:
989 // Byte 1 – Completion Code
990 ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
991                               ipmi_request_t request, ipmi_response_t response,
992                               ipmi_data_len_t data_len, ipmi_context_t context)
993 {
994     uint8_t* req = reinterpret_cast<uint8_t*>(request);
995     std::string ppinStr;
996     int len;
997 
998     if (*data_len > SIZE_CPU_PPIN * 2)
999         len = SIZE_CPU_PPIN * 2;
1000     else
1001         len = *data_len;
1002     *data_len = 0;
1003 
1004     ppinStr = bytesToStr(req, len);
1005     oemData[KEY_PPIN_INFO] = ppinStr.c_str();
1006     flushOemData();
1007 
1008     return IPMI_CC_OK;
1009 }
1010 
1011 //----------------------------------------------------------------------
1012 // Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
1013 //----------------------------------------------------------------------
1014 ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1015                                 ipmi_request_t request,
1016                                 ipmi_response_t response,
1017                                 ipmi_data_len_t data_len,
1018                                 ipmi_context_t context)
1019 {
1020     /* Do nothing, return success */
1021     *data_len = 0;
1022     return IPMI_CC_OK;
1023 }
1024 
1025 // Helper function to set guid at offset in EEPROM
1026 static int setGUID(off_t offset, uint8_t* guid)
1027 {
1028     int fd = -1;
1029     ssize_t len;
1030     int ret = 0;
1031 
1032     errno = 0;
1033 
1034     // Check if file is present
1035     if (access(FRU_EEPROM, F_OK) == -1)
1036     {
1037         std::cerr << "Unable to access: " << FRU_EEPROM << std::endl;
1038         return errno;
1039     }
1040 
1041     // Open the file
1042     fd = open(FRU_EEPROM, O_WRONLY);
1043     if (fd == -1)
1044     {
1045         std::cerr << "Unable to open: " << FRU_EEPROM << std::endl;
1046         return errno;
1047     }
1048 
1049     // seek to the offset
1050     lseek(fd, offset, SEEK_SET);
1051 
1052     // Write bytes to location
1053     len = write(fd, guid, GUID_SIZE);
1054     if (len != GUID_SIZE)
1055     {
1056         phosphor::logging::log<phosphor::logging::level::ERR>(
1057             "GUID write data to EEPROM failed");
1058         ret = errno;
1059     }
1060 
1061     close(fd);
1062     return ret;
1063 }
1064 
1065 //----------------------------------------------------------------------
1066 // Set System GUID (CMD_OEM_SET_SYSTEM_GUID)
1067 //----------------------------------------------------------------------
1068 #if BIC_ENABLED
1069 ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx, uint8_t cmdReq,
1070                                      std::vector<uint8_t> reqData)
1071 {
1072     std::vector<uint8_t> respData;
1073 
1074     if (reqData.size() != GUID_SIZE) // 16bytes
1075     {
1076 
1077         return ipmi::responseReqDataLenInvalid();
1078     }
1079 
1080     auto ptrReqData = reqData.insert(reqData.begin(), reqData.size());
1081 
1082     uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
1083 
1084     if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
1085         return ipmi::responseUnspecifiedError();
1086 
1087     return ipmi::responseSuccess();
1088 }
1089 
1090 #else
1091 ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1092                                 ipmi_request_t request,
1093                                 ipmi_response_t response,
1094                                 ipmi_data_len_t data_len,
1095                                 ipmi_context_t context)
1096 {
1097     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1098 
1099     if (*data_len != GUID_SIZE) // 16bytes
1100     {
1101         *data_len = 0;
1102         return IPMI_CC_REQ_DATA_LEN_INVALID;
1103     }
1104 
1105     *data_len = 0;
1106 
1107     if (setGUID(OFFSET_SYS_GUID, req))
1108     {
1109         return IPMI_CC_UNSPECIFIED_ERROR;
1110     }
1111     return IPMI_CC_OK;
1112 }
1113 #endif
1114 
1115 //----------------------------------------------------------------------
1116 // Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
1117 //----------------------------------------------------------------------
1118 ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1119                                    ipmi_request_t request,
1120                                    ipmi_response_t response,
1121                                    ipmi_data_len_t data_len,
1122                                    ipmi_context_t context)
1123 {
1124     /* Do nothing, return success */
1125     *data_len = 0;
1126     return IPMI_CC_OK;
1127 }
1128 
1129 //----------------------------------------------------------------------
1130 // Set PPR (CMD_OEM_SET_PPR)
1131 //----------------------------------------------------------------------
1132 ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1133                          ipmi_request_t request, ipmi_response_t response,
1134                          ipmi_data_len_t data_len, ipmi_context_t context)
1135 {
1136     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1137     uint8_t pprCnt, pprAct, pprIndex;
1138     uint8_t selParam = req[0];
1139     uint8_t len = *data_len;
1140     std::stringstream ss;
1141     std::string str;
1142 
1143     *data_len = 0;
1144 
1145     switch (selParam)
1146     {
1147         case PPR_ACTION:
1148             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
1149                 oemData[KEY_PPR].end())
1150                 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1151 
1152             pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1153             if (pprCnt == 0)
1154                 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1155 
1156             pprAct = req[1];
1157             /* Check if ppr is enabled or disabled */
1158             if (!(pprAct & 0x80))
1159                 pprAct = 0;
1160 
1161             oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
1162             break;
1163         case PPR_ROW_COUNT:
1164             if (req[1] > 100)
1165                 return IPMI_CC_PARM_OUT_OF_RANGE;
1166 
1167             oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
1168             break;
1169         case PPR_ROW_ADDR:
1170             pprIndex = req[1];
1171             if (pprIndex > 100)
1172                 return IPMI_CC_PARM_OUT_OF_RANGE;
1173 
1174             if (len < PPR_ROW_ADDR_LEN + 1)
1175             {
1176                 phosphor::logging::log<phosphor::logging::level::ERR>(
1177                     "Invalid PPR Row Address length received");
1178                 return IPMI_CC_REQ_DATA_LEN_INVALID;
1179             }
1180 
1181             ss << std::hex;
1182             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1183 
1184             oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1185 
1186             str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
1187             oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
1188             break;
1189         case PPR_HISTORY_DATA:
1190             pprIndex = req[1];
1191             if (pprIndex > 100)
1192                 return IPMI_CC_PARM_OUT_OF_RANGE;
1193 
1194             if (len < PPR_HST_DATA_LEN + 1)
1195             {
1196                 phosphor::logging::log<phosphor::logging::level::ERR>(
1197                     "Invalid PPR history data length received");
1198                 return IPMI_CC_REQ_DATA_LEN_INVALID;
1199             }
1200 
1201             ss << std::hex;
1202             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1203 
1204             oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1205 
1206             str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
1207             oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
1208             break;
1209         default:
1210             return IPMI_CC_PARM_OUT_OF_RANGE;
1211             break;
1212     }
1213 
1214     flushOemData();
1215 
1216     return IPMI_CC_OK;
1217 }
1218 
1219 //----------------------------------------------------------------------
1220 // Get PPR (CMD_OEM_GET_PPR)
1221 //----------------------------------------------------------------------
1222 ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1223                          ipmi_request_t request, ipmi_response_t response,
1224                          ipmi_data_len_t data_len, ipmi_context_t context)
1225 {
1226     uint8_t* req = reinterpret_cast<uint8_t*>(request);
1227     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1228     uint8_t pprCnt, pprIndex;
1229     uint8_t selParam = req[0];
1230     std::stringstream ss;
1231     std::string str;
1232 
1233     /* Any failure will return zero length data */
1234     *data_len = 0;
1235 
1236     switch (selParam)
1237     {
1238         case PPR_ACTION:
1239             res[0] = 0;
1240             *data_len = 1;
1241 
1242             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1243                 oemData[KEY_PPR].end())
1244             {
1245                 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1246                 if (pprCnt != 0)
1247                 {
1248                     if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
1249                         oemData[KEY_PPR].end())
1250                     {
1251                         res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
1252                     }
1253                 }
1254             }
1255             break;
1256         case PPR_ROW_COUNT:
1257             res[0] = 0;
1258             *data_len = 1;
1259             if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1260                 oemData[KEY_PPR].end())
1261                 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1262             break;
1263         case PPR_ROW_ADDR:
1264             pprIndex = req[1];
1265             if (pprIndex > 100)
1266                 return IPMI_CC_PARM_OUT_OF_RANGE;
1267 
1268             ss << std::hex;
1269             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1270 
1271             if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1272                 return IPMI_CC_PARM_OUT_OF_RANGE;
1273 
1274             if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
1275                 oemData[KEY_PPR][ss.str()].end())
1276                 return IPMI_CC_PARM_OUT_OF_RANGE;
1277 
1278             str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
1279             *data_len = strToBytes(str, res);
1280             break;
1281         case PPR_HISTORY_DATA:
1282             pprIndex = req[1];
1283             if (pprIndex > 100)
1284                 return IPMI_CC_PARM_OUT_OF_RANGE;
1285 
1286             ss << std::hex;
1287             ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1288 
1289             if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1290                 return IPMI_CC_PARM_OUT_OF_RANGE;
1291 
1292             if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
1293                 oemData[KEY_PPR][ss.str()].end())
1294                 return IPMI_CC_PARM_OUT_OF_RANGE;
1295 
1296             str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
1297             *data_len = strToBytes(str, res);
1298             break;
1299         default:
1300             return IPMI_CC_PARM_OUT_OF_RANGE;
1301             break;
1302     }
1303 
1304     return IPMI_CC_OK;
1305 }
1306 
1307 /* FB OEM QC Commands */
1308 
1309 //----------------------------------------------------------------------
1310 // Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1311 //----------------------------------------------------------------------
1312 //"Request:
1313 // Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1314 // Byte 4 – Processor Index, 0 base
1315 // Byte 5 – Parameter Selector
1316 // Byte 6..N – Configuration parameter data (see below for Parameters
1317 // of Processor Information)
1318 // Response:
1319 // Byte 1 – Completion code
1320 //
1321 // Parameter#1: (Processor Product Name)
1322 //
1323 // Byte 1..48 –Product name(ASCII code)
1324 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1325 //
1326 // Param#2: Processor Basic Information
1327 // Byte 1 – Core Number
1328 // Byte 2 – Thread Number (LSB)
1329 // Byte 3 – Thread Number (MSB)
1330 // Byte 4 – Processor frequency in MHz (LSB)
1331 // Byte 5 – Processor frequency in MHz (MSB)
1332 // Byte 6..7 – Revision
1333 //
1334 ipmi_ret_t ipmiOemQSetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1335                                ipmi_request_t request, ipmi_response_t response,
1336                                ipmi_data_len_t data_len, ipmi_context_t context)
1337 {
1338     qProcInfo_t* req = reinterpret_cast<qProcInfo_t*>(request);
1339     uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
1340     std::stringstream ss;
1341     std::string str;
1342     uint8_t len = *data_len;
1343 
1344     *data_len = 0;
1345 
1346     /* check for requested data params */
1347     if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
1348     {
1349         phosphor::logging::log<phosphor::logging::level::ERR>(
1350             "Invalid parameter received");
1351         return IPMI_CC_PARM_OUT_OF_RANGE;
1352     }
1353 
1354     len = len - 5; // Get Actual data length
1355 
1356     ss << std::hex;
1357     ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
1358     oemData[KEY_Q_PROC_INFO][ss.str()][KEY_PROC_INDEX] = req->procIndex;
1359 
1360     str = bytesToStr(req->data, len);
1361     oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]] = str.c_str();
1362     flushOemData();
1363 
1364     return IPMI_CC_OK;
1365 }
1366 
1367 //----------------------------------------------------------------------
1368 // Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1369 //----------------------------------------------------------------------
1370 // Request:
1371 // Byte 1:3 –  Manufacturer ID – XXYYZZ h, LSB first
1372 // Byte 4 – Processor Index, 0 base
1373 // Byte 5 – Parameter Selector
1374 // Response:
1375 // Byte 1 – Completion code
1376 // Byte 2..N – Configuration Parameter Data (see below for Parameters
1377 // of Processor Information)
1378 //
1379 // Parameter#1: (Processor Product Name)
1380 //
1381 // Byte 1..48 –Product name(ASCII code)
1382 // Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1383 //
1384 // Param#2: Processor Basic Information
1385 // Byte 1 – Core Number
1386 // Byte 2 – Thread Number (LSB)
1387 // Byte 3 – Thread Number (MSB)
1388 // Byte 4 – Processor frequency in MHz (LSB)
1389 // Byte 5 – Processor frequency in MHz (MSB)
1390 // Byte 6..7 – Revision
1391 //
1392 ipmi_ret_t ipmiOemQGetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1393                                ipmi_request_t request, ipmi_response_t response,
1394                                ipmi_data_len_t data_len, ipmi_context_t context)
1395 {
1396     qProcInfo_t* req = reinterpret_cast<qProcInfo_t*>(request);
1397     uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
1398     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1399     std::stringstream ss;
1400     std::string str;
1401 
1402     *data_len = 0;
1403 
1404     /* check for requested data params */
1405     if (req->paramSel < 1 || req->paramSel >= numParam)
1406     {
1407         phosphor::logging::log<phosphor::logging::level::ERR>(
1408             "Invalid parameter received");
1409         return IPMI_CC_PARM_OUT_OF_RANGE;
1410     }
1411 
1412     ss << std::hex;
1413     ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
1414 
1415     if (oemData[KEY_Q_PROC_INFO].find(ss.str()) ==
1416         oemData[KEY_Q_PROC_INFO].end())
1417         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1418 
1419     if (oemData[KEY_Q_PROC_INFO][ss.str()].find(cpuInfoKey[req->paramSel]) ==
1420         oemData[KEY_Q_PROC_INFO][ss.str()].end())
1421         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1422 
1423     str = oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]];
1424     *data_len = strToBytes(str, res);
1425 
1426     return IPMI_CC_OK;
1427 }
1428 
1429 //----------------------------------------------------------------------
1430 // Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1431 //----------------------------------------------------------------------
1432 // Request:
1433 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1434 // Byte 4 – DIMM Index, 0 base
1435 // Byte 5 – Parameter Selector
1436 // Byte 6..N – Configuration parameter data (see below for Parameters
1437 // of DIMM Information)
1438 // Response:
1439 // Byte 1 – Completion code
1440 //
1441 // Param#1 (DIMM Location):
1442 // Byte 1 – DIMM Present
1443 // Byte 1 – DIMM Present
1444 // 01h – Present
1445 // FFh – Not Present
1446 // Byte 2 – Node Number, 0 base
1447 // Byte 3 – Channel Number , 0 base
1448 // Byte 4 – DIMM Number , 0 base
1449 //
1450 // Param#2 (DIMM Type):
1451 // Byte 1 – DIMM Type
1452 // Bit [7:6]
1453 // For DDR3
1454 //  00 – Normal Voltage (1.5V)
1455 //  01 – Ultra Low Voltage (1.25V)
1456 //  10 – Low Voltage (1.35V)
1457 //  11 – Reserved
1458 // For DDR4
1459 //  00 – Reserved
1460 //  01 – Reserved
1461 //  10 – Reserved
1462 //  11 – Normal Voltage (1.2V)
1463 // Bit [5:0]
1464 //  0x00 – SDRAM
1465 //  0x01 – DDR-1 RAM
1466 //  0x02 – Rambus
1467 //  0x03 – DDR-2 RAM
1468 //  0x04 – FBDIMM
1469 //  0x05 – DDR-3 RAM
1470 //  0x06 – DDR-4 RAM
1471 //
1472 // Param#3 (DIMM Speed):
1473 // Byte 1..2 – DIMM speed in MHz, LSB
1474 // Byte 3..6 – DIMM size in Mbytes, LSB
1475 //
1476 // Param#4 (Module Part Number):
1477 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1478 //
1479 // Param#5 (Module Serial Number):
1480 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1481 //
1482 // Param#6 (Module Manufacturer ID):
1483 // Byte 1 - Module Manufacturer ID, LSB
1484 // Byte 2 - Module Manufacturer ID, MSB
1485 //
1486 ipmi_ret_t ipmiOemQSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1487                                ipmi_request_t request, ipmi_response_t response,
1488                                ipmi_data_len_t data_len, ipmi_context_t context)
1489 {
1490     qDimmInfo_t* req = reinterpret_cast<qDimmInfo_t*>(request);
1491     uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
1492     std::stringstream ss;
1493     std::string str;
1494     uint8_t len = *data_len;
1495 
1496     *data_len = 0;
1497 
1498     /* check for requested data params */
1499     if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
1500     {
1501         phosphor::logging::log<phosphor::logging::level::ERR>(
1502             "Invalid parameter received");
1503         return IPMI_CC_PARM_OUT_OF_RANGE;
1504     }
1505 
1506     len = len - 5; // Get Actual data length
1507 
1508     ss << std::hex;
1509     ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
1510     oemData[KEY_Q_DIMM_INFO][ss.str()][KEY_DIMM_INDEX] = req->dimmIndex;
1511 
1512     str = bytesToStr(req->data, len);
1513     oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]] =
1514         str.c_str();
1515     flushOemData();
1516 
1517     return IPMI_CC_OK;
1518 }
1519 
1520 //----------------------------------------------------------------------
1521 // Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1522 //----------------------------------------------------------------------
1523 // Request:
1524 // Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1525 // Byte 4 – DIMM Index, 0 base
1526 // Byte 5 – Parameter Selector
1527 // Byte 6..N – Configuration parameter data (see below for Parameters
1528 // of DIMM Information)
1529 // Response:
1530 // Byte 1 – Completion code
1531 // Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1532 // of DIMM Information)
1533 //
1534 // Param#1 (DIMM Location):
1535 // Byte 1 – DIMM Present
1536 // Byte 1 – DIMM Present
1537 // 01h – Present
1538 // FFh – Not Present
1539 // Byte 2 – Node Number, 0 base
1540 // Byte 3 – Channel Number , 0 base
1541 // Byte 4 – DIMM Number , 0 base
1542 //
1543 // Param#2 (DIMM Type):
1544 // Byte 1 – DIMM Type
1545 // Bit [7:6]
1546 // For DDR3
1547 //  00 – Normal Voltage (1.5V)
1548 //  01 – Ultra Low Voltage (1.25V)
1549 //  10 – Low Voltage (1.35V)
1550 //  11 – Reserved
1551 // For DDR4
1552 //  00 – Reserved
1553 //  01 – Reserved
1554 //  10 – Reserved
1555 //  11 – Normal Voltage (1.2V)
1556 // Bit [5:0]
1557 //  0x00 – SDRAM
1558 //  0x01 – DDR-1 RAM
1559 //  0x02 – Rambus
1560 //  0x03 – DDR-2 RAM
1561 //  0x04 – FBDIMM
1562 //  0x05 – DDR-3 RAM
1563 //  0x06 – DDR-4 RAM
1564 //
1565 // Param#3 (DIMM Speed):
1566 // Byte 1..2 – DIMM speed in MHz, LSB
1567 // Byte 3..6 – DIMM size in Mbytes, LSB
1568 //
1569 // Param#4 (Module Part Number):
1570 // Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1571 //
1572 // Param#5 (Module Serial Number):
1573 // Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1574 //
1575 // Param#6 (Module Manufacturer ID):
1576 // Byte 1 - Module Manufacturer ID, LSB
1577 // Byte 2 - Module Manufacturer ID, MSB
1578 //
1579 ipmi_ret_t ipmiOemQGetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1580                                ipmi_request_t request, ipmi_response_t response,
1581                                ipmi_data_len_t data_len, ipmi_context_t context)
1582 {
1583     qDimmInfo_t* req = reinterpret_cast<qDimmInfo_t*>(request);
1584     uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
1585     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1586     std::stringstream ss;
1587     std::string str;
1588 
1589     *data_len = 0;
1590 
1591     /* check for requested data params */
1592     if (req->paramSel < 1 || req->paramSel >= numParam)
1593     {
1594         phosphor::logging::log<phosphor::logging::level::ERR>(
1595             "Invalid parameter received");
1596         return IPMI_CC_PARM_OUT_OF_RANGE;
1597     }
1598 
1599     ss << std::hex;
1600     ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
1601 
1602     if (oemData[KEY_Q_DIMM_INFO].find(ss.str()) ==
1603         oemData[KEY_Q_DIMM_INFO].end())
1604         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1605 
1606     if (oemData[KEY_Q_DIMM_INFO][ss.str()].find(dimmInfoKey[req->paramSel]) ==
1607         oemData[KEY_Q_DIMM_INFO][ss.str()].end())
1608         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1609 
1610     str = oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]];
1611     *data_len = strToBytes(str, res);
1612 
1613     return IPMI_CC_OK;
1614 }
1615 
1616 //----------------------------------------------------------------------
1617 // Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
1618 //----------------------------------------------------------------------
1619 // BIOS issue this command to provide HDD information to BMC.
1620 //
1621 // BIOS just can get information by standard ATA / SMART command for
1622 // OB SATA controller.
1623 // BIOS can get
1624 // 1.     Serial Number
1625 // 2.     Model Name
1626 // 3.     HDD FW Version
1627 // 4.     HDD Capacity
1628 // 5.     HDD WWN
1629 //
1630 //  Use Get HDD info Param #5 to know the MAX HDD info index.
1631 //
1632 //  Request:
1633 //  Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1634 //  Byte 4 –
1635 //  [7:4] Reserved
1636 //  [3:0] HDD Controller Type
1637 //     0x00 – BIOS
1638 //     0x01 – Expander
1639 //     0x02 – LSI
1640 //  Byte 5 – HDD Info Index, 0 base
1641 //  Byte 6 – Parameter Selector
1642 //  Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
1643 //  Information)
1644 //
1645 //  Response:
1646 //  Byte 1 – Completion Code
1647 //
1648 //  Param#0 (HDD Location):
1649 //  Byte 1 – Controller
1650 //    [7:3] Device Number
1651 //    [2:0] Function Number
1652 //  For Intel C610 series (Wellsburg)
1653 //    D31:F2 (0xFA) – SATA control 1
1654 //    D31:F5 (0xFD) – SATA control 2
1655 //    D17:F4 (0x8C) – sSata control
1656 //  Byte 2 – Port Number
1657 //  Byte 3 – Location (0xFF: No HDD Present)
1658 //  BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
1659 //  #1~4, #6,  #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
1660 //  the HDD present. BMC or other people who know the HDD location has
1661 //  responsibility for update Location info
1662 //
1663 //  Param#1 (Serial Number):
1664 //  Bytes 1..33: HDD Serial Number
1665 //
1666 //  Param#2 (Model Name):
1667 //  Byte 1..33 – HDD Model Name
1668 //
1669 //  Param#3 (HDD FW Version):
1670 //  Byte 1..17 –HDD FW version
1671 //
1672 //  Param#4 (Capacity):
1673 //  Byte 1..4 –HDD Block Size, LSB
1674 //  Byte 5..12 - HDD Block Number, LSB
1675 //  HDD Capacity = HDD Block size * HDD BLock number  (Unit Byte)
1676 //
1677 //  Param#5 (Max HDD Quantity):
1678 //  Byte 1 - Max HDD Quantity
1679 //  Max supported port numbers in this PCH
1680 //
1681 //  Param#6 (HDD Type)
1682 //  Byte 1 – HDD Type
1683 //  0h – Reserved
1684 //  1h – SAS
1685 //  2h – SATA
1686 //  3h – PCIE SSD (NVME)
1687 //
1688 //  Param#7 (HDD WWN)
1689 //  Data 1...8: HDD World Wide Name, LSB
1690 //
1691 ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1692                                 ipmi_request_t request,
1693                                 ipmi_response_t response,
1694                                 ipmi_data_len_t data_len,
1695                                 ipmi_context_t context)
1696 {
1697     qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1698     uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1699     uint8_t ctrlType = req->hddCtrlType & 0x0f;
1700     std::stringstream ss;
1701     std::string str;
1702     uint8_t len = *data_len;
1703 
1704     *data_len = 0;
1705 
1706     /* check for requested data params */
1707     if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam ||
1708         ctrlType > 2)
1709     {
1710         phosphor::logging::log<phosphor::logging::level::ERR>(
1711             "Invalid parameter received");
1712         return IPMI_CC_PARM_OUT_OF_RANGE;
1713     }
1714 
1715     len = len - 6; // Get Actual data length
1716 
1717     ss << std::hex;
1718     ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1719     oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
1720     oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
1721         req->hddIndex;
1722 
1723     str = bytesToStr(req->data, len);
1724     oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1725            [driveInfoKey[req->paramSel]] = str.c_str();
1726     flushOemData();
1727 
1728     return IPMI_CC_OK;
1729 }
1730 
1731 //----------------------------------------------------------------------
1732 // Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
1733 //----------------------------------------------------------------------
1734 // BMC needs to check HDD presented or not first. If NOT presented, return
1735 // completion code 0xD5.
1736 //
1737 // Request:
1738 // Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1739 // Byte 4 –
1740 //[7:4] Reserved
1741 //[3:0] HDD Controller Type
1742 //   0x00 – BIOS
1743 //   0x01 – Expander
1744 //   0x02 – LSI
1745 // Byte 5 – HDD Index, 0 base
1746 // Byte 6 – Parameter Selector (See Above Set HDD Information)
1747 // Response:
1748 // Byte 1 – Completion Code
1749 //   0xD5 – Not support in current status (HDD Not Present)
1750 // Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
1751 // Information)
1752 //
1753 ipmi_ret_t ipmiOemQGetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1754                                 ipmi_request_t request,
1755                                 ipmi_response_t response,
1756                                 ipmi_data_len_t data_len,
1757                                 ipmi_context_t context)
1758 {
1759     qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1760     uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1761     uint8_t* res = reinterpret_cast<uint8_t*>(response);
1762     uint8_t ctrlType = req->hddCtrlType & 0x0f;
1763     std::stringstream ss;
1764     std::string str;
1765 
1766     *data_len = 0;
1767 
1768     /* check for requested data params */
1769     if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2)
1770     {
1771         phosphor::logging::log<phosphor::logging::level::ERR>(
1772             "Invalid parameter received");
1773         return IPMI_CC_PARM_OUT_OF_RANGE;
1774     }
1775 
1776     if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
1777         oemData[KEY_Q_DRIVE_INFO].end())
1778         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1779 
1780     ss << std::hex;
1781     ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1782 
1783     if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
1784         oemData[KEY_Q_DRIVE_INFO].end())
1785         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1786 
1787     if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
1788             dimmInfoKey[req->paramSel]) ==
1789         oemData[KEY_Q_DRIVE_INFO][ss.str()].end())
1790         return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1791 
1792     str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1793                  [dimmInfoKey[req->paramSel]];
1794     *data_len = strToBytes(str, res);
1795 
1796     return IPMI_CC_OK;
1797 }
1798 
1799 /* Helper function for sending DCMI commands to ME and getting response back */
1800 ipmi::RspType<std::vector<uint8_t>> sendDCMICmd(uint8_t cmd,
1801                                                 std::vector<uint8_t>& cmdData)
1802 {
1803     std::vector<uint8_t> respData;
1804 
1805     /* Add group id as first byte to request for ME command */
1806     cmdData.insert(cmdData.begin(), groupDCMI);
1807 
1808     if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
1809         return ipmi::responseUnspecifiedError();
1810 
1811     /* Remove group id as first byte as it will be added by IPMID */
1812     respData.erase(respData.begin());
1813 
1814     return ipmi::responseSuccess(std::move(respData));
1815 }
1816 
1817 /* DCMI Command handellers. */
1818 
1819 ipmi::RspType<std::vector<uint8_t>>
1820     ipmiOemDCMIGetPowerReading(std::vector<uint8_t> reqData)
1821 {
1822     return sendDCMICmd(ipmi::dcmi::cmdGetPowerReading, reqData);
1823 }
1824 
1825 ipmi::RspType<std::vector<uint8_t>>
1826     ipmiOemDCMIGetPowerLimit(std::vector<uint8_t> reqData)
1827 {
1828     return sendDCMICmd(ipmi::dcmi::cmdGetPowerLimit, reqData);
1829 }
1830 
1831 ipmi::RspType<std::vector<uint8_t>>
1832     ipmiOemDCMISetPowerLimit(std::vector<uint8_t> reqData)
1833 {
1834     return sendDCMICmd(ipmi::dcmi::cmdSetPowerLimit, reqData);
1835 }
1836 
1837 ipmi::RspType<std::vector<uint8_t>>
1838     ipmiOemDCMIApplyPowerLimit(std::vector<uint8_t> reqData)
1839 {
1840     return sendDCMICmd(ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
1841 }
1842 
1843 static void registerOEMFunctions(void)
1844 {
1845     /* Get OEM data from json file */
1846     std::ifstream file(JSON_OEM_DATA_FILE);
1847     if (file)
1848     {
1849         file >> oemData;
1850         file.close();
1851     }
1852 
1853     phosphor::logging::log<phosphor::logging::level::INFO>(
1854         "Registering OEM commands");
1855 
1856     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
1857                          NULL, ipmiOemDbgGetFrameInfo,
1858                          PRIVILEGE_USER); // get debug frame info
1859     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
1860                          CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
1861                          ipmiOemDbgGetUpdFrames,
1862                          PRIVILEGE_USER); // get debug updated frames
1863     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
1864                          NULL, ipmiOemDbgGetPostDesc,
1865                          PRIVILEGE_USER); // get debug post description
1866     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
1867                          NULL, ipmiOemDbgGetGpioDesc,
1868                          PRIVILEGE_USER); // get debug gpio description
1869     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
1870                          NULL, ipmiOemDbgGetFrameData,
1871                          PRIVILEGE_USER); // get debug frame data
1872     ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
1873                          NULL, ipmiOemDbgGetCtrlPanel,
1874                          PRIVILEGE_USER); // get debug control panel
1875     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL,
1876                          ipmiOemSetDimmInfo,
1877                          PRIVILEGE_USER); // Set Dimm Info
1878     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL,
1879                          ipmiOemGetBoardID,
1880                          PRIVILEGE_USER); // Get Board ID
1881     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL,
1882                          ipmiOemSetMachineCfgInfo,
1883                          PRIVILEGE_USER); // Set Machine Config Info
1884     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL,
1885                          ipmiOemSetPostStart,
1886                          PRIVILEGE_USER); // Set POST start
1887     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL,
1888                          ipmiOemSetPostEnd,
1889                          PRIVILEGE_USER); // Set POST End
1890     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL,
1891                          ipmiOemSetPPINInfo,
1892                          PRIVILEGE_USER); // Set PPIN Info
1893 #if BIC_ENABLED
1894 
1895     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1896                           ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
1897                           ipmiOemSetSystemGuid);
1898 #else
1899 
1900     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_SYSTEM_GUID, NULL,
1901                          ipmiOemSetSystemGuid,
1902                          PRIVILEGE_USER); // Set System GUID
1903 #endif
1904     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL,
1905                          ipmiOemSetAdrTrigger,
1906                          PRIVILEGE_USER); // Set ADR Trigger
1907     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
1908                          ipmiOemSetBiosFlashInfo,
1909                          PRIVILEGE_USER); // Set Bios Flash Info
1910     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr,
1911                          PRIVILEGE_USER); // Set PPR
1912     ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr,
1913                          PRIVILEGE_USER); // Get PPR
1914     /* FB OEM QC Commands */
1915     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_PROC_INFO, NULL,
1916                          ipmiOemQSetProcInfo,
1917                          PRIVILEGE_USER); // Set Proc Info
1918     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_PROC_INFO, NULL,
1919                          ipmiOemQGetProcInfo,
1920                          PRIVILEGE_USER); // Get Proc Info
1921     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DIMM_INFO, NULL,
1922                          ipmiOemQSetDimmInfo,
1923                          PRIVILEGE_USER); // Set Dimm Info
1924     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DIMM_INFO, NULL,
1925                          ipmiOemQGetDimmInfo,
1926                          PRIVILEGE_USER); // Get Dimm Info
1927     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
1928                          ipmiOemQSetDriveInfo,
1929                          PRIVILEGE_USER); // Set Drive Info
1930     ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
1931                          ipmiOemQGetDriveInfo,
1932                          PRIVILEGE_USER); // Get Drive Info
1933 
1934     /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
1935     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1936                                ipmi::dcmi::cmdGetPowerReading,
1937                                ipmi::Privilege::User,
1938                                ipmiOemDCMIGetPowerReading); // Get Power Reading
1939 
1940     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1941                                ipmi::dcmi::cmdGetPowerLimit,
1942                                ipmi::Privilege::User,
1943                                ipmiOemDCMIGetPowerLimit); // Get Power Limit
1944 
1945     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1946                                ipmi::dcmi::cmdSetPowerLimit,
1947                                ipmi::Privilege::Operator,
1948                                ipmiOemDCMISetPowerLimit); // Set Power Limit
1949 
1950     ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
1951                                ipmi::dcmi::cmdActDeactivatePwrLimit,
1952                                ipmi::Privilege::Operator,
1953                                ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
1954 
1955     /* FB OEM BOOT ORDER COMMANDS */
1956     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1957                           CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
1958                           ipmiOemGetBootOrder); // Get Boot Order
1959 
1960     ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1961                           CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
1962                           ipmiOemSetBootOrder); // Set Boot Order
1963 
1964     return;
1965 }
1966 
1967 } // namespace ipmi
1968