blob: c721f0de089897b24a946480aff422595ebb051c [file] [log] [blame]
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001/*
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"
Vijay Khemkae7d23d02019-03-08 13:13:40 -080019
Patrick Williams2405ae92023-05-10 07:50:09 -050020#include <commandutils.hpp>
21#include <ipmid/api-types.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070022#include <ipmid/api.hpp>
Vijay Khemka1b6fae32019-03-25 17:43:01 -070023#include <ipmid/utils.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070024#include <nlohmann/json.hpp>
25#include <oemcommands.hpp>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080026#include <phosphor-logging/log.hpp>
27#include <sdbusplus/bus.hpp>
Patrick Williams2405ae92023-05-10 07:50:09 -050028#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
29#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
30#include <xyz/openbmc_project/Control/Boot/Type/server.hpp>
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053031
Vijay Khemka63c99be2020-05-27 19:14:35 -070032#include <array>
33#include <cstring>
34#include <fstream>
35#include <iomanip>
36#include <iostream>
Patrick Williams2405ae92023-05-10 07:50:09 -050037#include <regex>
Vijay Khemka63c99be2020-05-27 19:14:35 -070038#include <sstream>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080039#include <string>
40#include <vector>
41
42#define SIZE_IANA_ID 3
43
44namespace ipmi
45{
Vijay Khemkaa7231892019-10-11 11:35:05 -070046
47using namespace phosphor::logging;
48
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +053049void getSelectorPosition(size_t& position);
Vijay Khemkae7d23d02019-03-08 13:13:40 -080050static void registerOEMFunctions() __attribute__((constructor));
Patrick Williamscd315e02022-07-22 19:26:52 -050051sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
Vijay Khemkae7d23d02019-03-08 13:13:40 -080052static constexpr size_t maxFRUStringLength = 0x3F;
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053053constexpr uint8_t cmdSetSystemGuid = 0xEF;
Vijay Khemkae7d23d02019-03-08 13:13:40 -080054
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +053055constexpr uint8_t cmdSetQDimmInfo = 0x12;
56constexpr uint8_t cmdGetQDimmInfo = 0x13;
57
Cosmo Chou7ab87bb2024-06-28 10:47:44 +080058constexpr ipmi_ret_t ccInvalidParam = 0x80;
59
Vijay Khemka63c99be2020-05-27 19:14:35 -070060int plat_udbg_get_post_desc(uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*,
61 uint8_t*);
62int plat_udbg_get_gpio_desc(uint8_t, uint8_t*, uint8_t*, uint8_t*, uint8_t*,
63 uint8_t*);
Patrick Williams5e589482024-07-13 16:18:13 -050064int plat_udbg_get_frame_data(uint8_t, uint8_t, uint8_t*, uint8_t*, uint8_t*);
Vijay Khemka63c99be2020-05-27 19:14:35 -070065ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t*,
66 uint8_t*);
67int sendMeCmd(uint8_t, uint8_t, std::vector<uint8_t>&, std::vector<uint8_t>&);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -070068
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +053069int sendBicCmd(uint8_t, uint8_t, uint8_t, std::vector<uint8_t>&,
70 std::vector<uint8_t>&);
71
Vijay Khemkafeaa9812019-08-27 15:08:08 -070072nlohmann::json oemData __attribute__((init_priority(101)));
Vijay Khemka1b6fae32019-03-25 17:43:01 -070073
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070074static constexpr size_t GUID_SIZE = 16;
75// TODO Make offset and location runtime configurable to ensure we
76// can make each define their own locations.
77static constexpr off_t OFFSET_SYS_GUID = 0x17F0;
78static constexpr const char* FRU_EEPROM = "/sys/bus/i2c/devices/6-0054/eeprom";
Delphine CC Chiu7bb45922023-04-10 13:34:04 +080079void flushOemData();
Vijay Khemkaf2246ce2020-05-27 14:26:35 -070080
Vijay Khemka1b6fae32019-03-25 17:43:01 -070081enum class LanParam : uint8_t
82{
83 INPROGRESS = 0,
84 AUTHSUPPORT = 1,
85 AUTHENABLES = 2,
86 IP = 3,
87 IPSRC = 4,
88 MAC = 5,
89 SUBNET = 6,
90 GATEWAY = 12,
91 VLAN = 20,
92 CIPHER_SUITE_COUNT = 22,
93 CIPHER_SUITE_ENTRIES = 23,
94 IPV6 = 59,
95};
96
Vijay Khemkaa7231892019-10-11 11:35:05 -070097namespace network
98{
99
100constexpr auto ROOT = "/xyz/openbmc_project/network";
101constexpr auto SERVICE = "xyz.openbmc_project.Network";
102constexpr auto IPV4_TYPE = "ipv4";
103constexpr auto IPV6_TYPE = "ipv6";
104constexpr auto IPV4_PREFIX = "169.254";
105constexpr auto IPV6_PREFIX = "fe80";
106constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
107constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
Potin Lai8d1a81e2022-12-20 11:13:45 +0800108constexpr auto IPV4_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv4";
109constexpr auto IPV6_PROTOCOL = "xyz.openbmc_project.Network.IP.Protocol.IPv6";
Vijay Khemkaa7231892019-10-11 11:35:05 -0700110
Vijay Khemka63c99be2020-05-27 19:14:35 -0700111bool isLinkLocalIP(const std::string& address)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700112{
113 return address.find(IPV4_PREFIX) == 0 || address.find(IPV6_PREFIX) == 0;
114}
115
Patrick Williamscd315e02022-07-22 19:26:52 -0500116DbusObjectInfo getIPObject(sdbusplus::bus_t& bus, const std::string& interface,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700117 const std::string& serviceRoot,
Potin Lai8d1a81e2022-12-20 11:13:45 +0800118 const std::string& protocol,
119 const std::string& ethdev)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700120{
Potin Lai8d1a81e2022-12-20 11:13:45 +0800121 auto objectTree = getAllDbusObjects(bus, serviceRoot, interface, ethdev);
Vijay Khemkaa7231892019-10-11 11:35:05 -0700122
123 if (objectTree.empty())
124 {
125 log<level::ERR>("No Object has implemented the IP interface",
126 entry("INTERFACE=%s", interface.c_str()));
127 }
128
129 DbusObjectInfo objectInfo;
130
Vijay Khemka63c99be2020-05-27 19:14:35 -0700131 for (auto& object : objectTree)
Vijay Khemkaa7231892019-10-11 11:35:05 -0700132 {
Patrick Williams2405ae92023-05-10 07:50:09 -0500133 auto variant = ipmi::getDbusProperty(bus, object.second.begin()->first,
134 object.first, IP_INTERFACE,
135 "Type");
Potin Lai8d1a81e2022-12-20 11:13:45 +0800136 if (std::get<std::string>(variant) != protocol)
137 {
138 continue;
139 }
140
141 variant = ipmi::getDbusProperty(bus, object.second.begin()->first,
142 object.first, IP_INTERFACE, "Address");
Vijay Khemkaa7231892019-10-11 11:35:05 -0700143
144 objectInfo = std::make_pair(object.first, object.second.begin()->first);
145
146 // if LinkLocalIP found look for Non-LinkLocalIP
147 if (isLinkLocalIP(std::get<std::string>(variant)))
148 {
149 continue;
150 }
151 else
152 {
153 break;
154 }
155 }
156 return objectInfo;
157}
158
159} // namespace network
160
Jayashree-Df0cf6652020-11-30 11:03:30 +0530161namespace boot
162{
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530163using BootSource =
164 sdbusplus::xyz::openbmc_project::Control::Boot::server::Source::Sources;
165using BootMode =
166 sdbusplus::xyz::openbmc_project::Control::Boot::server::Mode::Modes;
167using BootType =
168 sdbusplus::xyz::openbmc_project::Control::Boot::server::Type::Types;
Jayashree-Df0cf6652020-11-30 11:03:30 +0530169
Jayashree-Df0cf6652020-11-30 11:03:30 +0530170using IpmiValue = uint8_t;
171
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530172std::map<IpmiValue, BootSource> sourceIpmiToDbus = {
173 {0x0f, BootSource::Default}, {0x00, BootSource::RemovableMedia},
174 {0x01, BootSource::Network}, {0x02, BootSource::Disk},
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800175 {0x03, BootSource::ExternalMedia}, {0x04, BootSource::RemovableMedia},
176 {0x09, BootSource::Network}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530177
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800178std::map<IpmiValue, BootMode> modeIpmiToDbus = {{0x04, BootMode::Setup},
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530179 {0x00, BootMode::Regular}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530180
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530181std::map<IpmiValue, BootType> typeIpmiToDbus = {{0x00, BootType::Legacy},
182 {0x01, BootType::EFI}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530183
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530184std::map<std::optional<BootSource>, IpmiValue> sourceDbusToIpmi = {
185 {BootSource::Default, 0x0f},
186 {BootSource::RemovableMedia, 0x00},
187 {BootSource::Network, 0x01},
188 {BootSource::Disk, 0x02},
189 {BootSource::ExternalMedia, 0x03}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530190
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530191std::map<std::optional<BootMode>, IpmiValue> modeDbusToIpmi = {
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800192 {BootMode::Setup, 0x04}, {BootMode::Regular, 0x00}};
Jayashree-Df0cf6652020-11-30 11:03:30 +0530193
Jayashree Dhanapal77ee4892022-04-08 16:53:51 +0530194std::map<std::optional<BootType>, IpmiValue> typeDbusToIpmi = {
195 {BootType::Legacy, 0x00}, {BootType::EFI, 0x01}};
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530196
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800197static constexpr auto bootEnableIntf = "xyz.openbmc_project.Object.Enable";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530198static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
199static constexpr auto bootSourceIntf =
200 "xyz.openbmc_project.Control.Boot.Source";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530201static constexpr auto bootTypeIntf = "xyz.openbmc_project.Control.Boot.Type";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530202static constexpr auto bootSourceProp = "BootSource";
203static constexpr auto bootModeProp = "BootMode";
Jayashree Dhanapal778147d2022-03-30 16:48:53 +0530204static constexpr auto bootTypeProp = "BootType";
Delphine CC Chiuc0f918b2023-03-22 14:48:04 +0800205static constexpr auto bootEnableProp = "Enabled";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530206
Jayashree-Df0cf6652020-11-30 11:03:30 +0530207std::tuple<std::string, std::string> objPath(size_t id)
208{
209 std::string hostName = "host" + std::to_string(id);
Patrick Williams2405ae92023-05-10 07:50:09 -0500210 std::string bootObjPath = "/xyz/openbmc_project/control/" + hostName +
211 "/boot";
Jayashree-Df0cf6652020-11-30 11:03:30 +0530212 return std::make_tuple(std::move(bootObjPath), std::move(hostName));
213}
214
Delphine CC Chiu7bb45922023-04-10 13:34:04 +0800215/* Helper functions to set boot order */
216void setBootOrder(std::string bootObjPath, const std::vector<uint8_t>& bootSeq,
217 std::string bootOrderKey)
218{
219 if (bootSeq.size() != SIZE_BOOT_ORDER)
220 {
221 phosphor::logging::log<phosphor::logging::level::ERR>(
222 "Invalid Boot order length received");
223 return;
224 }
225
226 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
227
228 uint8_t mode = bootSeq.front();
229
230 // SETTING BOOT MODE PROPERTY
231 uint8_t bootModeBit = mode & 0x04;
232 auto bootValue = ipmi::boot::modeIpmiToDbus.at(bootModeBit);
233
234 std::string bootOption =
235 sdbusplus::message::convert_to_string<boot::BootMode>(bootValue);
236
237 std::string service = getService(*dbus, ipmi::boot::bootModeIntf,
238 bootObjPath);
239 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootModeIntf,
240 ipmi::boot::bootModeProp, bootOption);
241
242 // SETTING BOOT SOURCE PROPERTY
243 auto bootOrder = ipmi::boot::sourceIpmiToDbus.at(bootSeq.at(1));
244 std::string bootSource =
245 sdbusplus::message::convert_to_string<boot::BootSource>(bootOrder);
246
247 service = getService(*dbus, ipmi::boot::bootSourceIntf, bootObjPath);
248 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootSourceIntf,
249 ipmi::boot::bootSourceProp, bootSource);
250
251 // SETTING BOOT TYPE PROPERTY
252 uint8_t bootTypeBit = mode & 0x01;
253 auto bootTypeVal = ipmi::boot::typeIpmiToDbus.at(bootTypeBit);
254
255 std::string bootType =
256 sdbusplus::message::convert_to_string<boot::BootType>(bootTypeVal);
257
258 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
259
260 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootTypeIntf,
261 ipmi::boot::bootTypeProp, bootType);
262
263 // Set the valid bit to boot enabled property
264 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
265
266 setDbusProperty(*dbus, service, bootObjPath, ipmi::boot::bootEnableIntf,
267 ipmi::boot::bootEnableProp,
268 (mode & BOOT_MODE_BOOT_FLAG) ? true : false);
269
270 nlohmann::json bootMode;
271
272 bootMode["UEFI"] = (mode & BOOT_MODE_UEFI) ? true : false;
273 bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR) ? true : false;
274 bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT) ? true : false;
275 bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG) ? true : false;
276 oemData[bootOrderKey][KEY_BOOT_MODE] = bootMode;
277
278 /* Initialize boot sequence array */
279 oemData[bootOrderKey][KEY_BOOT_SEQ] = {};
280 for (size_t i = 1; i < SIZE_BOOT_ORDER; i++)
281 {
282 if (bootSeq.at(i) >= BOOT_SEQ_ARRAY_SIZE)
283 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] = "NA";
284 else
285 oemData[bootOrderKey][KEY_BOOT_SEQ][i - 1] =
286 bootSeqDefine[bootSeq.at(i)];
287 }
288
289 flushOemData();
290}
291
292void getBootOrder(std::string bootObjPath, std::vector<uint8_t>& bootSeq,
293 std::string hostName)
294{
295 if (oemData.find(hostName) == oemData.end())
296 {
297 /* Return default boot order 0100090203ff */
298 bootSeq.push_back(BOOT_MODE_UEFI);
299 bootSeq.push_back(static_cast<uint8_t>(bootMap["USB_DEV"]));
300 bootSeq.push_back(static_cast<uint8_t>(bootMap["NET_IPV6"]));
301 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_HDD"]));
302 bootSeq.push_back(static_cast<uint8_t>(bootMap["SATA_CD"]));
303 bootSeq.push_back(0xff);
304
305 phosphor::logging::log<phosphor::logging::level::INFO>(
306 "Set default boot order");
307 setBootOrder(bootObjPath, bootSeq, hostName);
308 return;
309 }
310
311 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
312
313 // GETTING PROPERTY OF MODE INTERFACE
314
315 std::string service = getService(*dbus, ipmi::boot::bootModeIntf,
316 bootObjPath);
317 Value variant = getDbusProperty(*dbus, service, bootObjPath,
318 ipmi::boot::bootModeIntf,
319 ipmi::boot::bootModeProp);
320
321 auto bootMode = sdbusplus::message::convert_from_string<boot::BootMode>(
322 std::get<std::string>(variant));
323
324 uint8_t bootOption = ipmi::boot::modeDbusToIpmi.at(bootMode);
325
326 // GETTING PROPERTY OF TYPE INTERFACE
327
328 service = getService(*dbus, ipmi::boot::bootTypeIntf, bootObjPath);
329 variant = getDbusProperty(*dbus, service, bootObjPath,
330 ipmi::boot::bootTypeIntf,
331 ipmi::boot::bootTypeProp);
332
333 auto bootType = sdbusplus::message::convert_from_string<boot::BootType>(
334 std::get<std::string>(variant));
335
336 // Get the valid bit to boot enabled property
337 service = getService(*dbus, ipmi::boot::bootEnableIntf, bootObjPath);
338 variant = getDbusProperty(*dbus, service, bootObjPath,
339 ipmi::boot::bootEnableIntf,
340 ipmi::boot::bootEnableProp);
341
342 bool validFlag = std::get<bool>(variant);
343
344 uint8_t bootTypeVal = ipmi::boot::typeDbusToIpmi.at(bootType);
345
346 bootSeq.push_back(bootOption | bootTypeVal);
347
348 if (validFlag)
349 {
350 bootSeq.front() |= BOOT_MODE_BOOT_FLAG;
351 }
352
353 nlohmann::json bootModeJson = oemData[hostName][KEY_BOOT_MODE];
354 if (bootModeJson["CMOS_CLR"])
355 bootSeq.front() |= BOOT_MODE_CMOS_CLR;
356
357 for (int i = 1; i < SIZE_BOOT_ORDER; i++)
358 {
359 std::string seqStr = oemData[hostName][KEY_BOOT_SEQ][i - 1];
360 if (bootMap.find(seqStr) != bootMap.end())
361 bootSeq.push_back(bootMap[seqStr]);
362 else
363 bootSeq.push_back(0xff);
364 }
365}
366
Jayashree-Df0cf6652020-11-30 11:03:30 +0530367} // namespace boot
368
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700369//----------------------------------------------------------------------
370// Helper functions for storing oem data
371//----------------------------------------------------------------------
372
373void flushOemData()
374{
375 std::ofstream file(JSON_OEM_DATA_FILE);
376 file << oemData;
Vijay Khemkafeaa9812019-08-27 15:08:08 -0700377 file.close();
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700378 return;
379}
380
Vijay Khemka63c99be2020-05-27 19:14:35 -0700381std::string bytesToStr(uint8_t* byte, int len)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700382{
383 std::stringstream ss;
384 int i;
385
386 ss << std::hex;
387 for (i = 0; i < len; i++)
388 {
389 ss << std::setw(2) << std::setfill('0') << (int)byte[i];
390 }
391
392 return ss.str();
393}
394
Vijay Khemka63c99be2020-05-27 19:14:35 -0700395int strToBytes(std::string& str, uint8_t* data)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700396{
397 std::string sstr;
Willy Tue39f9392022-06-15 13:24:20 -0700398 size_t i;
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700399
400 for (i = 0; i < (str.length()) / 2; i++)
401 {
402 sstr = str.substr(i * 2, 2);
403 data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16);
404 }
405 return i;
406}
407
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530408int readDimmType(std::string& data, uint8_t param)
409{
410 nlohmann::json dimmObj;
411 /* Get dimm type names stored in json file */
412 std::ifstream file(JSON_DIMM_TYPE_FILE);
413 if (file)
414 {
415 file >> dimmObj;
416 file.close();
417 }
418 else
419 {
420 phosphor::logging::log<phosphor::logging::level::ERR>(
421 "DIMM type names file not found",
422 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
423 return -1;
424 }
425
426 std::string dimmKey = "dimm_type" + std::to_string(param);
427 auto obj = dimmObj[dimmKey]["short_name"];
428 data = obj;
429 return 0;
430}
431
Vijay Khemka63c99be2020-05-27 19:14:35 -0700432ipmi_ret_t getNetworkData(uint8_t lan_param, char* data)
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700433{
434 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Williamscd315e02022-07-22 19:26:52 -0500435 sdbusplus::bus_t bus(ipmid_get_sd_bus_connection());
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700436
437 const std::string ethdevice = "eth0";
438
439 switch (static_cast<LanParam>(lan_param))
440 {
Vijay Khemkad1194022020-05-27 18:58:33 -0700441 case LanParam::IP:
442 {
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700443 std::string ipaddress;
Vijay Khemkaa7231892019-10-11 11:35:05 -0700444 auto ipObjectInfo = ipmi::network::getIPObject(
Potin Lai8d1a81e2022-12-20 11:13:45 +0800445 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT,
446 ipmi::network::IPV4_PROTOCOL, ethdevice);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700447
448 auto properties = ipmi::getAllDbusProperties(
449 bus, ipObjectInfo.second, ipObjectInfo.first,
450 ipmi::network::IP_INTERFACE);
451
Patrick Williamsef0efbc2020-05-13 11:26:51 -0500452 ipaddress = std::get<std::string>(properties["Address"]);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700453
454 std::strcpy(data, ipaddress.c_str());
455 }
456 break;
457
Vijay Khemkad1194022020-05-27 18:58:33 -0700458 case LanParam::IPV6:
459 {
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700460 std::string ipaddress;
Vijay Khemkaa7231892019-10-11 11:35:05 -0700461 auto ipObjectInfo = ipmi::network::getIPObject(
Potin Lai8d1a81e2022-12-20 11:13:45 +0800462 bus, ipmi::network::IP_INTERFACE, ipmi::network::ROOT,
463 ipmi::network::IPV6_PROTOCOL, ethdevice);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700464
465 auto properties = ipmi::getAllDbusProperties(
466 bus, ipObjectInfo.second, ipObjectInfo.first,
467 ipmi::network::IP_INTERFACE);
468
Patrick Williamsef0efbc2020-05-13 11:26:51 -0500469 ipaddress = std::get<std::string>(properties["Address"]);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700470
471 std::strcpy(data, ipaddress.c_str());
472 }
473 break;
474
Vijay Khemkad1194022020-05-27 18:58:33 -0700475 case LanParam::MAC:
476 {
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700477 std::string macAddress;
478 auto macObjectInfo =
479 ipmi::getDbusObject(bus, ipmi::network::MAC_INTERFACE,
480 ipmi::network::ROOT, ethdevice);
481
482 auto variant = ipmi::getDbusProperty(
483 bus, macObjectInfo.second, macObjectInfo.first,
484 ipmi::network::MAC_INTERFACE, "MACAddress");
485
Patrick Williamsef0efbc2020-05-13 11:26:51 -0500486 macAddress = std::get<std::string>(variant);
Vijay Khemka1b6fae32019-03-25 17:43:01 -0700487
488 sscanf(macAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT,
489 (data), (data + 1), (data + 2), (data + 3), (data + 4),
490 (data + 5));
491 std::strcpy(data, macAddress.c_str());
492 }
493 break;
494
495 default:
496 rc = IPMI_CC_PARM_OUT_OF_RANGE;
497 }
498 return rc;
499}
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800500
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530501bool isMultiHostPlatform()
502{
503 bool platform;
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +0530504 if (hostInstances == "0")
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530505 {
506 platform = false;
507 }
508 else
509 {
510 platform = true;
511 }
512 return platform;
513}
514
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800515// return code: 0 successful
Vijay Khemka63c99be2020-05-27 19:14:35 -0700516int8_t getFruData(std::string& data, std::string& name)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800517{
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530518 size_t pos;
519 static constexpr const auto depth = 0;
520 std::vector<std::string> paths;
521 std::string machinePath;
522 std::string baseBoard = "Baseboard";
523
524 bool platform = isMultiHostPlatform();
525 if (platform == true)
526 {
Karthikeyan Pasupathie1ff81f2022-11-21 17:54:46 +0530527 getSelectorPosition(pos);
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530528 }
529
530 sd_bus* bus = NULL;
531 int ret = sd_bus_default_system(&bus);
532 if (ret < 0)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800533 {
534 phosphor::logging::log<phosphor::logging::level::ERR>(
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530535 "Failed to connect to system bus",
536 phosphor::logging::entry("ERRNO=0x%X", -ret));
537 sd_bus_unref(bus);
538 return -1;
539 }
Patrick Williamscd315e02022-07-22 19:26:52 -0500540 sdbusplus::bus_t dbus(bus);
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530541 auto mapperCall = dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
542 "/xyz/openbmc_project/object_mapper",
543 "xyz.openbmc_project.ObjectMapper",
544 "GetSubTreePaths");
545 static constexpr std::array<const char*, 1> interface = {
546 "xyz.openbmc_project.Inventory.Decorator.Asset"};
547 mapperCall.append("/xyz/openbmc_project/inventory/", depth, interface);
548
549 try
550 {
551 auto reply = dbus.call(mapperCall);
552 reply.read(paths);
553 }
554 catch (sdbusplus::exception_t& e)
555 {
556 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800557 return -1;
558 }
559
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530560 for (const auto& path : paths)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800561 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530562 if (platform == true)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800563 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530564 if (pos == BMC_POS)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800565 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530566 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800567 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530568 else
569 {
570 machinePath = "_" + std::to_string(pos);
571 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800572 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530573 else
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800574 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530575 machinePath = baseBoard;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800576 }
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530577
578 auto found = path.find(machinePath);
Patrick Williams123cbcc2022-06-24 06:13:59 -0500579 if (found == std::string::npos)
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530580 {
581 continue;
582 }
583
584 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
585 std::string service = getService(
586 *dbus, "xyz.openbmc_project.Inventory.Decorator.Asset", path);
587
588 auto Value = ipmi::getDbusProperty(
589 *dbus, service, path,
590 "xyz.openbmc_project.Inventory.Decorator.Asset", name);
591
592 data = std::get<std::string>(Value);
593 return 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800594 }
595 return -1;
596}
597
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530598int8_t sysConfig(std::vector<std::string>& data, size_t pos)
599{
600 nlohmann::json sysObj;
601 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(pos);
602 std::string result, typeName;
603 uint8_t res[MAX_BUF];
604
605 /* Get sysConfig data stored in json file */
606 std::ifstream file(JSON_OEM_DATA_FILE);
607 if (file)
608 {
609 file >> sysObj;
610 file.close();
611 }
612 else
613 {
614 phosphor::logging::log<phosphor::logging::level::ERR>(
615 "oemData file not found",
616 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
617 return -1;
618 }
619
620 if (sysObj.find(dimmInfo) == sysObj.end())
621 {
622 phosphor::logging::log<phosphor::logging::level::ERR>(
623 "sysconfig key not available",
624 phosphor::logging::entry("SYS_JSON_KEY=%s", dimmInfo.c_str()));
625 return -1;
626 }
627 /* Get dimm type names stored in json file */
628 nlohmann::json dimmObj;
629 std::ifstream dimmFile(JSON_DIMM_TYPE_FILE);
630 if (file)
631 {
632 dimmFile >> dimmObj;
633 dimmFile.close();
634 }
635 else
636 {
637 phosphor::logging::log<phosphor::logging::level::ERR>(
638 "DIMM type names file not found",
639 phosphor::logging::entry("DIMM_TYPE_FILE=%s", JSON_DIMM_TYPE_FILE));
640 return -1;
641 }
642 std::vector<std::string> a;
643 for (auto& j : dimmObj.items())
644 {
645 std::string name = j.key();
646 a.push_back(name);
647 }
648
649 uint8_t len = a.size();
650 for (uint8_t ii = 0; ii < len; ii++)
651 {
652 std::string indKey = std::to_string(ii);
653 std::string speedSize = sysObj[dimmInfo][indKey][DIMM_SPEED];
654 strToBytes(speedSize, res);
655 auto speed = (res[1] << 8 | res[0]);
656 size_t dimmSize = ((res[3] << 8 | res[2]) / 1000);
657
658 if (dimmSize == 0)
659 {
660 std::cerr << "Dimm information not available for slot_" +
661 std::to_string(ii)
662 << std::endl;
663 continue;
664 }
665 std::string type = sysObj[dimmInfo][indKey][DIMM_TYPE];
666 std::string dualInlineMem = sysObj[dimmInfo][indKey][KEY_DIMM_TYPE];
667 strToBytes(type, res);
668 size_t dimmType = res[0];
669 if (dimmVenMap.find(dimmType) == dimmVenMap.end())
670 {
671 typeName = "unknown";
672 }
673 else
674 {
675 typeName = dimmVenMap[dimmType];
676 }
677 result = dualInlineMem + "/" + typeName + "/" + std::to_string(speed) +
678 "MHz" + "/" + std::to_string(dimmSize) + "GB";
679 data.push_back(result);
680 }
681 return 0;
682}
683
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +0530684int8_t procInfo(std::string& result, size_t pos)
685{
686 std::vector<char> data;
687 uint8_t res[MAX_BUF];
688 std::string procIndex = "00";
689 nlohmann::json proObj;
690 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(pos);
691 /* Get processor data stored in json file */
692 std::ifstream file(JSON_OEM_DATA_FILE);
693 if (file)
694 {
695 file >> proObj;
696 file.close();
697 }
698 else
699 {
700 phosphor::logging::log<phosphor::logging::level::ERR>(
701 "oemData file not found",
702 phosphor::logging::entry("OEM_DATA_FILE=%s", JSON_OEM_DATA_FILE));
703 return -1;
704 }
705 if (proObj.find(procInfo) == proObj.end())
706 {
707 phosphor::logging::log<phosphor::logging::level::ERR>(
708 "processor info key not available",
709 phosphor::logging::entry("PROC_JSON_KEY=%s", procInfo.c_str()));
710 return -1;
711 }
712 std::string procName = proObj[procInfo][procIndex][KEY_PROC_NAME];
713 std::string basicInfo = proObj[procInfo][procIndex][KEY_BASIC_INFO];
714 // Processor Product Name
715 strToBytes(procName, res);
716 data.assign(reinterpret_cast<char*>(&res),
717 reinterpret_cast<char*>(&res) + sizeof(res));
718
719 std::string s(data.begin(), data.end());
720 std::regex regex(" ");
721 std::vector<std::string> productName(
722 std::sregex_token_iterator(s.begin(), s.end(), regex, -1),
723 std::sregex_token_iterator());
724
725 // Processor core and frequency
726 strToBytes(basicInfo, res);
727 uint16_t coreNum = res[0];
728 double procFrequency = (float)(res[4] << 8 | res[3]) / 1000;
729 result = "CPU:" + productName[2] + "/" + std::to_string(procFrequency) +
730 "GHz" + "/" + std::to_string(coreNum) + "c";
731 return 0;
732}
733
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800734typedef struct
735{
736 uint8_t cur_power_state;
737 uint8_t last_power_event;
738 uint8_t misc_power_state;
739 uint8_t front_panel_button_cap_status;
740} ipmi_get_chassis_status_t;
741
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800742//----------------------------------------------------------------------
743// Get Debug Frame Info
744//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700745ipmi_ret_t ipmiOemDbgGetFrameInfo(ipmi_netfn_t, ipmi_cmd_t,
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800746 ipmi_request_t request,
747 ipmi_response_t response,
Willy Tue39f9392022-06-15 13:24:20 -0700748 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800749{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700750 uint8_t* req = reinterpret_cast<uint8_t*>(request);
751 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Peter Yinb340aa22024-07-08 16:07:55 +0800752 uint8_t num_frames = debugCardFrameSize;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800753
754 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
755 res[SIZE_IANA_ID] = num_frames;
756 *data_len = SIZE_IANA_ID + 1;
757
758 return IPMI_CC_OK;
759}
760
761//----------------------------------------------------------------------
762// Get Debug Updated Frames
763//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700764ipmi_ret_t ipmiOemDbgGetUpdFrames(ipmi_netfn_t, ipmi_cmd_t,
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800765 ipmi_request_t request,
766 ipmi_response_t response,
Willy Tue39f9392022-06-15 13:24:20 -0700767 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800768{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700769 uint8_t* req = reinterpret_cast<uint8_t*>(request);
770 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800771 uint8_t num_updates = 3;
772 *data_len = 4;
773
774 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
775 res[SIZE_IANA_ID] = num_updates;
776 *data_len = SIZE_IANA_ID + num_updates + 1;
777 res[SIZE_IANA_ID + 1] = 1; // info page update
778 res[SIZE_IANA_ID + 2] = 2; // cri sel update
779 res[SIZE_IANA_ID + 3] = 3; // cri sensor update
780
781 return IPMI_CC_OK;
782}
783
784//----------------------------------------------------------------------
785// Get Debug POST Description
786//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700787ipmi_ret_t ipmiOemDbgGetPostDesc(ipmi_netfn_t, ipmi_cmd_t,
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800788 ipmi_request_t request,
789 ipmi_response_t response,
Willy Tue39f9392022-06-15 13:24:20 -0700790 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800791{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700792 uint8_t* req = reinterpret_cast<uint8_t*>(request);
793 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800794 uint8_t index = 0;
795 uint8_t next = 0;
796 uint8_t end = 0;
797 uint8_t phase = 0;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700798 uint8_t descLen = 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800799 int ret;
800
801 index = req[3];
802 phase = req[4];
803
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700804 ret = plat_udbg_get_post_desc(index, &next, phase, &end, &descLen, &res[8]);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800805 if (ret)
806 {
807 memcpy(res, req, SIZE_IANA_ID); // IANA ID
808 *data_len = SIZE_IANA_ID;
809 return IPMI_CC_UNSPECIFIED_ERROR;
810 }
811
812 memcpy(res, req, SIZE_IANA_ID); // IANA ID
813 res[3] = index;
814 res[4] = next;
815 res[5] = phase;
816 res[6] = end;
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700817 res[7] = descLen;
818 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800819
820 return IPMI_CC_OK;
821}
822
823//----------------------------------------------------------------------
824// Get Debug GPIO Description
825//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700826ipmi_ret_t ipmiOemDbgGetGpioDesc(ipmi_netfn_t, ipmi_cmd_t,
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800827 ipmi_request_t request,
828 ipmi_response_t response,
Willy Tue39f9392022-06-15 13:24:20 -0700829 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800830{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700831 uint8_t* req = reinterpret_cast<uint8_t*>(request);
832 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800833
Vijay Khemka38183d62019-08-28 16:19:33 -0700834 uint8_t index = 0;
835 uint8_t next = 0;
836 uint8_t level = 0;
837 uint8_t pinDef = 0;
838 uint8_t descLen = 0;
839 int ret;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800840
Vijay Khemka38183d62019-08-28 16:19:33 -0700841 index = req[3];
842
843 ret = plat_udbg_get_gpio_desc(index, &next, &level, &pinDef, &descLen,
844 &res[8]);
845 if (ret)
846 {
847 memcpy(res, req, SIZE_IANA_ID); // IANA ID
848 *data_len = SIZE_IANA_ID;
849 return IPMI_CC_UNSPECIFIED_ERROR;
850 }
851
852 memcpy(res, req, SIZE_IANA_ID); // IANA ID
853 res[3] = index;
854 res[4] = next;
855 res[5] = level;
856 res[6] = pinDef;
857 res[7] = descLen;
858 *data_len = SIZE_IANA_ID + 5 + descLen;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800859
860 return IPMI_CC_OK;
861}
862
863//----------------------------------------------------------------------
864// Get Debug Frame Data
865//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700866ipmi_ret_t ipmiOemDbgGetFrameData(ipmi_netfn_t, ipmi_cmd_t,
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800867 ipmi_request_t request,
868 ipmi_response_t response,
Willy Tue39f9392022-06-15 13:24:20 -0700869 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800870{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700871 uint8_t* req = reinterpret_cast<uint8_t*>(request);
872 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800873 uint8_t frame;
874 uint8_t page;
875 uint8_t next;
876 uint8_t count;
877 int ret;
878
879 frame = req[3];
880 page = req[4];
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800881
882 ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res[7]);
883 if (ret)
884 {
885 memcpy(res, req, SIZE_IANA_ID); // IANA ID
886 *data_len = SIZE_IANA_ID;
887 return IPMI_CC_UNSPECIFIED_ERROR;
888 }
889
890 memcpy(res, req, SIZE_IANA_ID); // IANA ID
891 res[3] = frame;
892 res[4] = page;
893 res[5] = next;
894 res[6] = count;
895 *data_len = SIZE_IANA_ID + 4 + count;
896
897 return IPMI_CC_OK;
898}
899
900//----------------------------------------------------------------------
901// Get Debug Control Panel
902//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700903ipmi_ret_t ipmiOemDbgGetCtrlPanel(ipmi_netfn_t, ipmi_cmd_t,
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800904 ipmi_request_t request,
905 ipmi_response_t response,
Willy Tue39f9392022-06-15 13:24:20 -0700906 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800907{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700908 uint8_t* req = reinterpret_cast<uint8_t*>(request);
909 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800910
911 uint8_t panel;
912 uint8_t operation;
913 uint8_t item;
914 uint8_t count;
915 ipmi_ret_t ret;
916
917 panel = req[3];
918 operation = req[4];
919 item = req[5];
920
921 ret = plat_udbg_control_panel(panel, operation, item, &count, &res[3]);
922
923 std::memcpy(res, req, SIZE_IANA_ID); // IANA ID
924 *data_len = SIZE_IANA_ID + count;
925
926 return ret;
927}
928
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800929//----------------------------------------------------------------------
930// Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
931//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700932ipmi_ret_t ipmiOemSetDimmInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
933 ipmi_response_t, ipmi_data_len_t data_len,
934 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800935{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700936 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700937
938 uint8_t index = req[0];
939 uint8_t type = req[1];
940 uint16_t speed;
941 uint32_t size;
942
943 memcpy(&speed, &req[2], 2);
944 memcpy(&size, &req[4], 4);
945
946 std::stringstream ss;
947 ss << std::hex;
948 ss << std::setw(2) << std::setfill('0') << (int)index;
949
950 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
951 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
952 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
953 oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
954
955 flushOemData();
956
957 *data_len = 0;
958
959 return IPMI_CC_OK;
960}
961
962//----------------------------------------------------------------------
963// Get Board ID (CMD_OEM_GET_BOARD_ID)
964//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -0700965ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
966 ipmi_response_t, ipmi_data_len_t data_len,
967 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700968{
Vijay Khemka1d4a0692019-04-09 15:20:28 -0700969 /* TODO: Needs to implement this after GPIO implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800970 *data_len = 0;
971
972 return IPMI_CC_OK;
973}
974
Bonnie Lo4ae63e72023-02-09 15:27:54 +0800975//----------------------------------------------------------------------
976// Get port 80 record (CMD_OEM_GET_80PORT_RECORD)
977//----------------------------------------------------------------------
978ipmi::RspType<std::vector<uint8_t>>
979 ipmiOemGet80PortRecord(ipmi::Context::ptr ctx)
980{
981 auto postCodeService = "xyz.openbmc_project.State.Boot.PostCode" +
982 std::to_string(ctx->hostIdx + 1);
983 auto postCodeObjPath = "/xyz/openbmc_project/State/Boot/PostCode" +
984 std::to_string(ctx->hostIdx + 1);
985 constexpr auto postCodeInterface =
986 "xyz.openbmc_project.State.Boot.PostCode";
987 const static uint16_t lastestPostCodeIndex = 1;
988 constexpr const auto maxPostCodeLen =
989 224; // The length must be lower than IPMB limitation
990 size_t startIndex = 0;
991
992 std::vector<std::tuple<uint64_t, std::vector<uint8_t>>> postCodes;
993 std::vector<uint8_t> resData;
994
995 auto conn = getSdBus();
996 /* Get the post codes by calling GetPostCodes method */
Patrick Williams2405ae92023-05-10 07:50:09 -0500997 auto msg = conn->new_method_call(postCodeService.c_str(),
998 postCodeObjPath.c_str(), postCodeInterface,
999 "GetPostCodes");
Bonnie Lo4ae63e72023-02-09 15:27:54 +08001000 msg.append(lastestPostCodeIndex);
1001
1002 try
1003 {
1004 auto reply = conn->call(msg);
1005 reply.read(postCodes);
1006 }
1007 catch (const sdbusplus::exception::SdBusError& e)
1008 {
1009 phosphor::logging::log<phosphor::logging::level::ERR>(
1010 "IPMI Get80PortRecord Failed in call method",
1011 phosphor::logging::entry("ERROR=%s", e.what()));
1012 return ipmi::responseUnspecifiedError();
1013 }
1014
1015 /* Get post code data */
1016 for (size_t i = 0; i < postCodes.size(); ++i)
1017 {
1018 uint64_t primaryPostCode = std::get<uint64_t>(postCodes[i]);
1019 for (int j = postCodeSize - 1; j >= 0; --j)
1020 {
1021 uint8_t postCode =
1022 ((primaryPostCode >> (sizeof(uint64_t) * j)) & 0xFF);
1023 resData.emplace_back(postCode);
1024 }
1025 }
1026
1027 std::vector<uint8_t> response;
1028 if (resData.size() > maxPostCodeLen)
1029 {
1030 startIndex = resData.size() - maxPostCodeLen;
1031 }
1032
1033 response.assign(resData.begin() + startIndex, resData.end());
1034
1035 return ipmi::responseSuccess(response);
1036}
1037
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001038//----------------------------------------------------------------------
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001039// Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
1040//----------------------------------------------------------------------
Jayashree-Df0cf6652020-11-30 11:03:30 +05301041ipmi::RspType<std::vector<uint8_t>>
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001042 ipmiOemSetBootOrder(ipmi::Context::ptr ctx, std::vector<uint8_t> bootSeq)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001043{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001044 size_t len = bootSeq.size();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001045
1046 if (len != SIZE_BOOT_ORDER)
1047 {
1048 phosphor::logging::log<phosphor::logging::level::ERR>(
1049 "Invalid Boot order length received");
Jayashree-Df0cf6652020-11-30 11:03:30 +05301050 return ipmi::responseReqDataLenInvalid();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001051 }
1052
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301053 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001054
Jayashree-Df0cf6652020-11-30 11:03:30 +05301055 if (!hostId)
1056 {
1057 phosphor::logging::log<phosphor::logging::level::ERR>(
1058 "Invalid Host Id received");
1059 return ipmi::responseInvalidCommand();
1060 }
1061 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1062
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001063 ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301064
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001065 return ipmi::responseSuccess(bootSeq);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001066}
1067
1068//----------------------------------------------------------------------
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001069// Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
1070//----------------------------------------------------------------------
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001071ipmi::RspType<std::vector<uint8_t>> ipmiOemGetBootOrder(ipmi::Context::ptr ctx)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001072{
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001073 std::vector<uint8_t> bootSeq;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001074
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +05301075 std::optional<size_t> hostId = findHost(ctx->hostIdx);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001076
Jayashree-Df0cf6652020-11-30 11:03:30 +05301077 if (!hostId)
1078 {
1079 phosphor::logging::log<phosphor::logging::level::ERR>(
1080 "Invalid Host Id received");
1081 return ipmi::responseInvalidCommand();
1082 }
1083 auto [bootObjPath, hostName] = ipmi::boot::objPath(*hostId);
1084
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001085 ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName);
Jayashree-Df0cf6652020-11-30 11:03:30 +05301086
Delphine CC Chiu7bb45922023-04-10 13:34:04 +08001087 return ipmi::responseSuccess(bootSeq);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001088}
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001089// Set Machine Config Info (CMD_OEM_SET_MACHINE_CONFIG_INFO)
1090//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001091ipmi_ret_t ipmiOemSetMachineCfgInfo(ipmi_netfn_t, ipmi_cmd_t,
1092 ipmi_request_t request, ipmi_response_t,
1093 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001094{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001095 machineConfigInfo_t* req = reinterpret_cast<machineConfigInfo_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001096 uint8_t len = *data_len;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001097
1098 *data_len = 0;
1099
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001100 if (len < sizeof(machineConfigInfo_t))
1101 {
1102 phosphor::logging::log<phosphor::logging::level::ERR>(
1103 "Invalid machine configuration length received");
1104 return IPMI_CC_REQ_DATA_LEN_INVALID;
1105 }
1106
Vijay Khemka63c99be2020-05-27 19:14:35 -07001107 if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001108 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
1109 else
1110 oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
1111 chassisType[req->chassis_type];
1112
Vijay Khemka63c99be2020-05-27 19:14:35 -07001113 if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001114 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
1115 else
1116 oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
1117
1118 oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
1119 oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
1120 oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
1121 oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
1122
Vijay Khemka63c99be2020-05-27 19:14:35 -07001123 if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001124 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
1125 else
1126 oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
1127
1128 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
1129 int i = 0;
1130 if (req->pcie_card_loc & BIT_0)
1131 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
1132 if (req->pcie_card_loc & BIT_1)
1133 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
1134 if (req->pcie_card_loc & BIT_2)
1135 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
1136 if (req->pcie_card_loc & BIT_3)
1137 oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
1138
Vijay Khemka63c99be2020-05-27 19:14:35 -07001139 if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001140 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
1141 else
1142 oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
1143 pcieType[req->slot1_pcie_type];
1144
Vijay Khemka63c99be2020-05-27 19:14:35 -07001145 if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001146 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
1147 else
1148 oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
1149 pcieType[req->slot2_pcie_type];
1150
Vijay Khemka63c99be2020-05-27 19:14:35 -07001151 if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001152 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
1153 else
1154 oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
1155 pcieType[req->slot3_pcie_type];
1156
Vijay Khemka63c99be2020-05-27 19:14:35 -07001157 if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t*))
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001158 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
1159 else
1160 oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
1161 pcieType[req->slot4_pcie_type];
1162
1163 oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
1164
1165 flushOemData();
1166
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001167 return IPMI_CC_OK;
1168}
1169
1170//----------------------------------------------------------------------
1171// Set POST start (CMD_OEM_SET_POST_START)
1172//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001173ipmi_ret_t ipmiOemSetPostStart(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1174 ipmi_response_t, ipmi_data_len_t data_len,
1175 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001176{
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001177 phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
1178
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001179 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001180 *data_len = 0;
1181 return IPMI_CC_OK;
1182}
1183
1184//----------------------------------------------------------------------
1185// Set POST End (CMD_OEM_SET_POST_END)
1186//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001187ipmi_ret_t ipmiOemSetPostEnd(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1188 ipmi_response_t, ipmi_data_len_t data_len,
1189 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001190{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001191 struct timespec ts;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001192
1193 phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
1194
1195 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001196
1197 // Timestamp post end time.
1198 clock_gettime(CLOCK_REALTIME, &ts);
1199 oemData[KEY_TS_SLED] = ts.tv_sec;
1200 flushOemData();
1201
1202 // Sync time with system
1203 // TODO: Add code for syncing time
1204
1205 return IPMI_CC_OK;
1206}
1207
1208//----------------------------------------------------------------------
1209// Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
1210//----------------------------------------------------------------------
1211// Inform BMC about PPIN data of 8 bytes for each CPU
1212//
1213// Request:
1214// Byte 1:8 – CPU0 PPIN data
1215// Optional:
1216// Byte 9:16 – CPU1 PPIN data
1217//
1218// Response:
1219// Byte 1 – Completion Code
Willy Tue39f9392022-06-15 13:24:20 -07001220ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1221 ipmi_response_t, ipmi_data_len_t data_len,
1222 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001223{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001224 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001225 std::string ppinStr;
1226 int len;
1227
1228 if (*data_len > SIZE_CPU_PPIN * 2)
1229 len = SIZE_CPU_PPIN * 2;
1230 else
1231 len = *data_len;
1232 *data_len = 0;
1233
1234 ppinStr = bytesToStr(req, len);
1235 oemData[KEY_PPIN_INFO] = ppinStr.c_str();
1236 flushOemData();
1237
1238 return IPMI_CC_OK;
1239}
1240
1241//----------------------------------------------------------------------
1242// Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
1243//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001244ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1245 ipmi_response_t, ipmi_data_len_t data_len,
1246 ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001247{
1248 /* Do nothing, return success */
1249 *data_len = 0;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001250 return IPMI_CC_OK;
1251}
1252
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001253// Helper function to set guid at offset in EEPROM
Willy Tue39f9392022-06-15 13:24:20 -07001254[[maybe_unused]] static int setGUID(off_t offset, uint8_t* guid)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001255{
1256 int fd = -1;
1257 ssize_t len;
1258 int ret = 0;
cchouxb2ae88b2023-09-13 00:35:36 +08001259 std::string eepromPath = FRU_EEPROM;
1260
1261 // find the eeprom path of MB FRU
1262 auto device = getMbFruDevice();
1263 if (device)
1264 {
1265 auto [bus, address] = *device;
1266 std::stringstream ss;
1267 ss << "/sys/bus/i2c/devices/" << static_cast<int>(bus) << "-"
1268 << std::setw(4) << std::setfill('0') << std::hex
1269 << static_cast<int>(address) << "/eeprom";
1270 eepromPath = ss.str();
1271 }
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001272
1273 errno = 0;
1274
1275 // Check if file is present
cchouxb2ae88b2023-09-13 00:35:36 +08001276 if (access(eepromPath.c_str(), F_OK) == -1)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001277 {
cchouxb2ae88b2023-09-13 00:35:36 +08001278 std::cerr << "Unable to access: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001279 return errno;
1280 }
1281
1282 // Open the file
cchouxb2ae88b2023-09-13 00:35:36 +08001283 fd = open(eepromPath.c_str(), O_WRONLY);
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001284 if (fd == -1)
1285 {
cchouxb2ae88b2023-09-13 00:35:36 +08001286 std::cerr << "Unable to open: " << eepromPath << std::endl;
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001287 return errno;
1288 }
1289
1290 // seek to the offset
1291 lseek(fd, offset, SEEK_SET);
1292
1293 // Write bytes to location
1294 len = write(fd, guid, GUID_SIZE);
1295 if (len != GUID_SIZE)
1296 {
1297 phosphor::logging::log<phosphor::logging::level::ERR>(
1298 "GUID write data to EEPROM failed");
1299 ret = errno;
1300 }
1301
1302 close(fd);
1303 return ret;
1304}
1305
1306//----------------------------------------------------------------------
1307// Set System GUID (CMD_OEM_SET_SYSTEM_GUID)
1308//----------------------------------------------------------------------
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301309#if BIC_ENABLED
Bonnie Lo3f671272022-10-12 15:46:45 +08001310ipmi::RspType<> ipmiOemSetSystemGuid(ipmi::Context::ptr ctx,
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301311 std::vector<uint8_t> reqData)
1312{
1313 std::vector<uint8_t> respData;
1314
1315 if (reqData.size() != GUID_SIZE) // 16bytes
1316 {
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301317 return ipmi::responseReqDataLenInvalid();
1318 }
1319
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301320 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
1321
1322 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, reqData, respData))
1323 return ipmi::responseUnspecifiedError();
1324
1325 return ipmi::responseSuccess();
1326}
1327
1328#else
Potin Laid5353ca2022-08-11 04:52:11 +00001329ipmi_ret_t ipmiOemSetSystemGuid(ipmi_netfn_t, ipmi_cmd_t,
1330 ipmi_request_t request, ipmi_response_t,
1331 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001332{
1333 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1334
1335 if (*data_len != GUID_SIZE) // 16bytes
1336 {
1337 *data_len = 0;
1338 return IPMI_CC_REQ_DATA_LEN_INVALID;
1339 }
1340
1341 *data_len = 0;
1342
1343 if (setGUID(OFFSET_SYS_GUID, req))
1344 {
1345 return IPMI_CC_UNSPECIFIED_ERROR;
1346 }
1347 return IPMI_CC_OK;
1348}
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05301349#endif
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07001350
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001351//----------------------------------------------------------------------
1352// Set Bios Flash Info (CMD_OEM_SET_BIOS_FLASH_INFO)
1353//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001354ipmi_ret_t ipmiOemSetBiosFlashInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1355 ipmi_response_t, ipmi_data_len_t data_len,
1356 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001357{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001358 /* Do nothing, return success */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001359 *data_len = 0;
1360 return IPMI_CC_OK;
1361}
1362
1363//----------------------------------------------------------------------
1364// Set PPR (CMD_OEM_SET_PPR)
1365//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001366ipmi_ret_t ipmiOemSetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1367 ipmi_response_t, ipmi_data_len_t data_len,
1368 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001369{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001370 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001371 uint8_t pprCnt, pprAct, pprIndex;
1372 uint8_t selParam = req[0];
1373 uint8_t len = *data_len;
1374 std::stringstream ss;
1375 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001376
1377 *data_len = 0;
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001378
1379 switch (selParam)
1380 {
1381 case PPR_ACTION:
1382 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
1383 oemData[KEY_PPR].end())
1384 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1385
1386 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1387 if (pprCnt == 0)
1388 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
1389
1390 pprAct = req[1];
1391 /* Check if ppr is enabled or disabled */
1392 if (!(pprAct & 0x80))
1393 pprAct = 0;
1394
1395 oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
1396 break;
1397 case PPR_ROW_COUNT:
1398 if (req[1] > 100)
1399 return IPMI_CC_PARM_OUT_OF_RANGE;
1400
1401 oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
1402 break;
1403 case PPR_ROW_ADDR:
1404 pprIndex = req[1];
1405 if (pprIndex > 100)
1406 return IPMI_CC_PARM_OUT_OF_RANGE;
1407
1408 if (len < PPR_ROW_ADDR_LEN + 1)
1409 {
1410 phosphor::logging::log<phosphor::logging::level::ERR>(
1411 "Invalid PPR Row Address length received");
1412 return IPMI_CC_REQ_DATA_LEN_INVALID;
1413 }
1414
1415 ss << std::hex;
1416 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1417
1418 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1419
1420 str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
1421 oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
1422 break;
1423 case PPR_HISTORY_DATA:
1424 pprIndex = req[1];
1425 if (pprIndex > 100)
1426 return IPMI_CC_PARM_OUT_OF_RANGE;
1427
1428 if (len < PPR_HST_DATA_LEN + 1)
1429 {
1430 phosphor::logging::log<phosphor::logging::level::ERR>(
1431 "Invalid PPR history data length received");
1432 return IPMI_CC_REQ_DATA_LEN_INVALID;
1433 }
1434
1435 ss << std::hex;
1436 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1437
1438 oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
1439
1440 str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
1441 oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
1442 break;
1443 default:
1444 return IPMI_CC_PARM_OUT_OF_RANGE;
1445 break;
1446 }
1447
1448 flushOemData();
1449
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001450 return IPMI_CC_OK;
1451}
1452
1453//----------------------------------------------------------------------
1454// Get PPR (CMD_OEM_GET_PPR)
1455//----------------------------------------------------------------------
Willy Tue39f9392022-06-15 13:24:20 -07001456ipmi_ret_t ipmiOemGetPpr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1457 ipmi_response_t response, ipmi_data_len_t data_len,
1458 ipmi_context_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001459{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001460 uint8_t* req = reinterpret_cast<uint8_t*>(request);
1461 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001462 uint8_t pprCnt, pprIndex;
1463 uint8_t selParam = req[0];
1464 std::stringstream ss;
1465 std::string str;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001466
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001467 /* Any failure will return zero length data */
1468 *data_len = 0;
1469
1470 switch (selParam)
1471 {
1472 case PPR_ACTION:
1473 res[0] = 0;
1474 *data_len = 1;
1475
1476 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1477 oemData[KEY_PPR].end())
1478 {
1479 pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1480 if (pprCnt != 0)
1481 {
1482 if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
1483 oemData[KEY_PPR].end())
1484 {
1485 res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
1486 }
1487 }
1488 }
1489 break;
1490 case PPR_ROW_COUNT:
1491 res[0] = 0;
1492 *data_len = 1;
1493 if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
1494 oemData[KEY_PPR].end())
1495 res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
1496 break;
1497 case PPR_ROW_ADDR:
1498 pprIndex = req[1];
1499 if (pprIndex > 100)
1500 return IPMI_CC_PARM_OUT_OF_RANGE;
1501
1502 ss << std::hex;
1503 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1504
1505 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1506 return IPMI_CC_PARM_OUT_OF_RANGE;
1507
1508 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
1509 oemData[KEY_PPR][ss.str()].end())
1510 return IPMI_CC_PARM_OUT_OF_RANGE;
1511
1512 str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
1513 *data_len = strToBytes(str, res);
1514 break;
1515 case PPR_HISTORY_DATA:
1516 pprIndex = req[1];
1517 if (pprIndex > 100)
1518 return IPMI_CC_PARM_OUT_OF_RANGE;
1519
1520 ss << std::hex;
1521 ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
1522
1523 if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
1524 return IPMI_CC_PARM_OUT_OF_RANGE;
1525
1526 if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
1527 oemData[KEY_PPR][ss.str()].end())
1528 return IPMI_CC_PARM_OUT_OF_RANGE;
1529
1530 str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
1531 *data_len = strToBytes(str, res);
1532 break;
1533 default:
1534 return IPMI_CC_PARM_OUT_OF_RANGE;
1535 break;
1536 }
1537
1538 return IPMI_CC_OK;
1539}
1540
1541/* FB OEM QC Commands */
1542
1543//----------------------------------------------------------------------
1544// Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
1545//----------------------------------------------------------------------
1546//"Request:
1547// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1548// Byte 4 – Processor Index, 0 base
1549// Byte 5 – Parameter Selector
1550// Byte 6..N – Configuration parameter data (see below for Parameters
1551// of Processor Information)
1552// Response:
1553// Byte 1 – Completion code
1554//
1555// Parameter#1: (Processor Product Name)
1556//
1557// Byte 1..48 –Product name(ASCII code)
1558// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1559//
1560// Param#2: Processor Basic Information
1561// Byte 1 – Core Number
1562// Byte 2 – Thread Number (LSB)
1563// Byte 3 – Thread Number (MSB)
1564// Byte 4 – Processor frequency in MHz (LSB)
1565// Byte 5 – Processor frequency in MHz (MSB)
1566// Byte 6..7 – Revision
1567//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301568
1569ipmi::RspType<> ipmiOemQSetProcInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t,
1570 uint8_t, uint8_t procIndex,
1571 uint8_t paramSel,
1572 std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001573{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001574 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001575 std::stringstream ss;
1576 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301577 uint8_t len = request.size();
1578 auto hostId = findHost(ctx->hostIdx);
1579 if (!hostId)
1580 {
1581 phosphor::logging::log<phosphor::logging::level::ERR>(
1582 "Invalid Host Id received");
1583 return ipmi::responseInvalidCommand();
1584 }
1585 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001586 /* check for requested data params */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301587 if (len < 5 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001588 {
1589 phosphor::logging::log<phosphor::logging::level::ERR>(
1590 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301591 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001592 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001593 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301594 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1595 oemData[procInfo][ss.str()][KEY_PROC_INDEX] = procIndex;
1596 str = bytesToStr(request.data(), len);
1597 oemData[procInfo][ss.str()][cpuInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001598 flushOemData();
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301599 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001600}
1601
1602//----------------------------------------------------------------------
1603// Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
1604//----------------------------------------------------------------------
1605// Request:
1606// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
1607// Byte 4 – Processor Index, 0 base
1608// Byte 5 – Parameter Selector
1609// Response:
1610// Byte 1 – Completion code
1611// Byte 2..N – Configuration Parameter Data (see below for Parameters
1612// of Processor Information)
1613//
1614// Parameter#1: (Processor Product Name)
1615//
1616// Byte 1..48 –Product name(ASCII code)
1617// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
1618//
1619// Param#2: Processor Basic Information
1620// Byte 1 – Core Number
1621// Byte 2 – Thread Number (LSB)
1622// Byte 3 – Thread Number (MSB)
1623// Byte 4 – Processor frequency in MHz (LSB)
1624// Byte 5 – Processor frequency in MHz (MSB)
1625// Byte 6..7 – Revision
1626//
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301627
1628ipmi::RspType<std::vector<uint8_t>>
1629 ipmiOemQGetProcInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t,
1630 uint8_t procIndex, uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001631{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001632 uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001633 std::stringstream ss;
1634 std::string str;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301635 uint8_t res[MAX_BUF];
1636 auto hostId = findHost(ctx->hostIdx);
1637 if (!hostId)
1638 {
1639 phosphor::logging::log<phosphor::logging::level::ERR>(
1640 "Invalid Host Id received");
1641 return ipmi::responseInvalidCommand();
1642 }
1643 std::string procInfo = KEY_Q_PROC_INFO + std::to_string(*hostId);
1644 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001645 {
1646 phosphor::logging::log<phosphor::logging::level::ERR>(
1647 "Invalid parameter received");
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301648 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001649 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001650 ss << std::hex;
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301651 ss << std::setw(2) << std::setfill('0') << (int)procIndex;
1652 if (oemData[procInfo].find(ss.str()) == oemData[procInfo].end())
1653 return ipmi::responseCommandNotAvailable();
1654 if (oemData[procInfo][ss.str()].find(cpuInfoKey[paramSel]) ==
1655 oemData[procInfo][ss.str()].end())
1656 return ipmi::responseCommandNotAvailable();
1657 str = oemData[procInfo][ss.str()][cpuInfoKey[paramSel]];
1658 int dataLen = strToBytes(str, res);
1659 std::vector<uint8_t> response(&res[0], &res[dataLen]);
1660 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001661}
1662
1663//----------------------------------------------------------------------
1664// Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
1665//----------------------------------------------------------------------
1666// Request:
1667// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1668// Byte 4 – DIMM Index, 0 base
1669// Byte 5 – Parameter Selector
1670// Byte 6..N – Configuration parameter data (see below for Parameters
1671// of DIMM Information)
1672// Response:
1673// Byte 1 – Completion code
1674//
1675// Param#1 (DIMM Location):
1676// Byte 1 – DIMM Present
1677// Byte 1 – DIMM Present
1678// 01h – Present
1679// FFh – Not Present
1680// Byte 2 – Node Number, 0 base
1681// Byte 3 – Channel Number , 0 base
1682// Byte 4 – DIMM Number , 0 base
1683//
1684// Param#2 (DIMM Type):
1685// Byte 1 – DIMM Type
1686// Bit [7:6]
1687// For DDR3
1688// 00 – Normal Voltage (1.5V)
1689// 01 – Ultra Low Voltage (1.25V)
1690// 10 – Low Voltage (1.35V)
1691// 11 – Reserved
1692// For DDR4
1693// 00 – Reserved
1694// 01 – Reserved
1695// 10 – Reserved
1696// 11 – Normal Voltage (1.2V)
1697// Bit [5:0]
1698// 0x00 – SDRAM
1699// 0x01 – DDR-1 RAM
1700// 0x02 – Rambus
1701// 0x03 – DDR-2 RAM
1702// 0x04 – FBDIMM
1703// 0x05 – DDR-3 RAM
1704// 0x06 – DDR-4 RAM
1705//
1706// Param#3 (DIMM Speed):
1707// Byte 1..2 – DIMM speed in MHz, LSB
1708// Byte 3..6 – DIMM size in Mbytes, LSB
1709//
1710// Param#4 (Module Part Number):
1711// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1712//
1713// Param#5 (Module Serial Number):
1714// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1715//
1716// Param#6 (Module Manufacturer ID):
1717// Byte 1 - Module Manufacturer ID, LSB
1718// Byte 2 - Module Manufacturer ID, MSB
1719//
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301720ipmi::RspType<> ipmiOemQSetDimmInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t,
1721 uint8_t, uint8_t dimmIndex,
1722 uint8_t paramSel,
1723 std::vector<uint8_t> request)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001724{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001725 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001726 std::stringstream ss;
1727 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301728 uint8_t len = request.size();
1729 std::string dimmType;
1730 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001731 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301732 if (!hostId)
1733 {
1734 phosphor::logging::log<phosphor::logging::level::ERR>(
1735 "Invalid Host Id received");
1736 return ipmi::responseInvalidCommand();
1737 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001738
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301739 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001740
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301741 if (len < 3 || paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001742 {
1743 phosphor::logging::log<phosphor::logging::level::ERR>(
1744 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301745 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001746 }
1747
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001748 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301749 ss << (int)dimmIndex;
1750 oemData[dimmInfo][ss.str()][KEY_DIMM_INDEX] = dimmIndex;
1751 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1752 str = bytesToStr(request.data(), len);
1753 oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]] = str.c_str();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001754 flushOemData();
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301755 return ipmi::responseSuccess();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001756}
1757
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001758// Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
1759//----------------------------------------------------------------------
1760// Request:
1761// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
1762// Byte 4 – DIMM Index, 0 base
1763// Byte 5 – Parameter Selector
1764// Byte 6..N – Configuration parameter data (see below for Parameters
1765// of DIMM Information)
1766// Response:
1767// Byte 1 – Completion code
1768// Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
1769// of DIMM Information)
1770//
1771// Param#1 (DIMM Location):
1772// Byte 1 – DIMM Present
1773// Byte 1 – DIMM Present
1774// 01h – Present
1775// FFh – Not Present
1776// Byte 2 – Node Number, 0 base
1777// Byte 3 – Channel Number , 0 base
1778// Byte 4 – DIMM Number , 0 base
1779//
1780// Param#2 (DIMM Type):
1781// Byte 1 – DIMM Type
1782// Bit [7:6]
1783// For DDR3
1784// 00 – Normal Voltage (1.5V)
1785// 01 – Ultra Low Voltage (1.25V)
1786// 10 – Low Voltage (1.35V)
1787// 11 – Reserved
1788// For DDR4
1789// 00 – Reserved
1790// 01 – Reserved
1791// 10 – Reserved
1792// 11 – Normal Voltage (1.2V)
1793// Bit [5:0]
1794// 0x00 – SDRAM
1795// 0x01 – DDR-1 RAM
1796// 0x02 – Rambus
1797// 0x03 – DDR-2 RAM
1798// 0x04 – FBDIMM
1799// 0x05 – DDR-3 RAM
1800// 0x06 – DDR-4 RAM
1801//
1802// Param#3 (DIMM Speed):
1803// Byte 1..2 – DIMM speed in MHz, LSB
1804// Byte 3..6 – DIMM size in Mbytes, LSB
1805//
1806// Param#4 (Module Part Number):
1807// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
1808//
1809// Param#5 (Module Serial Number):
1810// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
1811//
1812// Param#6 (Module Manufacturer ID):
1813// Byte 1 - Module Manufacturer ID, LSB
1814// Byte 2 - Module Manufacturer ID, MSB
1815//
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301816ipmi::RspType<std::vector<uint8_t>>
1817 ipmiOemQGetDimmInfo(ipmi::Context::ptr ctx, uint8_t, uint8_t, uint8_t,
1818 uint8_t dimmIndex, uint8_t paramSel)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001819{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001820 uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t*);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301821 uint8_t res[MAX_BUF];
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001822 std::stringstream ss;
1823 std::string str;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301824 std::string dimmType;
1825 readDimmType(dimmType, dimmIndex);
Patrick Williams6d9e9a72022-07-18 10:30:50 -05001826 auto hostId = findHost(ctx->hostIdx);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301827 if (!hostId)
1828 {
1829 phosphor::logging::log<phosphor::logging::level::ERR>(
1830 "Invalid Host Id received");
1831 return ipmi::responseInvalidCommand();
1832 }
1833 std::string dimmInfo = KEY_Q_DIMM_INFO + std::to_string(*hostId);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001834
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301835 if (paramSel < 1 || paramSel >= numParam)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001836 {
1837 phosphor::logging::log<phosphor::logging::level::ERR>(
1838 "Invalid parameter received");
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301839 return ipmi::responseParmOutOfRange();
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001840 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001841 ss << std::hex;
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301842 ss << (int)dimmIndex;
1843 oemData[dimmInfo][ss.str()][KEY_DIMM_TYPE] = dimmType;
1844 if (oemData[dimmInfo].find(ss.str()) == oemData[dimmInfo].end())
1845 return ipmi::responseCommandNotAvailable();
1846 if (oemData[dimmInfo][ss.str()].find(dimmInfoKey[paramSel]) ==
1847 oemData[dimmInfo][ss.str()].end())
1848 return ipmi::responseCommandNotAvailable();
1849 str = oemData[dimmInfo][ss.str()][dimmInfoKey[paramSel]];
1850 int data_length = strToBytes(str, res);
1851 std::vector<uint8_t> response(&res[0], &res[data_length]);
1852 return ipmi::responseSuccess(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001853}
1854
1855//----------------------------------------------------------------------
1856// Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
1857//----------------------------------------------------------------------
1858// BIOS issue this command to provide HDD information to BMC.
1859//
1860// BIOS just can get information by standard ATA / SMART command for
1861// OB SATA controller.
1862// BIOS can get
1863// 1. Serial Number
1864// 2. Model Name
1865// 3. HDD FW Version
1866// 4. HDD Capacity
1867// 5. HDD WWN
1868//
1869// Use Get HDD info Param #5 to know the MAX HDD info index.
1870//
1871// Request:
1872// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1873// Byte 4 –
1874// [7:4] Reserved
1875// [3:0] HDD Controller Type
1876// 0x00 – BIOS
1877// 0x01 – Expander
1878// 0x02 – LSI
1879// Byte 5 – HDD Info Index, 0 base
1880// Byte 6 – Parameter Selector
1881// Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
1882// Information)
1883//
1884// Response:
1885// Byte 1 – Completion Code
1886//
1887// Param#0 (HDD Location):
1888// Byte 1 – Controller
1889// [7:3] Device Number
1890// [2:0] Function Number
1891// For Intel C610 series (Wellsburg)
1892// D31:F2 (0xFA) – SATA control 1
1893// D31:F5 (0xFD) – SATA control 2
1894// D17:F4 (0x8C) – sSata control
1895// Byte 2 – Port Number
1896// Byte 3 – Location (0xFF: No HDD Present)
1897// BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
1898// #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
1899// the HDD present. BMC or other people who know the HDD location has
1900// responsibility for update Location info
1901//
1902// Param#1 (Serial Number):
1903// Bytes 1..33: HDD Serial Number
1904//
1905// Param#2 (Model Name):
1906// Byte 1..33 – HDD Model Name
1907//
1908// Param#3 (HDD FW Version):
1909// Byte 1..17 –HDD FW version
1910//
1911// Param#4 (Capacity):
1912// Byte 1..4 –HDD Block Size, LSB
1913// Byte 5..12 - HDD Block Number, LSB
1914// HDD Capacity = HDD Block size * HDD BLock number (Unit Byte)
1915//
1916// Param#5 (Max HDD Quantity):
1917// Byte 1 - Max HDD Quantity
1918// Max supported port numbers in this PCH
1919//
1920// Param#6 (HDD Type)
1921// Byte 1 – HDD Type
1922// 0h – Reserved
1923// 1h – SAS
1924// 2h – SATA
1925// 3h – PCIE SSD (NVME)
1926//
1927// Param#7 (HDD WWN)
1928// Data 1...8: HDD World Wide Name, LSB
1929//
Willy Tue39f9392022-06-15 13:24:20 -07001930ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t, ipmi_cmd_t,
1931 ipmi_request_t request, ipmi_response_t,
1932 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001933{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001934 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1935 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001936 uint8_t ctrlType = req->hddCtrlType & 0x0f;
1937 std::stringstream ss;
1938 std::string str;
1939 uint8_t len = *data_len;
1940
1941 *data_len = 0;
1942
1943 /* check for requested data params */
1944 if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam ||
1945 ctrlType > 2)
1946 {
1947 phosphor::logging::log<phosphor::logging::level::ERR>(
1948 "Invalid parameter received");
1949 return IPMI_CC_PARM_OUT_OF_RANGE;
1950 }
1951
1952 len = len - 6; // Get Actual data length
1953
1954 ss << std::hex;
1955 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
1956 oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
1957 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
1958 req->hddIndex;
1959
1960 str = bytesToStr(req->data, len);
1961 oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
1962 [driveInfoKey[req->paramSel]] = str.c_str();
1963 flushOemData();
1964
1965 return IPMI_CC_OK;
1966}
1967
1968//----------------------------------------------------------------------
1969// Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
1970//----------------------------------------------------------------------
1971// BMC needs to check HDD presented or not first. If NOT presented, return
1972// completion code 0xD5.
1973//
1974// Request:
1975// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
1976// Byte 4 –
1977//[7:4] Reserved
1978//[3:0] HDD Controller Type
1979// 0x00 – BIOS
1980// 0x01 – Expander
1981// 0x02 – LSI
1982// Byte 5 – HDD Index, 0 base
1983// Byte 6 – Parameter Selector (See Above Set HDD Information)
1984// Response:
1985// Byte 1 – Completion Code
1986// 0xD5 – Not support in current status (HDD Not Present)
1987// Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
1988// Information)
1989//
Willy Tue39f9392022-06-15 13:24:20 -07001990ipmi_ret_t ipmiOemQGetDriveInfo(ipmi_netfn_t, ipmi_cmd_t,
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001991 ipmi_request_t request,
1992 ipmi_response_t response,
Willy Tue39f9392022-06-15 13:24:20 -07001993 ipmi_data_len_t data_len, ipmi_context_t)
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001994{
Vijay Khemka63c99be2020-05-27 19:14:35 -07001995 qDriveInfo_t* req = reinterpret_cast<qDriveInfo_t*>(request);
1996 uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t*);
1997 uint8_t* res = reinterpret_cast<uint8_t*>(response);
Vijay Khemka1d4a0692019-04-09 15:20:28 -07001998 uint8_t ctrlType = req->hddCtrlType & 0x0f;
1999 std::stringstream ss;
2000 std::string str;
2001
2002 *data_len = 0;
2003
2004 /* check for requested data params */
2005 if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2)
2006 {
2007 phosphor::logging::log<phosphor::logging::level::ERR>(
2008 "Invalid parameter received");
2009 return IPMI_CC_PARM_OUT_OF_RANGE;
2010 }
2011
2012 if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
2013 oemData[KEY_Q_DRIVE_INFO].end())
2014 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2015
2016 ss << std::hex;
2017 ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
2018
2019 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
2020 oemData[KEY_Q_DRIVE_INFO].end())
2021 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2022
2023 if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
2024 dimmInfoKey[req->paramSel]) ==
2025 oemData[KEY_Q_DRIVE_INFO][ss.str()].end())
2026 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2027
2028 str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
2029 [dimmInfoKey[req->paramSel]];
2030 *data_len = strToBytes(str, res);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002031
2032 return IPMI_CC_OK;
2033}
2034
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302035/* Helper function for sending DCMI commands to ME/BIC and
2036 * getting response back
2037 */
2038ipmi::RspType<std::vector<uint8_t>>
2039 sendDCMICmd([[maybe_unused]] ipmi::Context::ptr ctx,
2040 [[maybe_unused]] uint8_t cmd, std::vector<uint8_t>& cmdData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002041{
2042 std::vector<uint8_t> respData;
2043
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302044#if BIC_ENABLED
2045
2046 uint8_t bicAddr = (uint8_t)ctx->hostIdx << 2;
2047
2048 if (sendBicCmd(ctx->netFn, ctx->cmd, bicAddr, cmdData, respData))
2049 {
2050 return ipmi::responseUnspecifiedError();
2051 }
2052
2053#else
2054
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002055 /* Add group id as first byte to request for ME command */
2056 cmdData.insert(cmdData.begin(), groupDCMI);
2057
2058 if (sendMeCmd(ipmi::netFnGroup, cmd, cmdData, respData))
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302059 {
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002060 return ipmi::responseUnspecifiedError();
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302061 }
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002062
2063 /* Remove group id as first byte as it will be added by IPMID */
2064 respData.erase(respData.begin());
2065
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302066#endif
2067
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002068 return ipmi::responseSuccess(std::move(respData));
2069}
2070
2071/* DCMI Command handellers. */
2072
2073ipmi::RspType<std::vector<uint8_t>>
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302074 ipmiOemDCMIGetPowerReading(ipmi::Context::ptr ctx,
2075 std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002076{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302077 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerReading, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002078}
2079
2080ipmi::RspType<std::vector<uint8_t>>
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302081 ipmiOemDCMIGetPowerLimit(ipmi::Context::ptr ctx,
2082 std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002083{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302084 return sendDCMICmd(ctx, ipmi::dcmi::cmdGetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002085}
2086
2087ipmi::RspType<std::vector<uint8_t>>
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302088 ipmiOemDCMISetPowerLimit(ipmi::Context::ptr ctx,
2089 std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002090{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302091 return sendDCMICmd(ctx, ipmi::dcmi::cmdSetPowerLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002092}
2093
2094ipmi::RspType<std::vector<uint8_t>>
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302095 ipmiOemDCMIApplyPowerLimit(ipmi::Context::ptr ctx,
2096 std::vector<uint8_t> reqData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002097{
Logananth Sundararaje4d6fe72022-08-23 20:36:31 +05302098 return sendDCMICmd(ctx, ipmi::dcmi::cmdActDeactivatePwrLimit, reqData);
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002099}
2100
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002101// OEM Crashdump related functions
2102static ipmi_ret_t setDumpState(CrdState& currState, CrdState newState)
2103{
2104 switch (newState)
2105 {
2106 case CrdState::waitData:
2107 if (currState == CrdState::packing)
2108 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2109 break;
2110 case CrdState::packing:
2111 if (currState != CrdState::waitData)
2112 return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
2113 break;
2114 case CrdState::free:
2115 break;
2116 default:
2117 return IPMI_CC_UNSPECIFIED_ERROR;
2118 }
2119 currState = newState;
2120
2121 return IPMI_CC_OK;
2122}
2123
2124static ipmi_ret_t handleMcaBank(const CrashDumpHdr& hdr,
2125 std::span<const uint8_t> data,
2126 CrdState& currState, std::stringstream& ss)
2127{
2128 if (data.size() < sizeof(CrdMcaBank))
2129 return IPMI_CC_REQ_DATA_LEN_INVALID;
2130
2131 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2132 if (res)
2133 return res;
2134
2135 const auto* pBank = reinterpret_cast<const CrdMcaBank*>(data.data());
2136 ss << std::format(" Bank ID : 0x{:02X}, Core ID : 0x{:02X}\n",
2137 hdr.bankHdr.bankId, hdr.bankHdr.coreId);
2138 ss << std::format(" MCA_CTRL : 0x{:016X}\n", pBank->mcaCtrl);
2139 ss << std::format(" MCA_STATUS : 0x{:016X}\n", pBank->mcaSts);
2140 ss << std::format(" MCA_ADDR : 0x{:016X}\n", pBank->mcaAddr);
2141 ss << std::format(" MCA_MISC0 : 0x{:016X}\n", pBank->mcaMisc0);
2142 ss << std::format(" MCA_CTRL_MASK : 0x{:016X}\n", pBank->mcaCtrlMask);
2143 ss << std::format(" MCA_CONFIG : 0x{:016X}\n", pBank->mcaConfig);
2144 ss << std::format(" MCA_IPID : 0x{:016X}\n", pBank->mcaIpid);
2145 ss << std::format(" MCA_SYND : 0x{:016X}\n", pBank->mcaSynd);
2146 ss << std::format(" MCA_DESTAT : 0x{:016X}\n", pBank->mcaDestat);
2147 ss << std::format(" MCA_DEADDR : 0x{:016X}\n", pBank->mcaDeaddr);
2148 ss << std::format(" MCA_MISC1 : 0x{:016X}\n", pBank->mcaMisc1);
2149 ss << "\n";
2150
2151 return IPMI_CC_OK;
2152}
2153
2154template <typename T>
2155static ipmi_ret_t handleVirtualBank(std::span<const uint8_t> data,
2156 CrdState& currState, std::stringstream& ss)
2157{
2158 if (data.size() < sizeof(T))
2159 return IPMI_CC_REQ_DATA_LEN_INVALID;
2160
2161 const auto* pBank = reinterpret_cast<const T*>(data.data());
2162
2163 if (data.size() < sizeof(T) + sizeof(BankCorePair) * pBank->mcaCount)
2164 return IPMI_CC_REQ_DATA_LEN_INVALID;
2165
2166 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2167 if (res)
2168 return res;
2169
2170 ss << " Virtual Bank\n";
2171 ss << std::format(" S5_RESET_STATUS : 0x{:08X}\n", pBank->s5ResetSts);
2172 ss << std::format(" PM_BREAKEVENT : 0x{:08X}\n", pBank->breakevent);
2173 if constexpr (std::is_same_v<T, CrdVirtualBankV3>)
2174 {
2175 ss << std::format(" WARMCOLDRSTSTATUS : 0x{:08X}\n", pBank->rstSts);
2176 }
2177 ss << std::format(" PROCESSOR NUMBER : 0x{:04X}\n", pBank->procNum);
2178 ss << std::format(" APIC ID : 0x{:08X}\n", pBank->apicId);
2179 ss << std::format(" EAX : 0x{:08X}\n", pBank->eax);
2180 ss << std::format(" EBX : 0x{:08X}\n", pBank->ebx);
2181 ss << std::format(" ECX : 0x{:08X}\n", pBank->ecx);
2182 ss << std::format(" EDX : 0x{:08X}\n", pBank->edx);
2183 ss << " VALID LIST : ";
2184 for (size_t i = 0; i < pBank->mcaCount; i++)
2185 {
2186 ss << std::format("(0x{:02X},0x{:02X}) ", pBank->mcaList[i].bankId,
2187 pBank->mcaList[i].coreId);
2188 }
2189 ss << "\n\n";
2190
2191 return IPMI_CC_OK;
2192}
2193
2194static ipmi_ret_t handleCpuWdtBank(std::span<const uint8_t> data,
2195 CrdState& currState, std::stringstream& ss)
2196{
2197 if (data.size() < sizeof(CrdCpuWdtBank))
2198 return IPMI_CC_REQ_DATA_LEN_INVALID;
2199
2200 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2201 if (res)
2202 return res;
2203
2204 const auto* pBank = reinterpret_cast<const CrdCpuWdtBank*>(data.data());
2205 for (size_t i = 0; i < ccmNum; i++)
2206 {
2207 ss << std::format(" [CCM{}]\n", i);
2208 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2209 pBank->hwAssertStsHi[i]);
2210 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2211 pBank->hwAssertStsLo[i]);
2212 ss << std::format(" OrigWdtAddrLogHi : 0x{:08X}\n",
2213 pBank->origWdtAddrLogHi[i]);
2214 ss << std::format(" OrigWdtAddrLogLo : 0x{:08X}\n",
2215 pBank->origWdtAddrLogLo[i]);
2216 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2217 pBank->hwAssertMskHi[i]);
2218 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2219 pBank->hwAssertMskLo[i]);
2220 ss << std::format(" OrigWdtAddrLogStat : 0x{:08X}\n",
2221 pBank->origWdtAddrLogStat[i]);
2222 }
2223 ss << "\n";
2224
2225 return IPMI_CC_OK;
2226}
2227
2228template <size_t N>
2229static ipmi_ret_t handleHwAssertBank(const char* name,
2230 std::span<const uint8_t> data,
2231 CrdState& currState, std::stringstream& ss)
2232{
2233 if (data.size() < sizeof(CrdHwAssertBank<N>))
2234 return IPMI_CC_REQ_DATA_LEN_INVALID;
2235
2236 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2237 if (res)
2238 return res;
2239
2240 const CrdHwAssertBank<N>* pBank =
2241 reinterpret_cast<const CrdHwAssertBank<N>*>(data.data());
2242
2243 for (size_t i = 0; i < N; i++)
2244 {
2245 ss << std::format(" [{}{}]\n", name, i);
2246 ss << std::format(" HwAssertStsHi : 0x{:08X}\n",
2247 pBank->hwAssertStsHi[i]);
2248 ss << std::format(" HwAssertStsLo : 0x{:08X}\n",
2249 pBank->hwAssertStsLo[i]);
2250 ss << std::format(" HwAssertMskHi : 0x{:08X}\n",
2251 pBank->hwAssertMskHi[i]);
2252 ss << std::format(" HwAssertMskLo : 0x{:08X}\n",
2253 pBank->hwAssertMskLo[i]);
2254 }
2255 ss << "\n";
2256
2257 return IPMI_CC_OK;
2258}
2259
2260static ipmi_ret_t handlePcieAerBank(std::span<const uint8_t> data,
2261 CrdState& currState, std::stringstream& ss)
2262{
2263 if (data.size() < sizeof(CrdPcieAerBank))
2264 return IPMI_CC_REQ_DATA_LEN_INVALID;
2265
2266 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2267 if (res)
2268 return res;
2269
2270 const auto* pBank = reinterpret_cast<const CrdPcieAerBank*>(data.data());
2271 ss << std::format(" [Bus{} Dev{} Fun{}]\n", pBank->bus, pBank->dev,
2272 pBank->fun);
2273 ss << std::format(" Command : 0x{:04X}\n",
2274 pBank->cmd);
2275 ss << std::format(" Status : 0x{:04X}\n",
2276 pBank->sts);
2277 ss << std::format(" Slot : 0x{:04X}\n",
2278 pBank->slot);
2279 ss << std::format(" Secondary Bus : 0x{:02X}\n",
2280 pBank->secondBus);
2281 ss << std::format(" Vendor ID : 0x{:04X}\n",
2282 pBank->vendorId);
2283 ss << std::format(" Device ID : 0x{:04X}\n",
2284 pBank->devId);
2285 ss << std::format(" Class Code : 0x{:02X}{:04X}\n",
2286 pBank->classCodeHi, pBank->classCodeLo);
2287 ss << std::format(" Bridge: Secondary Status : 0x{:04X}\n",
2288 pBank->secondSts);
2289 ss << std::format(" Bridge: Control : 0x{:04X}\n",
2290 pBank->ctrl);
2291 ss << std::format(" Uncorrectable Error Status : 0x{:08X}\n",
2292 pBank->uncorrErrSts);
2293 ss << std::format(" Uncorrectable Error Mask : 0x{:08X}\n",
2294 pBank->uncorrErrMsk);
2295 ss << std::format(" Uncorrectable Error Severity : 0x{:08X}\n",
2296 pBank->uncorrErrSeverity);
2297 ss << std::format(" Correctable Error Status : 0x{:08X}\n",
2298 pBank->corrErrSts);
2299 ss << std::format(" Correctable Error Mask : 0x{:08X}\n",
2300 pBank->corrErrMsk);
2301 ss << std::format(" Header Log DW0 : 0x{:08X}\n",
2302 pBank->hdrLogDw0);
2303 ss << std::format(" Header Log DW1 : 0x{:08X}\n",
2304 pBank->hdrLogDw1);
2305 ss << std::format(" Header Log DW2 : 0x{:08X}\n",
2306 pBank->hdrLogDw2);
2307 ss << std::format(" Header Log DW3 : 0x{:08X}\n",
2308 pBank->hdrLogDw3);
2309 ss << std::format(" Root Error Status : 0x{:08X}\n",
2310 pBank->rootErrSts);
2311 ss << std::format(" Correctable Error Source ID : 0x{:04X}\n",
2312 pBank->corrErrSrcId);
2313 ss << std::format(" Error Source ID : 0x{:04X}\n",
2314 pBank->errSrcId);
2315 ss << std::format(" Lane Error Status : 0x{:08X}\n",
2316 pBank->laneErrSts);
2317 ss << "\n";
2318
2319 return IPMI_CC_OK;
2320}
2321
2322static ipmi_ret_t handleWdtRegBank(std::span<const uint8_t> data,
2323 CrdState& currState, std::stringstream& ss)
2324{
2325 if (data.size() < sizeof(CrdWdtRegBank))
2326 return IPMI_CC_REQ_DATA_LEN_INVALID;
2327
2328 const auto* pBank = reinterpret_cast<const CrdWdtRegBank*>(data.data());
2329 if (data.size() < sizeof(CrdWdtRegBank) + sizeof(uint32_t) * pBank->count)
2330 return IPMI_CC_REQ_DATA_LEN_INVALID;
2331
2332 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2333 if (res)
2334 return res;
2335
2336 ss << std::format(" [NBIO{}] {}\n", pBank->nbio, pBank->name);
2337 ss << std::format(" Address: 0x{:08X}\n", pBank->addr);
2338 ss << std::format(" Data Count: {}\n", pBank->count);
2339 ss << " Data:\n";
2340 for (size_t i = 0; i < pBank->count; i++)
2341 {
2342 ss << std::format(" {}: 0x{:08X}\n", i, pBank->data[i]);
2343 }
2344 ss << "\n";
2345
2346 return IPMI_CC_OK;
2347}
2348
2349static ipmi_ret_t handleCrdHdrBank(std::span<const uint8_t> data,
2350 CrdState& currState, std::stringstream& ss)
2351{
2352 if (data.size() < sizeof(CrdHdrBank))
2353 return IPMI_CC_REQ_DATA_LEN_INVALID;
2354
2355 ipmi_ret_t res = setDumpState(currState, CrdState::waitData);
2356 if (res)
2357 return res;
2358
2359 const auto* pBank = reinterpret_cast<const CrdHdrBank*>(data.data());
2360 ss << " Crashdump Header\n";
2361 ss << std::format(" CPU PPIN : 0x{:016X}\n", pBank->ppin);
2362 ss << std::format(" UCODE VERSION : 0x{:08X}\n", pBank->ucodeVer);
2363 ss << std::format(" PMIO 80h : 0x{:08X}\n", pBank->pmio);
2364 ss << std::format(
2365 " BIT0 - SMN Parity/SMN Timeouts PSP/SMU Parity and ECC/SMN On-Package Link Error : {}\n",
2366 pBank->pmio & 0x1);
2367 ss << std::format(" BIT2 - PSP Parity and ECC : {}\n",
2368 (pBank->pmio & 0x4) >> 2);
2369 ss << std::format(" BIT3 - SMN Timeouts SMU : {}\n",
2370 (pBank->pmio & 0x8) >> 3);
2371 ss << std::format(" BIT4 - SMN Off-Package Link Packet Error : {}\n",
2372 (pBank->pmio & 0x10) >> 4);
2373 ss << "\n";
2374
2375 return IPMI_CC_OK;
2376}
2377
2378static std::string getFilename(const std::filesystem::path& dir,
2379 const std::string& prefix)
2380{
2381 std::vector<int> indices;
2382 std::regex pattern(prefix + "(\\d+)\\.txt");
2383
2384 for (const auto& entry : std::filesystem::directory_iterator(dir))
2385 {
2386 std::string filename = entry.path().filename().string();
2387 std::smatch match;
2388 if (std::regex_match(filename, match, pattern))
2389 indices.push_back(std::stoi(match[1]));
2390 }
2391
2392 std::sort(indices.rbegin(), indices.rend());
2393 while (indices.size() > 2) // keep 3 files, so remove if more than 2
2394 {
2395 std::filesystem::remove(
2396 dir / (prefix + std::to_string(indices.back()) + ".txt"));
2397 indices.pop_back();
2398 }
2399
2400 int nextIndex = indices.empty() ? 1 : indices.front() + 1;
2401 return prefix + std::to_string(nextIndex) + ".txt";
2402}
2403
2404static ipmi_ret_t handleCtrlBank(std::span<const uint8_t> data,
2405 CrdState& currState, std::stringstream& ss)
2406{
2407 if (data.empty())
2408 return IPMI_CC_REQ_DATA_LEN_INVALID;
2409
2410 switch (static_cast<CrdCtrl>(data[0]))
2411 {
2412 case CrdCtrl::getState:
2413 break;
2414 case CrdCtrl::finish:
2415 {
2416 ipmi_ret_t res = setDumpState(currState, CrdState::packing);
2417 if (res)
2418 return res;
2419
2420 const std::filesystem::path dumpDir = "/var/lib/fb-ipmi-oem";
2421 std::string filename = getFilename(dumpDir, "crashdump_");
2422 std::ofstream outFile(dumpDir / filename);
2423 if (!outFile.is_open())
2424 return IPMI_CC_UNSPECIFIED_ERROR;
2425
2426 auto now = std::chrono::system_clock::to_time_t(
2427 std::chrono::system_clock::now());
2428 outFile << "Crash Dump generated at: "
2429 << std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M:%S")
2430 << "\n\n";
2431 outFile << ss.str();
2432 outFile.close();
2433 ss.str("");
2434 ss.clear();
2435 setDumpState(currState, CrdState::free);
2436 break;
2437 }
2438 default:
2439 return ccInvalidParam;
2440 }
2441
2442 return IPMI_CC_OK;
2443}
2444
2445ipmi::RspType<std::vector<uint8_t>>
2446 ipmiOemCrashdump([[maybe_unused]] ipmi::Context::ptr ctx,
2447 std::vector<uint8_t> reqData)
2448{
2449 static CrdState dumpState = CrdState::free;
2450 static std::stringstream ss;
2451
2452 if (reqData.size() < sizeof(CrashDumpHdr))
2453 return ipmi::responseReqDataLenInvalid();
2454
2455 const auto* pHdr = reinterpret_cast<const CrashDumpHdr*>(reqData.data());
2456 std::span<const uint8_t> bData{reqData.data() + sizeof(CrashDumpHdr),
2457 reqData.size() - sizeof(CrashDumpHdr)};
2458 ipmi_ret_t res;
2459
2460 switch (pHdr->bankHdr.bankType)
2461 {
2462 case BankType::mca:
2463 res = handleMcaBank(*pHdr, bData, dumpState, ss);
2464 break;
2465 case BankType::virt:
2466 if (pHdr->bankHdr.version >= 3)
2467 {
2468 res = handleVirtualBank<CrdVirtualBankV3>(bData, dumpState, ss);
2469 break;
2470 }
2471 res = handleVirtualBank<CrdVirtualBankV2>(bData, dumpState, ss);
2472 break;
2473 case BankType::cpuWdt:
2474 res = handleCpuWdtBank(bData, dumpState, ss);
2475 break;
2476 case BankType::tcdx:
2477 res = handleHwAssertBank<tcdxNum>("TCDX", bData, dumpState, ss);
2478 break;
2479 case BankType::cake:
2480 res = handleHwAssertBank<cakeNum>("CAKE", bData, dumpState, ss);
2481 break;
2482 case BankType::pie0:
2483 res = handleHwAssertBank<pie0Num>("PIE", bData, dumpState, ss);
2484 break;
2485 case BankType::iom:
2486 res = handleHwAssertBank<iomNum>("IOM", bData, dumpState, ss);
2487 break;
2488 case BankType::ccix:
2489 res = handleHwAssertBank<ccixNum>("CCIX", bData, dumpState, ss);
2490 break;
2491 case BankType::cs:
2492 res = handleHwAssertBank<csNum>("CS", bData, dumpState, ss);
2493 break;
2494 case BankType::pcieAer:
2495 res = handlePcieAerBank(bData, dumpState, ss);
2496 break;
2497 case BankType::wdtReg:
2498 res = handleWdtRegBank(bData, dumpState, ss);
2499 break;
2500 case BankType::ctrl:
2501 res = handleCtrlBank(bData, dumpState, ss);
2502 if (res == IPMI_CC_OK &&
2503 static_cast<CrdCtrl>(bData[0]) == CrdCtrl::getState)
2504 {
2505 return ipmi::responseSuccess(
2506 std::vector<uint8_t>{static_cast<uint8_t>(dumpState)});
2507 }
2508 break;
2509 case BankType::crdHdr:
2510 res = handleCrdHdrBank(bData, dumpState, ss);
2511 break;
2512 default:
2513 return ipmi::responseInvalidFieldRequest();
2514 }
2515
2516 return ipmi::response(res);
2517}
2518
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002519static void registerOEMFunctions(void)
2520{
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002521 /* Get OEM data from json file */
2522 std::ifstream file(JSON_OEM_DATA_FILE);
2523 if (file)
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002524 {
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002525 file >> oemData;
Vijay Khemkafeaa9812019-08-27 15:08:08 -07002526 file.close();
2527 }
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002528
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002529 phosphor::logging::log<phosphor::logging::level::INFO>(
2530 "Registering OEM commands");
Vijay Khemka7c0aea42020-03-05 13:31:53 -08002531
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002532 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_INFO,
2533 NULL, ipmiOemDbgGetFrameInfo,
2534 PRIVILEGE_USER); // get debug frame info
2535 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ,
2536 CMD_OEM_USB_DBG_GET_UPDATED_FRAMES, NULL,
2537 ipmiOemDbgGetUpdFrames,
2538 PRIVILEGE_USER); // get debug updated frames
2539 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_POST_DESC,
2540 NULL, ipmiOemDbgGetPostDesc,
2541 PRIVILEGE_USER); // get debug post description
2542 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_GPIO_DESC,
2543 NULL, ipmiOemDbgGetGpioDesc,
2544 PRIVILEGE_USER); // get debug gpio description
2545 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_GET_FRAME_DATA,
2546 NULL, ipmiOemDbgGetFrameData,
2547 PRIVILEGE_USER); // get debug frame data
2548 ipmiPrintAndRegister(NETFN_OEM_USB_DBG_REQ, CMD_OEM_USB_DBG_CTRL_PANEL,
2549 NULL, ipmiOemDbgGetCtrlPanel,
2550 PRIVILEGE_USER); // get debug control panel
2551 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL,
2552 ipmiOemSetDimmInfo,
2553 PRIVILEGE_USER); // Set Dimm Info
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002554 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL,
2555 ipmiOemGetBoardID,
2556 PRIVILEGE_USER); // Get Board ID
Bonnie Lo4ae63e72023-02-09 15:27:54 +08002557 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnOemOne,
2558 CMD_OEM_GET_80PORT_RECORD, ipmi::Privilege::User,
2559 ipmiOemGet80PortRecord); // Get 80 Port Record
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002560 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_MACHINE_CONFIG_INFO, NULL,
2561 ipmiOemSetMachineCfgInfo,
2562 PRIVILEGE_USER); // Set Machine Config Info
2563 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_START, NULL,
2564 ipmiOemSetPostStart,
2565 PRIVILEGE_USER); // Set POST start
2566 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL,
2567 ipmiOemSetPostEnd,
2568 PRIVILEGE_USER); // Set POST End
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002569 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL,
2570 ipmiOemSetPPINInfo,
2571 PRIVILEGE_USER); // Set PPIN Info
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302572#if BIC_ENABLED
2573
2574 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2575 ipmi::cmdSetSystemGuid, ipmi::Privilege::User,
2576 ipmiOemSetSystemGuid);
2577#else
2578
Vijay Khemkaf2246ce2020-05-27 14:26:35 -07002579 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_SYSTEM_GUID, NULL,
2580 ipmiOemSetSystemGuid,
2581 PRIVILEGE_USER); // Set System GUID
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +05302582#endif
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002583 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL,
2584 ipmiOemSetAdrTrigger,
2585 PRIVILEGE_USER); // Set ADR Trigger
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002586 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
2587 ipmiOemSetBiosFlashInfo,
2588 PRIVILEGE_USER); // Set Bios Flash Info
2589 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPR, NULL, ipmiOemSetPpr,
2590 PRIVILEGE_USER); // Set PPR
2591 ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr,
2592 PRIVILEGE_USER); // Get PPR
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002593 /* FB OEM QC Commands */
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05302594 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2595 CMD_OEM_Q_SET_PROC_INFO, ipmi::Privilege::User,
2596 ipmiOemQSetProcInfo); // Set Proc Info
2597 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2598 CMD_OEM_Q_GET_PROC_INFO, ipmi::Privilege::User,
2599 ipmiOemQGetProcInfo); // Get Proc Info
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05302600 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2601 ipmi::cmdSetQDimmInfo, ipmi::Privilege::User,
2602 ipmiOemQSetDimmInfo); // Set Dimm Info
2603 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemFour,
2604 ipmi::cmdGetQDimmInfo, ipmi::Privilege::User,
2605 ipmiOemQGetDimmInfo); // Get Dimm Info
Vijay Khemka1d4a0692019-04-09 15:20:28 -07002606 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
2607 ipmiOemQSetDriveInfo,
2608 PRIVILEGE_USER); // Set Drive Info
2609 ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
2610 ipmiOemQGetDriveInfo,
2611 PRIVILEGE_USER); // Get Drive Info
Vijay Khemkadd14c0f2020-03-18 14:48:13 -07002612
2613 /* FB OEM DCMI Commands as per DCMI spec 1.5 Section 6 */
2614 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
2615 ipmi::dcmi::cmdGetPowerReading,
2616 ipmi::Privilege::User,
2617 ipmiOemDCMIGetPowerReading); // Get Power Reading
2618
2619 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
2620 ipmi::dcmi::cmdGetPowerLimit,
2621 ipmi::Privilege::User,
2622 ipmiOemDCMIGetPowerLimit); // Get Power Limit
2623
2624 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
2625 ipmi::dcmi::cmdSetPowerLimit,
2626 ipmi::Privilege::Operator,
2627 ipmiOemDCMISetPowerLimit); // Set Power Limit
2628
2629 ipmi::registerGroupHandler(ipmi::prioOpenBmcBase, groupDCMI,
2630 ipmi::dcmi::cmdActDeactivatePwrLimit,
2631 ipmi::Privilege::Operator,
2632 ipmiOemDCMIApplyPowerLimit); // Apply Power Limit
2633
Jayashree-Df0cf6652020-11-30 11:03:30 +05302634 /* FB OEM BOOT ORDER COMMANDS */
2635 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2636 CMD_OEM_GET_BOOT_ORDER, ipmi::Privilege::User,
2637 ipmiOemGetBootOrder); // Get Boot Order
2638
2639 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2640 CMD_OEM_SET_BOOT_ORDER, ipmi::Privilege::User,
2641 ipmiOemSetBootOrder); // Set Boot Order
2642
Cosmo Chou7ab87bb2024-06-28 10:47:44 +08002643 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2644 CMD_OEM_CRASHDUMP, ipmi::Privilege::User,
2645 ipmiOemCrashdump);
2646
Vijay Khemkae7d23d02019-03-08 13:13:40 -08002647 return;
2648}
2649
2650} // namespace ipmi