void IPMB_RXTask()

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]],
							&current_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],
							       &current_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],
						       &current_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],
						       &current_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],
						       &current_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);
	}
}