in common/ipmi/ipmb.c [492:820]
void IPMB_RXTask(void *pvParameters, void *arvg0, void *arvg1)
{
struct ipmi_msg_cfg *current_msg_rx;
struct IPMB_config ipmb_cfg;
struct ipmb_msg *msg = NULL;
uint8_t *ipmb_buffer_rx;
uint8_t rx_len;
static uint16_t i = 0;
int ret;
memcpy(&ipmb_cfg, (IPMB_config *)pvParameters, sizeof(IPMB_config));
if (DEBUG_IPMI) {
printf("Rx poll bus %d, index %d\n", ipmb_cfg.bus, ipmb_cfg.index);
}
while (1) {
k_msleep(IPMB_MQUEUE_POLL_DELAY_ms);
current_msg_rx = (struct ipmi_msg_cfg *)malloc(sizeof(struct ipmi_msg_cfg));
if (current_msg_rx == NULL) {
k_msleep(10); // allocate fail, retry later
continue;
}
ipmb_buffer_rx =
malloc((IPMI_MSG_MAX_LENGTH + IPMB_RESP_HEADER_LENGTH) * sizeof(uint8_t));
if (ipmb_buffer_rx == NULL) {
free(current_msg_rx);
k_msleep(10); // allocate fail, retry later
continue;
}
rx_len = 0;
if (ipmb_cfg.Inf == I2C_IF) {
ret = ipmb_slave_read(dev_ipmb[ipmb_cfg.bus], &msg, &rx_len);
if (!ret) {
memcpy(ipmb_buffer_rx, (uint8_t *)msg, rx_len);
ipmb_buffer_rx[0] = ipmb_buffer_rx[0] >> 1;
} else {
free(current_msg_rx);
free(ipmb_buffer_rx);
continue;
}
} else if (ipmb_cfg.Inf == I3C_IF) {
;
} else {
printf("IPMB_RXTask: Invalid IPMB interface \n");
}
if (rx_len > 0) {
if (DEBUG_IPMI) {
printf("bus %d recv[%d]", ipmb_cfg.bus, rx_len);
for (i = 0; i < rx_len; i++) {
printf(" %x", ipmb_buffer_rx[i + 1]);
}
printf("\n");
}
/* Perform a checksum test on the message, if it doesn't pass, just ignore it.
* Following the IPMB specs, we have no way to know if we're the one who should
* receive it. In MicroTCA crates with star topology for IPMB, we are assured we
* are the recipients, however, malformed messages may be safely ignored as the
* MCMC should take care of retrying.
*/
if (ipmb_assert_chksum(ipmb_buffer_rx, rx_len) != ipmb_error_success) {
printf("Recv invalid chksum from index %d\n", ipmb_cfg.index);
if (current_msg_rx != NULL) {
free(current_msg_rx);
}
if (ipmb_buffer_rx != NULL) {
free(ipmb_buffer_rx);
}
continue;
}
/* Clear our local buffer before writing new data into it */
ipmb_error IPMB_ERR_STATUS;
IPMB_ERR_STATUS =
ipmb_decode(&(current_msg_rx->buffer), ipmb_buffer_rx, rx_len);
if (ipmb_buffer_rx != NULL) {
free(ipmb_buffer_rx);
}
if (IPMB_ERR_STATUS != ipmb_error_success) {
printf("IPMB_ERR_STATUS: %x\n", IPMB_ERR_STATUS);
}
if (DEBUG_IPMI) {
printf("buff[%d]", current_msg_rx->buffer.data_len);
for (i = 0; i < current_msg_rx->buffer.data_len; i++) {
printf(" %x", current_msg_rx->buffer.data[i]);
}
printf("\n");
}
if (IS_RESPONSE(current_msg_rx->buffer)) {
/* The message is a response, check if it's request from BIC and respond in time */
current_msg_rx->buffer.seq_target = current_msg_rx->buffer.seq;
if (find_node(P_start[ipmb_cfg.index], &(current_msg_rx->buffer), 0,
ipmb_cfg.index)) {
if (DEBUG_IPMI) {
printf("find node IFs:%x, IFt:%x\n",
current_msg_rx->buffer.InF_source,
current_msg_rx->buffer.InF_target);
printf("find buff[%d] seq %x:",
current_msg_rx->buffer.data_len,
current_msg_rx->buffer.seq_target);
for (i = 0; i < current_msg_rx->buffer.data_len;
i++) {
printf(" %x",
current_msg_rx->buffer.data[i]);
}
printf("\n");
}
if (current_msg_rx->buffer.InF_source ==
SELF_IPMB_IF) { // Send from other thread
struct ipmi_msg current_msg;
current_msg =
(struct ipmi_msg)current_msg_rx->buffer;
k_msgq_put(
&ipmb_rxqueue[IPMB_inf_index_map
[current_msg_rx->buffer
.InF_target]],
¤t_msg, K_NO_WAIT);
#ifdef CONFIG_IPMI_KCS_ASPEED
} else if (current_msg_rx->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("IPMB_RXTask: Fail to malloc for kcs_buff\n");
free(current_msg_rx);
continue;
}
}
kcs_buff[0] = current_msg_rx->buffer.netfn << 2;
kcs_buff[1] = current_msg_rx->buffer.cmd;
kcs_buff[2] =
current_msg_rx->buffer.completion_code;
if (current_msg_rx->buffer.data_len > 0) {
memcpy(&kcs_buff[3],
¤t_msg_rx->buffer.data[0],
current_msg_rx->buffer.data_len);
}
kcs_write(kcs_buff,
current_msg_rx->buffer.data_len +
3); // data len + netfn + cmd + cc
if (kcs_buff != NULL) {
free(kcs_buff);
}
#endif
} else if (current_msg_rx->buffer.InF_source ==
ME_IPMB_IFs) {
ipmb_error status;
ipmi_msg *bridge_msg =
(ipmi_msg *)malloc(sizeof(ipmi_msg));
memset(bridge_msg, 0, sizeof(ipmi_msg));
bridge_msg->netfn =
current_msg_rx->buffer.netfn -
1; // fix response netfn and would be shift later in ipmb_send_response
bridge_msg->cmd = current_msg_rx->buffer.cmd;
bridge_msg->completion_code =
current_msg_rx->buffer.completion_code;
bridge_msg->seq = current_msg_rx->buffer.seq_source;
bridge_msg->data_len =
current_msg_rx->buffer.data_len;
memcpy(&bridge_msg->data[0],
¤t_msg_rx->buffer.data[0],
current_msg_rx->buffer.data_len);
if (DEBUG_IPMI) {
printf("ME bridge[%d] seq_s %x, seq_t %x, Inf_source %x, Inf_source_index %x :\n",
bridge_msg->data_len,
current_msg_rx->buffer.seq_source,
current_msg_rx->buffer.seq_target,
current_msg_rx->buffer.InF_source,
IPMB_inf_index_map
[current_msg_rx->buffer
.InF_source]);
for (i = 0; i < bridge_msg->data_len; i++) {
printf(" %x", bridge_msg->data[i]);
}
printf("\n");
}
status = ipmb_send_response(
bridge_msg,
IPMB_inf_index_map[current_msg_rx->buffer
.InF_source]);
if (status != ipmb_error_success) {
printf("IPMB_RXTask: Send IPMB resp fail status: %x",
status);
}
if (bridge_msg != NULL) {
free(bridge_msg);
}
} else { // Bridge response to other fru
ipmb_error status;
ipmi_msg *bridge_msg =
(ipmi_msg *)malloc(sizeof(ipmi_msg));
memset(bridge_msg, 0, sizeof(ipmi_msg));
bridge_msg->data[0] =
WW_IANA_ID &
0xFF; // Move target response to bridge response data
bridge_msg->data[1] = (WW_IANA_ID >> 8) & 0xFF;
bridge_msg->data[2] = (WW_IANA_ID >> 16) & 0xFF;
bridge_msg->data[3] =
IPMB_config_table[ipmb_cfg.index]
.Inf_source; // return response source as request target
bridge_msg->data[4] =
current_msg_rx->buffer
.netfn; // Move target response to bridge response data
bridge_msg->data[5] = current_msg_rx->buffer.cmd;
bridge_msg->data[6] =
current_msg_rx->buffer.completion_code;
bridge_msg->data_len =
current_msg_rx->buffer.data_len +
7; // add 7 byte len for bridge header
memcpy(&bridge_msg->data[7],
¤t_msg_rx->buffer.data[0],
current_msg_rx->buffer.data_len);
bridge_msg->netfn =
NETFN_OEM_1S_REQ; // Add bridge response header
bridge_msg->cmd = CMD_OEM_1S_MSG_OUT;
bridge_msg->completion_code = CC_SUCCESS;
bridge_msg->seq = current_msg_rx->buffer.seq_source;
if (DEBUG_IPMI) {
printf("bridge[%d] seq_s %x, seq_t %x, Inf_source %x, Inf_source_index %x :\n",
bridge_msg->data_len,
current_msg_rx->buffer.seq_source,
current_msg_rx->buffer.seq_target,
current_msg_rx->buffer.InF_source,
IPMB_inf_index_map
[current_msg_rx->buffer
.InF_source]);
for (i = 0; i < bridge_msg->data_len; i++) {
printf(" %x", bridge_msg->data[i]);
}
printf("\n");
}
status = ipmb_send_response(
bridge_msg,
IPMB_inf_index_map[current_msg_rx->buffer
.InF_source]);
if (status != ipmb_error_success) {
printf("IPMB_RXTask: Send IPMB resp fail status: %x",
status);
}
if (bridge_msg != NULL) {
free(bridge_msg);
}
}
}
} else {
// Exception: ME sends standard IPMI commands to BMC but not BIC.
// So BIC should bridge ME request to BMC directly, instead of
// executing IPMI handler.
if (IPMB_config_table[ipmb_cfg.index].Inf_source == ME_IPMB_IFs &&
(!pal_ME_is_to_ipmi_handler(current_msg_rx->buffer.netfn,
current_msg_rx->buffer.cmd))) {
ipmb_error status;
ipmi_msg *bridge_msg = (ipmi_msg *)malloc(sizeof(ipmi_msg));
memset(bridge_msg, 0, sizeof(ipmi_msg));
bridge_msg->data_len = current_msg_rx->buffer.data_len;
bridge_msg->seq_source = current_msg_rx->buffer.seq;
bridge_msg->InF_target = BMC_IPMB_IFs;
bridge_msg->InF_source = ME_IPMB_IFs;
bridge_msg->netfn = current_msg_rx->buffer.netfn;
bridge_msg->cmd = current_msg_rx->buffer.cmd;
if (bridge_msg->data_len != 0) {
memcpy(&bridge_msg->data[0],
¤t_msg_rx->buffer.data[0],
current_msg_rx->buffer.data_len);
}
status = ipmb_send_request(
bridge_msg, IPMB_inf_index_map[BMC_IPMB_IFs]);
if (status != ipmb_error_success) {
printf("OEM_MSG_OUT send IPMB req fail status: %x",
status);
bridge_msg->completion_code = CC_TIMEOUT;
status = ipmb_send_response(
bridge_msg,
IPMB_inf_index_map[bridge_msg->InF_source]);
if (status != ipmb_error_success) {
printf("IPMI_handler send IPMB resp fail status: %x",
status);
}
}
if (bridge_msg != NULL) {
free(bridge_msg);
}
} else {
/* The received message is a request */
/* Record sequence number for later response */
current_msg_rx->buffer.seq_source =
current_msg_rx->buffer.seq;
/* Record source interface for later bridge response */
current_msg_rx->buffer.InF_source =
IPMB_config_table[ipmb_cfg.index].Inf_source;
/* Notify the client about the new request */
if (DEBUG_IPMI) {
printf("recv req: data: %x, InfS: %x, seq_s: %x\n",
current_msg_rx->buffer.netfn,
current_msg_rx->buffer.InF_source,
current_msg_rx->buffer.seq_source);
}
ipmb_notify_client(current_msg_rx);
}
}
}
free(current_msg_rx);
}
}