[Skiboot] [PATCH 4/4] core/pldm/test : pldm FRU test

Abhishek Singh Tomar abhishek at linux.ibm.com
Wed May 4 16:55:55 AEST 2022


The self test for PLDM FRU message implementation

Signed-off-by: Abhishek Singh Tomar <abhishek at linux.ibm.com>
---
 core/pldm/test/Makefile.check  |   1 +
 core/pldm/test/test_pldm-fru.c | 316 +++++++++++++++++++++++++++++++++
 2 files changed, 317 insertions(+)
 create mode 100644 core/pldm/test/test_pldm-fru.c

diff --git a/core/pldm/test/Makefile.check b/core/pldm/test/Makefile.check
index c184702f..2295a99b 100644
--- a/core/pldm/test/Makefile.check
+++ b/core/pldm/test/Makefile.check
@@ -2,6 +2,7 @@
 PLDM_TEST := core/pldm/test/test_pldm-fileio \
 	     core/pldm/test/test_pldm-bios \
 	     core/pldm/test/test_pldm-platform \
+	     core/pldm/test/test_pldm-fru
 
 LCOV_EXCLUDE += $(PLDM_TEST:%=%.c)
 
diff --git a/core/pldm/test/test_pldm-fru.c b/core/pldm/test/test_pldm-fru.c
new file mode 100644
index 00000000..dc25691f
--- /dev/null
+++ b/core/pldm/test/test_pldm-fru.c
@@ -0,0 +1,316 @@
+#include "common/test_pldm-common.c"
+
+
+#define TEST_BMC_VERSION "tes_t_1.0"
+
+bool get_fru_record_table_in_progress;
+int pldm_test_verify_response(void *response_msg, size_t response_len);
+int pldm_test_verify_response_fru(void *response_msg, size_t response_len);
+int test_fru_table_metadata_request(void);
+int pldm_test_reply_request_fru(void *request_msg, size_t request_len,
+		void **response_msg, size_t *response_len);
+int pldm_test_generate_reply_field_type_version(uint8_t record_type, uint8_t field_type,
+		uint8_t **fru_table, size_t *fru_table_size);
+
+
+/*
+ * This function tries to duplicate BMC functionality for Pldm self test
+ * It will only handle PLDM_FRU type response
+ */
+int pldm_test_verify_response(void *response_msg, size_t response_len)
+{
+	switch (((struct pldm_msg *)response_msg)->hdr.type) {
+
+	case PLDM_FRU:
+		return pldm_test_verify_response_fru(response_msg, response_len);
+
+	default:
+		printf("PLDM_TEST: Not equal to PLDM_FRU\n");
+		return OPAL_PARAMETER;
+	}
+
+
+}
+
+
+/*
+ * This function tries to duplicate BMC functionality for Pldm self test
+ * It will only handle PLDM_FRU type response and tries to verify that
+ * PLDM response is same as expected
+ */
+int pldm_test_verify_response_fru(void *response_msg, size_t response_len)
+{
+	uint8_t completion_code;
+	int ret = 0;
+	int  payload_len = 0;
+	uint8_t fru_data_major_version;
+	uint8_t fru_data_minor_version;
+	uint32_t fru_table_maximum_size;
+	uint32_t fru_table_length;
+	uint16_t total_record_set_identifiers;
+	uint16_t total_table_records;
+	uint32_t checksum;
+
+	switch (((struct pldm_msg *)response_msg)->hdr.command) {
+	case PLDM_GET_FRU_RECORD_TABLE_METADATA:
+
+		// Test that response  receive for
+		// PLDM_GET_FRU_RECORD_TABLE_METADATA
+		// only when specific request in progress
+		if (get_fru_record_table_in_progress != true)
+			return OPAL_PARAMETER;
+
+		payload_len = response_len - sizeof(struct pldm_msg_hdr);
+		ret = decode_get_fru_record_table_metadata_resp(response_msg, payload_len,
+				&(completion_code), &fru_data_major_version,
+				&fru_data_minor_version,
+				&fru_table_maximum_size,
+				&fru_table_length,
+				&total_record_set_identifiers,
+				&total_table_records,
+				&checksum);
+
+		// Test if PLDM request completed with success i.e. completion code = PLDM_SUCCESS
+		// and test if other parameter as expected then return PLDM_SUCCESS
+		// else return error PLDM_ERROR_INVALID_DATA
+		if (ret == OPAL_SUCCESS && completion_code == PLDM_SUCCESS &&
+				total_record_set_identifiers == 1
+				&& total_table_records == 1)
+			return PLDM_SUCCESS;
+		else
+			return PLDM_ERROR_INVALID_DATA;
+		break;
+
+	default:
+		return PLDM_ERROR_INVALID_DATA;
+
+	}
+
+	return PLDM_SUCCESS;
+
+
+
+}
+
+
+/*
+ * This function tries to duplicate BMC functionality for Pldm self test
+ * It will only handle PLDM_FRU type request
+ */
+int pldm_test_reply_request(void *request_msg, size_t request_len,
+		void **response_msg, size_t *response_len)
+{
+	switch (((struct pldm_msg *)request_msg)->hdr.type) {
+
+	case PLDM_FRU:
+		return pldm_test_reply_request_fru(request_msg, request_len,
+				response_msg, response_len);
+
+	default:
+		printf("PLDM_TEST: Not equal to PLDM_FRU \n");
+		return OPAL_PARAMETER;
+	}
+
+}
+
+
+/*
+ * This function tries to duplicate BMC functionality for Pldm self test
+ * It generate reply for PLDM_GET_FRU_RECORD_BY_OPTION for self test.
+ * It generates fru Dta structure with BMC version tlv
+ */
+int pldm_test_generate_reply_field_type_version(uint8_t record_type, uint8_t field_type,
+		uint8_t **fru_table, size_t *fru_table_size)
+{
+	struct pldm_fru_record_tlv *tlv;
+	int tlv_size, ret;
+	size_t curr_size = 0;
+	size_t	pad_bytes = 0;
+	uint32_t checksum;
+
+	if (field_type == PLDM_FRU_FIELD_TYPE_VERSION &&
+			record_type == PLDM_FRU_RECORD_TYPE_GENERAL) {
+
+		tlv_size = sizeof(struct pldm_fru_record_tlv) + strlen(TEST_BMC_VERSION) - 1;
+		tlv = malloc(tlv_size);
+		tlv->type = PLDM_FRU_FIELD_TYPE_VERSION;
+		tlv->length = strlen(TEST_BMC_VERSION);
+		memcpy(tlv->value, TEST_BMC_VERSION, tlv->length);
+		*fru_table_size = sizeof(struct pldm_fru_record_data_format) + tlv->length - 1;
+
+		// Culculate pad bytes in fru
+		if (*fru_table_size % 4)
+			pad_bytes = 4 - (*fru_table_size % 4);
+		else
+			pad_bytes = 0;
+
+		*fru_table = malloc(*fru_table_size + pad_bytes + sizeof(uint32_t));
+		ret = encode_fru_record(*fru_table, *fru_table_size, &curr_size, 0,
+				PLDM_FRU_RECORD_TYPE_GENERAL, 1, 1, (uint8_t *)tlv, tlv_size);
+		if (ret != PLDM_SUCCESS)
+			return ret;
+		*fru_table_size += pad_bytes + sizeof(uint32_t);
+
+		// Pad with 0
+		memset(*fru_table + curr_size, 0, pad_bytes);
+
+		checksum = htole32(pldm_crc32(*fru_table, *fru_table_size - sizeof(uint32_t)));
+		memcpy(*fru_table + curr_size + pad_bytes, (void *)&checksum, sizeof(uint32_t));
+		free(tlv);
+	} else
+		return OPAL_PARAMETER;
+
+	return PLDM_SUCCESS;
+}
+
+
+/*
+ * This function tries to duplicate BMC functionality for Pldm self test
+ * it tries to handle PLDM_REQUEST for PLDM_FRU and reply with appropriate
+ * PLDM_RESPONSE message
+ */
+int pldm_test_reply_request_fru(void *request_msg, size_t request_len,
+		void **response_msg, size_t *response_len)
+{
+	int  ret, payload_len = 0;
+	uint32_t transfer_handle;
+	uint16_t fru_table_handle;
+	uint16_t record_set_identifier;
+	uint8_t record_type;
+	uint8_t field_type;
+	uint8_t transfer_op_flag;
+	uint8_t *fru_ds;
+	size_t fru_ds_size;
+
+	// Check PLDM command and reply with appropriate reply
+	switch (((struct pldm_msg *)request_msg)->hdr.command) {
+	case PLDM_GET_FRU_RECORD_BY_OPTION:
+		payload_len = request_len - sizeof(struct pldm_msg_hdr);
+		ret = decode_get_fru_record_by_option_req(request_msg, payload_len,
+				&transfer_handle, &fru_table_handle, &record_set_identifier,
+				&record_type, &field_type, &transfer_op_flag);
+		if (ret != PLDM_SUCCESS)
+			return ret;
+
+		// Test if field type and record type is as expected i.e.
+		// field type = PLDM_FRU_FIELD_TYPE_VERSION and
+		// record_type == PLDM_FRU_RECORD_TYPE_GENERAL
+		// else return error
+		if (field_type == PLDM_FRU_FIELD_TYPE_VERSION &&
+				record_type == PLDM_FRU_RECORD_TYPE_GENERAL) {
+
+			//  generate the fru data structure to reply request
+			//  on behalf on BMC for PLDM self test
+			ret = pldm_test_generate_reply_field_type_version(
+					PLDM_FRU_RECORD_TYPE_GENERAL,
+					PLDM_FRU_FIELD_TYPE_VERSION, &fru_ds, &fru_ds_size);
+			if (ret != PLDM_SUCCESS)
+				return ret;
+
+			payload_len = fru_ds_size +
+				sizeof(struct pldm_get_fru_record_by_option_resp) - 1;
+			*response_len = sizeof(struct pldm_msg_hdr) + payload_len;
+			*response_msg = malloc(*response_len);
+
+			ret = encode_get_fru_record_by_option_resp(
+					((struct pldm_msg *)request_msg)->hdr.instance_id,
+					PLDM_SUCCESS, PLDM_GET_NEXTPART, PLDM_START_AND_END,
+					fru_ds, fru_ds_size, *response_msg, payload_len);
+			if (ret != PLDM_SUCCESS)
+				return ret;
+			free(fru_ds);
+			return PLDM_SUCCESS;
+		} else
+			return OPAL_PARAMETER;
+		break;
+	default:
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return PLDM_SUCCESS;
+
+}
+
+
+
+/*
+ * This function tries to duplicate BMC functionality for Pldm self test
+ * It tries to send PLDM_GET_FRU_RECORD_TABLE_METADATA on behalf of BMC
+ */
+int test_fru_table_metadata_request(void)
+{
+	void *pldm_req;
+	int size, ret;
+
+	size = sizeof(struct pldm_msg_hdr);
+	pldm_req = malloc(size);
+	// Enable flag that indicate PLDM_GET_FRU_RECORD_TABLE_METADATA
+	// request in progress.
+	// This flag is used only for test
+	get_fru_record_table_in_progress = true;
+
+	// Encode request on behalf of BMC
+	ret = encode_get_fru_record_table_metadata_req(0, pldm_req, 0);
+	if (ret != PLDM_SUCCESS)
+		return ret;
+
+	// initialize responder
+	ret = pldm_mctp_responder_init();
+	if (ret != PLDM_SUCCESS)
+		return ret;
+
+	// skip mctp layer directly call handle
+	ret = pldm_handle(BMC_EID, pldm_req, size);
+	if (ret != PLDM_SUCCESS)
+		return ret;
+
+	// Disable flag that indicate PLDM_GET_FRU_RECORD_TABLE_METADATA
+	// request in progress.
+	// This flag is used only for test
+	get_fru_record_table_in_progress = false;
+
+	return ret;
+
+}
+
+
+int main(void)
+{
+	int ret;
+	void *fru_record_table;
+	uint32_t fru_record_table_size;
+	struct variable_field fru_structure_data;
+
+	// Trying to get fru table when fru table not created
+	// @return error OPAL_PARAMETER
+	ret = pldm_fru_get_table(&fru_record_table, &fru_record_table_size);
+	if (ret != OPAL_PARAMETER)
+		return OPAL_PARAMETER;
+
+	// Sending request in behalf of bmc and checking response
+	ret = test_fru_table_metadata_request();
+	if (ret != PLDM_SUCCESS) {
+		perror("encode_get_fru_record_table_metadata_req");
+		return ret;
+	}
+
+	// Trying to get fru table when fru table created
+	ret = pldm_fru_get_table(&fru_record_table, &fru_record_table_size);
+	if (ret != PLDM_SUCCESS)
+		return OPAL_PARAMETER;
+
+	/* retrieve the bmc information with
+	 * "FRU Field Type": Version
+	 * "FRU Record Set Identifier": 1,
+	 * "FRU Record Type": "General(1)"
+	 */
+	ret = pldm_fru_get_record_by_option(0, 1, PLDM_FRU_RECORD_TYPE_GENERAL,
+			PLDM_FRU_FIELD_TYPE_VERSION, &fru_structure_data);
+	if (ret != PLDM_SUCCESS) {
+		perror("encode_get_fru_record_table_metadata_req");
+		return ret;
+	}
+
+
+}
+
-- 
2.34.1



More information about the Skiboot mailing list