diff options
Diffstat (limited to 'meta-raptor/meta-asus/recipes-asus/ipmid')
14 files changed, 3431 insertions, 0 deletions
diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/Makefile b/meta-raptor/meta-asus/recipes-asus/ipmid/files/Makefile new file mode 100644 index 0000000..c65c3c5 --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/Makefile @@ -0,0 +1,29 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +all: ipmid + +ipmid: ipmid.c \ + platform/timestamp.c platform/sel.c platform/sdr.c \ + platform/wedge/sensor.c \ + platform/wedge/fruid.c + $(CC) -pthread -std=c99 -o $@ $^ $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf *.o platform/*.o platform/wedge/*.o ipmid diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/ipmid.c b/meta-raptor/meta-asus/recipes-asus/ipmid/files/ipmid.c new file mode 100644 index 0000000..ed2b75f --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/ipmid.c @@ -0,0 +1,1490 @@ +/* + * + * 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 "platform/sdr.h" +#include "platform/sel.h" +#include "platform/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> + +#define SOCK_PATH "/tmp/ipmi_socket" + +#define MAX_NUM_DIMMS 4 +#define IPMI_SEL_VERSION 0x51 +#define IPMI_SDR_VERSION 0x51 + +#define SIZE_AUTH_ENABLES 5 +#define SIZE_IP_ADDR 4 +#define SIZE_MAC_ADDR 6 +#define SIZE_NET_MASK 4 +#define SIZE_IP_HDR 3 +#define SIZE_RMCP_PORT 2 +#define SIZE_COMMUNITY_STR 18 +#define SIZE_DEST_TYPE 4 +#define SIZE_DEST_ADDR 18 +#define SIZE_TIME_STAMP 4 + +#define SIZE_PROC_FREQ 2 +#define SIZE_DIMM_SPEED 2 +#define SIZE_DIMM_SIZE 2 + +#define SIZE_SYSFW_VER 17 +#define SIZE_SYS_NAME 17 +#define SIZE_OS_NAME 17 +#define SIZE_OS_VER 17 +#define SIZE_BMC_URL 17 +#define SIZE_OS_HV_URL 17 + +#define SIZE_SEL_REC 16 +#define SIZE_IPMI_RES_HDR 3 + +#define MAX_IPMI_MSG_SIZE 100 + +// IPMI request Structure (IPMI/Section 9.2) +typedef struct +{ + unsigned char netfn_lun; + unsigned char cmd; + unsigned char data[]; +} ipmi_req_t; + +// IPMI response Structure (IPMI/Section 9.3) +typedef struct +{ + unsigned char netfn_lun; + unsigned char cmd; + unsigned char cc; + unsigned char data[]; +} ipmi_res_t; + +// LAN Configuration Structure (IPMI/Table 23.4) +typedef struct +{ + unsigned char set_in_prog; + unsigned char auth_support; + unsigned char auth_enables[SIZE_AUTH_ENABLES]; + unsigned char ip_addr[SIZE_IP_ADDR]; + unsigned char ip_src; + unsigned char mac_addr[SIZE_MAC_ADDR]; + unsigned char net_mask[SIZE_NET_MASK]; + unsigned char ip_hdr[SIZE_IP_HDR]; + unsigned char pri_rmcp_port[SIZE_RMCP_PORT]; + unsigned char sec_rmcp_port[SIZE_RMCP_PORT]; + unsigned char arp_ctrl; + unsigned char garp_interval; + unsigned char df_gw_ip_addr[SIZE_IP_ADDR]; + unsigned char df_gw_mac_addr[SIZE_MAC_ADDR]; + unsigned char back_gw_ip_addr[SIZE_IP_ADDR]; + unsigned char back_gw_mac_addr[SIZE_MAC_ADDR]; + unsigned char community_str[SIZE_COMMUNITY_STR]; + unsigned char no_of_dest; + unsigned char dest_type[SIZE_DEST_TYPE]; + unsigned char dest_addr[SIZE_DEST_ADDR]; +} lan_config_t; + +// Structure to store Processor Information +typedef struct +{ + unsigned char type; + unsigned char freq[SIZE_PROC_FREQ]; +} proc_info_t; + +// Structure to store DIMM Information +typedef struct +{ + unsigned char type; + unsigned char speed[SIZE_DIMM_SPEED]; + unsigned char size[SIZE_DIMM_SIZE]; +} dimm_info_t; + +// Structure for System Info Params (IPMI/Section 22.14a) +typedef struct +{ + unsigned char set_in_prog; + unsigned char sysfw_ver[SIZE_SYSFW_VER]; + unsigned char sys_name[SIZE_SYS_NAME]; + unsigned char pri_os_name[SIZE_OS_NAME]; + unsigned char present_os_name[SIZE_OS_NAME]; + unsigned char present_os_ver[SIZE_OS_VER]; + unsigned char bmc_url[SIZE_BMC_URL]; + unsigned char os_hv_url[SIZE_OS_HV_URL]; +} sys_info_param_t; + +// Network Function Codes (IPMI/Section 5.1) +enum +{ + NETFN_CHASSIS_REQ = 0x00, + NETFN_CHASSIS_RES, + NETFN_BRIDGE_REQ, + NETFN_BRIDGE_RES, + NETFN_SENSOR_REQ, + NETFN_SENSOR_RES, + NETFN_APP_REQ, + NETFN_APP_RES, + NETFN_FIRMWARE_REQ, + NETFN_FIRMWARE_RES, + NETFN_STORAGE_REQ, + NETFN_STORAGE_RES, + NETFN_TRANSPORT_REQ, + NETFN_TRANSPORT_RES, + NETFN_OEM_REQ = 0x30, + NETFN_OEM_RES = 0x31, +}; + +// Chassis Command Codes (IPMI/Table H-1) +enum +{ + CMD_CHASSIS_GET_STATUS = 0x01, + CMD_CHASSIS_GET_BOOT_OPTIONS = 0x09, +}; + +// Application Command Codes (IPMI/Table H-1) +enum +{ + CMD_APP_GET_DEVICE_ID = 0x01, + CMD_APP_GET_SELFTEST_RESULTS = 0x04, + CMD_APP_GET_DEVICE_GUID = 0x08, + CMD_APP_RESET_WDT = 0x22, + CMD_APP_SET_WDT = 0x24, + CMD_APP_GET_WDT = 0x25, + CMD_APP_GET_GLOBAL_ENABLES = 0x2F, + CMD_APP_GET_SYSTEM_GUID = 0x37, + CMD_APP_SET_SYS_INFO_PARAMS = 0x58, + CMD_APP_GET_SYS_INFO_PARAMS = 0x59, +}; + +// Storage Command Codes (IPMI/Table H-1) +enum +{ + CMD_STORAGE_GET_FRUID_INFO = 0x10, + CMD_STORAGE_READ_FRUID_DATA = 0x11, + CMD_STORAGE_GET_SDR_INFO = 0x20, + CMD_STORAGE_RSV_SDR = 0x22, + CMD_STORAGE_GET_SDR = 0x23, + CMD_STORAGE_GET_SEL_INFO = 0x40, + CMD_STORAGE_RSV_SEL = 0x42, + CMD_STORAGE_GET_SEL = 0x43, + CMD_STORAGE_ADD_SEL = 0x44, + CMD_STORAGE_CLR_SEL = 0x47, + CMD_STORAGE_GET_SEL_TIME = 0x48, + CMD_STORAGE_GET_SEL_UTC = 0x5C, +}; + +// Transport Command Codes (IPMI/Table H-1) +enum +{ + CMD_TRANSPORT_SET_LAN_CONFIG = 0x01, + CMD_TRANSPORT_GET_LAN_CONFIG = 0x02, +}; + +// OEM Command Codes (Quanta/FB defined commands) +enum +{ + CMD_OEM_SET_PROC_INFO = 0x1A, + CMD_OEM_SET_DIMM_INFO = 0x1C, + CMD_OEM_SET_POST_START = 0x73, + CMD_OEM_SET_POST_END = 0x74, +}; + +// IPMI command Completion Codes (IPMI/Section 5.2) +enum +{ + CC_SUCCESS = 0x00, + CC_INVALID_PARAM = 0x80, + CC_SEL_ERASE_PROG = 0x81, + CC_INVALID_CMD = 0xC1, + CC_PARAM_OUT_OF_RANGE = 0xC9, + CC_UNSPECIFIED_ERROR = 0xFF, +}; + +// LAN Configuration parameters (IPMI/Table 23-4) +enum +{ + LAN_PARAM_SET_IN_PROG, + LAN_PARAM_AUTH_SUPPORT, + LAN_PARAM_AUTH_ENABLES, + LAN_PARAM_IP_ADDR, + LAN_PARAM_IP_SRC, + LAN_PARAM_MAC_ADDR, + LAN_PARAM_NET_MASK, + LAN_PARAM_IP_HDR, + LAN_PARAM_PRI_RMCP_PORT, + LAN_PARAM_SEC_RMCP_PORT, + LAN_PARAM_ARP_CTRL, + LAN_PARAM_GARP_INTERVAL, + LAN_PARAM_DF_GW_IP_ADDR, + LAN_PARAM_DF_GW_MAC_ADDR, + LAN_PARAM_BACK_GW_IP_ADDR, + LAN_PARAM_BACK_GW_MAC_ADDR, + LAN_PARAM_COMMUNITY_STR, + LAN_PARAM_NO_OF_DEST, + LAN_PARAM_DEST_TYPE, + LAN_PARAM_DEST_ADDR, +}; + +// Boot Option Parameters (IPMI/Table 28-14) +enum +{ + PARAM_SET_IN_PROG = 0x00, + PARAM_SVC_PART_SELECT, + PARAM_SVC_PART_SCAN, + PARAM_BOOT_FLAG_CLR, + PARAM_BOOT_INFO_ACK, + PARAM_BOOT_FLAGS, + PARAM_BOOT_INIT_INFO, +}; + +//System Info Parameters (IPMI/Table 22-16c) +enum +{ + SYS_INFO_PARAM_SET_IN_PROG, + SYS_INFO_PARAM_SYSFW_VER, + SYS_INFO_PARAM_SYS_NAME, + SYS_INFO_PARAM_PRI_OS_NAME, + SYS_INFO_PARAM_PRESENT_OS_NAME, + SYS_INFO_PARAM_PRESENT_OS_VER, + SYS_INFO_PARAM_BMC_URL, + SYS_INFO_PARAM_OS_HV_URL, +}; + +// TODO: Once data storage is finalized, the following structure needs +// to be retrieved/updated from persistant backend storage +static lan_config_t g_lan_config = { 0 }; +static proc_info_t g_proc_info = { 0 }; +static dimm_info_t g_dimm_info[MAX_NUM_DIMMS] = { 0 }; + +// TODO: Need to store this info after identifying proper storage +static sys_info_param_t g_sys_info_params; + +// 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_app; +static pthread_mutex_t m_storage; +static pthread_mutex_t m_transport; +static pthread_mutex_t m_oem; + +/* + * Function(s) to handle IPMI messages with NetFn: Chassis + */ +// Get Chassis Status (IPMI/Section 28.2) +static void +chassis_get_status (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: Need to obtain current power state and last power event + // from platform and return + *data++ = 0x01; // Current Power State + *data++ = 0x00; // Last Power Event + *data++ = 0x40; // Misc. Chassis Status + *data++ = 0x00; // Front Panel Button Disable + + *res_len = data - &res->data[0]; +} + +// Get System Boot Options (IPMI/Section 28.12) +static void +chassis_get_boot_options (unsigned char *request, unsigned char *response, + unsigned char *res_len) +{ + ipmi_req_t *req = (ipmi_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 + res->cc = CC_SUCCESS; + *data++ = 0x01; // Parameter Version + *data++ = req->data[0]; // Parameter + + // TODO: Need to store user settings and return + switch (param) + { + case PARAM_SET_IN_PROG: + *data++ = 0x00; // Set In Progress + break; + case PARAM_SVC_PART_SELECT: + *data++ = 0x00; // Service Partition Selector + break; + case PARAM_SVC_PART_SCAN: + *data++ = 0x00; // Service Partition Scan + break; + case PARAM_BOOT_FLAG_CLR: + *data++ = 0x00; // BMC Boot Flag Valid Bit Clear + break; + case PARAM_BOOT_INFO_ACK: + *data++ = 0x00; // Write Mask + *data++ = 0x00; // Boot Initiator Ack Data + break; + case PARAM_BOOT_FLAGS: + *data++ = 0x00; // Boot Flags + *data++ = 0x00; // Boot Device Selector + *data++ = 0x00; // Firmwaer Verbosity + *data++ = 0x00; // BIOS Override + *data++ = 0x00; // Device Instance Selector + break; + case PARAM_BOOT_INIT_INFO: + *data++ = 0x00; // Chanel Number + *data++ = 0x00; // Session ID (4 bytes) + *data++ = 0x00; + *data++ = 0x00; + *data++ = 0x00; + *data++ = 0x00; // Boot Info Timestamp (4 bytes) + *data++ = 0x00; + *data++ = 0x00; + *data++ = 0x00; + break; + deault: + res->cc = CC_PARAM_OUT_OF_RANGE; + break; + } + + if (res->cc == CC_SUCCESS) { + *res_len = data - &res->data[0]; + } +} + +// 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_req_t *req = (ipmi_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 (response, res_len); + break; + case CMD_CHASSIS_GET_BOOT_OPTIONS: + chassis_get_boot_options (request, response, res_len); + break; + default: + res->cc = CC_INVALID_CMD; + break; + } + pthread_mutex_unlock(&m_chassis); +} + +/* + * Function(s) to handle IPMI messages with NetFn: Application + */ +// Get Device ID (IPMI/Section 20.1) +static void +app_get_device_id (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 platform + *data++ = 0x20; // Device ID + *data++ = 0x81; // Device Revision + *data++ = 0x00; // Firmware Revision Major + *data++ = 0x09; // 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++ = 0x00; // Aux. Firmware Version1 + *data++ = 0x00; // Aux. Firmware Version2 + *data++ = 0x00; // Aux. Firmware Version3 + *data++ = 0x00; // Aux. Firmware Version4 + + *res_len = data - &res->data[0]; +} + +// Get Self Test Results (IPMI/Section 20.4) +static void +app_get_selftest_results (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]; +} + +// Get Device GUID (IPMI/Section 20.8) +static void +app_get_device_guid (unsigned char *response, unsigned char *res_len) +{ + ipmi_res_t *res = (ipmi_res_t *) response; + unsigned char *data = &res->data[0]; + + res->cc = 0x00; + + // TODO: Following data is Globaly Unique ID i.e. MAC Address.. + *data++ = 0x0; + *data++ = 0x1; + *data++ = 0x2; + *data++ = 0x3; + *data++ = 0x4; + *data++ = 0x5; + *data++ = 0x6; + *data++ = 0x7; + *data++ = 0x8; + *data++ = 0x9; + *data++ = 0xa; + *data++ = 0xb; + *data++ = 0xc; + *data++ = 0xd; + *data++ = 0xe; + *data++ = 0xf; + + *res_len = data - &res->data[0]; +} + +// Get BMC Global Enables (IPMI/Section 22.2) +static void +app_get_global_enables (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; + + *data++ = 0x09; // Global Enable + + *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 *response, + unsigned char *res_len) +{ + + ipmi_req_t *req = (ipmi_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); + 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; + 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 *response, + unsigned char *res_len) +{ + + ipmi_req_t *req = (ipmi_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 + + switch (param) + { + case SYS_INFO_PARAM_SET_IN_PROG: + *data++ = g_sys_info_params.set_in_prog; + break; + case SYS_INFO_PARAM_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; + default: + res->cc = CC_INVALID_PARAM; + break; + } + + if (res->cc == CC_SUCCESS) { + *res_len = data - &res->data[0]; + } + + return; +} + +// 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_req_t *req = (ipmi_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 (response, res_len); + break; + case CMD_APP_GET_SELFTEST_RESULTS: + app_get_selftest_results (response, res_len); + break; + case CMD_APP_GET_DEVICE_GUID: + case CMD_APP_GET_SYSTEM_GUID: + // Get Device GUID and Get System GUID returns same data + // from IPMI stack. FYI, Get System GUID will have to be + // sent with in an IPMI session that includes session info + app_get_device_guid (response, res_len); + break; + case CMD_APP_GET_GLOBAL_ENABLES: + app_get_global_enables (response, res_len); + break; + case CMD_APP_SET_SYS_INFO_PARAMS: + app_set_sys_info_params (request, response, res_len); + break; + case CMD_APP_GET_SYS_INFO_PARAMS: + app_get_sys_info_params (request, 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 *response, unsigned char *res_len) +{ + ipmi_res_t *res = (ipmi_res_t *) response; + unsigned char *data = &res->data[0]; + int size = plat_fruid_size(); + + 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_req_t *req = (ipmi_req_t *) request; + ipmi_res_t *res = (ipmi_res_t *) response; + unsigned char *data = &res->data[0]; + + int offset = req->data[1] + (req->data[2] << 8); + int count = req->data[3]; + + int ret = plat_fruid_data(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) { + *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 = plat_sdr_num_entries (); + free_space = plat_sdr_free_space (); + plat_sdr_ts_recent_add (&ts_recent_add); + plat_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 *response, unsigned char *res_len) +{ + 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 = plat_sdr_rsv_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_req_t *req = (ipmi_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 = plat_sdr_get_entry (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 *response, unsigned char *res_len) +{ + 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 = plat_sel_num_entries (); + free_space = plat_sel_free_space (); + plat_sel_ts_recent_add (&ts_recent_add); + plat_sel_ts_recent_erase (&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 *response, unsigned char *res_len) +{ + 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 = plat_sel_rsv_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_req_t *req = (ipmi_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; + + read_rec_id = (req->data[3] >> 8) | req->data[2]; + + // Use platform API to read the record Id and get next ID + ret = plat_sel_get_entry (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, SIZE_SEL_REC); + data += SIZE_SEL_REC; + + *res_len = data - &res->data[0]; + + return; +} + +static void +storage_add_sel (unsigned char *request, unsigned char *response, + unsigned char *res_len) +{ + ipmi_req_t *req = (ipmi_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 = plat_sel_add_entry (&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_req_t *req = (ipmi_req_t *) request; + ipmi_res_t *res = (ipmi_res_t *) response; + unsigned char *data = &res->data[0]; + + sel_erase_stat_t status; + 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 = plat_sel_erase (rsv_id); + } + else if (req->data[5] == IPMI_SEL_ERASE_STAT) + { + ret = plat_sel_erase_status (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; +} + +static void +ipmi_handle_storage (unsigned char *request, unsigned char req_len, + unsigned char *response, unsigned char *res_len) +{ + ipmi_req_t *req = (ipmi_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 (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 (response, res_len); + break; + case CMD_STORAGE_RSV_SEL: + storage_rsv_sel (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; + case CMD_STORAGE_GET_SDR_INFO: + storage_get_sdr_info (response, res_len); + break; + case CMD_STORAGE_RSV_SDR: + storage_rsv_sdr (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_req_t *req = (ipmi_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; + 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_req_t *req = (ipmi_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 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: + 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: + 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; + 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_req_t *req = (ipmi_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; + default: + res->cc = CC_INVALID_CMD; + break; + } + pthread_mutex_unlock(&m_transport); +} + +/* + * Function(s) to handle IPMI messages with NetFn: OEM + */ + +static void +oem_set_proc_info (unsigned char *request, unsigned char *response, + unsigned char *res_len) +{ + ipmi_req_t *req = (ipmi_req_t *) request; + ipmi_res_t *res = (ipmi_res_t *) response; + + g_proc_info.type = req->data[1]; + g_proc_info.freq[0] = req->data[2]; + g_proc_info.freq[1] = req->data[3]; + + res->cc = CC_SUCCESS; + *res_len = 0; +} + +static void +oem_set_dimm_info (unsigned char *request, unsigned char *response, + unsigned char *res_len) +{ + ipmi_req_t *req = (ipmi_req_t *) request; + ipmi_res_t *res = (ipmi_res_t *) response; + + unsigned char index = req->data[0]; + + g_dimm_info[index].type = req->data[1]; + g_dimm_info[index].speed[0] = req->data[2]; + g_dimm_info[index].speed[1] = req->data[3]; + g_dimm_info[index].size[0] = req->data[4]; + g_dimm_info[index].size[1] = req->data[5]; + + res->cc = CC_SUCCESS; + *res_len = 0; +} + +static void +oem_set_post_start (unsigned char *response, unsigned char *res_len) +{ + + ipmi_res_t *res = (ipmi_res_t *) response; + + // TODO: For now logging the event, need to find usage for this info + syslog (LOG_INFO, "POST Start Event\n"); + + res->cc = CC_SUCCESS; + *res_len = 0; +} + +static void +oem_set_post_end (unsigned char *response, unsigned char *res_len) +{ + + ipmi_res_t *res = (ipmi_res_t *) response; + + // TODO: For now logging the event, need to find usage for this info + syslog (LOG_INFO, "POST End Event\n"); + + res->cc = CC_SUCCESS; + *res_len = 0; +} + +static void +ipmi_handle_oem (unsigned char *request, unsigned char req_len, + unsigned char *response, unsigned char *res_len) +{ + + ipmi_req_t *req = (ipmi_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_SET_PROC_INFO: + oem_set_proc_info (request, response, res_len); + break; + case CMD_OEM_SET_DIMM_INFO: + oem_set_dimm_info (request, response, res_len); + break; + case CMD_OEM_SET_POST_START: + oem_set_post_start (response, res_len); + break; + case CMD_OEM_SET_POST_END: + oem_set_post_end (response, res_len); + break; + default: + res->cc = CC_INVALID_CMD; + break; + } + pthread_mutex_unlock(&m_oem); +} + +/* + * 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_req_t *req = (ipmi_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 + *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_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_OEM_REQ: + res->netfn_lun = NETFN_OEM_RES << 2; + ipmi_handle_oem (request, req_len, response, res_len); + break; + default: + res->netfn_lun = (netfn + 1) << 2; + break; + } + + // This header includes NetFunction, Command, and Completion Code + *res_len += SIZE_IPMI_RES_HDR; + + return; +} + +void +*conn_handler(void *socket_desc) { + int sock = *(int*)socket_desc; + int n; + unsigned char req_buf[MAX_IPMI_MSG_SIZE]; + unsigned char res_buf[MAX_IPMI_MSG_SIZE]; + unsigned char res_len = 0; + + n = recv (sock, req_buf, sizeof(req_buf), 0); + if (n <= 0) { + syslog(LOG_ALERT, "ipmid: recv() failed with %d\n", n); + goto conn_cleanup; + } + + ipmi_handle(req_buf, n, res_buf, &res_len); + + if (send (sock, res_buf, res_len, 0) < 0) { + syslog(LOG_ALERT, "ipmid: send() failed\n"); + } + +conn_cleanup: + close(sock); + + pthread_exit(NULL); + return 0; +} + + +int +main (void) +{ + int s, s2, t, len; + struct sockaddr_un local, remote; + pthread_t tid; + + daemon(1, 0); + openlog("ipmid", LOG_CONS, LOG_DAEMON); + + plat_sel_init(); + plat_sensor_init(); + plat_sdr_init(); + plat_fruid_init(); + + pthread_mutex_init(&m_chassis, 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); + + if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) + { + syslog(LOG_ALERT, "ipmid: socket() failed\n"); + exit (1); + } + + local.sun_family = AF_UNIX; + strcpy (local.sun_path, SOCK_PATH); + unlink (local.sun_path); + len = strlen (local.sun_path) + sizeof (local.sun_family); + if (bind (s, (struct sockaddr *) &local, len) == -1) + { + syslog(LOG_ALERT, "ipmid: bind() failed\n"); + exit (1); + } + + if (listen (s, 5) == -1) + { + syslog(LOG_ALERT, "ipmid: listen() failed\n"); + exit (1); + } + + while(1) { + int n; + t = sizeof (remote); + if ((s2 = accept (s, (struct sockaddr *) &remote, &t)) < 0) { + syslog(LOG_ALERT, "ipmid: accept() failed\n"); + break; + } + + // Creating a worker thread to handle the request + // TODO: Need to monitor the server performance with higher load and + // see if we need to create pre-defined number of workers and schedule + // the requests among them. + if (pthread_create(&tid, NULL, conn_handler, (void*) &s2) < 0) { + syslog(LOG_ALERT, "ipmid: pthread_create failed\n"); + close(s2); + continue; + } + + pthread_detach(tid); + } + + close(s); + + pthread_mutex_destroy(&m_chassis); + pthread_mutex_destroy(&m_app); + pthread_mutex_destroy(&m_storage); + pthread_mutex_destroy(&m_transport); + pthread_mutex_destroy(&m_oem); + + return 0; +} diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/fruid.h b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/fruid.h new file mode 100644 index 0000000..3580b08 --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/fruid.h @@ -0,0 +1,28 @@ +/* + * + * Copyright 2015-present Facebook. All Rights Reserved. + * + * + * 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. + */ + +#ifndef __FRUID_H__ +#define __FRUID_H__ + +int plat_fruid_size(void); +int plat_fruid_data(int offset, int count, unsigned char *data); +int plat_fruid_init(void); + +#endif /* __FRUID_H__ */ diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sdr.c b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sdr.c new file mode 100644 index 0000000..e0a2f9a --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sdr.c @@ -0,0 +1,412 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * This file represents platform specific implementation for storing + * SDR record entries and acts as back-end for IPMI stack + * + * + * 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 "sensor.h" +#include "timestamp.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> + +// SDR Header magic number +#define SDR_HDR_MAGIC 0xFBFBFBFB + +// SDR Header version number +#define SDR_HDR_VERSION 0x01 + +// SDR reservation IDs can not be 0x00 or 0xFFFF +#define SDR_RSVID_MIN 0x01 +#define SDR_RSVID_MAX 0xFFFE + +#define SDR_RECORDS_MAX 64 // to support around 64 sensors + +// SDR index to keep track +#define SDR_INDEX_MIN 0 +#define SDR_INDEX_MAX (SDR_RECORDS_MAX - 1) + +// Record ID can not be 0x0 (IPMI/Section 31) +#define SDR_RECID_MIN 1 +#define SDR_RECID_MAX SDR_RECORDS_MAX + +// Special RecID value for first and last (IPMI/Section 31) +#define SDR_RECID_FIRST 0x0000 +#define SDR_RECID_LAST 0xFFFF + +#define SDR_VERSION 0x51 +#define SDR_LEN_MAX 64 + +#define SDR_FULL_TYPE 0x01 +#define SDR_MGMT_TYPE 0x12 +#define SDR_OEM_TYPE 0xC0 + +#define SDR_FULL_LEN 64 +#define SDR_MGMT_LEN 32 +#define SDR_OEM_LEN 64 + +// SDR header struct to keep track of SEL Log entries +typedef struct { + int magic; // Magic number to check validity + int version; // version number of this header + int begin; // index to the first SDR entry + int end; // index to the last SDR entry + time_stamp_t ts_add; // last addition time stamp + time_stamp_t ts_erase; // last erase time stamp +} sdr_hdr_t; + +// Keep track of last Reservation ID +static int g_rsv_id = 0x01; + +// SDR Header and data global structures +static sdr_hdr_t g_sdr_hdr; +static sdr_rec_t g_sdr_data[SDR_RECORDS_MAX]; + +// Add a new SDR entry +static int +plat_sdr_add_entry(sdr_rec_t *rec, int *rec_id) { + // If SDR is full, return error + if (plat_sdr_num_entries() == SDR_RECORDS_MAX) { + syslog(LOG_ALERT, "plat_sdr_add_entry: SDR full\n"); + return -1; + } + + // Add Record ID which is array index + 1 + rec->rec[0] = g_sdr_hdr.end+1; + + // Add the enry at end + memcpy(g_sdr_data[g_sdr_hdr.end].rec, rec->rec, sizeof(sdr_rec_t)); + + // Return the newly added record ID + *rec_id = g_sdr_hdr.end+1; + + // Increment the end pointer + ++g_sdr_hdr.end; + + // Update timestamp for add in header + time_stamp_fill(g_sdr_hdr.ts_add.ts); + + return 0; +} + +static int +sdr_add_mgmt_rec(sensor_mgmt_t *p_rec) { + int rec_id = 0; + sdr_rec_t sdr = { 0 }; + sdr_mgmt_t rec = { 0 }; + + // Populate SDR MGMT record + rec.ver = SDR_VERSION; + rec.type = SDR_MGMT_TYPE; + rec.len = SDR_MGMT_LEN; + + rec.slave_addr = p_rec->slave_addr; + rec.chan_no = p_rec->chan_no; + + rec.pwr_state_init = p_rec->pwr_state_init; + rec.dev_caps = p_rec->dev_caps; + rec.ent_id = p_rec->ent_id; + rec.ent_inst = p_rec->ent_inst; + rec.oem = p_rec->oem; + rec.str_type_len = p_rec->str_type_len; + memcpy(rec.str, p_rec->str, SENSOR_STR_SIZE); + + // Copy this record to generic SDR record + memcpy(sdr.rec, &rec, SDR_LEN_MAX); + + // Add this record to SDR repo + if (plat_sdr_add_entry(&sdr, &rec_id)) { + syslog(LOG_ALERT, "sdr_add_mgmt_rec: plat_sdr_add_entry failed\n"); + return -1; + } + + return 0; +} + +static int +sdr_add_disc_rec(sensor_disc_t *p_rec) { + int rec_id = 0; + sdr_rec_t sdr = { 0 }; + sdr_full_t rec = { 0 }; + + // Populate SDR FULL record + rec.ver = SDR_VERSION; + rec.type = SDR_FULL_TYPE; + rec.len = SDR_FULL_LEN; + + rec.owner = p_rec->owner; + rec.lun = p_rec->lun; + + rec.ent_id = p_rec->ent_id; + rec.ent_inst = p_rec->ent_inst; + rec.sensor_init = p_rec->sensor_init; + rec.sensor_caps = p_rec->sensor_caps; + rec.sensor_type = p_rec->sensor_type; + rec.evt_read_type = p_rec->evt_read_type; + memcpy(rec.assert_evt_mask, p_rec->assert_evt_mask, 2); + memcpy(rec.deassert_evt_mask, p_rec->deassert_evt_mask, 2); + memcpy(rec.read_evt_mask, p_rec->read_evt_mask, 2); + rec.oem = p_rec->oem; + rec.str_type_len = p_rec->str_type_len; + memcpy(rec.str, p_rec->str, SENSOR_STR_SIZE); + + // Copy this record to generic SDR record + memcpy(sdr.rec, &rec, SDR_LEN_MAX); + + // Add this record to SDR repo + if (plat_sdr_add_entry(&sdr, &rec_id)) { + syslog(LOG_ALERT, "sdr_add_disc_rec: plat_sdr_add_entry failed\n"); + return -1; + } + + return 0; +} + +static int +sdr_add_thresh_rec(sensor_thresh_t *p_rec) { + int rec_id = 0; + sdr_rec_t sdr = { 0 }; + sdr_full_t rec = { 0 }; + + // Populate SDR FULL record + rec.ver = SDR_VERSION; + rec.type = SDR_FULL_TYPE; + rec.len = SDR_FULL_LEN; + + rec.owner = p_rec->owner; + rec.lun = p_rec->lun; + + rec.ent_id = p_rec->ent_id; + rec.ent_inst = p_rec->ent_inst; + rec.sensor_init = p_rec->sensor_init; + rec.sensor_caps = p_rec->sensor_caps; + rec.sensor_type = p_rec->sensor_type; + rec.evt_read_type = p_rec->evt_read_type; + memcpy(rec.lt_read_mask, p_rec->lt_read_mask, 2); + memcpy(rec.ut_read_mask, p_rec->ut_read_mask, 2); + memcpy(rec.set_thresh_mask, p_rec->set_thresh_mask, 2); + rec.sensor_units1 = p_rec->sensor_units1; + rec.sensor_units2 = p_rec->sensor_units2; + rec.sensor_units3 = p_rec->sensor_units3; + rec.linear = p_rec->linear; + rec.m_val = p_rec->m_val; + rec.m_tolerance = p_rec->m_tolerance; + rec.b_val = p_rec->b_val; + rec.b_accuracy = p_rec->b_accuracy; + rec.analog_flags = p_rec->analog_flags; + rec.nominal = p_rec->nominal; + rec.normal_max = p_rec->normal_max; + rec.normal_min = p_rec->normal_min; + rec.max_reading = p_rec->max_reading; + rec.min_reading = p_rec->min_reading; + rec.unr_thresh = p_rec->unr_thresh; + rec.uc_thresh = p_rec->uc_thresh; + rec.unc_thresh = p_rec->unc_thresh; + rec.lnr_thresh = p_rec->lnr_thresh; + rec.lc_thresh = p_rec->lc_thresh; + rec.lnc_thresh = p_rec->lnc_thresh; + rec.pos_hyst = p_rec->pos_hyst; + rec.neg_hyst = p_rec->neg_hyst; + rec.oem = p_rec->oem; + rec.str_type_len = p_rec->str_type_len; + memcpy(rec.str, p_rec->str, SENSOR_STR_SIZE); + + // Copy this record to generic SDR record + memcpy(sdr.rec, &rec, SDR_LEN_MAX); + + // Add this record to SDR repo + if (plat_sdr_add_entry(&sdr, &rec_id)) { + syslog(LOG_ALERT, "sdr_add_thresh_rec: plat_sdr_add_entry failed\n"); + return -1; + } + + return 0; +} + +static int +sdr_add_oem_rec(sensor_oem_t *p_rec) { + int rec_id = 0; + sdr_rec_t sdr = { 0 }; + sdr_oem_t rec = { 0 }; + + // Populate SDR OEM record + rec.ver = SDR_VERSION; + rec.type = SDR_OEM_TYPE; + rec.len = SDR_OEM_LEN; + + memcpy(rec.mfr_id, p_rec->mfr_id, 3); + memcpy(rec.oem_data, p_rec->oem_data, SENSOR_OEM_DATA_SIZE); + + // Copy this record to generic SDR record + memcpy(sdr.rec, &rec, SDR_LEN_MAX); + + // Add this record to SDR repo + if (plat_sdr_add_entry(&sdr, &rec_id)) { + syslog(LOG_ALERT, "sdr_add_oem_rec: plat_sdr_add_entry failed\n"); + return -1; + } + + return 0; +} + +// Platform specific SEL API entry points +// Retrieve time stamp for recent add operation +void +plat_sdr_ts_recent_add(time_stamp_t *ts) { + memcpy(ts->ts, g_sdr_hdr.ts_add.ts, 0x04); +} + +// Retrieve time stamp for recent erase operation +void +plat_sdr_ts_recent_erase(time_stamp_t *ts) { + memcpy(ts->ts, g_sdr_hdr.ts_erase.ts, 0x04); +} + +// Retrieve total number of entries in SDR repo +int +plat_sdr_num_entries(void) { + return (g_sdr_hdr.end - g_sdr_hdr.begin); +} + +// Retrieve total free space available in SDR repo +int +plat_sdr_free_space(void) { + int total_space; + int used_space; + + total_space = SDR_RECORDS_MAX * sizeof(sdr_rec_t); + used_space = plat_sdr_num_entries() * sizeof(sdr_rec_t); + + return (total_space - used_space); +} + +// Reserve an ID that will be used in later operations +// IPMI/Section 33.11 +int +plat_sdr_rsv_id() { + // Increment the current reservation ID and return + if (g_rsv_id++ == SDR_RSVID_MAX) { + g_rsv_id = SDR_RSVID_MIN; + } + + return g_rsv_id; +} + +// Get the SDR entry for a given record ID +// IPMI/Section 33.12 +int +plat_sdr_get_entry(int rsv_id, int read_rec_id, sdr_rec_t *rec, + int *next_rec_id) { + + int index; + + // Make sure the rsv_id matches + if (rsv_id != g_rsv_id) { + syslog(LOG_ALERT, "plat_sdr_get_entry: Reservation ID mismatch\n"); + return -1; + } + + // Find the index in to array based on given index + if (read_rec_id == SDR_RECID_FIRST) { + index = g_sdr_hdr.begin; + } else if (read_rec_id == SDR_RECID_LAST) { + index = g_sdr_hdr.end - 1; + } else { + index = read_rec_id - 1; + } + + // If the SDR repo is empty return error + if (plat_sdr_num_entries() == 0) { + syslog(LOG_ALERT, "plat_sdr_get_entry: No entries\n"); + return -1; + } + + // Check for boundary conditions + if ((index < SDR_INDEX_MIN) || (index > SDR_INDEX_MAX)) { + syslog(LOG_ALERT, "plat_sdr_get_entry: Invalid Record ID %d\n", read_rec_id); + return -1; + } + + // Check to make sure the given id is valid + if (index < g_sdr_hdr.begin || index >= g_sdr_hdr.end) { + syslog(LOG_ALERT, "plat_sdr_get_entry: Wrong Record ID %d\n", read_rec_id); + return -1; + } + + memcpy(rec->rec, g_sdr_data[index].rec, sizeof(sdr_rec_t)); + + // Return the next record ID in the log + *next_rec_id = ++read_rec_id; + + // If this is the last entry in the log, return 0xFFFF + if (*next_rec_id == g_sdr_hdr.end) { + *next_rec_id = SDR_RECID_LAST; + } + + return 0; +} + + +// Initialize SDR Repo structure +int +plat_sdr_init(void) { + int num; + sensor_mgmt_t *p_mgmt; + sensor_thresh_t *p_thresh; + sensor_disc_t *p_disc; + sensor_oem_t *p_oem; + + // Populate SDR Header + g_sdr_hdr.magic = SDR_HDR_MAGIC; + g_sdr_hdr.version = SDR_HDR_VERSION; + g_sdr_hdr.begin = SDR_INDEX_MIN; + g_sdr_hdr.end = SDR_INDEX_MIN; + memset(g_sdr_hdr.ts_add.ts, 0x0, 4); + memset(g_sdr_hdr.ts_erase.ts, 0x0, 4); + + // Populate all mgmt control sensors + plat_sensor_mgmt_info(&num, &p_mgmt); + for (int i = 0; i < num; i++) { + sdr_add_mgmt_rec(&p_mgmt[i]); + } + + // Populate all discrete sensors + plat_sensor_disc_info(&num, &p_disc); + for (int i = 0; i < num; i++) { + sdr_add_disc_rec(&p_disc[i]); + } + + // Populate all threshold sensors + plat_sensor_thresh_info(&num, &p_thresh); + for (int i = 0; i < num; i++) { + sdr_add_thresh_rec(&p_thresh[i]); + } + + // Populate all OEM sensors + plat_sensor_oem_info(&num, &p_oem); + for (int i = 0; i < num; i++) { + sdr_add_oem_rec(&p_oem[i]); + } + + return 0; +} diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sdr.h b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sdr.h new file mode 100644 index 0000000..5e2a591 --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sdr.h @@ -0,0 +1,132 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * + * 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. + */ + +#ifndef __SDR_H__ +#define __SDR_H__ + +#include "timestamp.h" + +typedef struct { + unsigned char rec[64]; +} sdr_rec_t; + +// Full Sensor SDR record; IPMI/Section 43.1 +typedef struct { + // Sensor Record Header + unsigned char rec_id[2]; + unsigned char ver; + unsigned char type; + unsigned char len; + // Record Key Bytes + unsigned char owner; + unsigned char lun; + unsigned char sensor_num; + // Record Body Bytes + unsigned char ent_id; + unsigned char ent_inst; + unsigned char sensor_init; + unsigned char sensor_caps; + unsigned char sensor_type; + unsigned char evt_read_type; + union { + unsigned char assert_evt_mask[2]; + unsigned char lt_read_mask[2]; + }; + union { + unsigned char deassert_evt_mask[2]; + unsigned char ut_read_mask[2]; + }; + union { + unsigned char read_evt_mask[2]; + unsigned char set_thresh_mask[2]; + }; + unsigned char sensor_units1; + unsigned char sensor_units2; + unsigned char sensor_units3; + unsigned char linear; + unsigned char m_val; + unsigned char m_tolerance; + unsigned char b_val; + unsigned char b_accuracy; + unsigned char accuracy_dir; + unsigned char rb_exp; + unsigned char analog_flags; + unsigned char nominal; + unsigned char normal_max; + unsigned char normal_min; + unsigned char max_reading; + unsigned char min_reading; + unsigned char unr_thresh; + unsigned char uc_thresh; + unsigned char unc_thresh; + unsigned char lnr_thresh; + unsigned char lc_thresh; + unsigned char lnc_thresh; + unsigned char pos_hyst; + unsigned char neg_hyst; + unsigned char rsvd[2]; + unsigned char oem; + unsigned char str_type_len; + char str[16]; +} sdr_full_t; + +// Mgmt. Controller SDR record; IPMI/ Section 43.9 +typedef struct { + // Sensor Record Header + unsigned char rec_id[2]; + unsigned char ver; + unsigned char type; + unsigned char len; + // Record Key Bytes + unsigned char slave_addr; + unsigned char chan_no; + // Record Body Bytes + unsigned char pwr_state_init; + unsigned char dev_caps; + unsigned char rsvd[3]; + unsigned char ent_id; + unsigned char ent_inst; + unsigned char oem; + unsigned char str_type_len; + char str[16]; +} sdr_mgmt_t; + +// OEM type SDR record; IPMI/Section 43.12 +typedef struct { + // Sensor Record Header + unsigned char rec_id[2]; + unsigned char ver; + unsigned char type; + unsigned char len; + // Record Body Bytes + unsigned char mfr_id[3]; + unsigned char oem_data[56]; +} sdr_oem_t; + +void plat_sdr_ts_recent_add(time_stamp_t *ts); +void plat_sdr_ts_recent_erase(time_stamp_t *ts); +int plat_sdr_num_entries(void); +int plat_sdr_free_space(void); +int plat_sdr_rsv_id(); +int plat_sdr_get_entry(int rsv_id, int read_rec_id, sdr_rec_t *rec, + int *next_rec_id); +int plat_sdr_init(void); + +#endif /* __SDR_H__ */ diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sel.c b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sel.c new file mode 100644 index 0000000..a7aa78f --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sel.c @@ -0,0 +1,438 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * This file represents platform specific implementation for storing + * SEL logs and acts as back-end for IPMI stack + * + * TODO: Optimize the file handling to keep file open always instead of + * current open/seek/close + * + * + * 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 "sel.h" +#include "timestamp.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> + +// SEL File. +#define SEL_LOG_FILE "/mnt/data/sel.bin" + +// SEL Header magic number +#define SEL_HDR_MAGIC 0xFBFBFBFB + +// SEL Header version number +#define SEL_HDR_VERSION 0x01 + +// SEL Data offset from file beginning +#define SEL_DATA_OFFSET 0x100 + +// SEL reservation IDs can not be 0x00 or 0xFFFF +#define SEL_RSVID_MIN 0x01 +#define SEL_RSVID_MAX 0xFFFE + +// Number of SEL records before wrap +#define SEL_RECORDS_MAX 128 // TODO: Based on need we can make it bigger +#define SEL_ELEMS_MAX (SEL_RECORDS_MAX+1) + +// Index for circular array +#define SEL_INDEX_MIN 0x00 +#define SEL_INDEX_MAX SEL_RECORDS_MAX + +// Record ID can not be 0x0 (IPMI/Section 31) +#define SEL_RECID_MIN (SEL_INDEX_MIN+1) +#define SEL_RECID_MAX (SEL_INDEX_MAX+1) + +// Special RecID value for first and last (IPMI/Section 31) +#define SEL_RECID_FIRST 0x0000 +#define SEL_RECID_LAST 0xFFFF + +// SEL header struct to keep track of SEL Log entries +typedef struct { + int magic; // Magic number to check validity + int version; // version number of this header + int begin; // index to the begining of the log + int end; // index to end of the log + time_stamp_t ts_add; // last addition time stamp + time_stamp_t ts_erase; // last erase time stamp +} sel_hdr_t; + +// Keep track of last Reservation ID +static int g_rsv_id = 0x01; + +// Cached version of SEL Header and data +static sel_hdr_t g_sel_hdr; +static sel_msg_t g_sel_data[SEL_ELEMS_MAX]; + +// Local helper functions to interact with file system +static int +file_get_sel_hdr(void) { + FILE *fp; + + fp = fopen(SEL_LOG_FILE, "r"); + if (fp == NULL) { + return -1; + } + + if (fread(&g_sel_hdr, sizeof(sel_hdr_t), 1, fp) <= 0) { + syslog(LOG_ALERT, "file_get_sel_hdr: fread\n"); + fclose (fp); + return -1; + } + + fclose(fp); + return 0; +} + +static int +file_get_sel_data(void) { + FILE *fp; + + fp = fopen(SEL_LOG_FILE, "r"); + if (fp == NULL) { + syslog(LOG_ALERT, "file_get_sel_data: fopen\n"); + return -1; + } + + if (fseek(fp, SEL_DATA_OFFSET, SEEK_SET)) { + syslog(LOG_ALERT, "file_get_sel_data: fseek\n"); + fclose(fp); + return -1; + } + + unsigned char buf[SEL_ELEMS_MAX * 16]; + if (fread(buf, 1, SEL_ELEMS_MAX * sizeof(sel_msg_t), fp) <= 0) { + syslog(LOG_ALERT, "file_get_sel_data: fread\n"); + fclose(fp); + return -1; + } + + fclose(fp); + + for (int i = 0; i < SEL_ELEMS_MAX; i++) { + for (int j = 0; j < sizeof(sel_msg_t);j++) { + g_sel_data[i].msg[j] = buf[i*16 + j]; + } + } + + return 0; +} + +static int +file_store_sel_hdr(void) { + FILE *fp; + + fp = fopen(SEL_LOG_FILE, "r+"); + if (fp == NULL) { + syslog(LOG_ALERT, "file_store_sel_hdr: fopen\n"); + return -1; + } + + if (fwrite(&g_sel_hdr, sizeof(sel_hdr_t), 1, fp) <= 0) { + syslog(LOG_ALERT, "file_store_sel_hdr: fwrite\n"); + fclose(fp); + return -1; + } + + fclose(fp); + + return 0; +} + +static int +file_store_sel_data(int recId, sel_msg_t *data) { + FILE *fp; + int index; + + fp = fopen(SEL_LOG_FILE, "r+"); + if (fp == NULL) { + syslog(LOG_ALERT, "file_store_sel_data: fopen\n"); + return -1; + } + + // Records are stored using zero-based index + index = (recId-1) * sizeof(sel_msg_t); + + if (fseek(fp, SEL_DATA_OFFSET+index, SEEK_SET)) { + syslog(LOG_ALERT, "file_store_sel_data: fseek\n"); + fclose(fp); + return -1; + } + + if (fwrite(data->msg, sizeof(sel_msg_t), 1, fp) <= 0) { + syslog(LOG_ALERT, "file_store_sel_data: fwrite\n"); + fclose(fp); + return -1; + } + + fclose(fp); + + return 0; +} + +// Platform specific SEL API entry points +// Retrieve time stamp for recent add operation +void +plat_sel_ts_recent_add(time_stamp_t *ts) { + memcpy(ts->ts, g_sel_hdr.ts_add.ts, 0x04); +} + +// Retrieve time stamp for recent erase operation +void +plat_sel_ts_recent_erase(time_stamp_t *ts) { + memcpy(ts->ts, g_sel_hdr.ts_erase.ts, 0x04); +} + +// Retrieve total number of entries in SEL log +int +plat_sel_num_entries(void) { + if (g_sel_hdr.begin <= g_sel_hdr.end) { + return (g_sel_hdr.end - g_sel_hdr.begin); + } else { + return (g_sel_hdr.end + (SEL_INDEX_MAX - g_sel_hdr.begin + 1)); + } +} + +// Retrieve total free space available in SEL log +int +plat_sel_free_space(void) { + int total_space; + int used_space; + + total_space = SEL_RECORDS_MAX * sizeof(sel_msg_t); + used_space = plat_sel_num_entries() * sizeof(sel_msg_t); + + return (total_space - used_space); +} + +// Reserve an ID that will be used in later operations +// IPMI/Section 31.4 +int +plat_sel_rsv_id() { + // Increment the current reservation ID and return + if (g_rsv_id++ == SEL_RSVID_MAX) { + g_rsv_id = SEL_RSVID_MIN; + } + + return g_rsv_id; +} + +// Get the SEL entry for a given record ID +// IPMI/Section 31.5 +int +plat_sel_get_entry(int read_rec_id, sel_msg_t *msg, int *next_rec_id) { + + int index; + + // Find the index in to array based on given index + if (read_rec_id == SEL_RECID_FIRST) { + index = g_sel_hdr.begin; + } else if (read_rec_id == SEL_RECID_LAST) { + if (g_sel_hdr.end) { + index = g_sel_hdr.end - 1; + } else { + index = SEL_INDEX_MAX; + } + } else { + index = read_rec_id - 1; + } + + // If the log is empty return error + if (plat_sel_num_entries() == 0) { + syslog(LOG_ALERT, "plat_sel_get_entry: No entries\n"); + return -1; + } + + // Check for boundary conditions + if ((index < SEL_INDEX_MIN) || (index > SEL_INDEX_MAX)) { + syslog(LOG_ALERT, "plat_sel_get_entry: Invalid Record ID %d\n", read_rec_id); + return -1; + } + + // If begin < end, check to make sure the given id falls between + if (g_sel_hdr.begin < g_sel_hdr.end) { + if (index < g_sel_hdr.begin || index >= g_sel_hdr.end) { + syslog(LOG_ALERT, "plat_sel_get_entry: Wrong Record ID %d\n", read_rec_id); + return -1; + } + } + + // If end < begin, check to make sure the given id is valid + if (g_sel_hdr.begin > g_sel_hdr.end) { + if (index >= g_sel_hdr.end && index < g_sel_hdr.begin) { + syslog(LOG_ALERT, "plat_sel_get_entry: Wrong Record ID2 %d\n", read_rec_id); + return -1; + } + } + + memcpy(msg->msg, g_sel_data[index].msg, sizeof(sel_msg_t)); + + // Return the next record ID in the log + *next_rec_id = read_rec_id++; + if (*next_rec_id > SEL_INDEX_MAX) { + *next_rec_id = SEL_INDEX_MIN; + } + + // If this is the last entry in the log, return 0xFFFF + if (*next_rec_id == g_sel_hdr.end) { + *next_rec_id = SEL_RECID_LAST; + } + + return 0; +} + +// Add a new entry in to SEL log +// IPMI/Section 31.6 +int +plat_sel_add_entry(sel_msg_t *msg, int *rec_id) { + // If the SEL if full, roll over. To keep track of empty condition, use + // one empty location less than the max records. + if (plat_sel_num_entries() == SEL_RECORDS_MAX) { + syslog(LOG_ALERT, "plat_sel_add_entry: SEL rollover\n"); + if (++g_sel_hdr.begin > SEL_INDEX_MAX) { + g_sel_hdr.begin = SEL_INDEX_MIN; + } + } + + // Update message's time stamp starting at byte 4 + time_stamp_fill(&msg->msg[3]); + + // Add the enry at end + memcpy(g_sel_data[g_sel_hdr.end].msg, msg->msg, sizeof(sel_msg_t)); + + // Return the newly added record ID + *rec_id = g_sel_hdr.end+1; + + if (file_store_sel_data(*rec_id, msg)) { + syslog(LOG_ALERT, "plat_sel_add_entry: file_store_sel_data\n"); + return -1; + } + + // Increment the end pointer + if (++g_sel_hdr.end > SEL_INDEX_MAX) { + g_sel_hdr.end = SEL_INDEX_MIN; + } + + // Update timestamp for add in header + time_stamp_fill(g_sel_hdr.ts_add.ts); + + // Store the structure persistently + if (file_store_sel_hdr()) { + syslog(LOG_ALERT, "plat_sel_add_entry: file_store_sel_hdr\n"); + return -1; + } + + return 0; +} + +// Erase the SEL completely +// IPMI/Section 31.9 +// Note: To reduce wear/tear, instead of erasing, manipulating the metadata +int +plat_sel_erase(int rsv_id) { + if (rsv_id != g_rsv_id) { + return -1; + } + + // Erase SEL Logs + g_sel_hdr.begin = SEL_INDEX_MIN; + g_sel_hdr.end = SEL_INDEX_MIN; + + // Update timestamp for erase in header + time_stamp_fill(g_sel_hdr.ts_erase.ts); + + // Store the structure persistently + if (file_store_sel_hdr()) { + syslog(LOG_ALERT, "plat_sel_erase: file_store_sel_hdr\n"); + return -1; + } + + return 0; +} + +// To get the erase status while erase happens +// IPMI/Section 31.2 +// Note: Since we are not doing offline erasing, need not return in-progress state +int +plat_sel_erase_status(int rsv_id, sel_erase_stat_t *status) { + if (rsv_id != g_rsv_id) { + return -1; + } + + // Since we do not do any offline erasing, always return erase done + *status = SEL_ERASE_DONE; + + return 0; +} + +// Initialize SEL log file +int +plat_sel_init(void) { + FILE *fp; + + // Check if the file exists or not + if (access(SEL_LOG_FILE, F_OK) == 0) { + // Since file is present, fetch all the contents to cache + if (file_get_sel_hdr()) { + syslog(LOG_ALERT, "plat_init_sel: file_get_sel_hdr\n"); + return -1; + } + + if (file_get_sel_data()) { + syslog(LOG_ALERT, "plat_init_sel: file_get_sel_data\n"); + return -1; + } + + return 0; + } + + // File not present, so create the file + fp = fopen(SEL_LOG_FILE, "w+"); + if (fp == NULL) { + syslog(LOG_ALERT, "plat_init_sel: fopen\n"); + return -1; + } + + fclose (fp); + + // Populate SEL Header in to the file + g_sel_hdr.magic = SEL_HDR_MAGIC; + g_sel_hdr.version = SEL_HDR_VERSION; + g_sel_hdr.begin = SEL_INDEX_MIN; + g_sel_hdr.end = SEL_INDEX_MIN; + memset(g_sel_hdr.ts_add.ts, 0x0, 4); + memset(g_sel_hdr.ts_erase.ts, 0x0, 4); + + if (file_store_sel_hdr()) { + syslog(LOG_ALERT, "plat_init_sel: file_store_sel_hdr\n"); + return -1; + } + + // Populate SEL Data in to the file + for (int i = 1; i <= SEL_RECORDS_MAX; i++) { + sel_msg_t msg = {0}; + if (file_store_sel_data(i, &msg)) { + syslog(LOG_ALERT, "plat_init_sel: file_store_sel_data\n"); + return -1; + } + } + + return 0; +} diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sel.h b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sel.h new file mode 100644 index 0000000..81dbcdf --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sel.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * + * 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. + */ + +#ifndef __SEL_H__ +#define __SEL_H__ + +#include "timestamp.h" + +enum { + IPMI_SEL_INIT_ERASE = 0xAA, + IPMI_SEL_ERASE_STAT = 0x00, +}; + +typedef enum { + SEL_ERASE_IN_PROG = 0x00, + SEL_ERASE_DONE = 0x01, +} sel_erase_stat_t; + +typedef struct { + unsigned char msg[16]; +} sel_msg_t; + +void plat_sel_ts_recent_add(time_stamp_t *ts); +void plat_sel_ts_recent_erase(time_stamp_t *ts); +int plat_sel_num_entries(void); +int plat_sel_free_space(void); +int plat_sel_rsv_id(); +int plat_sel_get_entry(int read_rec_id, sel_msg_t *msg, int *next_rec_id); +int plat_sel_add_entry(sel_msg_t *msg, int *rec_id); +int plat_sel_erase(int rsv_id); +int plat_sel_erase_status(int rsv_id, sel_erase_stat_t *status); +int plat_sel_init(void); + +#endif /* __SEL_H__ */ diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sensor.h b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sensor.h new file mode 100644 index 0000000..5d8c11a --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/sensor.h @@ -0,0 +1,117 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * + * 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. + */ + +#ifndef __SENSOR_H__ +#define __SENSOR_H__ + +#include "timestamp.h" + +#define IANA_ID_SIZE 3 +#define SENSOR_STR_SIZE 16 +#define SENSOR_OEM_DATA_SIZE 56 + +// Threshold Sensor Descriptor +typedef struct { + unsigned char owner; + unsigned char lun; + unsigned char sensor_num; + unsigned char ent_id; + unsigned char ent_inst; + unsigned char sensor_init; + unsigned char sensor_caps; + unsigned char sensor_type; + unsigned char evt_read_type; + unsigned char lt_read_mask[2]; + unsigned char ut_read_mask[2]; + unsigned char set_thresh_mask[2]; + unsigned char sensor_units1; + unsigned char sensor_units2; + unsigned char sensor_units3; + unsigned char linear; + unsigned char m_val; + unsigned char m_tolerance; + unsigned char b_val; + unsigned char b_accuracy; + unsigned char accuracy_dir; + unsigned char rb_exp; + unsigned char analog_flags; + unsigned char nominal; + unsigned char normal_max; + unsigned char normal_min; + unsigned char max_reading; + unsigned char min_reading; + unsigned char unr_thresh; + unsigned char uc_thresh; + unsigned char unc_thresh; + unsigned char lnr_thresh; + unsigned char lc_thresh; + unsigned char lnc_thresh; + unsigned char pos_hyst; + unsigned char neg_hyst; + unsigned char oem; + unsigned char str_type_len; + char str[SENSOR_STR_SIZE]; +} sensor_thresh_t; + +// Discrete Sensor Descriptor +typedef struct { + unsigned char owner; + unsigned char lun; + unsigned char sensor_num; + unsigned char ent_id; + unsigned char ent_inst; + unsigned char sensor_init; + unsigned char sensor_caps; + unsigned char sensor_type; + unsigned char evt_read_type; + unsigned char assert_evt_mask[2]; + unsigned char deassert_evt_mask[2]; + unsigned char read_evt_mask[2]; + unsigned char oem; + unsigned char str_type_len; + char str[SENSOR_STR_SIZE]; +} sensor_disc_t; + +// Mgmt. Controller Sensor Descriptor +typedef struct { + unsigned char slave_addr; + unsigned char chan_no; + unsigned char pwr_state_init; + unsigned char dev_caps; + unsigned char ent_id; + unsigned char ent_inst; + unsigned char oem; + unsigned char str_type_len; + char str[SENSOR_STR_SIZE]; +} sensor_mgmt_t; + +// OEM type Sensor Descriptor +typedef struct { + unsigned char mfr_id[IANA_ID_SIZE]; + unsigned char oem_data[SENSOR_OEM_DATA_SIZE]; +} sensor_oem_t; + +void plat_sensor_mgmt_info(int *num, sensor_mgmt_t **p_sensor); +void plat_sensor_disc_info(int *num, sensor_disc_t **p_sensor); +void plat_sensor_thresh_info(int *num, sensor_thresh_t **p_sensor); +void plat_sensor_oem_info(int *num, sensor_oem_t **p_sensor); +int plat_sensor_init(void); + +#endif /* __SENSOR_H__ */ diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/timestamp.c b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/timestamp.c new file mode 100644 index 0000000..11ac03e --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/timestamp.c @@ -0,0 +1,46 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * This file is a helper file to fill timestamps from platform + * used by SEL Logs, SDR records etc. + * + * 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> +#include <sys/time.h> +#include <time.h> + +// Local helper function to fill time stamp +void +time_stamp_fill(unsigned char *ts) { + unsigned int time; + struct timeval tv; + + gettimeofday(&tv, NULL); + + time = tv.tv_sec; + ts[0] = time & 0xFF; + ts[1] = (time >> 8) & 0xFF; + ts[2] = (time >> 16) & 0xFF; + ts[3] = (time >> 24) & 0xFF; + + return; +} diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/timestamp.h b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/timestamp.h new file mode 100644 index 0000000..430dd23 --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/timestamp.h @@ -0,0 +1,30 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * + * 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. + */ + +#ifndef __TIMESTAMP_H__ +#define __TIMESTAMP_H__ + +typedef struct { + unsigned char ts[4]; +} time_stamp_t; + +void time_stamp_fill(unsigned char *ts); + +#endif /* __TIMESTAMP_H__ */ diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/wedge/fruid.c b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/wedge/fruid.c new file mode 100644 index 0000000..5076ebe --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/wedge/fruid.c @@ -0,0 +1,185 @@ +/* + * + * Copyright 2015-present Facebook. All Rights Reserved. + * + * This file provides platform specific implementation of FRUID information + * + * FRUID specification can be found at + * www.intel.com/content/dam/www/public/us/en/documents/product-briefs/platform-management-fru-document-rev-1-2-feb-2013.pdf + * + * + * 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 "../fruid.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> +//#include <facebook/wedge_eeprom.h> + +#define WEDGE_FRUID_SIZE 0x100 + +#define COMMON_HDR_VER 1 +#define PROD_INFO_VER 1 + +#define PROD_INFO_AREA_OFFSET 0x10 +#define PROD_INFO_CKSUM_OFFSET (PROD_INFO_AREA_OFFSET + 1) +#define LANG_CODE_ENGLISH 25 +#define TYPE_STR 0xC0 +#define TYPE_LAST 0xC1 +#define ZERO_CKSUM_CONST 0x100 +#define LEN_BYTE_SIZE 8 + +typedef struct _fruid_common_hdr_t { + unsigned char ver; + unsigned char internal_use_area_offset; + unsigned char chassis_info_area_offset; + unsigned char board_info_area_offset; + unsigned char prod_info_area_offset; + unsigned char multi_record_area_offset; + unsigned char padding; + unsigned char cksum; +} fruid_common_hdr_t; + +// Global structures +static unsigned char g_fruid[WEDGE_FRUID_SIZE] = {0}; + +static void +populate_fruid(void) { + + memset(&g_fruid, sizeof(g_fruid), 0); + +#if 0 + fruid_common_hdr_t *chdr = g_fruid; + + // Set Common Header version + chdr->ver = COMMON_HDR_VER; + + // Product Info Area offset in multiples of 8 bytes + chdr->prod_info_area_offset = PROD_INFO_AREA_OFFSET/LEN_BYTE_SIZE; + + // Calculate zero checksum + chdr->cksum = chdr->ver + chdr->prod_info_area_offset; + chdr->cksum = ZERO_CKSUM_CONST - chdr->cksum; + + // Retrieve Wedge EEPROM content + struct wedge_eeprom_st eeprom; + int rc = 0; + rc = wedge_eeprom_parse(NULL, &eeprom); + if (rc) + { + syslog(LOG_ALERT, "populate_fruid: wedge_eeprom_parse returns %d\n", rc); + return; + } + + // Start index at beginning of product info area + int i = PROD_INFO_AREA_OFFSET; + g_fruid[i++] = PROD_INFO_VER; + g_fruid[i++] = 0x00; // prod area length; filled at end + g_fruid[i++] = LANG_CODE_ENGLISH; + +#define _APPEND_STR_VALUE(name) do { \ + if (sizeof(name) < 1 || i + 1 + sizeof(name) >= sizeof(g_fruid)) { \ + break; \ + } \ + g_fruid[i++] = TYPE_STR + sizeof(name); \ + memcpy(&g_fruid[i], name, sizeof(name)); \ + i += sizeof(name); \ +} while(0) + + // Fill system manufacturer field + + _APPEND_STR_VALUE(eeprom.fbw_system_manufacturer); + + // Fill product name field + _APPEND_STR_VALUE(eeprom.fbw_product_name); + + // Fill product number field + _APPEND_STR_VALUE(eeprom.fbw_product_number); + + // convert product version to string and fill + char vbuf[5] = {0}; + snprintf(vbuf, sizeof(vbuf), "%0X", eeprom.fbw_product_version); + _APPEND_STR_VALUE(vbuf); + + // Fill product serial number field + _APPEND_STR_VALUE(eeprom.fbw_product_serial); + + // Fill product asset tag field + _APPEND_STR_VALUE(eeprom.fbw_product_asset); + + // Fill fruid file with dummy file name + char fruid_file_name[] = "fruid_1.0"; + _APPEND_STR_VALUE(fruid_file_name); + + // Field to indicate the last entry + g_fruid[i++] = TYPE_LAST; + + // length of the area in multiples of 8 bytes + int len = i-PROD_INFO_AREA_OFFSET+1; + if (len % LEN_BYTE_SIZE){ + // For non-multiple of 8 bytes, add one for partial data + g_fruid[PROD_INFO_CKSUM_OFFSET] = len/LEN_BYTE_SIZE + 1; + // And also increment index to keep checksum byte + i += (len % LEN_BYTE_SIZE); + } else { + g_fruid[PROD_INFO_CKSUM_OFFSET] = len/LEN_BYTE_SIZE; + } + + // Calculate zero checksum by adding all the values in product info area + for (int j = PROD_INFO_AREA_OFFSET; j < i; j++) { + g_fruid[i] += g_fruid[j]; + } + + // Calculate final cksum by subtraction + g_fruid[i] = ZERO_CKSUM_CONST - g_fruid[i]; + +#undef _APPEND_STR_VALUE +#endif + + return; +} + +// Access functions for FRUID +int +plat_fruid_size(void) { + return WEDGE_FRUID_SIZE; +} + +int +plat_fruid_data(int offset, int count, unsigned char *data) { + // Check for the boundary condition + if ((offset + count) > WEDGE_FRUID_SIZE) { + return -1; + } + + // Copy the FRUID content from the global structure + memcpy(data, &(g_fruid[offset]), count); + + return 0; +} + +// Initialize FRUID +int +plat_fruid_init(void) { + + // Populate FRUID global structure + populate_fruid(); + + return 0; +} diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/wedge/sensor.c b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/wedge/sensor.c new file mode 100644 index 0000000..ce3d4fb --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/platform/wedge/sensor.c @@ -0,0 +1,371 @@ +/* + * + * Copyright 2014-present Facebook. All Rights Reserved. + * + * This file provides platform specific implementation of sensor information + * + * + * 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 "../sensor.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <syslog.h> +#include <string.h> + +#define SENSOR_MGMT_MAX 1 +#define SENSOR_DISC_MAX 8 +#define SENSOR_THRESH_MAX 1 +#define SENSOR_OEM_MAX 1 + +#define BMC_SLAVE_ADDR 0x20 + +typedef struct { + unsigned char num; + sensor_mgmt_t sensor[SENSOR_MGMT_MAX]; +} sensor_mgmt_info_t; + +typedef struct { + unsigned char num; + sensor_disc_t sensor[SENSOR_DISC_MAX]; +} sensor_disc_info_t; + +typedef struct { + unsigned char num; + sensor_thresh_t sensor[SENSOR_THRESH_MAX]; +} sensor_thresh_info_t; + +typedef struct { + unsigned char num; + sensor_oem_t sensor[SENSOR_OEM_MAX]; +} sensor_oem_info_t; + +// Global structures +static sensor_mgmt_info_t g_sensor_mgmt = {0}; +static sensor_disc_info_t g_sensor_disc = {0}; +static sensor_thresh_info_t g_sensor_thresh = {0}; +static sensor_oem_info_t g_sensor_oem = {0}; + +static void +populate_mgmt_sensors(void) { + sensor_mgmt_t sensor = {0}; + + // Add record for the AST2100 BMC + sensor.slave_addr = BMC_SLAVE_ADDR; + sensor.chan_no = 0x0; // Primary BMC controller + + // Init Agent = false + sensor.pwr_state_init = 0x00; + + // FRUID = true, SEL = true, SDR = true, Sensor = true + sensor.dev_caps = 0x0F; + + // Device ID string + // Type - 0xC0: ASCII, Length - 0x09 + sensor.str_type_len = 0xC0 + 0x09; + strncpy(sensor.str, "Wedge-BMC", 0x09); + + // Add this sensor to the global table + if (g_sensor_mgmt.num >= SENSOR_MGMT_MAX) { + syslog(LOG_ALERT, "populate_mgmt_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_mgmt.sensor[g_sensor_mgmt.num], &sensor, sizeof(sensor_mgmt_t)); + + g_sensor_mgmt.num++; + + return; +} + +static void +populate_disc_sensors(void) { + + sensor_disc_t sensor = {0}; + + // Sensor uS Status + // Sensor# 0x10 + // EntitiyId# 0xD0, EntityInst# 0x00 + // Sensor Type# Chassis 0x18 + // Event Read/Type# OEM 0x70 + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x10; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x00; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0x18; + sensor.evt_read_type = 0x70; + // 1-bit for CPU0 Thermal Trip + sensor.assert_evt_mask[0] = 0x04; + sensor.deassert_evt_mask[0] = 0x00; + sensor.read_evt_mask[0] = 0x04; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 9; + strncpy(sensor.str, "uS-Status", 9); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + // Sensor SEL Status + // Sensor# 0x5F + // EntitiyId# 0xD0, EntityInst# 0x02 + // Sensor Type# OEM: 0xC0 + // Event Read/Type# Sensor Specific: 0x6F + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x5F; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x02; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC0; + sensor.evt_read_type = 0x6F; + // SEL Clear(bit1), SEL Rollover(bit8) + sensor.assert_evt_mask[0] = 0x02; + sensor.assert_evt_mask[1] = 0x01; + sensor.deassert_evt_mask[0] = 0x00; + sensor.deassert_evt_mask[1] = 0x00; + sensor.read_evt_mask[0] = 0x02; + sensor.read_evt_mask[1] = 0x01; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 10; + strncpy(sensor.str, "SEL-Status", 10); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + + // Sensor WDT + // Sensor# 0x60 + // EntitiyId# 0xD0, EntityInst# 0x03 + // Sensor Type# WDT2: 0x23 + // Event Read/Type# Sensor Specific: 0x6F + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x60; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x03; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0x23; + sensor.evt_read_type = 0x6F; + // 5 bits for expiry, reset, pwrdown, pwrcycle, timer + sensor.assert_evt_mask[0] = 0x0F; + sensor.assert_evt_mask[1] = 0x01; + sensor.deassert_evt_mask[0] = 0x00; + sensor.deassert_evt_mask[1] = 0x00; + sensor.read_evt_mask[0] = 0x0F; + sensor.read_evt_mask[1] = 0x01; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 3; + strncpy(sensor.str, "WDT", 3); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + + // Sensor Chassis Pwr Sts + // Sensor# 0x70 + // EntitiyId# 0x15, EntityInst# 0x00 + // Sensor Type# OEM: 0xC8 + // Event Read/Type# Sensor Specific: 0x6F + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0x70; + + sensor.ent_id = 0x15; + sensor.ent_inst = 0x00; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC8; + sensor.evt_read_type = 0x6F; + // 6 bits for pwroff, pwrcycle, pwron, softdown, ac-lost, hard-reset + sensor.assert_evt_mask[0] = 0x3F; + sensor.deassert_evt_mask[0] = 0x00; + sensor.read_evt_mask[0] = 0x3F; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 13; + strncpy(sensor.str, "CH-Pwr-Status", 13); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + // Sensor CPU DIMM Hot + // Sensor# 0xB3 + // EntitiyId# 0xD0, EntityInst# 0x05 + // Sensor Type# OEM 0xC6 + // Event Read/Type# Sensor Specific 6Fh + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0xB3; + + sensor.ent_id = 0xD0; + sensor.ent_inst = 0x05; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC6; + sensor.evt_read_type = 0x6F; + // Two bits for CPU Hot, DIMM Hot + sensor.assert_evt_mask[0] = 0x05; + sensor.deassert_evt_mask[0] = 0x05; + sensor.read_evt_mask[0] = 0x05; + + // Device ID string + // Type - 0xC0: ASCII, Length - 12 + sensor.str_type_len = 0xC0 + 12; + strncpy(sensor.str, "CPU_DIMM_HOT", 12); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + // Sensor PMBus Status Word Low + // Sensor PMBus Status Word High + // Sensor PMBus Status MFR + // Sensor PMBus Status Input + // Sensor NTP Status + // Sensor# 0xED + // EntitiyId# 0x35, EntityInst# 0x00 + // Sensor Type# OEM 0xC7 + // Event Read/Type# Sensor Specific 6Fh + sensor.owner= BMC_SLAVE_ADDR; + sensor.lun = 0x00; + sensor.sensor_num = 0xED; + + sensor.ent_id = 0x35; + sensor.ent_inst = 0x00; + // Enable Scanning, Enable Events + sensor.sensor_init = 0x63; + // Supports Auto Re-Arm + sensor.sensor_caps = 0x40; + sensor.sensor_type = 0xC7; + sensor.evt_read_type = 0x6F; + // 1-bit for date/time sync failed + sensor.assert_evt_mask[0] = 0x01; + sensor.deassert_evt_mask[0] = 0x00; + sensor.read_evt_mask[0] = 0x01; + + // Device ID string + // Type - 0xC0: ASCII, Length - 10 + sensor.str_type_len = 0xC0 + 12; + strncpy(sensor.str, "NTP-Status", 10); + + // Add this sensor to the global table + if (g_sensor_disc.num >= SENSOR_DISC_MAX) { + syslog(LOG_ALERT, "populate_disc_sensors: num exceeded\n"); + return; + } + + memcpy(&g_sensor_disc.sensor[g_sensor_disc.num], &sensor, sizeof(sensor_disc_t)); + + g_sensor_disc.num++; + + return; +} + +// Access functions for Sensor Table +void +plat_sensor_mgmt_info(int *p_num, sensor_mgmt_t **p_sensor) { + *p_num = g_sensor_mgmt.num; + *p_sensor = g_sensor_mgmt.sensor; +} + +void +plat_sensor_disc_info(int *p_num, sensor_disc_t **p_sensor) { + *p_num = g_sensor_disc.num; + *p_sensor = g_sensor_disc.sensor; +} + +void +plat_sensor_thresh_info(int *p_num, sensor_thresh_t **p_sensor) { + *p_num = g_sensor_thresh.num; + *p_sensor = g_sensor_thresh.sensor; +} + +void +plat_sensor_oem_info(int *p_num, sensor_oem_t **p_sensor) { + *p_num = g_sensor_oem.num; + *p_sensor = g_sensor_oem.sensor; +} + +// Initialize Sensor Table +int +plat_sensor_init(void) { + + // Populate all Sensors + populate_mgmt_sensors(); + populate_disc_sensors(); + + return 0; +} diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/files/setup-ipmid.sh b/meta-raptor/meta-asus/recipes-asus/ipmid/files/setup-ipmid.sh new file mode 100644 index 0000000..b724d70 --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/files/setup-ipmid.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright 2014-present Facebook. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA +# + +### BEGIN INIT INFO +# Provides: setup-ipmid +# Required-Start: +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Set IPMI Message handler +### END INIT INFO + +echo -n "Setup IPMI message handler... " +/usr/local/bin/ipmid +echo "done." diff --git a/meta-raptor/meta-asus/recipes-asus/ipmid/ipmid_0.1.bb b/meta-raptor/meta-asus/recipes-asus/ipmid/ipmid_0.1.bb new file mode 100644 index 0000000..7ec7eaf --- /dev/null +++ b/meta-raptor/meta-asus/recipes-asus/ipmid/ipmid_0.1.bb @@ -0,0 +1,70 @@ +# Copyright 2014-present Facebook. All Rights Reserved. +# Copyright 2017 Raptor Engineering, LLC. All Rights Reserved. +# +# This program file 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; version 2 of the License. +# +# 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 in a file named COPYING; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301 USA + +SUMMARY = "IPMI Daemon" +DESCRIPTION = "Daemon to handle IPMI Messages." +SECTION = "base" +PR = "r1" +LICENSE = "GPLv2" +LIC_FILES_CHKSUM = "file://ipmid.c;beginline=8;endline=20;md5=da35978751a9d71b73679307c4d296ec" + + +DEPENDS_append = " update-rc.d-native" + +SRC_URI = "file://Makefile \ + file://setup-ipmid.sh \ + file://ipmid.c \ + file://platform/timestamp.c \ + file://platform/timestamp.h \ + file://platform/sel.c \ + file://platform/sel.h \ + file://platform/sdr.c \ + file://platform/sdr.h \ + file://platform/sensor.h \ + file://platform/fruid.h \ + file://platform/wedge/sensor.c \ + file://platform/wedge/fruid.c \ + " + +S = "${WORKDIR}" + +binfiles = "ipmid" + +pkgdir = "ipmid" + +do_install() { + dst="${D}/usr/local/fbpackages/${pkgdir}" + bin="${D}/usr/local/bin" + install -d $dst + install -d $bin + install -m 755 ipmid ${dst}/ipmid + ln -snf ../fbpackages/${pkgdir}/ipmid ${bin}/ipmid + install -d ${D}${sysconfdir}/init.d + install -d ${D}${sysconfdir}/rcS.d + install -m 755 setup-ipmid.sh ${D}${sysconfdir}/init.d/setup-ipmid.sh + update-rc.d -r ${D} setup-ipmid.sh start 64 S . +} + +FBPACKAGEDIR = "${prefix}/local/fbpackages" + +FILES_${PN} = "${FBPACKAGEDIR}/ipmid ${prefix}/local/bin ${sysconfdir} " + +# Inhibit complaints about .debug directories for the fand binary: + +INHIBIT_PACKAGE_DEBUG_SPLIT = "1" +INHIBIT_PACKAGE_STRIP = "1" |