common/recipes-core/ipmid/files/ipmid.c (4,051 lines of code) (raw):

/* * * Copyright 2014-present Facebook. All Rights Reserved. * * This file contains code to support IPMI2.0 Specificaton available @ * http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "sdr.h" #include "sel.h" #include "fruid.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <syslog.h> #include <string.h> #include <pthread.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <openbmc/ipmi.h> #include <openbmc/kv.h> #include <openbmc/pal.h> #include <openbmc/pal_sensors.h> #include <sys/reboot.h> #include <openbmc/obmc-i2c.h> #include <openbmc/ipc.h> #include <sys/stat.h> #include <fcntl.h> #include "sensor.h" #define MAX_REQUESTS 64 #define SIZE_IANA_ID 3 #define SIZE_GUID 16 //declare for clearing BIOS flag #define BIOS_Timeout 600 // Boot valid flag #define BIOS_BOOT_VALID_FLAG (1U << 7) #define CMOS_VALID_FLAG (1U << 1) #define FORCE_BOOT_BIOS_SETUP_VALID_FLAG (1U << 2) //#define CHASSIS_GET_BOOT_OPTION_SUPPORT //#define CHASSIS_SET_BOOT_OPTION_SUPPORT #define CONFIG_FBTP 1 #define OBMC_DUMP_STAT_KEY "obmc_dump_stat" // PPR definition #define PPR_MAX_ROW_COUNT 100 #define PPR_MAX_HISTORY_COUNT 100 #define PPR_ROW_ADDR_DATA_LEN 8 #define PPR_HISTORY_DATA_LEN 17 static unsigned char IsTimerStart[MAX_NODES] = {0}; static unsigned char bmc_global_enable_setting[] = {0x0c,0x0c,0x0c,0x0c}; extern void plat_lan_init(lan_config_t *lan); // TODO: Once data storage is finalized, the following structure needs // to be retrieved/updated from persistent backend storage static lan_config_t g_lan_config = { 0 }; // TODO: Need to store this info after identifying proper storage static sys_info_param_t g_sys_info_params; // enable IPMI cmd logging static uint8_t gLogEnable = 0; // IPMI Watchdog Timer Structure struct watchdog_data { pthread_mutex_t mutex; pthread_t tid; uint8_t slot; uint8_t valid; uint8_t run; uint8_t no_log; uint8_t use; uint8_t pre_action; uint8_t action; uint8_t pre_interval; uint8_t expiration; uint16_t init_count_down; uint16_t present_count_down; }; static struct watchdog_data *g_wdt[MAX_NUM_FRUS]; static char* wdt_use_name[8] = { "reserved", "BIOS FRB2", "BIOS/POST", "OS Load", "SMS/OS", "OEM", "reserved", "reserved", }; static char* wdt_action_name[8] = { "Timer expired", "Hard Reset", "Power Down", "Power Cycle", "reserved", "reserved", "reserved", "reserved", }; static char *cpu_info_key[] = { "", "product_name", "basic_info", "type", "micro_code", "turbo_mode" }; static char *dimm_info_key[] = { "", "location", "type", "speed", "part_name", "serial_num", "manufacturer_id", "status", "present_bit" }; static char *drive_info_key[] = { "location", "serial_num", "model_name", "fw_version", "capacity", "quantity", "type", "wwn" }; // obmc-dump status enum { DUMP_DONE = 0x0, DUMP_FAIL = 0x1, DUMP_NEVER = 0x2, DUMP_ONGOING = 0x3, }; // TODO: Based on performance testing results, might need fine grained locks // Since the global data is specific to a NetFunction, adding locs at NetFn level static pthread_mutex_t m_chassis; static pthread_mutex_t m_sensor; static pthread_mutex_t m_app; static pthread_mutex_t m_storage; static pthread_mutex_t m_transport; static pthread_mutex_t m_oem; static pthread_mutex_t m_oem_storage; static pthread_mutex_t m_oem_1s; static pthread_mutex_t m_oem_usb_dbg; static pthread_mutex_t m_oem_q; static pthread_mutex_t m_oem_zion; extern int plat_udbg_get_frame_info(); extern int plat_udbg_get_updated_frames(uint8_t *count, uint8_t *buffer); extern int plat_udbg_get_post_desc(uint8_t index, uint8_t *next, uint8_t phase, uint8_t *end, uint8_t *length, uint8_t *buffer); extern int plat_udbg_get_gpio_desc(uint8_t index, uint8_t *next, uint8_t *level, uint8_t *def, uint8_t *count, uint8_t *buffer); extern int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t *next, uint8_t *count, uint8_t *buffer); extern int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item, uint8_t *count, uint8_t *buffer); static void ipmi_handle(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len); extern int bbv_power_cycle(int delay_time); static struct watchdog_data *get_watchdog(int slot_id) { if (slot_id > MAX_NUM_FRUS) return NULL; return g_wdt[slot_id - 1]; } static int length_check(unsigned char cmd_len, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; // req_len = cmd_len + 3 (payload_id, cmd and netfn) if( req_len != (cmd_len + IPMI_MN_REQ_HDR_SIZE) ){ res->cc = CC_INVALID_LENGTH; *res_len = 0; return 1; } return 0; } /* **Function to handle with clearing BIOS flag */ void *clear_bios_data_timer(void *ptr) { int timer = 0; int slot_id = (int)ptr; int oldstate; unsigned char boot[SIZE_BOOT_ORDER]={0}; unsigned char res_len; pthread_detach(pthread_self()); while( timer <= BIOS_Timeout ) { #ifdef DEBUG syslog(LOG_WARNING, "[%s][%lu] Timer: %d\n", __func__, pthread_self(), timer); #endif sleep(1); timer++; } //get boot order setting pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pal_get_boot_order(slot_id, NULL, boot, &res_len); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); #ifdef DEBUG syslog(LOG_WARNING, "[%s][%lu] Get: %x %x %x %x %x %x\n", __func__, pthread_self() ,boot[0], boot[1], boot[2], boot[3], boot[4], boot[5]); #endif //clear boot-valid and cmos bits due to timeout: boot[0] &= ~(BIOS_BOOT_VALID_FLAG | CMOS_VALID_FLAG); #ifdef DEBUG syslog(LOG_WARNING, "[%s][%lu] Set: %x %x %x %x %x %x\n", __func__, pthread_self() , boot[0], boot[1], boot[2], boot[3], boot[4], boot[5]); #endif //set data pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); pal_set_boot_order(slot_id, boot, NULL, &res_len); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); IsTimerStart[slot_id - 1] = false; pthread_exit(0); } /* * Function(s) to handle IPMI messages with NetFn: Chassis */ // Get Chassis Status (IPMI/Section 28.2) static void chassis_get_status (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = CC_SUCCESS; pal_get_chassis_status(req->payload_id, req->data, res->data, res_len); } static void chassis_control(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; ret = pal_chassis_control(req->payload_id, req->data, (req_len - 3)); if (ret == PAL_ENOTSUP) { res->cc = CC_INVALID_CMD; } else { res->cc = ret; } *res_len = 0; return; } // Set Power Restore Policy (IPMI/Section 28.8) static void chassis_set_power_restore_policy(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; unsigned char *data = &res->data[0]; *data++ = 0x07; // Power restore policy support(bitfield) res->cc = pal_set_power_restore_policy(req->payload_id, req->data, res->data); if (res->cc == CC_SUCCESS) { *res_len = data - &res->data[0]; } } // Set Power Restore Policy (IPMI/Section 28.11) static void chassis_get_system_restart_cause(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; unsigned char *data = &res->data[0]; *res_len = 0; if (pal_get_restart_cause(req->payload_id, &data[0])) { res->cc = CC_UNSPECIFIED_ERROR; } data[1] = 0; // Channel number res->cc = CC_SUCCESS; *res_len = 2; } static void chassis_identify(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_set_slot_led(req->payload_id, req->data, req_len, res->data, res_len); return; } #ifdef CHASSIS_GET_BOOT_OPTION_SUPPORT // Get System Boot Options (IPMI/Section 28.12) static void chassis_get_boot_options (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; unsigned char *data = &res->data[0]; unsigned char param = req->data[0]; if(param >= 8) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } // Fill response with default values res->cc = CC_SUCCESS; *data++ = 0x01; // Parameter Version *data++ = req->data[0]; // Parameter *res_len = pal_get_boot_option(param, data) + 2; } #endif #ifdef CHASSIS_SET_BOOT_OPTION_SUPPORT // Set System Boot Options (IPMI/Section 28) static void chassis_set_boot_options (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; unsigned char *data = &res->data[0]; unsigned char param = req->data[0]; // Fill response with default values if(param >= 8) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } res->cc = CC_SUCCESS; pal_set_boot_option(param,req->data+1); *res_len = data - &res->data[0]; } #endif // Handle Chassis Commands (IPMI/Section 28) static void ipmi_handle_chassis (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_chassis); switch (cmd) { case CMD_CHASSIS_GET_STATUS: chassis_get_status (request, req_len, response, res_len); break; case CMD_CHASSIS_CONTROL: chassis_control(request, req_len, response, res_len); break; case CMD_CHASSIS_IDENTIFY: chassis_identify (request, req_len, response, res_len); break; case CMD_CHASSIS_SET_POWER_RESTORE_POLICY: chassis_set_power_restore_policy(request, req_len, response, res_len); break; case CMD_CHASSIS_GET_SYSTEM_RESTART_CAUSE: chassis_get_system_restart_cause(request, req_len, response, res_len); break; #ifdef CHASSIS_GET_BOOT_OPTION_SUPPORT case CMD_CHASSIS_GET_BOOT_OPTIONS: chassis_get_boot_options(request, req_len, response, res_len); break; #endif #ifdef CHASSIS_SET_BOOT_OPTION_SUPPORT case CMD_CHASSIS_SET_BOOT_OPTIONS: chassis_set_boot_options(request, req_len, response, res_len); break; #endif default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_chassis); } /* * Function(s) to handle IPMI messages with NetFn: Sensor */ // Platform Event Message (IPMI/Section 29.3) static void sensor_plat_event_msg(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int record_id; // Record ID for added entry int ret; sel_msg_t entry; entry.msg[2] = 0x02; /* Set Record Type to be system event record.*/ if (req_len == 11) { // For messaging from system interface entry.msg[7] = req->data[0]; //Store Generator ID memcpy(&entry.msg[9], req->data + 1, 7); } else { memcpy(&entry.msg[9], req->data, 7); // Platform event provides only last 7 bytes of SEL's 16-byte entry } // Use platform APIs to add the new SEL entry ret = sel_add_entry (req->payload_id, &entry, &record_id); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; } // Alert Immediate Command (IPMI/Section 30.7) static void sensor_alert_immediate_msg(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int record_id; // Record ID for added entry int ret; sel_msg_t entry; entry.msg[2] = 0x02; /* Set Record Type to be system event record.*/ memcpy(&entry.msg[10], &req->data[5], 6); // Use platform APIs to add the new SEL entry ret = sel_add_entry (req->payload_id, &entry, &record_id); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; } // Set sensor reading (IPMI/Section 35.17) static void sensor_set_reading(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t sensor_num; uint8_t flags; float value; bool available = true; // We do not support the command in full. if (length_check(3, req_len, response, res_len)) return; sensor_num = req->data[0]; flags = req->data[1]; value = req->data[2]; // We support the case only when flags == 1 (write given value // to sensor reading byte ([1:0] - sensor reading operation)) if (flags != 0x1) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; return; } if (!pal_sensor_is_source_host(req->payload_id, sensor_num)) { res->cc = CC_INVALID_PARAM; return; } // may use NVMe-MI CTemp spec or other spec to decode cache send from IPMI command if (pal_correct_sensor_reading_from_cache(req->payload_id, sensor_num, &value) != 0) { available = false; } if (sensor_cache_write(req->payload_id, sensor_num, available, value)) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; } // Handle Sensor/Event Commands (IPMI/Section 29) static void ipmi_handle_sensor(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_sensor); switch (cmd) { case CMD_SENSOR_PLAT_EVENT_MSG: sensor_plat_event_msg(request, req_len, response, res_len); break; case CMD_SENSOR_ALERT_IMMEDIATE_MSG: sensor_alert_immediate_msg(request, req_len, response, res_len); break; case CMD_SENSOR_SET_SENSOR_READING: sensor_set_reading(request, req_len, response, res_len); break; default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_sensor); } /* * Function(s) to handle IPMI messages with NetFn: Application */ // Get Device ID (IPMI/Section 20.1) static void app_get_device_id (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; FILE *fp=NULL; int fv_major = 0x01, fv_minor = 0x03, fv_patch = 0x00; char buffer[64]; if(length_check(0, req_len, response, res_len)) { return; } fp = fopen("/etc/issue","r"); if (fp != NULL) { if (fgets(buffer, sizeof(buffer), fp)) { char *version = strstr(buffer, "-v"); if (version != NULL) { sscanf(version, "-v%d.%d.%d", &fv_major, &fv_minor, &fv_patch); } } fclose(fp); } // If we are using date based versioning, return // the two digit year instead of the 4 digit year. // Look out for year 2127 when this overflows the // 7 bit allowance for major version :-) if (fv_major > 2000) { fv_major -= 2000; } res->cc = CC_SUCCESS; //TODO: Following data needs to be updated based on platform *data++ = 0x20; // Device ID *data++ = 0x81; // Device Revision *data++ = fv_major & 0x7f; // Firmware Revision Major *data++ = ((fv_minor / 10) << 4) | (fv_minor % 10); // Firmware Revision Minor *data++ = 0x02; // IPMI Version *data++ = 0xBF; // Additional Device Support *data++ = 0x15; // Manufacturer ID1 *data++ = 0xA0; // Manufacturer ID2 *data++ = 0x00; // Manufacturer ID3 *data++ = 0x46; // Product ID1 *data++ = 0x31; // Product ID2 *data++ = (uint8_t) fv_patch; // Aux. Firmware Version1 (patch ver) *data++ = 0x00; // Aux. Firmware Version2 *data++ = 0x00; // Aux. Firmware Version3 *data++ = 0x00; // Aux. Firmware Version4 *res_len = data - &res->data[0]; } static void * wait_and_reboot() { sleep(1); pal_bmc_reboot(RB_AUTOBOOT); return NULL; } // Cold Reset (IPMI/Section 20.2) static void app_cold_reset(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; int i; pthread_t do_reboot; *res_len = 0; res->cc = CC_SUCCESS; if (pal_is_fw_update_ongoing_system()) { res->cc = CC_NODE_BUSY; return; } for (i = 1; i < MAX_NUM_FRUS; i++) { if (pal_is_crashdump_ongoing(i)) { res->cc = CC_NODE_BUSY; return; } } for (i = 1; i < MAX_NUM_FRUS; i++) { if (pal_is_cplddump_ongoing(i)) { res->cc = CC_NODE_BUSY; return; } } syslog(LOG_CRIT, "BMC Cold Reset."); if (pthread_create(&do_reboot, NULL, wait_and_reboot, NULL) < 0) { syslog(LOG_WARNING, "pthread_create for doing reset failed\n"); } } // Get Self Test Results (IPMI/Section 20.4) static void app_get_selftest_results (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; res->cc = CC_SUCCESS; //TODO: Following data needs to be updated based on self-test results *data++ = 0x55; // Self-Test result *data++ = 0x00; // Extra error info in case of failure *res_len = data - &res->data[0]; } // Manufacturing Test On (IPMI/Section 20.5) static void app_manufacturing_test_on (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; char stat_buf[10] = {0}; size_t len = 0; bool is_first_exc = false; res->cc = CC_SUCCESS; if ((!memcmp(req->data, "sled-cycle", strlen("sled-cycle"))) && (req_len - ((void*)req->data - (void*)req)) == strlen("sled-cycle")) { if (system("/usr/local/bin/power-util sled-cycle") != 0) { res->cc = CC_UNSPECIFIED_ERROR; } } else if ((!memcmp(req->data, "obmc-dump", strlen("obmc-dump"))) && (req_len - ((void*)req->data - (void*)req)) == strlen("obmc-dump")) { if (kv_get(OBMC_DUMP_STAT_KEY, stat_buf, &len, KV_FPERSIST) < 0) { is_first_exc = true; } // If obmc-dump is ongiong, skip the request if ((is_first_exc == true) || strncmp(stat_buf, "Ongoing", strlen("Ongoing")) != 0) { if (system("/usr/local/bin/obmc-dump -y &") != 0) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; } } } else if ((!memcmp(req->data, "obmc-dump -s", strlen("obmc-dump -s"))) && (req_len - ((void*)req->data - (void*)req)) == strlen("obmc-dump -s")) { if (kv_get(OBMC_DUMP_STAT_KEY, stat_buf, &len, KV_FPERSIST) < 0) { *data++ = DUMP_NEVER; goto exit; } if (strncmp(stat_buf, "Ongoing", strlen("Ongoing")) == 0) { *data++ = DUMP_ONGOING; } else if (strncmp(stat_buf, "Done", strlen("Done")) == 0) { *data++ = DUMP_DONE; } else if (strncmp(stat_buf, "Fail", strlen("Fail")) == 0) { *data++ = DUMP_FAIL; } else { res->cc = CC_UNSPECIFIED_ERROR; } } else { res->cc = CC_INVALID_PARAM; } exit: *res_len = data - &res->data[0]; } // Get Device GUID (IPMI/Section 20.8) static void app_get_device_guid (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { int ret; ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; // Get the 16 bytes of Device GUID from PAL library ret = pal_get_dev_guid(req->payload_id, (char *)res->data); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0x00; } else { res->cc = CC_SUCCESS; *res_len = SIZE_GUID; } } static void app_get_device_sys_guid (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { int ret; ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; // Get the 16 bytes of System GUID from PAL library ret = pal_get_sys_guid(req->payload_id, (char *)res->data); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0x00; } else { res->cc = CC_SUCCESS; *res_len = SIZE_GUID; } } static void oem_set_device_sys_guid (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { int ret; ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; // Get the 16 bytes of System GUID from PAL library ret = pal_set_sys_guid(req->payload_id, (char *)req->data); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0x00; } else { res->cc = CC_SUCCESS; *res_len = 0x00; } } // Reset Watchdog Timer (IPMI/Section 27.5) static void app_reset_watchdog_timer (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; struct watchdog_data *wdt = get_watchdog(req->payload_id); if (!wdt) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } pthread_mutex_lock(&wdt->mutex); if (wdt->valid) { res->cc = CC_SUCCESS; wdt->present_count_down = wdt->init_count_down; wdt->run = 1; } else res->cc = CC_INVALID_PARAM; // un-initialized watchdog pthread_mutex_unlock(&wdt->mutex); *res_len = data - &res->data[0]; } // Set Watchdog Timer (IPMI/Section 27.6) static void app_set_watchdog_timer (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t*) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; struct watchdog_data *wdt = get_watchdog(req->payload_id); if (!wdt) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } // no support pre-itmeout interrupt if (req->data[1] & 0xF0) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } pthread_mutex_lock(&wdt->mutex); wdt->no_log = req->data[0] >> 7; wdt->use = req->data[0] & 0x7; wdt->pre_action = 0; // no support wdt->action = req->data[1] & 0x7; wdt->pre_interval = req->data[2]; wdt->expiration &= ~(req->data[3]); wdt->init_count_down = (req->data[5]<<8 | req->data[4]); wdt->present_count_down = wdt->init_count_down; if (!(req->data[0] & 0x40)) // 'do not stop timer' bit wdt->run = 0; wdt->valid = 1; pthread_mutex_unlock(&wdt->mutex); res->cc = CC_SUCCESS; *res_len = data - &res->data[0]; } // Get Watchdog Timer (IPMI/Section 27.7) static void app_get_watchdog_timer (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; unsigned char byte; struct watchdog_data *wdt = get_watchdog(req->payload_id); if (!wdt) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } pthread_mutex_lock(&wdt->mutex); byte = wdt->use; if (wdt->no_log) byte |= 0x80; if (wdt->run) byte |= 0x40; *data++ = byte; *data++ = (wdt->pre_action << 4 | wdt->action); *data++ = wdt->pre_interval; *data++ = wdt->expiration; *data++ = wdt->init_count_down & 0xFF; *data++ = (wdt->init_count_down >> 8) & 0xFF; *data++ = wdt->present_count_down & 0xFF; *data++ = (wdt->present_count_down >> 8) & 0xFF; pthread_mutex_unlock(&wdt->mutex); res->cc = CC_SUCCESS; *res_len = data - &res->data[0]; } // Set BMC Global Enables (IPMI/Section 22.1) static void app_set_global_enables (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; bmc_global_enable_setting[req->payload_id - 1] = req->data[0]; res->cc = CC_SUCCESS; // Do nothing *res_len = 0; } // Get BMC Global Enables (IPMI/Section 22.2) static void app_get_global_enables (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; res->cc = CC_SUCCESS; *data++ = bmc_global_enable_setting[req->payload_id - 1]; // Global Enable *res_len = data - &res->data[0]; } // Clear Message flags Command (IPMI/Section 22.3) static void app_clear_message_flags (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; res->cc = CC_SUCCESS; // Do nothing *res_len = data - &res->data[0]; } // Set System Info Params (IPMI/Section 22.14a) static void app_set_sys_info_params (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char param = req->data[0]; res->cc = CC_SUCCESS; switch (param) { case SYS_INFO_PARAM_SET_IN_PROG: g_sys_info_params.set_in_prog = req->data[1]; break; case SYS_INFO_PARAM_SYSFW_VER: memcpy(g_sys_info_params.sysfw_ver, &req->data[1], SIZE_SYSFW_VER); pal_set_sysfw_ver(req->payload_id, g_sys_info_params.sysfw_ver); break; case SYS_INFO_PARAM_SYS_NAME: memcpy(g_sys_info_params.sys_name, &req->data[1], SIZE_SYS_NAME); break; case SYS_INFO_PARAM_PRI_OS_NAME: memcpy(g_sys_info_params.pri_os_name, &req->data[1], SIZE_OS_NAME); break; case SYS_INFO_PARAM_PRESENT_OS_NAME: memcpy(g_sys_info_params.present_os_name, &req->data[1], SIZE_OS_NAME); break; case SYS_INFO_PARAM_PRESENT_OS_VER: memcpy(g_sys_info_params.present_os_ver, &req->data[1], SIZE_OS_VER); break; case SYS_INFO_PARAM_BMC_URL: memcpy(g_sys_info_params.bmc_url, &req->data[1], SIZE_BMC_URL); break; case SYS_INFO_PARAM_OS_HV_URL: memcpy(g_sys_info_params.os_hv_url, &req->data[1], SIZE_OS_HV_URL); break; case SYS_INFO_PARAM_BIOS_CURRENT_BOOT_LIST: memcpy(g_sys_info_params.bios_current_boot_list, &req->data[1], req_len-4); // boot list length = req_len-4 (payload_id, cmd, netfn, param) pal_set_bios_current_boot_list(req->payload_id, g_sys_info_params.bios_current_boot_list, req_len-4, &res->cc); break; case SYS_INFO_PARAM_BIOS_FIXED_BOOT_DEVICE: if(length_check(SIZE_BIOS_FIXED_BOOT_DEVICE+1, req_len, response, res_len)) break; memcpy(g_sys_info_params.bios_fixed_boot_device, &req->data[1], SIZE_BIOS_FIXED_BOOT_DEVICE); pal_set_bios_fixed_boot_device(req->payload_id, g_sys_info_params.bios_fixed_boot_device); break; case SYS_INFO_PARAM_BIOS_RESTORES_DEFAULT_SETTING: if(length_check(SIZE_BIOS_RESTORES_DEFAULT_SETTING+1, req_len, response, res_len)) break; memcpy(g_sys_info_params.bios_restores_default_setting, &req->data[1], SIZE_BIOS_RESTORES_DEFAULT_SETTING); pal_set_bios_restores_default_setting(req->payload_id, g_sys_info_params.bios_restores_default_setting); break; case SYS_INFO_PARAM_LAST_BOOT_TIME: if(length_check(SIZE_LAST_BOOT_TIME+1, req_len, response, res_len)) break; memcpy(g_sys_info_params.last_boot_time, &req->data[1], SIZE_LAST_BOOT_TIME); pal_set_last_boot_time(req->payload_id, g_sys_info_params.last_boot_time); break; default: res->cc = CC_INVALID_PARAM; break; } return; } // Get System Info Params (IPMI/Section 22.14b) static void app_get_sys_info_params (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; unsigned char param = req->data[1]; // Fill default return values res->cc = CC_SUCCESS; *data++ = 1; // Parameter revision if(!length_check(4, req_len, response, res_len)) { switch (param) { case SYS_INFO_PARAM_SET_IN_PROG: *data++ = g_sys_info_params.set_in_prog; break; case SYS_INFO_PARAM_SYSFW_VER: pal_get_sysfw_ver(req->payload_id, g_sys_info_params.sysfw_ver); memcpy(data, g_sys_info_params.sysfw_ver, SIZE_SYSFW_VER); data += SIZE_SYSFW_VER; break; case SYS_INFO_PARAM_SYS_NAME: memcpy(data, g_sys_info_params.sys_name, SIZE_SYS_NAME); data += SIZE_SYS_NAME; break; case SYS_INFO_PARAM_PRI_OS_NAME: memcpy(data, g_sys_info_params.pri_os_name, SIZE_OS_NAME); data += SIZE_OS_NAME; break; case SYS_INFO_PARAM_PRESENT_OS_NAME: memcpy(data, g_sys_info_params.present_os_name, SIZE_OS_NAME); data += SIZE_OS_NAME; break; case SYS_INFO_PARAM_PRESENT_OS_VER: memcpy(data, g_sys_info_params.present_os_ver, SIZE_OS_VER); data += SIZE_OS_VER; break; case SYS_INFO_PARAM_BMC_URL: memcpy(data, g_sys_info_params.bmc_url, SIZE_BMC_URL); data += SIZE_BMC_URL; break; case SYS_INFO_PARAM_OS_HV_URL: memcpy(data, g_sys_info_params.os_hv_url, SIZE_OS_HV_URL); data += SIZE_OS_HV_URL; break; case SYS_INFO_PARAM_BIOS_CURRENT_BOOT_LIST: if(pal_get_bios_current_boot_list(req->payload_id, g_sys_info_params.bios_current_boot_list, res_len)) { res->cc = CC_UNSPECIFIED_ERROR; break; } memcpy(data, g_sys_info_params.bios_current_boot_list, *res_len); data += *res_len; break; case SYS_INFO_PARAM_BIOS_FIXED_BOOT_DEVICE: if(pal_get_bios_fixed_boot_device(req->payload_id, g_sys_info_params.bios_fixed_boot_device)) { res->cc = CC_UNSPECIFIED_ERROR; break; } memcpy(data, g_sys_info_params.bios_fixed_boot_device, SIZE_BIOS_FIXED_BOOT_DEVICE); data += SIZE_BIOS_FIXED_BOOT_DEVICE; break; case SYS_INFO_PARAM_BIOS_RESTORES_DEFAULT_SETTING: if(pal_get_bios_restores_default_setting(req->payload_id, g_sys_info_params.bios_restores_default_setting)) { res->cc = CC_UNSPECIFIED_ERROR; break; } memcpy(data, g_sys_info_params.bios_restores_default_setting, SIZE_BIOS_RESTORES_DEFAULT_SETTING); data += SIZE_BIOS_RESTORES_DEFAULT_SETTING; break; case SYS_INFO_PARAM_LAST_BOOT_TIME: if(pal_get_last_boot_time(req->payload_id, g_sys_info_params.last_boot_time)) { res->cc = CC_UNSPECIFIED_ERROR; break; } memcpy(data, g_sys_info_params.last_boot_time, SIZE_LAST_BOOT_TIME); data += SIZE_LAST_BOOT_TIME; break; default: res->cc = CC_INVALID_PARAM; break; } } if (res->cc == CC_SUCCESS) { *res_len = data - &res->data[0]; } return; } static void app_master_write_read (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t *ptr = req->data; uint8_t writeCnt, readCnt; uint8_t buf[42]; uint8_t bus_num, ret; int fd; char fn[32]; if( req_len < 6 ){ res->cc = CC_INVALID_LENGTH; return; } readCnt = req->data[2]; writeCnt = req_len - 6; if ( ptr[0] & 0x01 ) { if ( (readCnt > 35) || (writeCnt > 36) ) { res->cc = CC_INVALID_DATA_FIELD; return; } else { if ( pal_is_cmd_valid(req->data) ) { res->cc = CC_INVALID_DATA_FIELD; return; } memcpy(buf, &req->data[3], writeCnt); bus_num = ((req->data[0] & 0x7E) >> 1); //extend bit[7:1] for bus ID //ret = pal_i2c_write_read(bus_num, req->data[1], buf, writeCnt, res->data, readCnt); snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus_num); fd = open(fn, O_RDWR); if (fd < 0) { res->cc = CC_UNSPECIFIED_ERROR; return; } ret = i2c_rdwr_msg_transfer(fd, req->data[1], buf, writeCnt, res->data, readCnt); if(!ret) { *res_len = readCnt; res->cc = CC_SUCCESS; } else { syslog(LOG_WARNING, "app_master_write_read: master read fail, bus %d, addr %x", bus_num, req->data[1]); res->cc = CC_UNSPECIFIED_ERROR; } close(fd); } } else { res->cc = CC_INVALID_DATA_FIELD; } } static void app_get_sys_intf_caps (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; res->cc = CC_SUCCESS; switch (req->data[0]) { case 0: // SSIF *data++ = 0x00; *data++ = 0x80; *data++ = 255; *data++ = 125; break; case 1: // KCS *data++ = 0x00; *data++ = 0x00; *data++ = 255; break; default: res->cc = CC_INVALID_DATA_FIELD; break; } *res_len = data - &res->data[0]; pal_get_sys_intf_caps(req->payload_id, req->data, res->data, res_len); } // Handle Appliction Commands (IPMI/Section 20) static void ipmi_handle_app (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_app); switch (cmd) { case CMD_APP_GET_DEVICE_ID: app_get_device_id (request, req_len, response, res_len); break; case CMD_APP_COLD_RESET: if(pal_is_fw_update_ongoing_system()) res->cc = CC_NODE_BUSY; else app_cold_reset (request, req_len, response, res_len); break; case CMD_APP_GET_SELFTEST_RESULTS: app_get_selftest_results (request, req_len, response, res_len); break; case CMD_APP_MANUFACTURING_TEST_ON: if(pal_is_fw_update_ongoing_system()) res->cc = CC_NODE_BUSY; else app_manufacturing_test_on (request, req_len, response, res_len); break; case CMD_APP_GET_DEVICE_GUID: app_get_device_guid (request, req_len, response, res_len); break; case CMD_APP_GET_SYSTEM_GUID: app_get_device_sys_guid (request, req_len, response, res_len); break; case CMD_APP_RESET_WDT: app_reset_watchdog_timer (request, req_len, response, res_len); break; case CMD_APP_SET_WDT: app_set_watchdog_timer (request, req_len, response, res_len); break; case CMD_APP_GET_WDT: app_get_watchdog_timer (request, req_len, response, res_len); break; case CMD_APP_SET_GLOBAL_ENABLES: app_set_global_enables (request, req_len, response, res_len); break; case CMD_APP_GET_GLOBAL_ENABLES: app_get_global_enables (request, req_len, response, res_len); break; case CMD_APP_SET_SYS_INFO_PARAMS: app_set_sys_info_params (request, req_len, response, res_len); break; case CMD_APP_CLEAR_MESSAGE_FLAGS: app_clear_message_flags (request, req_len, response, res_len); break; case CMD_APP_GET_SYS_INFO_PARAMS: app_get_sys_info_params (request, req_len, response, res_len); break; case CMD_APP_MASTER_WRITE_READ: app_master_write_read (request, req_len, response, res_len); break; case CMD_APP_GET_SYS_INTF_CAPS: app_get_sys_intf_caps (request, req_len, response, res_len); break; default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_app); } /* * Function(s) to handle IPMI messages with NetFn: Storage */ static void storage_get_fruid_info(unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int size = plat_fruid_size(req->payload_id); res->cc = CC_SUCCESS; *data++ = size & 0xFF; // FRUID size LSB *data++ = (size >> 8) & 0xFF; // FRUID size MSB *data++ = 0x00; // Device accessed by bytes *res_len = data - &res->data[0]; return; } static void storage_get_fruid_data(unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int fru_id = req->data[0]; int offset = req->data[1] + (req->data[2] << 8); int count = req->data[3]; int ret = plat_fruid_data(req->payload_id, fru_id, offset, count, &(res->data[1])); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; } else { res->cc = CC_SUCCESS; *data++ = count; data += count; } if (res->cc == CC_SUCCESS) { *(unsigned short*)res_len = data - &res->data[0]; } return; } static void storage_get_sdr_info (unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int num_entries; // number of sdr records int free_space; // free space in SDR device in bytes time_stamp_t ts_recent_add; // Recent Addition Timestamp time_stamp_t ts_recent_erase; // Recent Erasure Timestamp // Use platform APIs to get SDR information num_entries = sdr_num_entries (); free_space = sdr_free_space (); sdr_ts_recent_add (&ts_recent_add); sdr_ts_recent_erase (&ts_recent_erase); res->cc = CC_SUCCESS; *data++ = IPMI_SDR_VERSION; // SDR version *data++ = num_entries & 0xFF; // number of sdr entries *data++ = (num_entries >> 8) & 0xFF; *data++ = free_space & 0xFF; // Free SDR Space *data++ = (free_space >> 8) & 0xFF; memcpy(data, ts_recent_add.ts, SIZE_TIME_STAMP); data += SIZE_TIME_STAMP; memcpy(data, ts_recent_erase.ts, SIZE_TIME_STAMP); data += SIZE_TIME_STAMP; *data++ = 0x02; // Operations supported *res_len = data - &res->data[0]; return; } static void storage_rsv_sdr (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int rsv_id; // SDR reservation ID // Use platform APIs to get a SDR reservation ID rsv_id = sdr_rsv_id(req->payload_id); if (rsv_id < 0) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; *data++ = rsv_id & 0xFF; // Reservation ID *data++ = (rsv_id >> 8) & 0XFF; *res_len = data - &res->data[0]; return; } static void storage_get_sdr (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int read_rec_id; //record ID to be read int next_rec_id; //record ID for the next entry int rsv_id; // Reservation ID for the request int rec_offset; // Read offset into the record int rec_bytes; // Number of bytes to be read sdr_rec_t entry; // SDR record entry int ret; rsv_id = (req->data[1] << 8) | req->data[0]; read_rec_id = (req->data[3] << 8) | req->data[2]; rec_offset = req->data[4]; rec_bytes = req->data[5]; // Use platform API to read the record Id and get next ID ret = sdr_get_entry (req->payload_id, rsv_id, read_rec_id, &entry, &next_rec_id); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; *data++ = next_rec_id & 0xFF; // next record ID *data++ = (next_rec_id >> 8) & 0xFF; memcpy (data, &entry.rec[rec_offset], rec_bytes); data += rec_bytes; *res_len = data - &res->data[0]; return; } static void storage_get_sel_info (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int num_entries; // number of log entries int free_space; // free space in SEL device in bytes time_stamp_t ts_recent_add; // Recent Addition Timestamp time_stamp_t ts_recent_erase; // Recent Erasure Timestamp // Use platform APIs to get SEL information num_entries = sel_num_entries (req->payload_id); free_space = sel_free_space (req->payload_id); sel_ts_recent_add (req->payload_id, &ts_recent_add); sel_ts_recent_erase (req->payload_id, &ts_recent_erase); res->cc = CC_SUCCESS; *data++ = IPMI_SEL_VERSION; // SEL version *data++ = num_entries & 0xFF; // number of log entries *data++ = (num_entries >> 8) & 0xFF; *data++ = free_space & 0xFF; // Free SEL Space *data++ = (free_space >> 8) & 0xFF; memcpy(data, ts_recent_add.ts, SIZE_TIME_STAMP); data += SIZE_TIME_STAMP; memcpy(data, ts_recent_erase.ts, SIZE_TIME_STAMP); data += SIZE_TIME_STAMP; *data++ = 0x02; // Operations supported *res_len = data - &res->data[0]; return; } static void storage_rsv_sel (unsigned char * request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int rsv_id; // SEL reservation ID // Use platform APIs to get a SEL reservation ID rsv_id = sel_rsv_id (req->payload_id); if (rsv_id < 0) { res->cc = CC_SEL_ERASE_PROG; return; } res->cc = CC_SUCCESS; *data++ = rsv_id & 0xFF; // Reservation ID *data++ = (rsv_id >> 8) & 0XFF; *res_len = data - &res->data[0]; return; } static void storage_get_sel (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int read_rec_id; //record ID to be read int next_rec_id; //record ID for the next msg sel_msg_t entry; // SEL log entry int ret; unsigned char offset = req->data[4]; unsigned char len = req->data[5]; if (len == 0xFF) { // FFh means read entire record offset = 0; len = SIZE_SEL_REC; } else if ((offset >= SIZE_SEL_REC) || (len > SIZE_SEL_REC) || ((offset+len) > SIZE_SEL_REC)) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } read_rec_id = (req->data[3] << 8) | req->data[2]; // Use platform API to read the record Id and get next ID ret = sel_get_entry (req->payload_id, read_rec_id, &entry, &next_rec_id); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; *data++ = next_rec_id & 0xFF; // next record ID *data++ = (next_rec_id >> 8) & 0xFF; memcpy(data, &entry.msg[offset], len); data += len; *res_len = data - &res->data[0]; return; } static void storage_add_sel (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; int record_id; // Record ID for added entry int ret; sel_msg_t entry; memcpy(entry.msg, req->data, SIZE_SEL_REC); // Use platform APIs to add the new SEL entry ret = sel_add_entry (req->payload_id, &entry, &record_id); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; *data++ = record_id & 0xFF; *data++ = (record_id >> 8) & 0xFF; *res_len = data - &res->data[0]; return; } static void storage_clr_sel (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; sel_erase_stat_t status = SEL_ERASE_DONE; int ret; int rsv_id; // Verify the request to contain 'CLR' characters if ((req->data[2] != 'C') || (req->data[3] != 'L') || (req->data[4] != 'R')) { res->cc = CC_INVALID_PARAM; return; } // Populate reservation ID given in request rsv_id = (req->data[1] << 8) | req->data[0]; // Use platform APIs to clear or get status if (req->data[5] == IPMI_SEL_INIT_ERASE) { ret = sel_erase (req->payload_id, rsv_id); } else if (req->data[5] == IPMI_SEL_ERASE_STAT) { ret = sel_erase_status (req->payload_id, rsv_id, &status); } else { res->cc = CC_INVALID_PARAM; return; } // Handle platform error and return if (ret) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; *data++ = status; *res_len = data - &res->data[0]; return; } #if defined(CONFIG_FBTTN) || defined(CONFIG_FBTP) static void storage_get_sel_time (unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; res->cc = CC_SUCCESS; time_stamp_fill(res->data); *res_len = SIZE_TIME_STAMP; return; } #endif #if defined(CONFIG_FBY2_ND) static void storage_set_sel_time (unsigned char *request, unsigned char *response, unsigned char req_len) { ipmi_res_t *res = (ipmi_res_t *) response; ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; static uint8_t time_sync = 0; if (req_len != 7) { // payload_id netfn_lun cmd data[4]; res->cc = CC_INVALID_LENGTH; } if (!time_sync) { if (pal_set_time_sync(req->data,req_len-3)) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; time_sync = 1; } else { res->cc = CC_NOT_SUPP_IN_CURR_STATE; } return; } #endif static void storage_get_sel_utc (unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; res->cc = CC_SUCCESS; // TODO: For now, the SEL time stamp is based on UTC time, // so return 0x0000 as offset. Might need to change once // supporting zones in SEL time stamps *data++ = 0x00; *data++ = 0x00; *res_len = data - &res->data[0]; } static void ipmi_handle_storage (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; res->cc = CC_SUCCESS; *res_len = 0; pthread_mutex_lock(&m_storage); switch (cmd) { case CMD_STORAGE_GET_FRUID_INFO: storage_get_fruid_info (request, response, res_len); break; case CMD_STORAGE_READ_FRUID_DATA: storage_get_fruid_data (request, response, res_len); break; case CMD_STORAGE_GET_SEL_INFO: storage_get_sel_info (request, response, res_len); break; case CMD_STORAGE_RSV_SEL: storage_rsv_sel (request, response, res_len); break; case CMD_STORAGE_ADD_SEL: storage_add_sel (request, response, res_len); break; case CMD_STORAGE_GET_SEL: storage_get_sel (request, response, res_len); break; case CMD_STORAGE_CLR_SEL: storage_clr_sel (request, response, res_len); break; #if defined(CONFIG_FBTTN) || defined(CONFIG_FBTP) // To avoid BIOS using this command to update RTC // TBD: Respond only if BMC's time has synced with NTP case CMD_STORAGE_GET_SEL_TIME: storage_get_sel_time (response, res_len); break; #endif #if defined(CONFIG_FBY2_ND) case CMD_STORAGE_SET_SEL_TIME: storage_set_sel_time (request, response, req_len); break; #endif case CMD_STORAGE_GET_SEL_UTC: storage_get_sel_utc (response, res_len); break; case CMD_STORAGE_GET_SDR_INFO: storage_get_sdr_info (response, res_len); break; case CMD_STORAGE_RSV_SDR: storage_rsv_sdr (request, response, res_len); break; case CMD_STORAGE_GET_SDR: storage_get_sdr (request, response, res_len); break; default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_storage); return; } /* * Function(s) to handle IPMI messages with NetFn: Transport */ // Set LAN Configuration (IPMI/Section 23.1) static void transport_set_lan_config (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char param = req->data[1]; // Fill the response with default values res->cc = CC_SUCCESS; switch (param) { case LAN_PARAM_SET_IN_PROG: g_lan_config.set_in_prog = req->data[2]; break; case LAN_PARAM_AUTH_SUPPORT: g_lan_config.auth_support = req->data[2]; break; case LAN_PARAM_AUTH_ENABLES: memcpy(g_lan_config.auth_enables, &req->data[2], SIZE_AUTH_ENABLES); break; case LAN_PARAM_IP_ADDR: memcpy(g_lan_config.ip_addr, &req->data[2], SIZE_IP_ADDR); break; case LAN_PARAM_IP_SRC: g_lan_config.ip_src = req->data[2]; break; case LAN_PARAM_MAC_ADDR: memcpy(g_lan_config.mac_addr, &req->data[2], SIZE_MAC_ADDR); break; case LAN_PARAM_NET_MASK: memcpy(g_lan_config.net_mask, &req->data[2], SIZE_NET_MASK); break; case LAN_PARAM_IP_HDR: memcpy(g_lan_config.ip_hdr, &req->data[2], SIZE_IP_HDR); break; case LAN_PARAM_PRI_RMCP_PORT: g_lan_config.pri_rmcp_port[0] = req->data[2]; g_lan_config.pri_rmcp_port[1] = req->data[3]; break; case LAN_PARAM_SEC_RMCP_PORT: g_lan_config.sec_rmcp_port[0] = req->data[2]; g_lan_config.sec_rmcp_port[1] = req->data[3]; break; case LAN_PARAM_ARP_CTRL: g_lan_config.arp_ctrl = req->data[2]; break; case LAN_PARAM_GARP_INTERVAL: g_lan_config.garp_interval = req->data[2]; break; case LAN_PARAM_DF_GW_IP_ADDR: memcpy(g_lan_config.df_gw_ip_addr, &req->data[2], SIZE_IP_ADDR); break; case LAN_PARAM_DF_GW_MAC_ADDR: memcpy(g_lan_config.df_gw_mac_addr, &req->data[2], SIZE_MAC_ADDR); break; case LAN_PARAM_BACK_GW_IP_ADDR: memcpy(g_lan_config.back_gw_ip_addr, &req->data[2], SIZE_IP_ADDR); break; case LAN_PARAM_BACK_GW_MAC_ADDR: memcpy(g_lan_config.back_gw_mac_addr, &req->data[2], SIZE_MAC_ADDR); break; case LAN_PARAM_COMMUNITY_STR: memcpy(g_lan_config.community_str, &req->data[2], SIZE_COMMUNITY_STR); break; case LAN_PARAM_NO_OF_DEST: g_lan_config.no_of_dest = req->data[2]; break; case LAN_PARAM_DEST_TYPE: memcpy(g_lan_config.dest_type, &req->data[2], SIZE_DEST_TYPE); break; case LAN_PARAM_DEST_ADDR: memcpy(g_lan_config.dest_addr, &req->data[2], SIZE_DEST_ADDR); break; case LAN_PARAM_IP6_ADDR: memcpy(g_lan_config.ip6_addr, &req->data[2], SIZE_IP6_ADDR); break; default: res->cc = CC_INVALID_PARAM; break; } } // Get LAN Configuration (IPMI/Section 23.2) static void transport_get_lan_config (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; unsigned char param = req->data[1]; // Fill the response with default values res->cc = CC_SUCCESS; *data++ = 0x11; // Parameter revision switch (param) { case LAN_PARAM_SET_IN_PROG: *data++ = g_lan_config.set_in_prog; break; case LAN_PARAM_AUTH_SUPPORT: *data++ = g_lan_config.auth_support; break; case LAN_PARAM_AUTH_ENABLES: memcpy(data, g_lan_config.auth_enables, SIZE_AUTH_ENABLES); data += SIZE_AUTH_ENABLES; break; case LAN_PARAM_IP_ADDR: plat_lan_init(&g_lan_config); memcpy(data, g_lan_config.ip_addr, SIZE_IP_ADDR); data += SIZE_IP_ADDR; break; case LAN_PARAM_IP_SRC: *data++ = g_lan_config.ip_src; break; case LAN_PARAM_MAC_ADDR: plat_lan_init(&g_lan_config); memcpy(data, g_lan_config.mac_addr, SIZE_MAC_ADDR); data += SIZE_MAC_ADDR; break; case LAN_PARAM_NET_MASK: memcpy(data, g_lan_config.net_mask, SIZE_NET_MASK); data += SIZE_NET_MASK; break; case LAN_PARAM_IP_HDR: memcpy(data, g_lan_config.ip_hdr, SIZE_IP_HDR); data += SIZE_IP_HDR; break; case LAN_PARAM_PRI_RMCP_PORT: *data++ = g_lan_config.pri_rmcp_port[0]; *data++ = g_lan_config.pri_rmcp_port[1]; break; case LAN_PARAM_SEC_RMCP_PORT: *data++ = g_lan_config.sec_rmcp_port[0]; *data++ = g_lan_config.sec_rmcp_port[1]; break; case LAN_PARAM_ARP_CTRL: *data++ = g_lan_config.arp_ctrl; break; case LAN_PARAM_GARP_INTERVAL: *data++ = g_lan_config.garp_interval; break; case LAN_PARAM_DF_GW_IP_ADDR: memcpy(data, g_lan_config.df_gw_ip_addr, SIZE_IP_ADDR); data += SIZE_IP_ADDR; break; case LAN_PARAM_DF_GW_MAC_ADDR: memcpy(data, g_lan_config.df_gw_mac_addr, SIZE_MAC_ADDR); data += SIZE_MAC_ADDR; break; case LAN_PARAM_BACK_GW_IP_ADDR: memcpy(data, g_lan_config.back_gw_ip_addr, SIZE_IP_ADDR); data += SIZE_IP_ADDR; break; case LAN_PARAM_BACK_GW_MAC_ADDR: memcpy(data, g_lan_config.back_gw_mac_addr, SIZE_MAC_ADDR); data += SIZE_MAC_ADDR; break; case LAN_PARAM_COMMUNITY_STR: memcpy(data, g_lan_config.community_str, SIZE_COMMUNITY_STR); data += SIZE_COMMUNITY_STR; break; case LAN_PARAM_NO_OF_DEST: *data++ = g_lan_config.no_of_dest; break; case LAN_PARAM_DEST_TYPE: memcpy(data, g_lan_config.dest_type, SIZE_DEST_TYPE); data += SIZE_DEST_TYPE; break; case LAN_PARAM_DEST_ADDR: memcpy(data, g_lan_config.dest_addr, SIZE_DEST_ADDR); data += SIZE_DEST_ADDR; break; case LAN_PARAM_IP6_ADDR: plat_lan_init(&g_lan_config); memcpy(data, g_lan_config.ip6_addr, SIZE_IP6_ADDR); data += SIZE_IP6_ADDR; break; case LAN_PARAM_IP6_DYNAMIC_ADDR: plat_lan_init(&g_lan_config); data[0] = 0; // Selector data[1] = 0x02; // DHCPv6 memcpy(&data[2], g_lan_config.ip6_addr, SIZE_IP6_ADDR); data[18] = g_lan_config.ip6_prefix; data[19] = 0x00; // Active data += SIZE_IP6_ADDR + 4; break; case LAN_PARAM_ADDR_ENABLES: data[0] = 0x02; // Enable both IPv4 and IPv6 data ++; break; default: res->cc = CC_INVALID_PARAM; break; } if (res->cc == CC_SUCCESS) { *res_len = data - &res->data[0]; } } // Get SoL Configuration (IPMI/Section 26.3) static void transport_get_sol_config (unsigned char *request, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char *data = &res->data[0]; unsigned char param = req->data[1]; // Fill the response with default values res->cc = CC_SUCCESS; *data++ = 0x01; // Parameter revision switch (param) { case SOL_PARAM_SET_IN_PROG: *data++ = 0x00; break; case SOL_PARAM_SOL_ENABLE: *data++ = 0x01; break; case SOL_PARAM_SOL_AUTH: *data++ = 0x02; break; case SOL_PARAM_SOL_THRESHOLD: *data++ = 0x00; *data++ = 0x01; break; case SOL_PARAM_SOL_RETRY: *data++ = 0x00; *data++ = 0x00; break; case SOL_PARAM_SOL_BITRATE: case SOL_PARAM_SOL_NV_BITRATE: *data++ = 0x09; break; default: res->cc = CC_INVALID_PARAM; break; } if (res->cc == CC_SUCCESS) { *res_len = data - &res->data[0]; } } // Handle Transport Commands (IPMI/Section 23) static void ipmi_handle_transport (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_transport); switch (cmd) { case CMD_TRANSPORT_SET_LAN_CONFIG: transport_set_lan_config (request, response, res_len); break; case CMD_TRANSPORT_GET_LAN_CONFIG: transport_get_lan_config (request, response, res_len); break; case CMD_TRANSPORT_GET_SOL_CONFIG: transport_get_sol_config (request, response, res_len); break; default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_transport); } /* * Function(s) to handle IPMI messages with NetFn: DCMI */ static void ipmi_handle_dcmi(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { int ret; ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; // If there is no command to process return if (req->cmd == 0x0) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } // Since DCMI handling is specific to platform, call PAL to process ret = pal_handle_dcmi(req->payload_id, &request[1], req_len-1, res->data, res_len); if (ret < 0) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; } /* * Function(s) to handle IPMI messages with NetFn: OEM */ static void oem_add_ras_sel (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; *res_len = 0; ras_sel_msg_t entry; memcpy(entry.msg, req->data, SIZE_RAS_SEL); res->cc = ras_sel_add_entry (req->payload_id, &entry); return; } static void oem_add_imc_log (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; *res_len = 0; res->cc = pal_add_imc_log (req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_q_sled_cycle_prepare_request (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[32] = "blk_fwupd"; char value[8] = {0}; if (pal_is_fw_update_ongoing_system()) { res->cc = CC_NODE_BUSY; return; } if ( req->data[0] > 1 ) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } if ( req_len != 4 ) { res->cc = CC_INVALID_LENGTH; return; } sprintf(value, "%02x", req->data[0]); if( kv_set(key, value, 0, 0) ) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = 0; } static void oem_q_sled_cycle_prepare_status (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; char key[32] = "blk_fwupd"; char value[8] = {0}; if ( req_len != 3 ) { res->cc = CC_INVALID_LENGTH; return; } if ( kv_get(key, value, 0, 0) != 0 ) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } res->data[0] = (uint8_t)atoi(value); *res_len = 1; res->cc = CC_SUCCESS; } static void oem_set_proc_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[MAX_KEY_LEN]; char value[MAX_VALUE_LEN]; unsigned int index = req->data[0]; *res_len = 0; res->cc = CC_UNSPECIFIED_ERROR; sprintf(key, "sys_config/fru%u_cpu%u_basic_info", req->payload_id, index); value[0] = 1; // Num cores (Unknown?) value[1] = 1; // Thread count (Unknown?) value[2] = 0; value[3] = req->data[2]; // Frequency value[4] = req->data[3]; value[5] = req->data[1]; // Type stored as revision. value[6] = 0; if(kv_set(key, value, 7, KV_FPERSIST) != 0) { return; } res->cc = CC_SUCCESS; } static void oem_get_proc_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[MAX_KEY_LEN]; char value[MAX_VALUE_LEN]; unsigned int index = req->data[0]; size_t ret; *res_len = 0; res->cc = CC_UNSPECIFIED_ERROR; sprintf(key, "sys_config/fru%u_cpu%u_basic_info", req->payload_id, index); if(kv_get(key, value, &ret, KV_FPERSIST) != 0 || ret < 7) { return; } res->data[0] = value[5]; // Return Processor revision as Type res->data[1] = value[3]; // Processor Frequency res->data[2] = value[4]; res->data[3] = 0x1; // Processor Present (0x1, 0xff Not present) *res_len = 4; res->cc = CC_SUCCESS; } static void oem_set_dimm_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[MAX_KEY_LEN] = {0}; char value[MAX_VALUE_LEN] = {0}; unsigned char index = req->data[0]; *res_len = 0; res->cc = CC_UNSPECIFIED_ERROR; sprintf(key, "sys_config/fru%d_dimm%d_type", req->payload_id, index); if(kv_set(key, (char *)&req->data[1], 1, KV_FPERSIST)) { return; } sprintf(key, "sys_config/fru%d_dimm%d_speed", req->payload_id, index); memcpy(value, &req->data[2], 2); memcpy(value + 2, &req->data[4], 4); if(kv_set(key, (char *)value, 6, KV_FPERSIST)) { return; } res->cc = CC_SUCCESS; } static void oem_get_dimm_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[MAX_KEY_LEN] = {0}; char value[MAX_VALUE_LEN] = {0}; unsigned char index = req->data[0]; size_t ret; *res_len = 0; res->cc = CC_UNSPECIFIED_ERROR; sprintf(key, "sys_config/fru%d_dimm%d_type", req->payload_id, index); if(kv_get(key, value, &ret, KV_FPERSIST) != 0 || ret < 1) { return; } memcpy(&res->data[0], value, 1); // Type sprintf(key, "sys_config/fru%d_dimm%d_speed", req->payload_id, index); if(kv_get(key, value, &ret, KV_FPERSIST) != 0 || ret < 6) { return; } memcpy(&res->data[1], value, 2); // speed memcpy(&res->data[3], value + 2, 4); // size res->data[7] = 0x2; // 0x2 DIMM Present, 0x3 DIMM not Present *res_len = 8; res->cc = CC_SUCCESS; } /* * Function(s) to handle IPMI messages with NetFn: OEM 0x36 */ static void oem_q_set_proc_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; char payload[100] = {0}; int numOfParam = sizeof(cpu_info_key)/sizeof(char *); if (req_len < 8 || req_len >= sizeof(payload) || (req->data[4] >= numOfParam) || (strlen(cpu_info_key[ (int) req->data[4]]) == 0)) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } sprintf(key, "sys_config/fru%d_cpu%d_%s", req->payload_id, req->data[3], cpu_info_key[req->data[4]]); memcpy(payload, &req->data[5], req_len -8); if(kv_set(key, payload, req_len - 8, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = 0; } static void oem_q_get_proc_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; size_t ret = 0; int numOfParam = sizeof(cpu_info_key)/sizeof(char *); if ((req->data[4] >= numOfParam) || (strlen(cpu_info_key[ (int) req->data[4]]) <= 0) ) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } sprintf(key, "sys_config/fru%d_cpu%d_%s", req->payload_id, req->data[3], cpu_info_key[req->data[4]]); if (kv_get(key, (char *)res->data, &ret, KV_FPERSIST) < 0) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = (unsigned char)ret; } static void oem_q_set_dimm_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; char payload[100] = {0}; int numOfParam = sizeof(dimm_info_key)/sizeof(char *); if (req_len < 8 || req_len >= sizeof(payload) || (req->data[4] >= numOfParam) || (strlen(dimm_info_key[ (int) req->data[4]]) == 0)) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } sprintf(key, "sys_config/fru%d_dimm%d_%s", req->payload_id, req->data[3], dimm_info_key[req->data[4]]); memcpy(payload, &req->data[5], req_len -8); if(kv_set(key, payload, req_len - 8, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = 0; } static void oem_q_get_dimm_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; size_t ret = 0; int numOfParam = sizeof(dimm_info_key)/sizeof(char *); if ((req->data[4] >= numOfParam) || (strlen(dimm_info_key[ (int) req->data[4]]) <= 0) ) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } sprintf(key, "sys_config/fru%d_dimm%d_%s", req->payload_id, req->data[3], dimm_info_key[req->data[4]]); if(kv_get(key, (char *)res->data, &ret, KV_FPERSIST) < 0) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = (unsigned char)ret; } static void oem_q_set_drive_info(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}, cltrType; char payload[100] = {0}; int numOfParam = sizeof(drive_info_key)/sizeof(char *); if (req_len < 9 || req_len >= sizeof(payload) || (req->data[5] >= numOfParam) || (strlen(drive_info_key[ (int) req->data[5]]) == 0)) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } if( (req->data[3] & 0x0f) ==0x00) cltrType = 'B'; // BIOS else if ((req->data[3] & 0x0f) ==0x01) cltrType = 'E'; // Expander else if ((req->data[3] & 0x0f) ==0x02) cltrType = 'L'; // LSI else { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } sprintf(key, "sys_config/fru%d_%c_drive%d_%s", req->payload_id, cltrType, req->data[4], drive_info_key[req->data[5]]); memcpy(payload, &req->data[6], req_len - 9); if(kv_set(key, payload, req_len - 9, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = 0; } static void oem_q_get_drive_info(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}, cltrType; size_t ret = 0; int numOfParam = sizeof(drive_info_key)/sizeof(char *); if ((req->data[5] >= numOfParam) || (strlen(drive_info_key[ (int) req->data[5]]) <= 0) ) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } if( (req->data[3] & 0x0f) ==0x00) cltrType = 'B'; // BIOS else if ((req->data[3] & 0x0f) ==0x01) cltrType = 'E'; // Expander else if ((req->data[3] & 0x0f) ==0x02) cltrType = 'L'; // LSI else { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } sprintf(key, "sys_config/fru%d_%c_drive%d_%s", req->payload_id, cltrType, req->data[4], drive_info_key[req->data[5]]); if(kv_get(key, (char *)res->data, &ret, KV_FPERSIST) < 0) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = (unsigned char)ret; } static void oem_q_set_smu_psp_ver(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; char payload[100] = {0}; if (req_len < 8) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } if( (req->data[4] & 0x0f) == 0x01) sprintf(key, "sys_config/fru%d_psp_ver", req->payload_id); else if ((req->data[4] & 0x0f) == 0x02) sprintf(key, "sys_config/fru%d_smu_ver", req->payload_id); memcpy(payload, &req->data[5], req_len - 8); if(kv_set(key, payload, req_len - 8, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = 0; } static void oem_q_get_smu_psp_ver(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; size_t ret = 0; if (req_len < 5) { res->cc = CC_PARAM_OUT_OF_RANGE; *res_len = 0; return; } if( (req->data[4] & 0x0f) == 0x01) sprintf(key, "sys_config/fru%d_psp_ver", req->payload_id); else if ((req->data[4] & 0x0f) == 0x02) sprintf(key, "sys_config/fru%d_smu_ver", req->payload_id); if(kv_get(key, (char *)res->data, &ret, KV_FPERSIST) < 0) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = (unsigned char)ret; } static void oem_set_boot_order(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; int slot_id = req->payload_id; static pthread_t bios_timer_tid[MAX_NODES]; if ( IsTimerStart[req->payload_id - 1] ) { #ifdef DEBUG syslog(LOG_WARNING, "[%s] Close the previous thread\n", __func__); #endif pthread_cancel(bios_timer_tid[req->payload_id - 1]); IsTimerStart[req->payload_id - 1] = false; } if (req->data[0] & (BIOS_BOOT_VALID_FLAG | CMOS_VALID_FLAG | FORCE_BOOT_BIOS_SETUP_VALID_FLAG)) { /*Create timer thread*/ ret = pthread_create(&bios_timer_tid[req->payload_id - 1], NULL, clear_bios_data_timer, (void *)slot_id); if (ret < 0) { syslog(LOG_WARNING, "[%s] Create BIOS timer thread failed!\n", __func__); res->cc = CC_NODE_BUSY; *res_len = 0; return; } IsTimerStart[req->payload_id - 1] = true; } ret = pal_set_boot_order(req->payload_id, req->data, res->data, res_len); if(ret == 0) { res->cc = CC_SUCCESS; } else { res->cc = CC_INVALID_PARAM; } } static void oem_get_boot_order(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; ret = pal_get_boot_order(req->payload_id, req->data, res->data, res_len); #ifdef DEBUG syslog(LOG_WARNING, "[%s] Get: %x %x %x %x %x %x\n", __func__, res->data[0], res->data[1], res->data[2], res->data[3], res->data[4], res->data[5]); #endif if(ret == 0) { res->cc = CC_SUCCESS; } else { res->cc = CC_INVALID_PARAM; } } static void oem_set_tpm_presence(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; int slot_id = req->payload_id; int presence = req->data[0]; if (presence == 0) { ret = pal_set_tpm_physical_presence(slot_id,presence); if (ret == 0) { res->cc = CC_SUCCESS; } else { res->cc = CC_NOT_SUPP_IN_CURR_STATE; } } else { // do not set tpm physical presence flag to 1 res->cc = CC_UNSPECIFIED_ERROR; } } static void oem_get_tpm_presence(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int value; value = pal_get_tpm_physical_presence(req->payload_id); syslog(LOG_WARNING, "[%s] Get: %x\n", __func__, value); if ((value != 0) && (value != 1)) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } // BMC auto-clear after BIOS retrieve it // if (value == 1) { // int ret = pal_set_tpm_physical_presence(req->payload_id,0); // if (ret != 0) { // res->cc = CC_UNSPECIFIED_ERROR; // *res_len = 0; // return; // } // } res->cc = CC_SUCCESS; res->data[0] = value; *res_len = 1; } static void oem_set_ppr (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t selector = req->data[0]; uint8_t ppr_enable, ppr_type, ppr_action = 0; int size = 0, offset; char temp[20]= {0}; char filepath[128]= {0}; bool append_mode = true; FILE *fp = NULL; if (access("/mnt/data/ppr/", F_OK) == -1) mkdir("/mnt/data/ppr/", 0777); *res_len = 0; res->cc = CC_SUCCESS; switch(selector) { case PPR_ACTION: ppr_enable = req->data[1] & 0x80; ppr_type = req->data[1] & 0x7f; if (ppr_enable) { if (ppr_type != PPR_SOFT && ppr_type != PPR_HARD && ppr_type != PPR_TEST_MODE) { res->cc = CC_INVALID_DATA_FIELD; return; } ppr_action = req->data[1]; } sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_row_count", req->payload_id); fp = fopen(filepath, "r"); if (!fp) { res->cc = CC_NOT_SUPP_IN_CURR_STATE; return; } if (fread(res->data, 1, 1, fp) != 1) { fclose(fp); res->cc = CC_NOT_SUPP_IN_CURR_STATE; return; } if(res->data[0] == 0) { fclose(fp); res->cc = CC_NOT_SUPP_IN_CURR_STATE; return; } fclose(fp); sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_action", req->payload_id); fp = fopen(filepath, "w"); if (fp != NULL) { fwrite(&ppr_action, sizeof(uint8_t), 1, fp); } break; case PPR_ROW_COUNT: if (req->data[1] > PPR_MAX_ROW_COUNT) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } else { sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_row_count", req->payload_id); fp = fopen(filepath, "w"); if(fp != NULL) fwrite(&req->data[1], sizeof(uint8_t), 1, fp); } break; case PPR_ROW_ADDR: if (req->data[1] > PPR_MAX_ROW_COUNT) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } if (req_len != (PPR_ROW_ADDR_DATA_LEN + 4)) { res->cc = CC_INVALID_LENGTH; return; } sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_row_addr", req->payload_id); fp = fopen(filepath, "a+"); fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); append_mode = true; offset = 0; if(size != 0) { while (fread(temp, sizeof(uint8_t), PPR_ROW_ADDR_DATA_LEN, fp)) { offset = ftell(fp); if(temp[0] == req->data[1]) { append_mode = false; fclose(fp); fp = fopen(filepath, "w+"); offset = ftell(fp) - PPR_ROW_ADDR_DATA_LEN; if (offset < 0) offset = 0; break; } } } if (append_mode && size > PPR_MAX_ROW_COUNT * PPR_ROW_ADDR_DATA_LEN) { res->cc = CC_PARAM_OUT_OF_RANGE; fclose(fp); return; } fseek(fp, offset , SEEK_SET); fwrite(&req->data[1], sizeof(uint8_t), PPR_ROW_ADDR_DATA_LEN, fp); break; case PPR_HISTORY_DATA: if (req->data[1] > PPR_MAX_HISTORY_COUNT) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } if (req_len != (PPR_HISTORY_DATA_LEN + 4)) { res->cc = CC_INVALID_LENGTH; return; } sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_history_data", req->payload_id); fp = fopen(filepath, "a+"); fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); append_mode = true; offset = 0; if(size != 0) { while (fread(temp, sizeof(uint8_t), PPR_HISTORY_DATA_LEN, fp)) { offset = ftell(fp); if(temp[0] == req->data[1]) { append_mode = false; fclose(fp); fp = fopen(filepath, "w+"); offset = ftell(fp) - PPR_HISTORY_DATA_LEN; if (offset < 0) offset = 0; break; } } } if (append_mode && size > PPR_MAX_HISTORY_COUNT * PPR_HISTORY_DATA_LEN) { res->cc = CC_PARAM_OUT_OF_RANGE; fclose(fp); return; } fseek(fp, offset , SEEK_SET); fwrite(&req->data[1], sizeof(uint8_t), PPR_HISTORY_DATA_LEN, fp); break; default: res->cc = CC_INVALID_PARAM; break; } if (fp) { fclose(fp); } } static void oem_get_ppr (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t selector = req->data[0]; FILE *fp = NULL; char filepath[128]= {0}; char temp[20], kpath[20]; sprintf(kpath, "%s", "/mnt/data/ppr"); if (access(kpath, F_OK) == -1) mkdir(kpath, 0777); *res_len = 0; res->cc = CC_SUCCESS; switch(selector) { case PPR_ACTION: sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_row_count", req->payload_id); fp = fopen(filepath, "r"); if (!fp) { fp = fopen(filepath, "w"); sprintf(temp, "%c",0); fwrite(temp, sizeof(char), 1, fp); } else { if (fread(res->data, 1, 1, fp) != 1) { fclose(fp); res->cc = CC_UNSPECIFIED_ERROR; return; } } fclose(fp); sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_action", req->payload_id); fp = fopen(filepath, "r"); if (!fp) { fp = fopen(filepath, "w"); sprintf(temp, "%c",0); fwrite(temp, sizeof(char), 1, fp); fclose(fp); res->data[0] = 0; *res_len = 1; return; } if (res->data[0] != 0 ) { if (fread(res->data, 1, 1, fp) != 1) { fclose(fp); res->cc = CC_UNSPECIFIED_ERROR; return; } if((res->data[0] & 0x80) == 0 ) res->data[0] = 0; } *res_len = 1; break; case PPR_ROW_COUNT: sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_row_count", req->payload_id); fp = fopen(filepath, "r"); if (!fp) { fp = fopen(filepath, "w"); sprintf(temp, "%c",0); fwrite(temp, sizeof(char), 1, fp); res->data[0] = 0; } else { if (fread(res->data, 1, 1, fp) != 1) { fclose(fp); res->cc = CC_UNSPECIFIED_ERROR; return; } } *res_len = 1; break; case PPR_ROW_ADDR: if (req->data[1] > PPR_MAX_ROW_COUNT) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_row_addr", req->payload_id); fp = fopen(filepath, "r+"); if (!fp) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } while(fread(res->data, sizeof(uint8_t), PPR_ROW_ADDR_DATA_LEN, fp)) { if(res->data[0] == req->data[1]) { *res_len = PPR_ROW_ADDR_DATA_LEN; break; } } break; case PPR_HISTORY_DATA: if (req->data[1] > PPR_MAX_HISTORY_COUNT) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } sprintf(filepath, "/mnt/data/ppr/fru%d_ppr_history_data", req->payload_id); fp = fopen(filepath, "r+"); if (!fp) { res->cc = CC_PARAM_OUT_OF_RANGE; return; } while(fread(res->data, sizeof(uint8_t), PPR_HISTORY_DATA_LEN, fp)) { if(res->data[0] == req->data[1]) { *res_len = PPR_HISTORY_DATA_LEN; break; } } break; default: res->cc = CC_INVALID_PARAM; break; } if (fp) { fclose(fp); } } static void oem_set_post_start (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; pal_set_post_start(req->payload_id, req->data, res->data, res_len); res->cc = CC_SUCCESS; } static void oem_set_post_end (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; pal_update_ts_sled(); pal_set_post_end(req->payload_id, req->data, res->data, res_len); res->cc = CC_SUCCESS; } static void oem_set_ppin_info(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_set_ppin_info(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_set_adr_trigger(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; bool trigger = (bool)req->data[3]; // high/low = true/false int ret; ret = pal_set_adr_trigger(req->payload_id, trigger); if (!ret) { res->cc = CC_SUCCESS; } else if (ret == PAL_ENOTSUP) { // If not supported on this platform act like // the command is not implemented. res->cc = CC_INVALID_CMD; } else { res->cc = CC_UNSPECIFIED_ERROR; } *res_len = 0; } static void oem_get_plat_info(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; uint8_t pres = 0x00; uint8_t pinfo = 0x00; // Platform info: // Bit[7]: Not Present:0/Present:1 (from pal) // Bit[6]: Test Board:1, Non Test Board:0 (TODO from pal) // Bit[5-3] : SKU ID:000:Yosemite, 010:Triton // Bit[2:0] : Slot Index, 1 based ret = pal_is_fru_prsnt(req->payload_id, &pres); if (ret) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0x00; return; } // Populate the presence bit[7] if (pres) { pinfo = 0x80; } // Bit[6]: Test Board:1, Non Test Board:0 if (pal_is_test_board()) { pinfo |= 0x40; } // Get the SKU ID bit[5-3] ret = pal_get_plat_sku_id(); if (ret == -1){ res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0x00; return; }else{ pinfo |= (ret << 3); } // Populate the slot Index bit[2:0] ret = pal_get_slot_index(req->payload_id); pinfo |= (ret & 0x7); // Prepare response buffer res->cc = CC_SUCCESS; res->data[0] = pinfo; *res_len = 0x01; } static void oem_sled_ac_cycle(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; ret = pal_sled_ac_cycle(req->payload_id, req->data, (req_len - 3), res->data, res_len); if (ret == PAL_ENOTSUP) { res->cc = CC_INVALID_CMD; } else { res->cc = ret; } *res_len = 0; return; } static void oem_get_poss_pcie_config(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_get_poss_pcie_config(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_set_imc_version(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_set_imc_version(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_set_fw_update_state(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret = -1; *res_len = 0; if (req_len == 5) { // Implicit FRU_ID ret = pal_set_fw_update_ongoing(req->payload_id, (req->data[1]<<8 | req->data[0])); } else if (req_len == 6) { // Explicit FRU_ID ret = pal_set_fw_update_ongoing(req->data[0], (req->data[1]<<8 | req->data[2])); } else { res->cc = CC_INVALID_LENGTH; return; } res->cc = ret == 0 ? CC_SUCCESS : CC_UNSPECIFIED_ERROR; } static void oem_bypass_cmd(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_bypass_cmd(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_bypass_dev_card(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_bypass_dev_card(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_get_board_id(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_get_board_id(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_get_80port_record ( unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; // XXX ipmi_handle() defines res_len as a size_t. // The correct change (but a much bigger one) is to replace // all `unsigned char *res_len` with `size_t *res_len`. ret = pal_get_80port_record (req->payload_id, res->data, 256, (size_t *)res_len); switch(ret) { case PAL_EOK: res->cc = CC_SUCCESS; break; case PAL_ENOTSUP: res->cc = CC_INVALID_PARAM; break; case PAL_ENOTREADY: res->cc = CC_NOT_SUPP_IN_CURR_STATE; break; default: res->cc = CC_UNSPECIFIED_ERROR; break; } } static void oem_get_fw_info ( unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; if (req_len != 4) { res->cc = CC_INVALID_LENGTH; *res_len = 0; return; } ret = pal_get_fw_info(req->payload_id, req->data[0], res->data, res_len); if (ret != 0) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0x00; return; } // Prepare response buffer res->cc = CC_SUCCESS; } static void oem_set_machine_config_info ( unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; pal_set_machine_configuration(req->payload_id, req->data, req_len-3, response, res_len); res->cc = CC_SUCCESS; *res_len = 0; } static void oem_set_flash_info ( unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[MAX_KEY_LEN]; char value[MAX_VALUE_LEN]; char fruname[32]; uint8_t mfg_id = 0; uint16_t dev_id = 0; uint16_t sts = 0; *res_len = 0x0; memcpy(&mfg_id, &req->data[3], 1); memcpy(&dev_id, &req->data[4], 2); memcpy(&sts, &req->data[6], 2); if (pal_get_fru_name(req->payload_id, fruname)) { res->cc = CC_UNSPECIFIED_ERROR; return; } sprintf(key, "%s_bios_flashinfo", fruname); sprintf(value, "%u %u %u", mfg_id, dev_id, sts); if (kv_set(key, value, 0, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; return; } res->cc = CC_SUCCESS; } static void oem_get_flash_info ( unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[MAX_KEY_LEN]; char value[MAX_VALUE_LEN]; char fruname[32]; unsigned int mfg_id = 0; unsigned int dev_id = 0; unsigned int sts = 0; *res_len = 0; if (pal_get_fru_name(req->payload_id, fruname)) { res->cc = CC_UNSPECIFIED_ERROR; return; } sprintf(key, "%s_bios_flashinfo", fruname); if (kv_get(key, value, NULL, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; return; } if (sscanf(value, "%u %u %u", &mfg_id, &dev_id, &sts) != 3) { res->cc = CC_UNSPECIFIED_ERROR; return; } // Prepare response buffer memcpy(&res->data[0], &mfg_id, 1); (*res_len)++; memcpy(&res->data[1], &dev_id, 2); (*res_len) += 2; memcpy(&res->data[3], &sts, 2); (*res_len) += 2; res->cc = CC_SUCCESS; } static void oem_get_pcie_port_config(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; ret = pal_get_pcie_port_config(req->payload_id, req->data, req_len, res->data, res_len); #ifdef DEBUG syslog(LOG_WARNING, "[%s] Get: %x %x\n", __func__, res->data[0], res->data[1]); #endif if(ret == 0) { res->cc = CC_SUCCESS; } else { res->cc = CC_UNSPECIFIED_ERROR; } } static void oem_set_pcie_port_config(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; ret = pal_set_pcie_port_config(req->payload_id, req->data, req_len, res->data, res_len); if(ret == 0) { res->cc = CC_SUCCESS; } else { res->cc = CC_UNSPECIFIED_ERROR; } } static void oem_add_cper_log(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; *res_len = 0; res->cc = pal_add_cper_log(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_set_psb_info(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; *res_len = 0; res->cc = pal_set_psb_info(req->payload_id, req->data, req_len, res->data, res_len); return; } static void oem_set_m2_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; char payload[100] = {0}; unsigned char cmd_len = 8; if (length_check(cmd_len, req_len, response, res_len)) return; sprintf(key, "sys_config/fru%d_m2_%d_info", req->payload_id, req->data[0]); memcpy(payload, &req->data[1], req_len - 4); if(kv_set(key, payload, req_len - 4, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = 0; return; } static void oem_get_80port_dword_record (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; *res_len = 0; ret = pal_get_80port_page_record (req->payload_id, req->data[0], res->data, 256, (size_t *)res_len); switch(ret) { case PAL_EOK: res->cc = CC_SUCCESS; break; case PAL_ENOTSUP: res->cc = CC_INVALID_CMD; break; case PAL_ENOTREADY: res->cc = CC_NOT_SUPP_IN_CURR_STATE; break; default: res->cc = CC_UNSPECIFIED_ERROR; break; } } static void oem_get_dev_card_sensor(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_get_dev_card_sensor(req->payload_id, req->data, req_len, res->data, res_len); } static void oem_get_sensor_real_reading(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t fru, snr_num; uint8_t ret = 0; float val = 0; if (req_len != 5) { res->cc = CC_INVALID_LENGTH; *res_len = 0; return; } fru = req->data[0]; snr_num = req->data[1]; ret = pal_sensor_read_raw(fru, snr_num, &val); if (ret == 0) { res->cc = CC_SUCCESS; *res_len = 3; res->data[0] = ((int)val) >> 8; res->data[1] = (int)val & 0xFF; res->data[2] = (((int)(val*100)) % 100); } else { *res_len = 0; res->cc = CC_UNSPECIFIED_ERROR; } } static void oem_bbv_power_cycle ( unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int delay_time; *res_len = 0; delay_time = req->data[0]; res->cc = bbv_power_cycle(delay_time); } static void oem_stor_add_string_sel(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { // Byte0 Reserved // Byte1 String length // Byte2~ByteN Event log string (ASCII) ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char string_log[248] = {0}; //Reserve byte[0:3] bytes for future implementation uint8_t string_log_len = req->data[4]; *res_len = 0; if (string_log_len >= sizeof(string_log)){ res->cc = CC_INVALID_LENGTH; syslog(LOG_ERR, "%s(): max supported string length is %d, but got %d", __func__, sizeof(string_log)-1, string_log_len); return; } memcpy(string_log, &req->data[5], string_log_len+1); // To avoid repeat display when Expander executes reset test // will filter fan fru checksum SEL if (!pal_handle_fan_fru_checksum_sel(string_log, string_log_len)) { res->cc = CC_SUCCESS; return; } syslog(LOG_CRIT, "%s", string_log); if (!pal_handle_string_sel(string_log, string_log_len)) res->cc = CC_SUCCESS; else res->cc = CC_UNSPECIFIED_ERROR; return; } static void oem_set_bios_cap_fw_ver(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; ret = pal_set_bios_cap_fw_ver(req->payload_id, req->data, req_len, res->data, res_len); if(ret == 0) { res->cc = CC_SUCCESS; } else { res->cc = CC_UNSPECIFIED_ERROR; } } static void oem_set_fscd(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char data = req->data[0]; char cmd[100] = {0}; switch (data) { case 0x00: sprintf(cmd, "sv force-stop fscd"); break; case 0x01: sprintf(cmd, "sv start fscd"); break; default: res->cc = CC_INVALID_CMD; break; } if (system(cmd)) { syslog(LOG_WARNING, "set fscd cmd failed (%s)\n", cmd); res->cc = CC_UNSPECIFIED_ERROR; } else { res->cc = CC_SUCCESS; } } static void oem_set_slot_power_policy(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; unsigned char *data = &res->data[0]; *data++ = 0x07; // Power restore policy support(bitfield) // Set specific slave addr device's power restore policy res->cc = pal_set_slot_power_policy(req->data, res->data); if (res->cc == CC_SUCCESS) { *res_len = data - &res->data[0]; } } static void oem_get_usb_cdc_status (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res= (ipmi_res_t *) response; int ret = 0; if (length_check(0, req_len, response, res_len)) { return; } ret = system("lsmod | grep -q g_cdc"); if (ret != 0) { res->data[0] = DISABLE_USB_CDC; } else { res->data[0] = ENABLE_USB_CDC; } res->cc = CC_SUCCESS; *res_len = 1; } static void oem_control_usb_cdc (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; uint8_t status_ctrl = req->data[0]; // 0 - disable, 1 - enable int ret = 0; if (length_check(1, req_len, response, res_len)) { return; } res->cc = CC_SUCCESS; if (status_ctrl == DISABLE_USB_CDC) { // Disable USB serial console by usbcons.sh, then unload USB CDC driver ret = run_command("/etc/init.d/usbcons.sh stop"); if (ret == 0) { ret = system("modprobe -qr g_cdc"); if (WIFEXITED(ret) == 0) { syslog(LOG_ERR, "%s: failed to disable ether-over-usb (usb0), ret: %d\n", __func__, ret); res->cc = CC_UNSPECIFIED_ERROR; } } else { syslog(LOG_ERR, "%s: failed to disable USB serial console, ret: %d\n", __func__, ret); res->cc = CC_UNSPECIFIED_ERROR; } } else if (status_ctrl == ENABLE_USB_CDC){ // Enable USB serial console and reload USB CDC driver by usbcons.sh, then link up usb0 // The 'restart' action will kill all usbmod.sh processes then start usbmon.sh ret = run_command("/etc/init.d/usbcons.sh restart"); if (ret == 0) { ret = system("sleep 1; ifconfig usb0 up"); if (WIFEXITED(ret) == 0) { syslog(LOG_ERR, "%s: failed to link up ether-over-usb (usb0), ret: %d\n", __func__, ret); res->cc = CC_UNSPECIFIED_ERROR; } } else { syslog(LOG_ERR, "%s: failed to enable ether-over-usb (usb0), ret: %d\n", __func__, ret); res->cc = CC_UNSPECIFIED_ERROR; } } else { res->cc = CC_INVALID_PARAM; } *res_len = 0; } static void oem_set_ioc_fw_recovery (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; *res_len = 0; if (length_check(2, req_len, response, res_len) != 0) { return; } // cmd_len = req_len - 3 (payload_id, cmd and netfn) res->cc = pal_set_ioc_fw_recovery(req->data, (req_len - IPMI_MN_REQ_HDR_SIZE), res->data, res_len); } static void oem_get_ioc_fw_recovery (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res= (ipmi_res_t *) response; uint8_t component = 0; *res_len = 0; if (length_check(1, req_len, response, res_len) != 0) { return; } component = req->data[0]; res->cc = pal_get_ioc_fw_recovery(component, res->data, res_len); } static void oem_setup_exp_uart_bridging (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; *res_len = 0; if (length_check(0, req_len, response, res_len) != 0) { return; } res->cc = pal_setup_exp_uart_bridging(); } static void oem_teardown_exp_uart_bridging (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_res_t *res = (ipmi_res_t *) response; *res_len = 0; if (length_check(0, req_len, response, res_len) != 0) { return; } res->cc = pal_teardown_exp_uart_bridging(); } static void oem_set_ioc_wwid (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; *res_len = 0; if (length_check(9, req_len, response, res_len) != 0) { return; } res->cc = pal_set_ioc_wwid(req->data, (req_len - IPMI_MN_REQ_HDR_SIZE), res->data, res_len); } static void oem_get_ioc_wwid (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t component = 0; *res_len = 0; if (length_check(1, req_len, response, res_len) != 0) { return; } component = req->data[0]; res->cc = pal_get_ioc_wwid(component, res->data, res_len); } static void oem_set_pcie_info (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; char key[100] = {0}; char payload[100] = {0}; size_t data_len = req_len - IPMI_MN_REQ_HDR_SIZE; sprintf(key, "sys_config/fru%d_pcie_i%02X_s%02X_info", req->payload_id, req->data[0], req->data[1]); memcpy(payload, &req->data[0], data_len); if(kv_set(key, payload, data_len, KV_FPERSIST)) { res->cc = CC_UNSPECIFIED_ERROR; *res_len = 0; return; } res->cc = CC_SUCCESS; *res_len = 0; return; } static void oem_bios_extra_setup(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_oem_bios_extra_setup(req->payload_id, req->data, req_len, res->data, res_len); } static void ipmi_handle_oem (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_oem); switch (cmd) { case CMD_OEM_ADD_RAS_SEL: oem_add_ras_sel (request, req_len, response, res_len); break; case CMD_OEM_ADD_IMC_LOG: oem_add_imc_log (request, req_len, response, res_len); break; case CMD_OEM_SET_PROC_INFO: oem_set_proc_info (request, req_len, response, res_len); break; case CMD_OEM_GET_PROC_INFO: oem_get_proc_info (request, req_len, response, res_len); break; case CMD_OEM_SET_DIMM_INFO: oem_set_dimm_info (request, req_len, response, res_len); break; case CMD_OEM_GET_DIMM_INFO: oem_get_dimm_info(request, req_len, response, res_len); break; case CMD_OEM_SET_BOOT_ORDER: if(length_check(SIZE_BOOT_ORDER, req_len, response, res_len)) { break; } oem_set_boot_order(request, req_len, response, res_len); break; case CMD_OEM_GET_BOOT_ORDER: oem_get_boot_order(request, req_len, response, res_len); break; case CMD_OEM_SET_TPM_PRESENCE: oem_set_tpm_presence(request, req_len, response, res_len); break; case CMD_OEM_GET_TPM_PRESENCE: oem_get_tpm_presence(request, req_len, response, res_len); break; case CMD_OEM_SET_PPR: case CMD_OEM_LEGACY_SET_PPR: oem_set_ppr (request, req_len, response, res_len); break; case CMD_OEM_GET_PPR: case CMD_OEM_LEGACY_GET_PPR: oem_get_ppr (request, req_len, response, res_len); break; case CMD_OEM_SET_POST_START: oem_set_post_start (request, req_len, response, res_len); break; case CMD_OEM_SET_POST_END: oem_set_post_end (request, req_len, response, res_len); break; case CMD_OEM_SET_PPIN_INFO: oem_set_ppin_info (request, req_len, response, res_len); break; case CMD_OEM_SET_ADR_TRIGGER: oem_set_adr_trigger(request, req_len, response, res_len); break; case CMD_OEM_GET_PLAT_INFO: oem_get_plat_info (request, req_len, response, res_len); break; case CMD_OEM_SET_SYSTEM_GUID: oem_set_device_sys_guid (request, req_len, response, res_len); break; case CMD_OEM_SLED_AC_CYCLE: oem_sled_ac_cycle (request, req_len, response, res_len); break; case CMD_OEM_GET_PCIE_CONFIG: oem_get_poss_pcie_config (request, req_len, response, res_len); break; case CMD_OEM_SET_IMC_VERSION: oem_set_imc_version (request, req_len, response, res_len); break; case CMD_OEM_SET_FW_UPDATE_STATE: oem_set_fw_update_state (request, req_len, response, res_len); break; case CMD_OEM_BYPASS_CMD: oem_bypass_cmd (request, req_len, response, res_len); break; case CMD_OEM_BYPASS_DEV_CARD: oem_bypass_dev_card (request, req_len, response, res_len); break; case CMD_OEM_GET_BOARD_ID: oem_get_board_id (request, req_len, response, res_len); break; case CMD_OEM_GET_80PORT_RECORD: oem_get_80port_record (request, req_len, response, res_len); break; case CMD_OEM_GET_FW_INFO: oem_get_fw_info (request, req_len, response, res_len); break; case CMD_OEM_SET_MACHINE_CONFIG_INFO: oem_set_machine_config_info (request, req_len, response, res_len); break; case CMD_OEM_SET_BIOS_FLASH_INFO: oem_set_flash_info(request, req_len, response, res_len); break; case CMD_OEM_GET_BIOS_FLASH_INFO: oem_get_flash_info(request, req_len, response, res_len); break; case CMD_OEM_GET_PCIE_PORT_CONFIG: if(length_check(0, req_len, response, res_len)) break; oem_get_pcie_port_config(request, req_len, response, res_len); break; case CMD_OEM_SET_PCIE_PORT_CONFIG: if(length_check(SIZE_PCIE_PORT_CONFIG, req_len, response, res_len)) break; oem_set_pcie_port_config(request, req_len, response, res_len); break; case CMD_OEM_BBV_POWER_CYCLE: oem_bbv_power_cycle(request, req_len, response, res_len); break; case CMD_OEM_ADD_CPER_LOG: oem_add_cper_log(request, req_len, response, res_len); break; case CMD_OEM_SET_PSB_INFO: oem_set_psb_info(request, req_len, response, res_len); break; case CMD_OEM_SET_M2_INFO: oem_set_m2_info(request, req_len, response, res_len); break; case CMD_OEM_GET_80_PORT_DWORD_BUFFER: oem_get_80port_dword_record (request, req_len, response, res_len); break; case CMD_OEM_GET_DEV_CARD_SENSOR: oem_get_dev_card_sensor(request, req_len, response, res_len); break; case CMD_OEM_GET_SENSOR_REAL_READING: oem_get_sensor_real_reading(request, req_len, response, res_len); break; case CMD_OEM_SET_BIOS_CAP_FW_VER: oem_set_bios_cap_fw_ver(request, req_len, response, res_len); break; case CMD_OEM_SET_FSCD: oem_set_fscd(request, req_len, response, res_len); break; case CMD_OEM_SET_POWER_POLICY: oem_set_slot_power_policy(request, req_len, response, res_len); break; case CMD_OEM_GET_USB_CDC_STATUS: oem_get_usb_cdc_status(request, req_len, response, res_len); break; case CMD_OEM_CTRL_USB_CDC: oem_control_usb_cdc(request, req_len, response, res_len); break; case CMD_OEM_SET_PCIE_INFO: oem_set_pcie_info(request, req_len, response, res_len); break; case CMD_OEM_BIOS_EXTRA_SETUP: oem_bios_extra_setup(request, req_len, response, res_len); break; default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_oem); } static void ipmi_handle_oem_storage (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_oem_storage); switch (cmd) { case CMD_OEM_STOR_ADD_STRING_SEL: oem_stor_add_string_sel (request, req_len, response, res_len); break; case CMD_OEM_SET_IOC_FW_RECOVERY: oem_set_ioc_fw_recovery (request, req_len, response, res_len); break; case CMD_OEM_GET_IOC_FW_RECOVERY: oem_get_ioc_fw_recovery (request, req_len, response, res_len); break; case CMD_OEM_SETUP_EXP_UART_BRIDGING: oem_setup_exp_uart_bridging (request, req_len, response, res_len); break; case CMD_OEM_TEARDOWN_EXP_UART_BRIDGING: oem_teardown_exp_uart_bridging (request, req_len, response, res_len); break; case CMD_OEM_SET_IOC_WWID: oem_set_ioc_wwid (request, req_len, response, res_len); break; case CMD_OEM_GET_IOC_WWID: oem_get_ioc_wwid (request, req_len, response, res_len); break; default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_oem_storage); } static void ipmi_handle_oem_q (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_oem_q); switch (cmd) { case CMD_OEM_Q_SET_PROC_INFO: oem_q_set_proc_info (request, req_len, response, res_len); break; case CMD_OEM_Q_GET_PROC_INFO: oem_q_get_proc_info (request, req_len, response, res_len); break; case CMD_OEM_Q_SET_DIMM_INFO: oem_q_set_dimm_info (request, req_len, response, res_len); break; case CMD_OEM_Q_GET_DIMM_INFO: oem_q_get_dimm_info (request, req_len, response, res_len); break; case CMD_OEM_Q_SET_DRIVE_INFO: oem_q_set_drive_info (request, req_len, response, res_len); break; case CMD_OEM_Q_GET_DRIVE_INFO: oem_q_get_drive_info (request, req_len, response, res_len); break; case CMD_OEM_Q_SET_SMU_PSP_VER: oem_q_set_smu_psp_ver (request, req_len, response, res_len); break; case CMD_OEM_Q_GET_SMU_PSP_VER: oem_q_get_smu_psp_ver (request, req_len, response, res_len); break; case CMD_OEM_Q_SLED_CYCLE_PREPARE_REQUEST: oem_q_sled_cycle_prepare_request (request, req_len, response, res_len); break; case CMD_OEM_Q_SLED_CYCLE_PREPARE_STATUS: oem_q_sled_cycle_prepare_status (request, req_len, response, res_len); break; default: res->cc = CC_INVALID_CMD; break; } pthread_mutex_unlock(&m_oem_q); } static void oem_1s_handle_ipmb_kcs(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; // Need to extract bridged IPMI command and handle unsigned char req_buf[MAX_IPMI_MSG_SIZE] = {0}; unsigned char res_buf[MAX_IPMI_MSG_SIZE] = {0}; // Add the payload id from the bridged command req_buf[0] = req->payload_id; // Remove OEM IPMI Header (including 1 byte for interface type, 3 bytes for IANA ID) // The offset moves by one due to the payload ID memcpy(&req_buf[1], &request[BIC_INTF_HDR_SIZE], req_len - BIC_INTF_HDR_SIZE); // Send the bridged KCS command along with the payload ID // The offset moves by one due to the payload ID ipmi_handle(req_buf, req_len - BIC_INTF_HDR_SIZE + 1, res_buf, res_len); // Copy the response back (1 byte interface type, 3 bytes for IANA ID) memcpy(&res->data[4], res_buf, *res_len); // Add the OEM command's response res->cc = CC_SUCCESS; memcpy(res->data, &req->data, SIZE_IANA_ID); // IANA ID res->data[3] = req->data[3]; // Bridge-IC interface *res_len += 4; // Interface type + IANA ID } static void oem_1s_handle_ipmb_req(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; // handle based on Bridge-IC interface switch(req->data[3]) { case BIC_INTF_ME: #ifdef DEBUG syslog(LOG_INFO, "oem_1s_handle_ipmb_req: Command received from ME for " "payload#%d\n", req->payload_id); #endif oem_1s_handle_ipmb_kcs(request, req_len, response, res_len); break; case BIC_INTF_SOL: // TODO: Need to call Optional SoL message handler #ifdef DEBUG syslog(LOG_INFO, "oem_1s_handle_ipmb_req: Command received from SOL for " "payload#%d\n", req->payload_id); #endif memcpy(res->data, req->data, 4); //IANA ID + Interface type res->cc = CC_SUCCESS; *res_len = 4; break; case BIC_INTF_KCS: case BIC_INTF_KCS_SMM: case BIC_INTF_SSIF: case BIC_INTF_IMC: oem_1s_handle_ipmb_kcs(request, req_len, response, res_len); break; default: // TODO: Need to add additonal interface handler, if supported syslog(LOG_WARNING, "oem_1s_handle_ipmb_req: Command received on intf#%d " "for payload#%d", req->data[3], req->payload_id); memcpy(res->data, req->data, 4); //IANA ID + Interface type res->cc = CC_INVALID_PARAM; *res_len = 4; break; } } static void ipmi_handle_oem_1s(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int i; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_oem_1s); switch (cmd) { case CMD_OEM_1S_MSG_IN: // As all bridge in messages are IPMI request // all IPMI request will be process by ipmi_handle // which will "properly" serialize the processing according to netfn // Thus it is not necessary to serialize processing of MSG-IN. pthread_mutex_unlock(&m_oem_1s); oem_1s_handle_ipmb_req(request, req_len, response, res_len); pthread_mutex_lock(&m_oem_1s); break; case CMD_OEM_1S_INTR: #ifdef DEBUG syslog(LOG_INFO, "ipmi_handle_oem_1s (cmd 0x%02x): 1S server interrupt#%d received " "for payload#%d\n", cmd, req->data[3], req->payload_id); #endif pal_handle_oem_1s_intr(req->payload_id, &(req->data[3])); res->cc = CC_SUCCESS; memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; case CMD_OEM_1S_POST_BUF: // Skip the first 3 bytes of IANA ID and one byte of length field for (i = SIZE_IANA_ID+1; i <= req->data[SIZE_IANA_ID]+SIZE_IANA_ID; i++) { pal_post_handle(req->payload_id, req->data[i]); } res->cc = CC_SUCCESS; memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; case CMD_OEM_1S_PLAT_DISC: syslog(LOG_INFO, "ipmi_handle_oem_1s: Platform Discovery received for " "payload#%d\n", req->payload_id); res->cc = CC_SUCCESS; memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; case CMD_OEM_1S_BIC_RESET: syslog(LOG_INFO, "ipmi_handle_oem_1s: BIC Reset received " "for payload#%d\n", req->payload_id); if (req->data[3] == 0x0) { syslog(LOG_WARNING, "Cold Reset by Firmware Update\n"); res->cc = CC_SUCCESS; } else if (req->data[3] == 0x01) { syslog(LOG_WARNING, "WDT Reset\n"); res->cc = CC_SUCCESS; } else { syslog(LOG_WARNING, "Error\n"); res->cc = CC_INVALID_PARAM; } memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; case CMD_OEM_1S_BIC_UPDATE_MODE: #ifdef DEBUG syslog(LOG_INFO, "ipmi_handle_oem_1s: BIC Update Mode received " "for payload#%d\n", req->payload_id); #endif if (req->data[3] == 0x1) { syslog(LOG_INFO, "BIC Mode: Normal\n"); res->cc = CC_SUCCESS; } else if (req->data[3] == 0x0F) { syslog(LOG_INFO, "BIC Mode: Update\n"); res->cc = CC_SUCCESS; } else { syslog(LOG_WARNING, "Error\n"); res->cc = CC_INVALID_PARAM; } pal_inform_bic_mode(req->payload_id, req->data[3]); memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; case CMD_OEM_1S_ASD_MSG_IN: if (req_len > 7) { // payload_id, netfn, cmd, IANA[3], data type pal_handle_oem_1s_asd_msg_in(req->payload_id, &req->data[3], req_len-6); res->cc = CC_SUCCESS; } else { res->cc = CC_INVALID_LENGTH; } memcpy(res->data, req->data, SIZE_IANA_ID); *res_len = 3; break; case CMD_OEM_1S_RAS_DUMP_IN: if (req_len > 7) { // payload_id, netfn, cmd, IANA[3], data type pal_handle_oem_1s_ras_dump_in(req->payload_id, &req->data[3], req_len-7); res->cc = CC_SUCCESS; } else { res->cc = CC_INVALID_LENGTH; } memcpy(res->data, req->data, SIZE_IANA_ID); *res_len = 3; break; case CMD_OEM_1S_4BYTE_POST_BUF: // Skip the first 3 bytes of IANA ID and one byte of length field for(int k = SIZE_IANA_ID + 1; k < req->data[SIZE_IANA_ID]+SIZE_IANA_ID; k+=(sizeof(uint32_t)/sizeof(uint8_t))) { uint32_t port_buff = req->data[k] | (req->data[k+1] << 8) | (req->data[k+2] << 16) | (req->data[k+3] << 24); pal_display_4byte_post_code(req->payload_id, port_buff); } res->cc = CC_SUCCESS; memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; case CMD_OEM_1S_GET_SYS_FW_VER: if (req_len == 8) { // payload_id, netfn, cmd, IANA[3], data[0] (fru), data[1] (component) memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID res->cc = pal_get_fw_ver(req->payload_id, &req->data[3], &res->data[3], res_len); *res_len += SIZE_IANA_ID; } else { res->cc = CC_INVALID_LENGTH; *res_len = SIZE_IANA_ID; } break; case CMD_OEM_1S_DEV_POWER: // payload_id, netfn, cmd, data[0] (device id), data[1] (action), data[2] (data) res->cc = pal_handle_oem_1s_dev_power(req->payload_id, &req->data[0], req_len-3, &res->data[0], res_len); break; case CMD_OEM_1S_UPDATE_SDR: res->cc = pal_handle_oem_1s_update_sdr(req->payload_id); break; default: res->cc = CC_INVALID_CMD; memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; } pthread_mutex_unlock(&m_oem_1s); } static void oem_usb_dbg_get_frame_info(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t num_frames; int ret; ret = plat_udbg_get_frame_info(); if (ret < 0) { memcpy(res->data, req->data, 3); // IANA ID res->cc = CC_UNSPECIFIED_ERROR; *res_len = SIZE_IANA_ID; return; } num_frames = (uint8_t) ret; memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->data[3] = num_frames; res->cc = CC_SUCCESS; *res_len = SIZE_IANA_ID + 1; } static void oem_usb_dbg_get_updated_frames(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t num_updates; int ret; ret = plat_udbg_get_updated_frames(&num_updates, &res->data[4]); if (ret) { memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->cc = CC_UNSPECIFIED_ERROR; *res_len = SIZE_IANA_ID; return; } memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->data[3] = num_updates; res->cc = CC_SUCCESS; *res_len = SIZE_IANA_ID + 1 + num_updates; } static void oem_usb_dbg_get_post_desc(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t index; uint8_t next; uint8_t end; uint8_t phase; uint8_t count; int ret; index = req->data[3]; phase = req->data[4]; ret = plat_udbg_get_post_desc(index, &next, phase, &end, &count, &res->data[8]); if (ret) { memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->cc = CC_UNSPECIFIED_ERROR; *res_len = SIZE_IANA_ID; return; } memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->data[3] = index; res->data[4] = next; res->data[5] = phase; res->data[6] = end; res->data[7] = count; res->cc = CC_SUCCESS; *res_len = SIZE_IANA_ID + 5 + count; } static void oem_usb_dbg_get_gpio_desc(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t index; uint8_t next; uint8_t level; uint8_t in_out; uint8_t count; int ret; index = req->data[3]; ret = plat_udbg_get_gpio_desc(index, &next, &level, &in_out, &count, &res->data[8]); if (ret) { memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->cc = CC_UNSPECIFIED_ERROR; *res_len = SIZE_IANA_ID; return; } memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->data[3] = index; res->data[4] = next; res->data[5] = level; res->data[6] = in_out; res->data[7] = count; res->cc = CC_SUCCESS; *res_len = SIZE_IANA_ID + 5 + count; } static void oem_usb_dbg_get_frame_data(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t frame; uint8_t page; uint8_t next; uint8_t count; int ret; frame = req->data[3]; page = req->data[4]; ret = plat_udbg_get_frame_data(frame, page, &next, &count, &res->data[7]); if (ret) { memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->cc = CC_UNSPECIFIED_ERROR; *res_len = SIZE_IANA_ID; return; } memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->data[3] = frame; res->data[4] = page; res->data[5] = next; res->data[6] = count; res->cc = CC_SUCCESS; *res_len = SIZE_IANA_ID + 4 + count; } static void oem_usb_dbg_control_panel(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t panel; uint8_t operation; uint8_t item; uint8_t count; int ret; panel = req->data[3]; operation = req->data[4]; item = req->data[5]; ret = plat_udbg_control_panel(panel, operation, item, &count, &res->data[3]); if (ret) { memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->cc = ret; *res_len = SIZE_IANA_ID; return; } memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID res->cc = CC_SUCCESS; *res_len = SIZE_IANA_ID + count; } static void ipmi_handle_oem_usb_dbg(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; char key[32] = "blk_ocp_cmd"; char value[8] = {0}; if ( kv_get(key, value, 0, 0) == 0 && atoi(value) != 0) { syslog(LOG_INFO, "lock cmd"); res->cc = CC_NOT_SUPP_IN_CURR_STATE; *res_len = 0; return; } pthread_mutex_lock(&m_oem_usb_dbg); switch (cmd) { case CMD_OEM_USB_DBG_GET_FRAME_INFO: oem_usb_dbg_get_frame_info(request, req_len, response, res_len); break; case CMD_OEM_USB_DBG_GET_UPDATED_FRAMES: oem_usb_dbg_get_updated_frames(request, req_len, response, res_len); break; case CMD_OEM_USB_DBG_GET_POST_DESC: oem_usb_dbg_get_post_desc(request, req_len, response, res_len); break; case CMD_OEM_USB_DBG_GET_GPIO_DESC: oem_usb_dbg_get_gpio_desc(request, req_len, response, res_len); break; case CMD_OEM_USB_DBG_GET_FRAME_DATA: oem_usb_dbg_get_frame_data(request, req_len, response, res_len); break; case CMD_OEM_USB_DBG_CTRL_PANEL: oem_usb_dbg_control_panel(request, req_len, response, res_len); break; default: res->cc = CC_INVALID_CMD; memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; } pthread_mutex_unlock(&m_oem_usb_dbg); } static void oem_zion_get_system_mode(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t mode = 0xff; int ret; ret = pal_get_host_system_mode(&mode); if (ret == PAL_ENOTSUP) { memcpy(res->data, req->data, SIZE_IANA_ID); // IANA ID *res_len = SIZE_IANA_ID; res->cc = CC_INVALID_CMD; } else { res->data[0] = mode; *res_len = 1; res->cc = ret; } } static void oem_zion_set_system_mode(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; int ret; ret = pal_set_host_system_mode(req->data[0]); if (ret == PAL_ENOTSUP) res->cc = CC_INVALID_CMD; else res->cc = ret; } static void oem_zion_set_usb_path(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; uint8_t slot = req->data[0]; uint8_t endpoint = req->data[1]; int ret; ret = pal_set_usb_path(slot, endpoint); if (ret == PAL_ENOTSUP) res->cc = CC_INVALID_CMD; else res->cc = ret; } static void oem_zion_get_sensor_value(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; res->cc = pal_ipmb_get_sensor_val(req->payload_id, req->data, req_len, res->data, res_len); return; } static void ipmi_handle_oem_zion(unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char cmd = req->cmd; pthread_mutex_lock(&m_oem_zion); switch (cmd) { case CMD_OEM_ZION_GET_SYSTEM_MODE: oem_zion_get_system_mode(request, req_len, response, res_len); break; case CMD_OEM_ZION_GET_SENSOR_VALUE: oem_zion_get_sensor_value(request, req_len, response, res_len); break; case CMD_OEM_ZION_SET_SYSTEM_MODE: oem_zion_set_system_mode(request, req_len, response, res_len); break; case CMD_OEM_ZION_SET_USB_PATH: oem_zion_set_usb_path(request, req_len, response, res_len); break; default: res->cc = CC_INVALID_CMD; memcpy(res->data, req->data, SIZE_IANA_ID); //IANA ID *res_len = 3; break; } pthread_mutex_unlock(&m_oem_zion); } /* * Function to handle all IPMI messages */ static void ipmi_handle (unsigned char *request, unsigned char req_len, unsigned char *response, unsigned char *res_len) { ipmi_mn_req_t *req = (ipmi_mn_req_t *) request; ipmi_res_t *res = (ipmi_res_t *) response; unsigned char netfn; netfn = req->netfn_lun >> 2; // Provide default values in the response message res->cmd = req->cmd; res->cc = 0xFF; // Unspecified completion code printf("ipmi_handle netfn %x cmd %x len %d\n", netfn, req->cmd, req_len); if (gLogEnable) { char logbuf[256]; uint16_t nleft = sizeof(logbuf); uint16_t nwrite = 0; uint16_t i = 0; syslog(LOG_INFO, "%lu ipmi_handle netfn %x cmd %x len %d\n", (unsigned long)time(NULL), netfn, req->cmd, req_len); nwrite = snprintf(logbuf, nleft, " ipmi_handle recv data: "); i += nwrite; nleft -= nwrite; for (int j = 0; j < req_len; ++j) { nwrite = snprintf(logbuf + i, nleft, "%x ", (unsigned int)(request[j])); i += nwrite; nleft -= nwrite; } syslog(LOG_INFO, "%s", logbuf); } *(unsigned short*)res_len = 0; switch (netfn) { case NETFN_CHASSIS_REQ: res->netfn_lun = NETFN_CHASSIS_RES << 2; ipmi_handle_chassis (request, req_len, response, res_len); break; case NETFN_SENSOR_REQ: res->netfn_lun = NETFN_SENSOR_RES << 2; ipmi_handle_sensor (request, req_len, response, res_len); break; case NETFN_APP_REQ: res->netfn_lun = NETFN_APP_RES << 2; ipmi_handle_app (request, req_len, response, res_len); break; case NETFN_STORAGE_REQ: res->netfn_lun = NETFN_STORAGE_RES << 2; ipmi_handle_storage (request, req_len, response, res_len); break; case NETFN_TRANSPORT_REQ: res->netfn_lun = NETFN_TRANSPORT_RES << 2; ipmi_handle_transport (request, req_len, response, res_len); break; case NETFN_DCMI_REQ: res->netfn_lun = NETFN_DCMI_RES << 2; ipmi_handle_dcmi(request, req_len, response, res_len); break; case NETFN_OEM_REQ: res->netfn_lun = NETFN_OEM_RES << 2; ipmi_handle_oem (request, req_len, response, res_len); break; case NETFN_OEM_STORAGE_REQ: res->netfn_lun = NETFN_OEM_STORAGE_RES << 2; ipmi_handle_oem_storage (request, req_len, response, res_len); break; case NETFN_OEM_Q_REQ: res->netfn_lun = NETFN_OEM_Q_RES << 2; ipmi_handle_oem_q (request, req_len, response, res_len); break; case NETFN_OEM_1S_REQ: res->netfn_lun = NETFN_OEM_1S_RES << 2; ipmi_handle_oem_1s(request, req_len, response, res_len); break; case NETFN_OEM_USB_DBG_REQ: res->netfn_lun = NETFN_OEM_USB_DBG_RES << 2; ipmi_handle_oem_usb_dbg(request, req_len, response, res_len); break; case NETFN_OEM_ZION_REQ: res->netfn_lun = NETFN_OEM_ZION_RES << 2; ipmi_handle_oem_zion(request, req_len, response, res_len); break; default: res->netfn_lun = (netfn + 1) << 2; break; } // This header includes NetFunction, Command, and Completion Code *(unsigned short*)res_len += IPMI_RESP_HDR_SIZE; return; } int conn_handler(client_t *cli) { unsigned char req_buf[MAX_IPMI_MSG_SIZE]; unsigned char res_buf[MAX_IPMI_MSG_SIZE]; size_t req_len = MAX_IPMI_MSG_SIZE, res_len = 0; memset(req_buf, 0, sizeof(req_buf)); memset(res_buf, 0, sizeof(res_buf)); if (ipc_recv_req(cli, req_buf, &req_len, TIMEOUT_IPMI)) { syslog(LOG_WARNING, "ipmid: recv() failed\n"); return -1; } ipmi_handle(req_buf, (unsigned char)req_len, res_buf, (unsigned char*)&res_len); if (res_len == 0) { return -1; } if(ipc_send_resp(cli, res_buf, res_len)) { syslog(LOG_WARNING, "ipmid: send() failed\n"); return -1; } return 0; } void * wdt_timer (void *arg) { int ret; struct watchdog_data *wdt = (struct watchdog_data *)arg; uint8_t status; int action = 0; while (1) { usleep(100*1000); pthread_mutex_lock(&wdt->mutex); if (wdt->valid && wdt->run) { // Check if power off ret = pal_get_server_power(wdt->slot, &status); if ((ret >= 0) && (status != SERVER_POWER_ON)) { wdt->run = 0; pthread_mutex_unlock(&wdt->mutex); continue; } // count down; counter 0 and run associated timer events occur immediately if (wdt->present_count_down) wdt->present_count_down--; // Pre-timeout no support /* if (wdt->present_count_down == wdt->pre_interval*10) { } */ // Timeout if (wdt->present_count_down == 0) { wdt->expiration |= (1 << wdt->use); // Execute actin out of mutex action = wdt->action; pal_set_fru_post(wdt->slot, 0); if (wdt->no_log) { wdt->no_log = 0; } else { syslog(LOG_CRIT, "FRU: %u, %s Watchdog %s", wdt->slot, wdt_use_name[wdt->use & 0x7], wdt_action_name[action & 0x7]); } wdt->run = 0; } /* End of Timeout Action*/ } /* End of Valid and Run */ pthread_mutex_unlock(&wdt->mutex); // Execute actin out of mutex if (action) { if (pal_is_crashdump_ongoing(wdt->slot)) { syslog(LOG_WARNING, "ipmid: fru%u crashdump is ongoing, ignore wdt action %s", wdt->slot, wdt_action_name[action & 0x7]); action = 0; continue; } pal_set_restart_cause(wdt->slot, RESTART_CAUSE_WATCHDOG_EXPIRATION); switch (action) { case 1: // Hard Reset pal_set_server_power(wdt->slot, SERVER_POWER_RESET); break; case 2: // Power Down pal_set_server_power(wdt->slot, SERVER_POWER_OFF); break; case 3: // Power Cycle pal_set_server_power(wdt->slot, SERVER_POWER_CYCLE); break; case 0: // no action default: break; } action = 0; } } /* Forever while */ pthread_exit(NULL); } // optional "-d" cmd line option to enable logging int main (int argc, char **argv) { int fru; pthread_t tid; uint8_t max_slot_num = 0; //daemon(1, 1); //openlog("ipmid", LOG_CONS, LOG_DAEMON); if (argc > 2) { syslog(LOG_ERR, "ipmid: argc > 2!"); exit(1); } else { if ((argc == 2) && (strncmp(argv[1], "-d", 2) == 0)) { syslog(LOG_INFO, "ipmid: enable logging"); gLogEnable = 1; } } plat_fruid_init(); plat_sensor_init(); plat_lan_init(&g_lan_config); sdr_init(); sel_init(); pthread_mutex_init(&m_chassis, NULL); pthread_mutex_init(&m_sensor, NULL); pthread_mutex_init(&m_app, NULL); pthread_mutex_init(&m_storage, NULL); pthread_mutex_init(&m_transport, NULL); pthread_mutex_init(&m_oem, NULL); pthread_mutex_init(&m_oem_1s, NULL); pthread_mutex_init(&m_oem_usb_dbg, NULL); pthread_mutex_init(&m_oem_q, NULL); pthread_mutex_init(&m_oem_zion, NULL); pal_get_num_slots(&max_slot_num); fru = 1; while(fru <= max_slot_num){ //tpm pal_create_TPMTimer(fru); struct watchdog_data *wdt_data = calloc(1, sizeof(struct watchdog_data)); if (!wdt_data) { syslog(LOG_WARNING, "ipmid: allocation wdt info failed!\n"); continue; } wdt_data->slot = fru; wdt_data->valid = 0; wdt_data->pre_interval = 1; pthread_mutex_init(&wdt_data->mutex, NULL); g_wdt[fru - 1] = wdt_data; pthread_create(&wdt_data->tid, NULL, wdt_timer, wdt_data); pthread_detach(wdt_data->tid); pal_set_def_restart_cause( fru ); fru++; } // set flag to notice BMC ipmid is ready kv_set("flag_ipmid", "1", 0, 0); if (ipc_start_svc(SOCK_PATH_IPMI, conn_handler, MAX_REQUESTS, NULL, &tid) == 0) { pthread_join(tid, NULL); } pthread_mutex_destroy(&m_chassis); pthread_mutex_destroy(&m_sensor); pthread_mutex_destroy(&m_app); pthread_mutex_destroy(&m_storage); pthread_mutex_destroy(&m_transport); pthread_mutex_destroy(&m_oem); pthread_mutex_destroy(&m_oem_1s); pthread_mutex_destroy(&m_oem_usb_dbg); pthread_mutex_destroy(&m_oem_q); return 0; }