Add more FB OEM commands
Added some of fb qc oem cmds like dimm info, proc info, drive info
and basic oem commands like ppin, ppr, machine config, boot order
Change-Id: I5f9c69325242a1df608a65fee2ee5a250b211898
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
diff --git a/src/oemcommands.cpp b/src/oemcommands.cpp
index af21713..3923501 100644
--- a/src/oemcommands.cpp
+++ b/src/oemcommands.cpp
@@ -18,10 +18,14 @@
#include "xyz/openbmc_project/Common/error.hpp"
#include <ipmid/api.h>
+#include <nlohmann/json.hpp>
#include <array>
#include <commandutils.hpp>
#include <cstring>
#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <fstream>
#include <oemcommands.hpp>
#include <ipmid/utils.hpp>
#include <phosphor-logging/log.hpp>
@@ -44,6 +48,7 @@
ipmi_ret_t plat_udbg_control_panel(uint8_t, uint8_t, uint8_t, uint8_t *,
uint8_t *);
namespace variant_ns = sdbusplus::message::variant_ns;
+nlohmann::json oemData;
enum class LanParam : uint8_t
{
@@ -61,6 +66,44 @@
IPV6 = 59,
};
+//----------------------------------------------------------------------
+// Helper functions for storing oem data
+//----------------------------------------------------------------------
+
+void flushOemData()
+{
+ std::ofstream file(JSON_OEM_DATA_FILE);
+ file << oemData;
+ return;
+}
+
+std::string bytesToStr(uint8_t *byte, int len)
+{
+ std::stringstream ss;
+ int i;
+
+ ss << std::hex;
+ for (i = 0; i < len; i++)
+ {
+ ss << std::setw(2) << std::setfill('0') << (int)byte[i];
+ }
+
+ return ss.str();
+}
+
+int strToBytes(std::string &str, uint8_t *data)
+{
+ std::string sstr;
+ int i;
+
+ for (i = 0; i < (str.length()) / 2; i++)
+ {
+ sstr = str.substr(i * 2, 2);
+ data[i] = (uint8_t)std::strtol(sstr.c_str(), NULL, 16);
+ }
+ return i;
+}
+
ipmi_ret_t getNetworkData(uint8_t lan_param, char *data)
{
ipmi_ret_t rc = IPMI_CC_OK;
@@ -461,7 +504,6 @@
return ret;
}
-// Todo: Need to implement all below functions for oem commands
//----------------------------------------------------------------------
// Set Dimm Info (CMD_OEM_SET_DIMM_INFO)
//----------------------------------------------------------------------
@@ -470,32 +512,111 @@
ipmi_data_len_t data_len, ipmi_context_t context)
{
uint8_t *req = reinterpret_cast<uint8_t *>(request);
+
+ uint8_t index = req[0];
+ uint8_t type = req[1];
+ uint16_t speed;
+ uint32_t size;
+
+ memcpy(&speed, &req[2], 2);
+ memcpy(&size, &req[4], 4);
+
+ std::stringstream ss;
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)index;
+
+ oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_INDEX] = index;
+ oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_TYPE] = type;
+ oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SPEED] = speed;
+ oemData[KEY_SYS_CONFIG][ss.str()][KEY_DIMM_SIZE] = size;
+
+ flushOemData();
+
+ *data_len = 0;
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Get Board ID (CMD_OEM_GET_BOARD_ID)
+//----------------------------------------------------------------------
+ipmi_ret_t ipmiOemGetBoardID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ uint8_t *req = reinterpret_cast<uint8_t *>(request);
uint8_t *res = reinterpret_cast<uint8_t *>(response);
- std::memcpy(res, req, SIZE_IANA_ID + 1); // IANA ID
- *data_len = SIZE_IANA_ID + 1;
+ /* TODO: Needs to implement this after GPIO implementation */
*data_len = 0;
return IPMI_CC_OK;
}
//----------------------------------------------------------------------
+// Set Boot Order (CMD_OEM_SET_BOOT_ORDER)
+//----------------------------------------------------------------------
+ipmi_ret_t ipmiOemSetBootOrder(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ uint8_t *req = reinterpret_cast<uint8_t *>(request);
+ uint8_t len = *data_len;
+ uint8_t mode = req[0];
+ nlohmann::json bootMode;
+ int i;
+
+ *data_len = 0;
+
+ if (len != SIZE_BOOT_ORDER)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid Boot order length received");
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ bootMode["UEFI"] = (mode & BOOT_MODE_UEFI ? true : false);
+ bootMode["CMOS_CLR"] = (mode & BOOT_MODE_CMOS_CLR ? true : false);
+ bootMode["FORCE_BOOT"] = (mode & BOOT_MODE_FORCE_BOOT ? true : false);
+ bootMode["BOOT_FLAG"] = (mode & BOOT_MODE_BOOT_FLAG ? true : false);
+
+ oemData[KEY_BOOT_ORDER][KEY_BOOT_MODE] = bootMode;
+
+ /* Initialize boot sequence array */
+ oemData[KEY_BOOT_ORDER][KEY_BOOT_SEQ] = {};
+ for (i = 1; i < SIZE_BOOT_ORDER; i++)
+ oemData[KEY_BOOT_ORDER][KEY_BOOT_SEQ][i - 1] = bootSeq[req[i]];
+
+ flushOemData();
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
// Get Boot Order (CMD_OEM_GET_BOOT_ORDER)
//----------------------------------------------------------------------
ipmi_ret_t ipmiOemGetBootOrder(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
- uint8_t *req = reinterpret_cast<uint8_t *>(request);
uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ nlohmann::json bootMode = oemData[KEY_BOOT_ORDER][KEY_BOOT_MODE];
+ uint8_t mode = 0;
+ int i;
- *res++ = 0x01;
- *res++ = 0x00;
- *res++ = 0x09;
- *res++ = 0x02;
- *res++ = 0x03;
- *res++ = 0xff;
- *data_len = 6;
+ *data_len = SIZE_BOOT_ORDER;
+
+ if (bootMode["UEFI"])
+ mode |= BOOT_MODE_UEFI;
+ if (bootMode["CMOS_CLR"])
+ mode |= BOOT_MODE_CMOS_CLR;
+ if (bootMode["BOOT_FLAG"])
+ mode |= BOOT_MODE_BOOT_FLAG;
+
+ res[0] = mode;
+
+ for (i = 1; i < SIZE_BOOT_ORDER; i++)
+ res[i] = bootMap[oemData[KEY_BOOT_ORDER][KEY_BOOT_SEQ][i - 1]];
return IPMI_CC_OK;
}
@@ -509,11 +630,78 @@
ipmi_data_len_t data_len,
ipmi_context_t context)
{
- uint8_t *req = reinterpret_cast<uint8_t *>(request);
- uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ machineConfigInfo_t *req = reinterpret_cast<machineConfigInfo_t *>(request);
+ uint8_t len = *data_len;
*data_len = 0;
+ if (len < sizeof(machineConfigInfo_t))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid machine configuration length received");
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ if (req->chassis_type >= sizeof(chassisType) / sizeof(uint8_t *))
+ oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] = "UNKNOWN";
+ else
+ oemData[KEY_MC_CONFIG][KEY_MC_CHAS_TYPE] =
+ chassisType[req->chassis_type];
+
+ if (req->mb_type >= sizeof(mbType) / sizeof(uint8_t *))
+ oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = "UNKNOWN";
+ else
+ oemData[KEY_MC_CONFIG][KEY_MC_MB_TYPE] = mbType[req->mb_type];
+
+ oemData[KEY_MC_CONFIG][KEY_MC_PROC_CNT] = req->proc_cnt;
+ oemData[KEY_MC_CONFIG][KEY_MC_MEM_CNT] = req->mem_cnt;
+ oemData[KEY_MC_CONFIG][KEY_MC_HDD35_CNT] = req->hdd35_cnt;
+ oemData[KEY_MC_CONFIG][KEY_MC_HDD25_CNT] = req->hdd25_cnt;
+
+ if (req->riser_type >= sizeof(riserType) / sizeof(uint8_t *))
+ oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = "UNKNOWN";
+ else
+ oemData[KEY_MC_CONFIG][KEY_MC_RSR_TYPE] = riserType[req->riser_type];
+
+ oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC] = {};
+ int i = 0;
+ if (req->pcie_card_loc & BIT_0)
+ oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT1";
+ if (req->pcie_card_loc & BIT_1)
+ oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT2";
+ if (req->pcie_card_loc & BIT_2)
+ oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT3";
+ if (req->pcie_card_loc & BIT_3)
+ oemData[KEY_MC_CONFIG][KEY_MC_PCIE_LOC][i++] = "SLOT4";
+
+ if (req->slot1_pcie_type >= sizeof(pcieType) / sizeof(uint8_t *))
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] = "UNKNOWN";
+ else
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT1_TYPE] =
+ pcieType[req->slot1_pcie_type];
+
+ if (req->slot2_pcie_type >= sizeof(pcieType) / sizeof(uint8_t *))
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] = "UNKNOWN";
+ else
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT2_TYPE] =
+ pcieType[req->slot2_pcie_type];
+
+ if (req->slot3_pcie_type >= sizeof(pcieType) / sizeof(uint8_t *))
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] = "UNKNOWN";
+ else
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT3_TYPE] =
+ pcieType[req->slot3_pcie_type];
+
+ if (req->slot4_pcie_type >= sizeof(pcieType) / sizeof(uint8_t *))
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] = "UNKNOWN";
+ else
+ oemData[KEY_MC_CONFIG][KEY_MC_SLOT4_TYPE] =
+ pcieType[req->slot4_pcie_type];
+
+ oemData[KEY_MC_CONFIG][KEY_MC_AEP_CNT] = req->aep_mem_cnt;
+
+ flushOemData();
+
return IPMI_CC_OK;
}
@@ -524,11 +712,9 @@
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
- uint8_t *req = reinterpret_cast<uint8_t *>(request);
- uint8_t *res = reinterpret_cast<uint8_t *>(response);
-
phosphor::logging::log<phosphor::logging::level::INFO>("POST Start Event");
+ /* Do nothing, return success */
*data_len = 0;
return IPMI_CC_OK;
}
@@ -540,12 +726,67 @@
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
- uint8_t *req = reinterpret_cast<uint8_t *>(request);
- uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ struct timespec ts;
phosphor::logging::log<phosphor::logging::level::INFO>("POST End Event");
*data_len = 0;
+
+ // Timestamp post end time.
+ clock_gettime(CLOCK_REALTIME, &ts);
+ oemData[KEY_TS_SLED] = ts.tv_sec;
+ flushOemData();
+
+ // Sync time with system
+ // TODO: Add code for syncing time
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Set PPIN Info (CMD_OEM_SET_PPIN_INFO)
+//----------------------------------------------------------------------
+// Inform BMC about PPIN data of 8 bytes for each CPU
+//
+// Request:
+// Byte 1:8 – CPU0 PPIN data
+// Optional:
+// Byte 9:16 – CPU1 PPIN data
+//
+// Response:
+// Byte 1 – Completion Code
+ipmi_ret_t ipmiOemSetPPINInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ uint8_t *req = reinterpret_cast<uint8_t *>(request);
+ std::string ppinStr;
+ int len;
+
+ if (*data_len > SIZE_CPU_PPIN * 2)
+ len = SIZE_CPU_PPIN * 2;
+ else
+ len = *data_len;
+ *data_len = 0;
+
+ ppinStr = bytesToStr(req, len);
+ oemData[KEY_PPIN_INFO] = ppinStr.c_str();
+ flushOemData();
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Set ADR Trigger (CMD_OEM_SET_ADR_TRIGGER)
+//----------------------------------------------------------------------
+ipmi_ret_t ipmiOemSetAdrTrigger(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+{
+ /* Do nothing, return success */
+ *data_len = 0;
return IPMI_CC_OK;
}
@@ -558,9 +799,7 @@
ipmi_data_len_t data_len,
ipmi_context_t context)
{
- uint8_t *req = reinterpret_cast<uint8_t *>(request);
- uint8_t *res = reinterpret_cast<uint8_t *>(response);
-
+ /* Do nothing, return success */
*data_len = 0;
return IPMI_CC_OK;
}
@@ -573,9 +812,85 @@
ipmi_data_len_t data_len, ipmi_context_t context)
{
uint8_t *req = reinterpret_cast<uint8_t *>(request);
- uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ uint8_t pprCnt, pprAct, pprIndex;
+ uint8_t selParam = req[0];
+ uint8_t len = *data_len;
+ std::stringstream ss;
+ std::string str;
*data_len = 0;
+
+ switch (selParam)
+ {
+ case PPR_ACTION:
+ if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) ==
+ oemData[KEY_PPR].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
+ if (pprCnt == 0)
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ pprAct = req[1];
+ /* Check if ppr is enabled or disabled */
+ if (!(pprAct & 0x80))
+ pprAct = 0;
+
+ oemData[KEY_PPR][KEY_PPR_ACTION] = pprAct;
+ break;
+ case PPR_ROW_COUNT:
+ if (req[1] > 100)
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ oemData[KEY_PPR][KEY_PPR_ROW_COUNT] = req[1];
+ break;
+ case PPR_ROW_ADDR:
+ pprIndex = req[1];
+ if (pprIndex > 100)
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ if (len < PPR_ROW_ADDR_LEN + 1)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid PPR Row Address length received");
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
+
+ oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
+
+ str = bytesToStr(&req[1], PPR_ROW_ADDR_LEN);
+ oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR] = str.c_str();
+ break;
+ case PPR_HISTORY_DATA:
+ pprIndex = req[1];
+ if (pprIndex > 100)
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ if (len < PPR_HST_DATA_LEN + 1)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid PPR history data length received");
+ return IPMI_CC_REQ_DATA_LEN_INVALID;
+ }
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
+
+ oemData[KEY_PPR][ss.str()][KEY_PPR_INDEX] = pprIndex;
+
+ str = bytesToStr(&req[1], PPR_HST_DATA_LEN);
+ oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA] = str.c_str();
+ break;
+ default:
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ break;
+ }
+
+ flushOemData();
+
return IPMI_CC_OK;
}
@@ -588,15 +903,584 @@
{
uint8_t *req = reinterpret_cast<uint8_t *>(request);
uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ uint8_t pprCnt, pprIndex;
+ uint8_t selParam = req[0];
+ std::stringstream ss;
+ std::string str;
- res[0] = 0x00;
- *data_len = 1;
+ /* Any failure will return zero length data */
+ *data_len = 0;
+
+ switch (selParam)
+ {
+ case PPR_ACTION:
+ res[0] = 0;
+ *data_len = 1;
+
+ if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
+ oemData[KEY_PPR].end())
+ {
+ pprCnt = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
+ if (pprCnt != 0)
+ {
+ if (oemData[KEY_PPR].find(KEY_PPR_ACTION) !=
+ oemData[KEY_PPR].end())
+ {
+ res[0] = oemData[KEY_PPR][KEY_PPR_ACTION];
+ }
+ }
+ }
+ break;
+ case PPR_ROW_COUNT:
+ res[0] = 0;
+ *data_len = 1;
+ if (oemData[KEY_PPR].find(KEY_PPR_ROW_COUNT) !=
+ oemData[KEY_PPR].end())
+ res[0] = oemData[KEY_PPR][KEY_PPR_ROW_COUNT];
+ break;
+ case PPR_ROW_ADDR:
+ pprIndex = req[1];
+ if (pprIndex > 100)
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
+
+ if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_ROW_ADDR) ==
+ oemData[KEY_PPR][ss.str()].end())
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ str = oemData[KEY_PPR][ss.str()][KEY_PPR_ROW_ADDR];
+ *data_len = strToBytes(str, res);
+ break;
+ case PPR_HISTORY_DATA:
+ pprIndex = req[1];
+ if (pprIndex > 100)
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)pprIndex;
+
+ if (oemData[KEY_PPR].find(ss.str()) == oemData[KEY_PPR].end())
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ if (oemData[KEY_PPR][ss.str()].find(KEY_PPR_HST_DATA) ==
+ oemData[KEY_PPR][ss.str()].end())
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ str = oemData[KEY_PPR][ss.str()][KEY_PPR_HST_DATA];
+ *data_len = strToBytes(str, res);
+ break;
+ default:
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ break;
+ }
+
+ return IPMI_CC_OK;
+}
+
+/* FB OEM QC Commands */
+
+//----------------------------------------------------------------------
+// Set Proc Info (CMD_OEM_Q_SET_PROC_INFO)
+//----------------------------------------------------------------------
+//"Request:
+// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
+// Byte 4 – Processor Index, 0 base
+// Byte 5 – Parameter Selector
+// Byte 6..N – Configuration parameter data (see below for Parameters
+// of Processor Information)
+// Response:
+// Byte 1 – Completion code
+//
+// Parameter#1: (Processor Product Name)
+//
+// Byte 1..48 –Product name(ASCII code)
+// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
+//
+// Param#2: Processor Basic Information
+// Byte 1 – Core Number
+// Byte 2 – Thread Number (LSB)
+// Byte 3 – Thread Number (MSB)
+// Byte 4 – Processor frequency in MHz (LSB)
+// Byte 5 – Processor frequency in MHz (MSB)
+// Byte 6..7 – Revision
+//
+ipmi_ret_t ipmiOemQSetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ qProcInfo_t *req = reinterpret_cast<qProcInfo_t *>(request);
+ uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t *);
+ std::stringstream ss;
+ std::string str;
+ uint8_t len = *data_len;
+
+ *data_len = 0;
+
+ /* check for requested data params */
+ if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid parameter received");
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ len = len - 5; // Get Actual data length
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
+ oemData[KEY_Q_PROC_INFO][ss.str()][KEY_PROC_INDEX] = req->procIndex;
+
+ str = bytesToStr(req->data, len);
+ oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]] = str.c_str();
+ flushOemData();
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Get Proc Info (CMD_OEM_Q_GET_PROC_INFO)
+//----------------------------------------------------------------------
+// Request:
+// Byte 1:3 – Manufacturer ID – XXYYZZ h, LSB first
+// Byte 4 – Processor Index, 0 base
+// Byte 5 – Parameter Selector
+// Response:
+// Byte 1 – Completion code
+// Byte 2..N – Configuration Parameter Data (see below for Parameters
+// of Processor Information)
+//
+// Parameter#1: (Processor Product Name)
+//
+// Byte 1..48 –Product name(ASCII code)
+// Ex. Intel(R) Xeon(R) CPU E5-2685 v3 @ 2.60GHz
+//
+// Param#2: Processor Basic Information
+// Byte 1 – Core Number
+// Byte 2 – Thread Number (LSB)
+// Byte 3 – Thread Number (MSB)
+// Byte 4 – Processor frequency in MHz (LSB)
+// Byte 5 – Processor frequency in MHz (MSB)
+// Byte 6..7 – Revision
+//
+ipmi_ret_t ipmiOemQGetProcInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ qProcInfo_t *req = reinterpret_cast<qProcInfo_t *>(request);
+ uint8_t numParam = sizeof(cpuInfoKey) / sizeof(uint8_t *);
+ uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ std::stringstream ss;
+ std::string str;
+
+ *data_len = 0;
+
+ /* check for requested data params */
+ if (req->paramSel < 1 || req->paramSel >= numParam)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid parameter received");
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)req->procIndex;
+
+ if (oemData[KEY_Q_PROC_INFO].find(ss.str()) ==
+ oemData[KEY_Q_PROC_INFO].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ if (oemData[KEY_Q_PROC_INFO][ss.str()].find(cpuInfoKey[req->paramSel]) ==
+ oemData[KEY_Q_PROC_INFO][ss.str()].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ str = oemData[KEY_Q_PROC_INFO][ss.str()][cpuInfoKey[req->paramSel]];
+ *data_len = strToBytes(str, res);
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Set Dimm Info (CMD_OEM_Q_SET_DIMM_INFO)
+//----------------------------------------------------------------------
+// Request:
+// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
+// Byte 4 – DIMM Index, 0 base
+// Byte 5 – Parameter Selector
+// Byte 6..N – Configuration parameter data (see below for Parameters
+// of DIMM Information)
+// Response:
+// Byte 1 – Completion code
+//
+// Param#1 (DIMM Location):
+// Byte 1 – DIMM Present
+// Byte 1 – DIMM Present
+// 01h – Present
+// FFh – Not Present
+// Byte 2 – Node Number, 0 base
+// Byte 3 – Channel Number , 0 base
+// Byte 4 – DIMM Number , 0 base
+//
+// Param#2 (DIMM Type):
+// Byte 1 – DIMM Type
+// Bit [7:6]
+// For DDR3
+// 00 – Normal Voltage (1.5V)
+// 01 – Ultra Low Voltage (1.25V)
+// 10 – Low Voltage (1.35V)
+// 11 – Reserved
+// For DDR4
+// 00 – Reserved
+// 01 – Reserved
+// 10 – Reserved
+// 11 – Normal Voltage (1.2V)
+// Bit [5:0]
+// 0x00 – SDRAM
+// 0x01 – DDR-1 RAM
+// 0x02 – Rambus
+// 0x03 – DDR-2 RAM
+// 0x04 – FBDIMM
+// 0x05 – DDR-3 RAM
+// 0x06 – DDR-4 RAM
+//
+// Param#3 (DIMM Speed):
+// Byte 1..2 – DIMM speed in MHz, LSB
+// Byte 3..6 – DIMM size in Mbytes, LSB
+//
+// Param#4 (Module Part Number):
+// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
+//
+// Param#5 (Module Serial Number):
+// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
+//
+// Param#6 (Module Manufacturer ID):
+// Byte 1 - Module Manufacturer ID, LSB
+// Byte 2 - Module Manufacturer ID, MSB
+//
+ipmi_ret_t ipmiOemQSetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ qDimmInfo_t *req = reinterpret_cast<qDimmInfo_t *>(request);
+ uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t *);
+ std::stringstream ss;
+ std::string str;
+ uint8_t len = *data_len;
+
+ *data_len = 0;
+
+ /* check for requested data params */
+ if (len < 5 || req->paramSel < 1 || req->paramSel >= numParam)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid parameter received");
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ len = len - 5; // Get Actual data length
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
+ oemData[KEY_Q_DIMM_INFO][ss.str()][KEY_DIMM_INDEX] = req->dimmIndex;
+
+ str = bytesToStr(req->data, len);
+ oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]] =
+ str.c_str();
+ flushOemData();
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Get Dimm Info (CMD_OEM_Q_GET_DIMM_INFO)
+//----------------------------------------------------------------------
+// Request:
+// Byte 1:3 – Manufacturer ID – XXYYZZh, LSB first
+// Byte 4 – DIMM Index, 0 base
+// Byte 5 – Parameter Selector
+// Byte 6..N – Configuration parameter data (see below for Parameters
+// of DIMM Information)
+// Response:
+// Byte 1 – Completion code
+// Byte 2..N – Configuration Parameter Data (see Table_1213h Parameters
+// of DIMM Information)
+//
+// Param#1 (DIMM Location):
+// Byte 1 – DIMM Present
+// Byte 1 – DIMM Present
+// 01h – Present
+// FFh – Not Present
+// Byte 2 – Node Number, 0 base
+// Byte 3 – Channel Number , 0 base
+// Byte 4 – DIMM Number , 0 base
+//
+// Param#2 (DIMM Type):
+// Byte 1 – DIMM Type
+// Bit [7:6]
+// For DDR3
+// 00 – Normal Voltage (1.5V)
+// 01 – Ultra Low Voltage (1.25V)
+// 10 – Low Voltage (1.35V)
+// 11 – Reserved
+// For DDR4
+// 00 – Reserved
+// 01 – Reserved
+// 10 – Reserved
+// 11 – Normal Voltage (1.2V)
+// Bit [5:0]
+// 0x00 – SDRAM
+// 0x01 – DDR-1 RAM
+// 0x02 – Rambus
+// 0x03 – DDR-2 RAM
+// 0x04 – FBDIMM
+// 0x05 – DDR-3 RAM
+// 0x06 – DDR-4 RAM
+//
+// Param#3 (DIMM Speed):
+// Byte 1..2 – DIMM speed in MHz, LSB
+// Byte 3..6 – DIMM size in Mbytes, LSB
+//
+// Param#4 (Module Part Number):
+// Byte 1..20 –Module Part Number (JEDEC Standard No. 21-C)
+//
+// Param#5 (Module Serial Number):
+// Byte 1..4 –Module Serial Number (JEDEC Standard No. 21-C)
+//
+// Param#6 (Module Manufacturer ID):
+// Byte 1 - Module Manufacturer ID, LSB
+// Byte 2 - Module Manufacturer ID, MSB
+//
+ipmi_ret_t ipmiOemQGetDimmInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ qDimmInfo_t *req = reinterpret_cast<qDimmInfo_t *>(request);
+ uint8_t numParam = sizeof(dimmInfoKey) / sizeof(uint8_t *);
+ uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ std::stringstream ss;
+ std::string str;
+
+ *data_len = 0;
+
+ /* check for requested data params */
+ if (req->paramSel < 1 || req->paramSel >= numParam)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid parameter received");
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)req->dimmIndex;
+
+ if (oemData[KEY_Q_DIMM_INFO].find(ss.str()) ==
+ oemData[KEY_Q_DIMM_INFO].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ if (oemData[KEY_Q_DIMM_INFO][ss.str()].find(dimmInfoKey[req->paramSel]) ==
+ oemData[KEY_Q_DIMM_INFO][ss.str()].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ str = oemData[KEY_Q_DIMM_INFO][ss.str()][dimmInfoKey[req->paramSel]];
+ *data_len = strToBytes(str, res);
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Set Drive Info (CMD_OEM_Q_SET_DRIVE_INFO)
+//----------------------------------------------------------------------
+// BIOS issue this command to provide HDD information to BMC.
+//
+// BIOS just can get information by standard ATA / SMART command for
+// OB SATA controller.
+// BIOS can get
+// 1. Serial Number
+// 2. Model Name
+// 3. HDD FW Version
+// 4. HDD Capacity
+// 5. HDD WWN
+//
+// Use Get HDD info Param #5 to know the MAX HDD info index.
+//
+// Request:
+// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
+// Byte 4 –
+// [7:4] Reserved
+// [3:0] HDD Controller Type
+// 0x00 – BIOS
+// 0x01 – Expander
+// 0x02 – LSI
+// Byte 5 – HDD Info Index, 0 base
+// Byte 6 – Parameter Selector
+// Byte 7..N – Configuration parameter data (see Table_1415h Parameters of HDD
+// Information)
+//
+// Response:
+// Byte 1 – Completion Code
+//
+// Param#0 (HDD Location):
+// Byte 1 – Controller
+// [7:3] Device Number
+// [2:0] Function Number
+// For Intel C610 series (Wellsburg)
+// D31:F2 (0xFA) – SATA control 1
+// D31:F5 (0xFD) – SATA control 2
+// D17:F4 (0x8C) – sSata control
+// Byte 2 – Port Number
+// Byte 3 – Location (0xFF: No HDD Present)
+// BIOS default set Byte 3 to 0xFF, if No HDD Present. And then skip send param
+// #1~4, #6, #7 to BMC (still send param #5) BIOS default set Byte 3 to 0, if
+// the HDD present. BMC or other people who know the HDD location has
+// responsibility for update Location info
+//
+// Param#1 (Serial Number):
+// Bytes 1..33: HDD Serial Number
+//
+// Param#2 (Model Name):
+// Byte 1..33 – HDD Model Name
+//
+// Param#3 (HDD FW Version):
+// Byte 1..17 –HDD FW version
+//
+// Param#4 (Capacity):
+// Byte 1..4 –HDD Block Size, LSB
+// Byte 5..12 - HDD Block Number, LSB
+// HDD Capacity = HDD Block size * HDD BLock number (Unit Byte)
+//
+// Param#5 (Max HDD Quantity):
+// Byte 1 - Max HDD Quantity
+// Max supported port numbers in this PCH
+//
+// Param#6 (HDD Type)
+// Byte 1 – HDD Type
+// 0h – Reserved
+// 1h – SAS
+// 2h – SATA
+// 3h – PCIE SSD (NVME)
+//
+// Param#7 (HDD WWN)
+// Data 1...8: HDD World Wide Name, LSB
+//
+ipmi_ret_t ipmiOemQSetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+{
+ qDriveInfo_t *req = reinterpret_cast<qDriveInfo_t *>(request);
+ uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t *);
+ uint8_t ctrlType = req->hddCtrlType & 0x0f;
+ std::stringstream ss;
+ std::string str;
+ uint8_t len = *data_len;
+
+ *data_len = 0;
+
+ /* check for requested data params */
+ if (len < 6 || req->paramSel < 1 || req->paramSel >= numParam ||
+ ctrlType > 2)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid parameter received");
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ len = len - 6; // Get Actual data length
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
+ oemData[KEY_Q_DRIVE_INFO][KEY_HDD_CTRL_TYPE] = req->hddCtrlType;
+ oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()][KEY_HDD_INDEX] =
+ req->hddIndex;
+
+ str = bytesToStr(req->data, len);
+ oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
+ [driveInfoKey[req->paramSel]] = str.c_str();
+ flushOemData();
+
+ return IPMI_CC_OK;
+}
+
+//----------------------------------------------------------------------
+// Get Drive Info (CMD_OEM_Q_GET_DRIVE_INFO)
+//----------------------------------------------------------------------
+// BMC needs to check HDD presented or not first. If NOT presented, return
+// completion code 0xD5.
+//
+// Request:
+// Byte 1:3 – Quanta Manufacturer ID – 001C4Ch, LSB first
+// Byte 4 –
+//[7:4] Reserved
+//[3:0] HDD Controller Type
+// 0x00 – BIOS
+// 0x01 – Expander
+// 0x02 – LSI
+// Byte 5 – HDD Index, 0 base
+// Byte 6 – Parameter Selector (See Above Set HDD Information)
+// Response:
+// Byte 1 – Completion Code
+// 0xD5 – Not support in current status (HDD Not Present)
+// Byte 2..N – Configuration parameter data (see Table_1415h Parameters of HDD
+// Information)
+//
+ipmi_ret_t ipmiOemQGetDriveInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request,
+ ipmi_response_t response,
+ ipmi_data_len_t data_len,
+ ipmi_context_t context)
+{
+ qDriveInfo_t *req = reinterpret_cast<qDriveInfo_t *>(request);
+ uint8_t numParam = sizeof(driveInfoKey) / sizeof(uint8_t *);
+ uint8_t *res = reinterpret_cast<uint8_t *>(response);
+ uint8_t ctrlType = req->hddCtrlType & 0x0f;
+ std::stringstream ss;
+ std::string str;
+
+ *data_len = 0;
+
+ /* check for requested data params */
+ if (req->paramSel < 1 || req->paramSel >= numParam || ctrlType > 2)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid parameter received");
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ if (oemData[KEY_Q_DRIVE_INFO].find(ctrlTypeKey[ctrlType]) ==
+ oemData[KEY_Q_DRIVE_INFO].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ ss << std::hex;
+ ss << std::setw(2) << std::setfill('0') << (int)req->hddIndex;
+
+ if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]].find(ss.str()) ==
+ oemData[KEY_Q_DRIVE_INFO].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ if (oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()].find(
+ dimmInfoKey[req->paramSel]) ==
+ oemData[KEY_Q_DRIVE_INFO][ss.str()].end())
+ return CC_PARAM_NOT_SUPP_IN_CURR_STATE;
+
+ str = oemData[KEY_Q_DRIVE_INFO][ctrlTypeKey[ctrlType]][ss.str()]
+ [dimmInfoKey[req->paramSel]];
+ *data_len = strToBytes(str, res);
return IPMI_CC_OK;
}
static void registerOEMFunctions(void)
{
+ /* Get OEM data from json file */
+ std::ifstream file(JSON_OEM_DATA_FILE);
+ if (file)
+ file >> oemData;
+
phosphor::logging::log<phosphor::logging::level::INFO>(
"Registering OEM commands");
ipmiPrintAndRegister(NETFUN_CHASSIS, 1, NULL, ipmiGetChassisStatus,
@@ -623,6 +1507,12 @@
ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_DIMM_INFO, NULL,
ipmiOemSetDimmInfo,
PRIVILEGE_USER); // Set Dimm Info
+ ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOARD_ID, NULL,
+ ipmiOemGetBoardID,
+ PRIVILEGE_USER); // Get Board ID
+ ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BOOT_ORDER, NULL,
+ ipmiOemSetBootOrder,
+ PRIVILEGE_USER); // Set Boot Order
ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_BOOT_ORDER, NULL,
ipmiOemGetBootOrder,
PRIVILEGE_USER); // Get Boot Order
@@ -635,6 +1525,12 @@
ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_POST_END, NULL,
ipmiOemSetPostEnd,
PRIVILEGE_USER); // Set POST End
+ ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_PPIN_INFO, NULL,
+ ipmiOemSetPPINInfo,
+ PRIVILEGE_USER); // Set PPIN Info
+ ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_ADR_TRIGGER, NULL,
+ ipmiOemSetAdrTrigger,
+ PRIVILEGE_USER); // Set ADR Trigger
ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_SET_BIOS_FLASH_INFO, NULL,
ipmiOemSetBiosFlashInfo,
PRIVILEGE_USER); // Set Bios Flash Info
@@ -642,6 +1538,25 @@
PRIVILEGE_USER); // Set PPR
ipmiPrintAndRegister(NETFUN_NONE, CMD_OEM_GET_PPR, NULL, ipmiOemGetPpr,
PRIVILEGE_USER); // Get PPR
+ /* FB OEM QC Commands */
+ ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_PROC_INFO, NULL,
+ ipmiOemQSetProcInfo,
+ PRIVILEGE_USER); // Set Proc Info
+ ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_PROC_INFO, NULL,
+ ipmiOemQGetProcInfo,
+ PRIVILEGE_USER); // Get Proc Info
+ ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DIMM_INFO, NULL,
+ ipmiOemQSetDimmInfo,
+ PRIVILEGE_USER); // Set Dimm Info
+ ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DIMM_INFO, NULL,
+ ipmiOemQGetDimmInfo,
+ PRIVILEGE_USER); // Get Dimm Info
+ ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_SET_DRIVE_INFO, NULL,
+ ipmiOemQSetDriveInfo,
+ PRIVILEGE_USER); // Set Drive Info
+ ipmiPrintAndRegister(NETFUN_FB_OEM_QC, CMD_OEM_Q_GET_DRIVE_INFO, NULL,
+ ipmiOemQGetDriveInfo,
+ PRIVILEGE_USER); // Get Drive Info
return;
}