common/ipmi/ipmi.c (394 lines of code) (raw):
#include "ipmi.h"
#include "cmsis_os2.h"
#include "kcs.h"
#include "usb.h"
#include <string.h>
#include <stdlib.h>
#include "mctp.h"
#include "pldm.h"
#include <kernel.h>
#include <logging/log.h>
#include <stdio.h>
#include <string.h>
#include <zephyr.h>
LOG_MODULE_REGISTER(ipmi);
#define IPMI_QUEUE_SIZE 5
struct k_thread IPMI_thread;
K_KERNEL_STACK_MEMBER(IPMI_thread_stack, IPMI_THREAD_STACK_SIZE);
char __aligned(4) ipmi_msgq_buffer[ipmi_buf_len * sizeof(struct ipmi_msg_cfg)];
struct k_msgq ipmi_msgq;
static uint8_t send_msg_by_pldm(ipmi_msg_cfg *msg_cfg)
{
if (!msg_cfg)
return 0;
/* get the mctp/pldm for sending response from buffer */
uint16_t pldm_hdr_ofs = sizeof(msg_cfg->buffer.data) - sizeof(pldm_hdr);
uint16_t mctp_ext_params_ofs = pldm_hdr_ofs - sizeof(mctp_ext_params);
uint16_t mctp_inst_ofs = mctp_ext_params_ofs - 4;
/* get the mctp_inst */
mctp *mctp_inst;
memcpy(&mctp_inst, msg_cfg->buffer.data + mctp_inst_ofs, 4);
LOG_DBG("mctp_inst = %p", mctp_inst);
LOG_HEXDUMP_DBG(msg_cfg->buffer.data + mctp_ext_params_ofs, sizeof(mctp_ext_params),
"mctp ext param");
/* get the pldm hdr for response */
pldm_hdr *hdr = (pldm_hdr *)(msg_cfg->buffer.data + pldm_hdr_ofs);
LOG_HEXDUMP_DBG(msg_cfg->buffer.data + pldm_hdr_ofs, sizeof(pldm_hdr), "pldm header");
/* make response data */
uint8_t resp_buf[PLDM_MAX_DATA_SIZE] = { 0 };
pldm_msg resp;
memset(&resp, 0, sizeof(resp));
/* pldm header */
resp.buf = resp_buf;
resp.hdr = *hdr;
resp.hdr.rq = 0;
LOG_DBG("msg_cfg->buffer.data_len = %d", msg_cfg->buffer.data_len);
LOG_DBG("msg_cfg->buffer.completion_code = %x", msg_cfg->buffer.completion_code);
/* setup ipmi response data of pldm */
struct _ipmi_cmd_resp *cmd_resp = (struct _ipmi_cmd_resp *)resp.buf;
set_iana(cmd_resp->iana, sizeof(cmd_resp->iana));
cmd_resp->completion_code = PLDM_BASE_CODES_SUCCESS;
cmd_resp->netfn_lun = (msg_cfg->buffer.netfn | 0x01) << 2;
cmd_resp->cmd = msg_cfg->buffer.cmd;
cmd_resp->ipmi_comp_code = msg_cfg->buffer.completion_code;
memcpy(&cmd_resp->first_data, msg_cfg->buffer.data, msg_cfg->buffer.data_len);
resp.len = sizeof(*cmd_resp) - 1 + msg_cfg->buffer.data_len;
LOG_HEXDUMP_DBG(&resp, sizeof(resp.hdr) + resp.len, "pldm resp data");
memcpy(&resp.ext_params, msg_cfg->buffer.data + mctp_ext_params_ofs,
sizeof(resp.ext_params));
mctp_pldm_send_msg(mctp_inst, &resp);
return 1;
}
__weak bool pal_is_not_return_cmd(uint8_t netfn, uint8_t cmd)
{
return 0;
}
void IPMI_CHASSIS_handler(ipmi_msg *msg)
{
switch (msg->cmd) {
case CMD_CHASSIS_GET_CHASSIS_STATUS:
pal_CHASSIS_GET_CHASSIS_STATUS(msg);
break;
default:
printf("invalid chassis msg netfn: %x, cmd: %x\n", msg->netfn, msg->cmd);
msg->data_len = 0;
break;
}
return;
}
void IPMI_SENSOR_handler(ipmi_msg *msg)
{
switch (msg->cmd) {
case CMD_SENSOR_GET_SENSOR_READING:
pal_SENSOR_GET_SENSOR_READING(msg);
break;
default:
printf("invalid sensor msg netfn: %x, cmd: %x\n", msg->netfn, msg->cmd);
msg->data_len = 0;
break;
}
return;
}
void IPMI_APP_handler(ipmi_msg *msg)
{
switch (msg->cmd) {
case CMD_APP_GET_DEVICE_ID:
pal_APP_GET_DEVICE_ID(msg);
break;
case CMD_APP_COLD_RESET:
pal_APP_COLD_RESET(msg);
break;
case CMD_APP_WARM_RESET:
pal_APP_WARM_RESET(msg);
break;
case CMD_APP_GET_SELFTEST_RESULTS:
pal_APP_GET_SELFTEST_RESULTS(msg);
break;
case CMD_APP_GET_SYSTEM_GUID:
pal_APP_GET_SYSTEM_GUID(msg);
break;
case CMD_APP_MASTER_WRITE_READ:
pal_APP_MASTER_WRITE_READ(msg);
break;
default:
printf("invalid APP msg netfn: %x, cmd: %x\n", msg->netfn, msg->cmd);
msg->data_len = 0;
break;
}
return;
}
void IPMI_Storage_handler(ipmi_msg *msg)
{
switch (msg->cmd) {
case CMD_STORAGE_GET_FRUID_INFO:
pal_STORAGE_GET_FRUID_INFO(msg);
break;
case CMD_STORAGE_READ_FRUID_DATA:
pal_STORAGE_READ_FRUID_DATA(msg);
break;
case CMD_STORAGE_WRITE_FRUID_DATA:
pal_STORAGE_WRITE_FRUID_DATA(msg);
break;
case CMD_STORAGE_RSV_SDR:
pal_STORAGE_RSV_SDR(msg);
break;
case CMD_STORAGE_GET_SDR:
pal_STORAGE_GET_SDR(msg);
break;
default:
printf("invalid Storage msg netfn: %x, cmd: %x\n", msg->netfn, msg->cmd);
msg->data_len = 0;
break;
}
return;
}
void IPMI_OEM_handler(ipmi_msg *msg)
{
switch (msg->cmd) {
case CMD_OEM_SENSOR_READ:
pal_OEM_SENSOR_READ(msg);
break;
case CMD_OEM_SET_SYSTEM_GUID:
pal_OEM_SET_SYSTEM_GUID(msg);
break;
case CMD_OEM_GET_MB_INDEX:
pal_OEM_GET_MB_INDEX(msg);
break;
case CMD_OEM_SET_FAN_DUTY_MANUAL:
pal_OEM_SET_FAN_DUTY_MANUAL(msg);
break;
case CMD_OEM_GET_SET_FAN_CTRL_MODE:
pal_OEM_GET_SET_FAN_CTRL_MODE(msg);
break;
default:
printf("invalid OEM msg netfn: %x, cmd: %x\n", msg->netfn, msg->cmd);
msg->data_len = 0;
break;
}
return;
}
void IPMI_OEM_1S_handler(ipmi_msg *msg)
{
switch (msg->cmd) {
case CMD_OEM_1S_MSG_IN:
break;
case CMD_OEM_1S_MSG_OUT:
pal_OEM_1S_MSG_OUT(msg);
break;
case CMD_OEM_1S_GET_GPIO:
pal_OEM_1S_GET_GPIO(msg);
break;
case CMD_OEM_1S_SET_GPIO:
pal_OEM_1S_SET_GPIO(msg);
break;
case CMD_OEM_1S_SEND_INTERRUPT_TO_BMC:
pal_OEM_1S_SEND_INTERRUPT_TO_BMC(msg);
break;
case CMD_OEM_1S_FW_UPDATE:
pal_OEM_1S_FW_UPDATE(msg);
break;
case CMD_OEM_1S_GET_FW_VERSION:
pal_OEM_1S_GET_FW_VERSION(msg);
break;
case CMD_OEM_1S_PECIaccess:
pal_OEM_1S_PECIaccess(msg);
break;
case CMD_OEM_1S_GET_POST_CODE:
pal_OEM_1S_GET_POST_CODE(msg);
break;
case CMD_OEM_1S_SET_VR_MONITOR_STATUS:
pal_OEM_1S_SET_VR_MONITOR_STATUS(msg);
break;
case CMD_OEM_1S_GET_VR_MONITOR_STATUS:
pal_OEM_1S_GET_VR_MONITOR_STATUS(msg);
break;
case CMD_OEM_1S_RESET_BMC:
pal_OEM_1S_RESET_BMC(msg);
break;
case CMD_OEM_1S_SET_JTAG_TAP_STA:
pal_OEM_1S_SET_JTAG_TAP_STA(msg);
break;
case CMD_OEM_1S_JTAG_DATA_SHIFT:
pal_OEM_1S_JTAG_DATA_SHIFT(msg);
break;
case CMD_OEM_1S_SENSOR_POLL_EN:
pal_OEM_1S_SENSOR_POLL_EN(msg);
break;
case CMD_OEM_1S_ACCURACY_SENSOR_READING:
pal_OEM_1S_ACCURACY_SENSOR_READING(msg);
break;
case CMD_OEM_1S_ASD_INIT:
pal_OEM_1S_ASD_INIT(msg);
break;
case CMD_OEM_1S_GET_SET_GPIO:
pal_OEM_1S_GET_SET_GPIO(msg);
break;
case CMD_OEM_1S_I2C_DEV_SCAN: // debug command
pal_OEM_1S_I2C_DEV_SCAN(msg);
break;
case CMD_OEM_1S_GET_BIC_STATUS:
pal_OEM_1S_GET_BIC_STATUS(msg);
break;
case CMD_OEM_1S_RESET_BIC:
pal_OEM_1S_RESET_BIC(msg);
break;
case CMD_OEM_1S_12V_CYCLE_SLOT:
pal_OEM_1S_12V_CYCLE_SLOT(msg);
break;
case CMD_OEM_1S_READ_BIC_REGISTER:
pal_OEM_1S_READ_BIC_REGISTER(msg);
break;
case CMD_OEM_1S_WRITE_BIC_REGISTER:
pal_OEM_1S_WRITE_BIC_REGISTER(msg);
break;
case CMD_OEM_1S_SET_FAN_DUTY_AUTO:
pal_OEM_1S_SET_FAN_DUTY_AUTO(msg);
break;
case CMD_OEM_1S_GET_FAN_DUTY:
pal_OEM_1S_GET_FAN_DUTY(msg);
break;
case CMD_OEM_1S_GET_FAN_RPM:
pal_OEM_1S_GET_FAN_RPM(msg);
break;
default:
printf("invalid OEM msg netfn: %x, cmd: %x\n", msg->netfn, msg->cmd);
msg->data_len = 0;
break;
}
return;
}
void IPMI_handler(void *arug0, void *arug1, void *arug2)
{
uint8_t i;
ipmi_msg_cfg msg_cfg;
while (1) {
k_msgq_get(&ipmi_msgq, &msg_cfg, K_FOREVER);
if (DEBUG_IPMI) {
printf("IPMI_handler[%d]: netfn: %x\n", msg_cfg.buffer.data_len,
msg_cfg.buffer.netfn);
for (i = 0; i < msg_cfg.buffer.data_len; i++) {
printf(" 0x%2x", msg_cfg.buffer.data[i]);
}
printf("\n");
}
msg_cfg.buffer.completion_code = CC_INVALID_CMD;
switch (msg_cfg.buffer.netfn) {
case NETFN_CHASSIS_REQ:
IPMI_CHASSIS_handler(&msg_cfg.buffer);
break;
case NETFN_BRIDGE_REQ:
// IPMI_BRIDGE_handler();
break;
case NETFN_SENSOR_REQ:
IPMI_SENSOR_handler(&msg_cfg.buffer);
break;
case NETFN_APP_REQ:
IPMI_APP_handler(&msg_cfg.buffer);
break;
case NETFN_FIRMWARE_REQ:
break;
case NETFN_STORAGE_REQ:
IPMI_Storage_handler(&msg_cfg.buffer);
break;
case NETFN_TRANSPORT_REQ:
break;
case NETFN_DCMI_REQ:
break;
case NETFN_NM_REQ:
break;
case NETFN_OEM_REQ:
IPMI_OEM_handler(&msg_cfg.buffer);
break;
case NETFN_OEM_1S_REQ:
if ((msg_cfg.buffer.data[0] | (msg_cfg.buffer.data[1] << 8) |
(msg_cfg.buffer.data[2] << 16)) == WW_IANA_ID) {
memcpy(&msg_cfg.buffer.data[0], &msg_cfg.buffer.data[3],
msg_cfg.buffer.data_len);
msg_cfg.buffer.data_len -= 3;
IPMI_OEM_1S_handler(&msg_cfg.buffer);
break;
} else if (pal_is_not_return_cmd(msg_cfg.buffer.netfn,
msg_cfg.buffer.cmd)) {
msg_cfg.buffer.completion_code = CC_INVALID_IANA;
IPMI_OEM_1S_handler(
&msg_cfg.buffer); // Due to command not returning to bridge command source, enter command handler and return with other invalid CC
break;
} else {
msg_cfg.buffer.completion_code = CC_INVALID_IANA;
msg_cfg.buffer.data_len = 0;
break;
}
default: // invalid net function
printf("invalid msg netfn: %x, cmd: %x\n", msg_cfg.buffer.netfn,
msg_cfg.buffer.cmd);
msg_cfg.buffer.data_len = 0;
break;
}
if (pal_is_not_return_cmd(msg_cfg.buffer.netfn, msg_cfg.buffer.cmd)) {
;
} else {
ipmb_error status;
if (msg_cfg.buffer.completion_code != CC_SUCCESS) {
msg_cfg.buffer.data_len = 0;
} else if (msg_cfg.buffer.netfn == NETFN_OEM_1S_REQ) {
uint8_t copy_data[msg_cfg.buffer.data_len];
memcpy(©_data[0], &msg_cfg.buffer.data[0],
msg_cfg.buffer.data_len);
memcpy(&msg_cfg.buffer.data[3], ©_data[0],
msg_cfg.buffer.data_len);
msg_cfg.buffer.data_len += 3;
msg_cfg.buffer.data[0] = WW_IANA_ID & 0xFF;
msg_cfg.buffer.data[1] = (WW_IANA_ID >> 8) & 0xFF;
msg_cfg.buffer.data[2] = (WW_IANA_ID >> 16) & 0xFF;
}
if (msg_cfg.buffer.InF_source == BMC_USB_IFs) {
USB_write(&msg_cfg.buffer);
#ifdef CONFIG_IPMI_KCS_ASPEED
} else if (msg_cfg.buffer.InF_source == HOST_KCS_IFs) {
uint8_t *kcs_buff;
kcs_buff = malloc(KCS_buff_size * sizeof(uint8_t));
if (kcs_buff == NULL) { // allocate fail, retry allocate
k_msleep(10);
kcs_buff = malloc(KCS_buff_size * sizeof(uint8_t));
if (kcs_buff == NULL) {
printk("IPMI_handler: Fail to malloc for kcs_buff\n");
continue;
}
}
kcs_buff[0] = (msg_cfg.buffer.netfn + 1)
<< 2; // ipmi netfn response package
kcs_buff[1] = msg_cfg.buffer.cmd;
kcs_buff[2] = msg_cfg.buffer.completion_code;
if (msg_cfg.buffer.data_len) {
if (msg_cfg.buffer.data_len <= (KCS_buff_size - 3))
memcpy(&kcs_buff[3], msg_cfg.buffer.data,
msg_cfg.buffer.data_len);
else
memcpy(&kcs_buff[3], msg_cfg.buffer.data,
(KCS_buff_size - 3));
}
if (DEBUG_KCS) {
printk("kcs from ipmi netfn %x, cmd %x, length %d, cc %x\n",
kcs_buff[0], kcs_buff[1], msg_cfg.buffer.data_len,
kcs_buff[2]);
}
kcs_write(kcs_buff, msg_cfg.buffer.data_len + 3);
if (kcs_buff != NULL)
free(kcs_buff);
#endif
} else if (msg_cfg.buffer.InF_source == PLDM_IFs) {
/* the message should be passed to source by pldm
* format */
send_msg_by_pldm(&msg_cfg);
} else {
status = ipmb_send_response(
&msg_cfg.buffer,
IPMB_inf_index_map[msg_cfg.buffer.InF_source]);
if (status != ipmb_error_success) {
printf("IPMI_handler send IPMB resp fail status: %x",
status);
}
}
}
}
}
void ipmi_init(void)
{
printf("ipmi_init\n"); // rain
k_msgq_init(&ipmi_msgq, ipmi_msgq_buffer, sizeof(struct ipmi_msg_cfg), ipmi_buf_len);
k_thread_create(&IPMI_thread, IPMI_thread_stack, K_THREAD_STACK_SIZEOF(IPMI_thread_stack),
IPMI_handler, NULL, NULL, NULL, CONFIG_MAIN_THREAD_PRIORITY, 0, K_NO_WAIT);
k_thread_name_set(&IPMI_thread, "IPMI_thread");
ipmb_init();
}