Adding FB OEM commands
Added Facebook OEM IPMI commands for Host as welll as IPMB with
ME and debug card
Change-Id: I794b0a293bec1416ca409e8a269cd34b81c592a8
Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
diff --git a/src/usb-dbg.cpp b/src/usb-dbg.cpp
new file mode 100644
index 0000000..efa0136
--- /dev/null
+++ b/src/usb-dbg.cpp
@@ -0,0 +1,952 @@
+/*
+ * Copyright (c) 2018-present Facebook. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <host-ipmid/ipmid-api.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <fstream>
+#include <iostream>
+
+namespace ipmi
+{
+
+#define ETH_INTF_NAME "eth0"
+
+#define ESCAPE "\x1B"
+#define ESC_BAT ESCAPE "B"
+#define ESC_MCU_BL_VER ESCAPE "U"
+#define ESC_MCU_RUN_VER ESCAPE "R"
+#define ESC_ALT ESCAPE "[5;7m"
+#define ESC_RST ESCAPE "[m"
+
+#define LINE_DELIMITER '\x1F'
+
+#define FRAME_BUFF_SIZE 4096
+#define FRAME_PAGE_BUF_SIZE 256
+#define FRU_ALL 0
+#define MAX_VALUE_LEN 64
+
+/* Used for systems which do not specifically have a
+ * phase, and we want to ignore the phase provided by the
+ * debug card */
+#define PHASE_ANY 0xff
+
+ipmi_ret_t getNetworkData(uint8_t lan_param, char *data);
+int8_t getFruData(std::string &serial, std::string &name);
+
+typedef struct _post_desc
+{
+ uint8_t code;
+ char desc[32];
+} post_desc_t;
+
+typedef struct _post_phase_desc
+{
+ int phase;
+ post_desc_t *post_tbl;
+ size_t post_tbl_cnt;
+} post_phase_desc_t;
+
+typedef struct _gpio_desc
+{
+ uint8_t pin;
+ uint8_t level;
+ uint8_t def;
+ char desc[32];
+} gpio_desc_t;
+
+typedef struct _sensor_desc
+{
+ char name[16];
+ uint8_t sensor_num;
+ char unit[5];
+ uint8_t fru;
+ uint8_t disp_prec;
+} sensor_desc_t;
+
+struct frame
+{
+ char title[32];
+ size_t max_size;
+ size_t max_page;
+ char *buf;
+ uint16_t idx_head, idx_tail;
+ uint8_t line_per_page;
+ uint8_t line_width;
+ uint16_t lines, pages;
+ uint8_t esc_sts;
+ uint8_t overwrite;
+ time_t mtime;
+ frame() : buf(NULL), pages(0), mtime(0)
+ {
+ }
+ int init(size_t size);
+ int append(const char *string, int indent);
+ int insert(const char *string, int indent);
+ int getPage(int page, char *page_buf, size_t page_buf_size);
+ int isFull();
+ int isEscSeq(char chr);
+ int parse(char *buf, size_t buf_size, const char *input, int indent);
+};
+
+struct frame frame_info;
+struct frame frame_sel;
+struct frame frame_snr;
+
+enum ENUM_PANEL
+{
+ PANEL_MAIN = 1,
+ PANEL_BOOT_ORDER = 2,
+ PANEL_POWER_POLICY = 3,
+};
+
+struct ctrl_panel
+{
+ uint8_t parent;
+ uint8_t item_num;
+ char item_str[8][32];
+ uint8_t (*select)(uint8_t item);
+};
+
+static uint8_t panel_main(uint8_t item);
+static uint8_t panel_boot_order(uint8_t item);
+static uint8_t panel_power_policy(uint8_t item);
+
+static struct ctrl_panel panels[] = {
+ {/* dummy entry for making other to 1-based */},
+ {
+ .parent = PANEL_MAIN,
+ .item_num = 2,
+ .item_str =
+ {
+ "User Setting",
+ ">Boot Order",
+ ">Power Policy",
+ },
+ .select = panel_main,
+ },
+ {
+ .parent = PANEL_MAIN,
+ .item_num = 0,
+ .item_str =
+ {
+ "Boot Order",
+ },
+ .select = panel_boot_order,
+ },
+ {
+ .parent = PANEL_MAIN,
+ .item_num = 0,
+ .item_str =
+ {
+ "Power Policy",
+ },
+ .select = panel_power_policy,
+ },
+};
+
+static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1;
+
+/* Returns the FRU the hand-switch is switched to. If it is switched to BMC
+ * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */
+static uint8_t plat_get_fru_sel()
+{
+ // For Tiogapass it just return 1, can modify to support more platform
+ return 1;
+}
+
+// return 0 on seccuess
+int frame::init(size_t size)
+{
+ // Reset status
+ idx_head = idx_tail = 0;
+ lines = 0;
+ esc_sts = 0;
+ pages = 1;
+
+ if (buf != NULL && max_size == size)
+ {
+ // reinit
+ return 0;
+ }
+
+ if (buf != NULL && max_size != size)
+ {
+ delete[] buf;
+ }
+ // Initialize Configuration
+ title[0] = '\0';
+ buf = new char[size];
+ max_size = size;
+ max_page = size;
+ line_per_page = 7;
+ line_width = 16;
+ overwrite = 0;
+
+ if (buf)
+ return 0;
+ else
+ return -1;
+}
+
+// return 0 on seccuess
+int frame::append(const char *string, int indent)
+{
+ const size_t buf_size = 64;
+ char lbuf[buf_size];
+ char *ptr;
+ int ret;
+
+ ret = parse(lbuf, buf_size, string, indent);
+
+ if (ret < 0)
+ return ret;
+
+ int len = strlen(string);
+ for (ptr = lbuf; *ptr != '\0'; ptr++)
+ {
+ if (isFull())
+ {
+ if (overwrite)
+ {
+ if (buf[idx_head] == LINE_DELIMITER)
+ lines--;
+ idx_head = (idx_head + 1) % max_size;
+ }
+ else
+ return -1;
+ }
+
+ buf[idx_tail] = *ptr;
+ if (*ptr == LINE_DELIMITER)
+ lines++;
+
+ idx_tail = (idx_tail + 1) % max_size;
+ }
+
+ pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
+
+ if (pages > max_page)
+ pages = max_page;
+
+ return 0;
+}
+
+// return 0 on seccuess
+int frame::insert(const char *string, int indent)
+{
+ const size_t buf_size = 128;
+ char lbuf[buf_size];
+ char *ptr;
+ int ret;
+ int i;
+
+ ret = parse(lbuf, buf_size, string, indent);
+
+ if (ret < 0)
+ return ret;
+
+ for (i = strlen(lbuf) - 1; i >= 0; i--)
+ {
+ ptr = &lbuf[i];
+ if (isFull())
+ {
+ if (overwrite)
+ {
+ idx_tail = (idx_tail + max_size - 1) % max_size;
+ if (buf[idx_tail] == LINE_DELIMITER)
+ lines--;
+ }
+ else
+ return -1;
+ }
+
+ idx_head = (idx_head + max_size - 1) % max_size;
+
+ buf[idx_head] = *ptr;
+ if (*ptr == LINE_DELIMITER)
+ lines++;
+ }
+
+ pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
+
+ if (pages > max_page)
+ pages = max_page;
+
+ return 0;
+}
+
+// return page size
+int frame::getPage(int page, char *page_buf, size_t page_buf_size)
+{
+ int ret;
+ uint16_t line = 0;
+ uint16_t idx, len;
+
+ if (buf == NULL)
+ return -1;
+
+ // 1-based page
+ if (page > pages || page < 1)
+ return -1;
+
+ if (page_buf == NULL || page_buf_size < 0)
+ return -1;
+
+ ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages);
+ len = strlen(page_buf);
+ if (ret < 0)
+ return -1;
+
+ line = 0;
+ idx = idx_head;
+ while (line < ((page - 1) * line_per_page) && idx != idx_tail)
+ {
+ if (buf[idx] == LINE_DELIMITER)
+ line++;
+ idx = (idx + 1) % max_size;
+ }
+
+ while (line < ((page)*line_per_page) && idx != idx_tail)
+ {
+ if (buf[idx] == LINE_DELIMITER)
+ {
+ line++;
+ }
+ else
+ {
+ page_buf[len++] = buf[idx];
+ if (len == (page_buf_size - 1))
+ {
+ break;
+ }
+ }
+ idx = (idx + 1) % max_size;
+ }
+
+ return len;
+}
+
+// return 1 for frame buffer full
+int frame::isFull()
+{
+ if (buf == NULL)
+ return -1;
+
+ if ((idx_tail + 1) % max_size == idx_head)
+ return 1;
+ else
+ return 0;
+}
+
+// return 1 for Escape Sequence
+int frame::isEscSeq(char chr)
+{
+ uint8_t curr_sts = esc_sts;
+
+ if (esc_sts == 0 && (chr == 0x1b))
+ esc_sts = 1; // Escape Sequence
+ else if (esc_sts == 1 && (chr == 0x5b))
+ esc_sts = 2; // Control Sequence Introducer(CSI)
+ else if (esc_sts == 1 && (chr != 0x5b))
+ esc_sts = 0;
+ else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e))
+ esc_sts = 0;
+
+ if (curr_sts || esc_sts)
+ return 1;
+ else
+ return 0;
+}
+
+// return 0 on success
+int frame::parse(char *lbuf, size_t buf_size, const char *input, int indent)
+{
+ uint8_t pos, esc;
+ int i;
+ const char *in, *end;
+
+ if (buf == NULL || input == NULL)
+ return -1;
+
+ if (indent >= line_width || indent < 0)
+ return -1;
+
+ in = input;
+ end = in + strlen(input);
+ pos = 0; // line position
+ esc = 0; // escape state
+ i = 0; // buf index
+ while (in != end)
+ {
+ if (i >= buf_size)
+ break;
+
+ if (pos < indent)
+ {
+ // fill indent
+ lbuf[i++] = ' ';
+ pos++;
+ continue;
+ }
+
+ esc = isEscSeq(*in);
+
+ if (!esc && pos == line_width)
+ {
+ lbuf[i++] = LINE_DELIMITER;
+ pos = 0;
+ continue;
+ }
+
+ if (!esc)
+ pos++;
+
+ // fill input data
+ lbuf[i++] = *(in++);
+ }
+
+ // padding
+ while (pos <= line_width)
+ {
+ if (i >= buf_size)
+ break;
+ if (pos < line_width)
+ lbuf[i++] = ' ';
+ else
+ lbuf[i++] = LINE_DELIMITER;
+ pos++;
+ }
+
+ // full
+ if (i >= buf_size)
+ return -1;
+
+ lbuf[i++] = '\0';
+
+ return 0;
+}
+
+static int chk_cri_sel_update(uint8_t *cri_sel_up)
+{
+ FILE *fp;
+ struct stat file_stat;
+ uint8_t pos = plat_get_fru_sel();
+ static uint8_t pre_pos = 0xff;
+
+ fp = fopen("/mnt/data/cri_sel", "r");
+ if (fp)
+ {
+ if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
+ (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos))
+ {
+ *cri_sel_up = 1;
+ }
+ else
+ {
+ *cri_sel_up = 0;
+ }
+ fclose(fp);
+ }
+ else
+ {
+ if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos)
+ {
+ *cri_sel_up = 1;
+ }
+ else
+ {
+ *cri_sel_up = 0;
+ }
+ }
+ pre_pos = pos;
+ return 0;
+}
+
+int plat_udbg_get_frame_info(uint8_t *num)
+{
+ *num = 3;
+ return 0;
+}
+
+int plat_udbg_get_updated_frames(uint8_t *count, uint8_t *buffer)
+{
+ uint8_t cri_sel_up = 0;
+ uint8_t info_page_up = 1;
+
+ *count = 0;
+
+ // info page update
+ if (info_page_up == 1)
+ {
+ buffer[*count] = 1;
+ *count += 1;
+ }
+
+ // cri sel update
+ chk_cri_sel_update(&cri_sel_up);
+ if (cri_sel_up == 1)
+ {
+ buffer[*count] = 2;
+ *count += 1;
+ }
+
+ // cri sensor update
+ buffer[*count] = 3;
+ *count += 1;
+
+ return 0;
+}
+
+int plat_udbg_get_post_desc(uint8_t index, uint8_t *next, uint8_t phase,
+ uint8_t *end, uint8_t *length, uint8_t *buffer)
+{
+ int target, pdesc_size;
+ post_phase_desc_t *post_phase;
+ size_t post_phase_desc_cnt, i;
+ post_desc_t *ptr = NULL;
+ post_desc_t *next_phase = NULL;
+ uint8_t pos = plat_get_fru_sel();
+
+ /* Temporary return sample */
+ *next = 0xff;
+ *end = 0x00;
+ memcpy(buffer, "Hello Post", 10);
+ *length = 10;
+ return 0;
+}
+
+/* Need to implement this */
+int plat_udbg_get_gpio_desc(uint8_t index, uint8_t *next, uint8_t *level,
+ uint8_t *def, uint8_t *count, uint8_t *buffer)
+{
+ return 0;
+}
+
+static int udbg_get_cri_sel(uint8_t frame, uint8_t page, uint8_t *next,
+ uint8_t *count, uint8_t *buffer)
+{
+ int len;
+ int ret;
+ char line_buff[FRAME_PAGE_BUF_SIZE], *fptr;
+ const char *ptr;
+ FILE *fp;
+ struct stat file_stat;
+ uint8_t pos = plat_get_fru_sel();
+ static uint8_t pre_pos = FRU_ALL;
+ bool pos_changed = pre_pos != pos;
+
+ pre_pos = pos;
+
+ /* Revisit this */
+ fp = fopen("/mnt/data/cri_sel", "r");
+ if (fp)
+ {
+ if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
+ (file_stat.st_mtime != frame_sel.mtime || pos_changed))
+ {
+ // initialize and clear frame
+ frame_sel.init(FRAME_BUFF_SIZE);
+ frame_sel.overwrite = 1;
+ frame_sel.max_page = 20;
+ frame_sel.mtime = file_stat.st_mtime;
+ snprintf(frame_sel.title, 32, "Cri SEL");
+
+ while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp))
+ {
+ // Remove newline
+ line_buff[strlen(line_buff) - 1] = '\0';
+ ptr = line_buff;
+ // Find message
+ ptr = strstr(ptr, "local0.err");
+ if (ptr == NULL)
+ {
+ continue;
+ }
+
+ if ((ptr = strrchr(ptr, ':')) == NULL)
+ {
+ continue;
+ }
+ len = strlen(ptr);
+ if (len > 2)
+ {
+ // to skip log string ": "
+ ptr += 2;
+ }
+ // Write new message
+ frame_sel.insert(ptr, 0);
+ }
+ }
+ fclose(fp);
+ }
+ else
+ {
+ // Title only
+ frame_sel.init(FRAME_BUFF_SIZE);
+ snprintf(frame_sel.title, 32, "Cri SEL");
+ frame_sel.mtime = 0;
+ }
+
+ if (page > frame_sel.pages)
+ {
+ return -1;
+ }
+
+ ret = frame_sel.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
+ if (ret < 0)
+ {
+ *count = 0;
+ return -1;
+ }
+ *count = (uint8_t)ret;
+
+ if (page < frame_sel.pages)
+ *next = page + 1;
+ else
+ *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
+ // last page
+
+ return 0;
+}
+
+static int udbg_get_cri_sensor(uint8_t frame, uint8_t page, uint8_t *next,
+ uint8_t *count, uint8_t *buffer)
+{
+ char str[32], temp_val[16], temp_thresh[8], print_format[32];
+ int i, ret;
+ float fvalue;
+ sensor_desc_t *cri_sensor = NULL;
+ size_t sensor_count = 0;
+ uint8_t pos = plat_get_fru_sel();
+ uint8_t fru;
+
+ if (page == 1)
+ {
+ // Only update frame data while getting page 1
+
+ // initialize and clear frame
+ frame_snr.init(FRAME_BUFF_SIZE);
+ snprintf(frame_snr.title, 32, "CriSensor");
+ frame_snr.append(str, 0);
+ } // End of update frame
+
+ if (page > frame_snr.pages)
+ {
+ return -1;
+ }
+
+ ret = frame_snr.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
+ if (ret < 0)
+ {
+ *count = 0;
+ return -1;
+ }
+ *count = (uint8_t)ret;
+
+ if (page < frame_snr.pages)
+ *next = page + 1;
+ else
+ *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
+ // last page
+
+ return 0;
+}
+
+static int udbg_get_info_page(uint8_t frame, uint8_t page, uint8_t *next,
+ uint8_t *count, uint8_t *buffer)
+{
+ char line_buff[1000], *pres_dev = line_buff;
+ uint8_t pos = plat_get_fru_sel();
+ const char *delim = "\n";
+ int ret;
+ std::string serialName = "BOARD_SERIAL_NUMBER";
+ std::string partName = "BOARD_PART_NUMBER";
+ std::string verDel = "VERSION=";
+ std::string verPath = "/etc/os-release";
+
+ if (page == 1)
+ {
+ // Only update frame data while getting page 1
+
+ // initialize and clear frame
+ frame_info.init(FRAME_BUFF_SIZE);
+ snprintf(frame_info.title, 32, "SYS_Info");
+
+ // FRU TBD:
+ std::string data;
+ frame_info.append("SN:", 0);
+ if (getFruData(data, serialName) != 0)
+ {
+ data = "Not Found";
+ }
+ frame_info.append(data.c_str(), 1);
+ frame_info.append("PN:", 0);
+ if (getFruData(data, partName) != 0)
+ {
+ data = "Not Found";
+ }
+ frame_info.append(data.c_str(), 1);
+
+ // LAN
+ getNetworkData(3, line_buff);
+ frame_info.append("BMC_IP:", 0);
+ frame_info.append(line_buff, 1);
+ getNetworkData(59, line_buff);
+ frame_info.append("BMC_IPv6:", 0);
+ frame_info.append(line_buff, 1);
+
+ // BMC ver
+ std::ifstream file(verPath);
+ if (file)
+ {
+ std::string line;
+ while (std::getline(file, line))
+ {
+ if (line.find(verDel) != std::string::npos)
+ {
+ std::string bmcVer = line.substr(verDel.size());
+ frame_info.append("BMC_FW_ver:", 0);
+ frame_info.append(bmcVer.c_str(), 1);
+ break;
+ }
+ }
+ }
+
+ /* TBD: BIOS ver, ME status and Board ID needs implementation */
+ // BIOS ver
+
+ // ME status
+
+ // Board ID
+
+ // Battery - Use Escape sequence
+ frame_info.append("Battery:", 0);
+ frame_info.append(ESC_BAT " ", 1);
+ // frame_info.append(&frame_info, esc_bat, 1);
+
+ // MCU Version - Use Escape sequence
+ frame_info.append("MCUbl_ver:", 0);
+ frame_info.append(ESC_MCU_BL_VER, 1);
+ frame_info.append("MCU_ver:", 0);
+ frame_info.append(ESC_MCU_RUN_VER, 1);
+
+ // TBD:
+ // Sys config present device
+
+ } // End of update frame
+
+ if (page > frame_info.pages)
+ {
+ return -1;
+ }
+
+ ret = frame_info.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
+ if (ret < 0)
+ {
+ *count = 0;
+ return -1;
+ }
+ *count = (uint8_t)ret;
+
+ if (page < frame_info.pages)
+ *next = page + 1;
+ else
+ *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
+ // last page
+
+ return 0;
+}
+
+int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t *next,
+ uint8_t *count, uint8_t *buffer)
+{
+ switch (frame)
+ {
+ case 1: // info_page
+ return udbg_get_info_page(frame, page, next, count, buffer);
+ case 2: // critical SEL
+ return udbg_get_cri_sel(frame, page, next, count, buffer);
+ case 3: // critical Sensor
+ return udbg_get_cri_sensor(frame, page, next, count, buffer);
+ default:
+ return -1;
+ }
+}
+
+static uint8_t panel_main(uint8_t item)
+{
+ // Update item list when select item 0
+ switch (item)
+ {
+ case 1:
+ return panels[PANEL_BOOT_ORDER].select(0);
+ case 2:
+ return panels[PANEL_POWER_POLICY].select(0);
+ default:
+ return PANEL_MAIN;
+ }
+}
+
+static uint8_t panel_boot_order(uint8_t item)
+{
+ int i;
+ unsigned char buff[MAX_VALUE_LEN], pickup, len;
+ uint8_t pos = plat_get_fru_sel();
+
+ /* To be implemented */
+ /*
+ if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
+ {
+ if (item > 0 && item < SIZE_BOOT_ORDER)
+ {
+ pickup = buff[item];
+ while (item > 1)
+ {
+ buff[item] = buff[item -1];
+ item--;
+ }
+ buff[item] = pickup;
+ buff[0] |= 0x80;
+ pal_set_boot_order(pos, buff, buff, &len);
+
+ // refresh items
+ return panels[PANEL_BOOT_ORDER].select(0);
+ }
+
+ // '*': boot flags valid, BIOS has not yet read
+ snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32,
+ "Boot Order%c", (buff[0] & 0x80)?'*':'\0');
+
+ for (i = 1; i < SIZE_BOOT_ORDER; i++)
+ {
+ switch (buff[i])
+ {
+ case 0x0:
+ snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
+ " USB device");
+ break;
+ case 0x1:
+ snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
+ " Network v4");
+ break;
+ case (0x1 | 0x8):
+ snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
+ " Network v6");
+ break;
+ case 0x2:
+ snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
+ " SATA HDD");
+ break;
+ case 0x3:
+ snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
+ " SATA-CDROM");
+ break;
+ case 0x4:
+ snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
+ " Other");
+ break;
+ default:
+ panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
+ break;
+ }
+ }
+
+ // remove empty items
+ for (i--; (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); i--)
+ ;
+
+ panels[PANEL_BOOT_ORDER].item_num = i;
+ } else
+ {
+ panels[PANEL_BOOT_ORDER].item_num = 0;
+ }
+ */
+ return PANEL_BOOT_ORDER;
+}
+
+static uint8_t panel_power_policy(uint8_t item)
+{
+ uint8_t buff[32] = {0};
+ uint8_t res_len;
+ uint8_t pos = plat_get_fru_sel();
+ uint8_t policy;
+ // uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
+ // POWER_CFG_OFF};
+
+ /* To be cleaned */
+ /*
+ if (pos != FRU_ALL) {
+ if (item > 0 && item <= sizeof(pwr_policy_item_map)) {
+ policy = pwr_policy_item_map[item - 1];
+ pal_set_power_restore_policy(pos, &policy, NULL);
+ }
+ pal_get_chassis_status(pos, NULL, buff, &res_len);
+ policy = (((uint8_t)buff[0]) >> 5) & 0x7;
+ snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32,
+ "%cPower On", policy == POWER_CFG_ON ? '*' : ' ');
+ snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32,
+ "%cLast State", policy == POWER_CFG_LPS ? '*' : ' ');
+ snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32,
+ "%cPower Off", policy == POWER_CFG_OFF ? '*' : ' ');
+ panels[PANEL_POWER_POLICY].item_num = 3;
+ } else {
+ panels[PANEL_POWER_POLICY].item_num = 0;
+ }
+ */
+ return PANEL_POWER_POLICY;
+}
+
+int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
+ uint8_t *count, uint8_t *buffer)
+{
+ if (panel > panelNum || panel < PANEL_MAIN)
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ // No more item; End of item list
+ if (item > panels[panel].item_num)
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+
+ switch (operation)
+ {
+ case 0: // Get Description
+ break;
+ case 1: // Select item
+ panel = panels[panel].select(item);
+ item = 0;
+ break;
+ case 2: // Back
+ panel = panels[panel].parent;
+ item = 0;
+ break;
+ default:
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ buffer[0] = panel;
+ buffer[1] = item;
+ buffer[2] = strlen(panels[panel].item_str[item]);
+ if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
+ {
+ memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
+ }
+ *count = buffer[2] + 3;
+ return IPMI_CC_OK;
+}
+
+} // end of namespace ipmi