/* * 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 <usb-dbg.hpp> #include <commandutils.hpp> namespace ipmi { ipmi_ret_t getNetworkData(uint8_t lan_param, char* data); int8_t getFruData(std::string& serial, std::string& name); int8_t sysConfig(std::vector<std::string>& data, size_t pos); bool isMultiHostPlatform(); /* Declare Host Selector interface and path */ namespace selector { const std::string path = "/xyz/openbmc_project/Chassis/Buttons/HostSelector"; const std::string interface = "xyz.openbmc_project.Chassis.HostSelector.Selector"; const std::string propertyName = "Position"; } // namespace selector /* Declare storage functions used here */ namespace storage { int getSensorValue(std::string&, double&); int getSensorUnit(std::string&, std::string&); } // namespace storage size_t getSelectorPosition() { std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); std::string service = getService(*dbus, ipmi::selector::interface, ipmi::selector::path); Value variant = getDbusProperty(*dbus, service, ipmi::selector::path, ipmi::selector::interface, ipmi::selector::propertyName); size_t result = std::get<size_t>(variant); return result; } 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 size_t plat_get_fru_sel() { size_t position; bool platform = isMultiHostPlatform(); if (platform == true) { try { size_t hostPosition = getSelectorPosition(); position = hostPosition; if (position == BMC_POSITION) { return FRU_ALL; } } catch (...) { std::cout << "Error reading host selector position" << std::endl; } } else { // For Tiogapass it just return 1, can modify to support more platform position = 1; } return position; } // 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 = 128; char lbuf[buf_size]; char* ptr; int ret; ret = parse(lbuf, buf_size, string, indent); if (ret < 0) return ret; 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; size_t 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; size_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) { nlohmann::json postObj; std::string postCode; /* Get post description data stored in json file */ std::ifstream file(JSON_POST_DATA_FILE); if (file) { file >> postObj; file.close(); } else { phosphor::logging::log<phosphor::logging::level::ERR>( "Post code description file not found", phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE)); return -1; } std::string phaseStr = "PhaseAny"; if (postObj.find(phaseStr) == postObj.end()) { phaseStr = "Phase" + std::to_string(phase); } if (postObj.find(phaseStr) == postObj.end()) { phosphor::logging::log<phosphor::logging::level::ERR>( "Post code phase not available", phosphor::logging::entry("PHASE=%d", phase)); return -1; } auto phaseObj = postObj[phaseStr]; int phaseSize = phaseObj.size(); for (int i = 0; i < phaseSize; i++) { postCode = phaseObj[i][0]; if (index == stoul(postCode, nullptr, 16)) { std::string postDesc = phaseObj[i][1]; *length = postDesc.size(); memcpy(buffer, postDesc.data(), *length); buffer[*length] = '\0'; if (phaseSize != i + 1) { postCode = phaseObj[i + 1][0]; *next = stoul(postCode, nullptr, 16); *end = 0; } else { if (postObj.size() != phase) { std::string nextPhaseStr = "Phase" + std::to_string(phase + 1); postCode = postObj[nextPhaseStr][0][0]; *next = stoul(postCode, nullptr, 16); *end = 0; } else { *next = 0xff; *end = 1; } } return 0; } } phosphor::logging::log<phosphor::logging::level::ERR>( "Post code description data not available", phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index)); return -1; } int plat_udbg_get_gpio_desc(uint8_t index, uint8_t* next, uint8_t* level, uint8_t* def, uint8_t* length, uint8_t* buffer) { nlohmann::json gpioObj; std::string gpioPin; /* Get gpio data stored in json file */ std::ifstream file(JSON_GPIO_DATA_FILE); if (file) { file >> gpioObj; file.close(); } else { phosphor::logging::log<phosphor::logging::level::ERR>( "GPIO pin description file not found", phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s", JSON_GPIO_DATA_FILE)); return -1; } if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end()) { phosphor::logging::log<phosphor::logging::level::ERR>( "GPIO pin details not available", phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY)); return -1; } auto obj = gpioObj[DEBUG_GPIO_KEY]; int objSize = obj.size(); for (int i = 0; i < objSize; i++) { if (obj[i].size() != GPIO_ARRAY_SIZE) { phosphor::logging::log<phosphor::logging::level::ERR>( "Size of gpio array is incorrect", phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE)); return -1; } gpioPin = obj[i][GPIO_PIN_INDEX]; if (index == stoul(gpioPin, nullptr, 16)) { if (objSize != i + 1) { gpioPin = obj[i + 1][GPIO_PIN_INDEX]; *next = stoul(gpioPin, nullptr, 16); } else { *next = 0xff; } *level = obj[i][GPIO_LEVEL_INDEX]; *def = obj[i][GPIO_DEF_INDEX]; std::string gpioDesc = obj[i][GPIO_DESC_INDEX]; *length = gpioDesc.size(); memcpy(buffer, gpioDesc.data(), *length); buffer[*length] = '\0'; return 0; } } phosphor::logging::log<phosphor::logging::level::ERR>( "GPIO pin description data not available", phosphor::logging::entry("GPIO_PIN=0x%x", index)); return -1; } static int udbg_get_cri_sel(uint8_t, uint8_t page, uint8_t* next, uint8_t* count, uint8_t* buffer) { int len; int ret; char line_buff[FRAME_PAGE_BUF_SIZE]; const char* ptr; FILE* fp; struct stat file_stat; size_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, uint8_t page, uint8_t* next, uint8_t* count, uint8_t* buffer) { int ret; double fvalue; size_t pos = plat_get_fru_sel(); 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"); nlohmann::json senObj; /* Get critical sensor names stored in json file */ std::ifstream file(JSON_SENSOR_NAMES_FILE); if (file) { file >> senObj; file.close(); } else { phosphor::logging::log<phosphor::logging::level::ERR>( "Critical Sensor names file not found", phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s", JSON_SENSOR_NAMES_FILE)); return -1; } /* Get sensors values for all critical sensors */ for (auto& j : senObj.items()) { std::string senName = j.key(); auto val = j.value(); if (senName[0] == '_') { senName = std::to_string(pos) + senName; } if (ipmi::storage::getSensorValue(senName, fvalue) == 0) { std::stringstream ss; int prec = 0; // Default value if (val.find("precision") != val.end()) prec = val["precision"]; ss << std::fixed << std::setprecision(prec) << fvalue; std::string senStr; if (val.find("short_name") != val.end()) senStr = val["short_name"]; else senStr = senName; senStr += ss.str(); /* Get unit string for sensor and append in output */ std::string unitStr; if (ipmi::storage::getSensorUnit(senName, unitStr) == 0) senStr += unitStr; frame_snr.append(senStr.c_str(), 0); } else { phosphor::logging::log<phosphor::logging::level::INFO>( "Critical sensor not found", phosphor::logging::entry("CRI_SENSOR_NAME=%s", senName.c_str())); } } } // 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 getBiosVer(std::string& ver) { nlohmann::json appObj; std::ifstream file(JSON_APP_DATA_FILE); if (file) { file >> appObj; file.close(); if (appObj.find(KEY_SYSFW_VER) != appObj.end()) { ver = appObj[KEY_SYSFW_VER].get<std::string>(); return 0; } } return -1; } int sendBicCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr, std::vector<uint8_t>& cmdData, std::vector<uint8_t>& respData) { static constexpr uint8_t lun = 0; auto bus = getSdBus(); auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", "sendRequest"); method.append(bicAddr, netFn, lun, cmd, cmdData); auto reply = bus->call(method); if (reply.is_method_error()) { phosphor::logging::log<phosphor::logging::level::ERR>( "Error reading from BIC"); return -1; } IpmbMethodType resp; reply.read(resp); respData = std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); return 0; } int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t>& cmdData, std::vector<uint8_t>& respData) { auto bus = getSdBus(); if (DEBUG) { std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n"; std::cout << "ME req data: "; for (auto d : cmdData) { std::cout << d << " "; } std::cout << "\n"; } auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", "sendRequest"); method.append(meAddress, netFn, lun, cmd, cmdData); auto reply = bus->call(method); if (reply.is_method_error()) { phosphor::logging::log<phosphor::logging::level::ERR>( "Error reading from ME"); return -1; } IpmbMethodType resp; reply.read(resp); respData = std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp)); if (DEBUG) { std::cout << "ME resp data: "; for (auto d : respData) { std::cout << d << " "; } std::cout << "\n"; } return 0; } static int getMeStatus(std::string& status, size_t pos) { uint8_t cmd = 0x01; // Get Device id command uint8_t netFn = 0x06; // Netfn for APP std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); std::vector<uint8_t> cmdData; uint8_t meAddr = meAddress; bool platform = isMultiHostPlatform(); if (platform == true) { meAddr = ((pos - 1) << 2); } auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb", "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", "sendRequest"); method.append(meAddr, netFn, lun, cmd, cmdData); auto reply = bus->call(method); if (reply.is_method_error()) { std::cerr << "Error reading from ME\n"; return -1; } IpmbMethodType resp; reply.read(resp); std::vector<uint8_t> data; data = std::get<5>(resp); if (DEBUG) { std::cout << "ME Get ID: "; for (size_t d : data) { std::cout << d << " "; } std::cout << "\n"; } if (data[2] & 0x80) status = "recovery mode"; else status = "operation mode"; return 0; } static int udbg_get_info_page(uint8_t, uint8_t page, uint8_t* next, uint8_t* count, uint8_t* buffer) { char line_buff[1000]; [[maybe_unused]] char* pres_dev = line_buff; [[maybe_unused]] size_t pos = plat_get_fru_sel(); int ret; std::string serialName = "SerialNumber"; std::string partName = "PartNumber"; std::string verDel = "VERSION="; std::string verPath = "/etc/os-release"; size_t hostPosition; 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"); bool platform = isMultiHostPlatform(); if (platform == true) { hostPosition = getSelectorPosition(); } if (hostPosition == BMC_POSITION || hostInstances == "0") { frame_info.append("FRU:spb", 0); } else if (hostPosition != BMC_POSITION && hostPosition <= MAX_HOST_POS) { std::string data = "FRU:slot" + std::to_string(hostPosition); frame_info.append(data.c_str(), 0); } // FRU 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; } } } if (hostPosition != BMC_POSITION) { // BIOS ver std::string biosVer; if (getBiosVer(biosVer) == 0) { frame_info.append("BIOS_FW_ver:", 0); frame_info.append(biosVer.c_str(), 1); } // ME status std::string meStatus; if (getMeStatus(meStatus, pos) != 0) { phosphor::logging::log<phosphor::logging::level::WARNING>( "Reading ME status failed"); meStatus = "unknown"; } frame_info.append("ME_status:", 0); frame_info.append(meStatus.c_str(), 1); } /* TBD: Board ID needs implementation */ // 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); // Sys config present device if (hostPosition != BMC_POSITION) { frame_info.append("Sys Conf. info:", 0); // Dimm info std::vector<std::string> data; sysConfig(data, pos); for (auto& info : data) { frame_info.append(info.c_str(), 1); } } } // 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) { /* To be implemented */ #if 0 int i; unsigned char buff[MAX_VALUE_LEN], pickup, len; size_t pos = plat_get_fru_sel(); 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; } #endif return PANEL_BOOT_ORDER; } static uint8_t panel_power_policy(uint8_t) { /* To be cleaned */ #if 0 uint8_t buff[32] = {0}; uint8_t res_len; size_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}; 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; } #endif 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