diff mbox series

[V10,19/21] core/pldm: Add file io read request

Message ID 20230829092338.75785-20-clombard@linux.ibm.com
State Accepted
Headers show
Series Implement MCTP and PLDM features | expand

Commit Message

Christophe Lombard Aug. 29, 2023, 9:23 a.m. UTC
Send/receive a PLDM ReadFile request message.

Due to maximum transfer size for PLDM protocol, we have to send several
read requests, if necessary.

Reviewed-by: Abhishek Singh Tomar <abhishek@linux.ibm.com>
Signed-off-by: Christophe Lombard <clombard@linux.ibm.com>
---
 core/pldm/pldm-file-io-requests.c | 134 ++++++++++++++++++++++++++++++
 core/pldm/pldm.h                  |   2 +
 2 files changed, 136 insertions(+)
diff mbox series

Patch

diff --git a/core/pldm/pldm-file-io-requests.c b/core/pldm/pldm-file-io-requests.c
index 11251a30c..3a68966d4 100644
--- a/core/pldm/pldm-file-io-requests.c
+++ b/core/pldm/pldm-file-io-requests.c
@@ -7,6 +7,7 @@ 
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
+#include <timebase.h>
 #include <libpldm/file_io.h>
 #include "pldm.h"
 
@@ -33,6 +34,139 @@  static void file_io_init_complete(bool success)
 	file_io_ready = true;
 }
 
+/* maximum currently transfer size for PLDM */
+#define KILOBYTE 1024ul
+#define MAX_TRANSFER_SIZE_BYTES (127 * KILOBYTE)
+
+/*
+ * Send/receive a PLDM ReadFile request message.
+ */
+static int read_file_req(uint32_t file_handle, uint32_t file_length,
+			 uint32_t pos, void *buf, uint64_t len)
+{
+	size_t data_size = PLDM_MSG_SIZE(struct pldm_read_file_req);
+	size_t response_len, payload_len, file_data_offset;
+	uint8_t completion_code;
+	struct pldm_tx_data *tx;
+	uint32_t resp_length;
+	uint64_t total_read;
+	void *response_msg;
+	int num_transfers;
+	void *curr_buf;
+	int rc, i;
+
+	struct pldm_read_file_req file_req = {
+		.file_handle = file_handle,
+		.offset = pos,
+		.length = len
+	};
+
+	if (!file_length)
+		return OPAL_PARAMETER;
+
+	if ((!len) || ((len + pos) > file_length))
+		return OPAL_PARAMETER;
+
+	num_transfers = 1;
+	curr_buf = buf;
+	total_read = 0;
+
+	if (file_req.length > MAX_TRANSFER_SIZE_BYTES) {
+		num_transfers = (file_req.length + MAX_TRANSFER_SIZE_BYTES - 1) /
+				MAX_TRANSFER_SIZE_BYTES;
+		file_req.length = MAX_TRANSFER_SIZE_BYTES;
+	}
+
+	prlog(PR_TRACE, "%s - file_handle: %d, offset: 0x%x, len: 0x%llx num_transfers: %d\n",
+			__func__, file_handle, file_req.offset,
+			len, num_transfers);
+
+	/* init request */
+	tx = zalloc(sizeof(struct pldm_tx_data) + data_size);
+	if (!tx)
+		return OPAL_NO_MEM;
+	tx->data_size = data_size;
+
+	for (i = 0; i < num_transfers; i++) {
+		file_req.offset = pos + (i * MAX_TRANSFER_SIZE_BYTES);
+
+		/* Encode the file request */
+		rc = encode_read_file_req(
+				DEFAULT_INSTANCE_ID,
+				file_req.file_handle,
+				file_req.offset,
+				file_req.length,
+				(struct pldm_msg *)tx->data);
+		if (rc != PLDM_SUCCESS) {
+			prlog(PR_ERR, "Encode ReadFileReq Error, rc: %d\n",
+				      rc);
+			free(tx);
+			return OPAL_PARAMETER;
+		}
+
+		/* Send and get the response message bytes */
+		rc = pldm_requester_queue_and_wait(tx,
+						   &response_msg, &response_len);
+		if (rc) {
+			prlog(PR_ERR, "Communication Error, req: ReadFileReq, rc: %d\n", rc);
+			free(tx);
+			return rc;
+		}
+
+		/* Decode the message */
+		payload_len = response_len - sizeof(struct pldm_msg_hdr);
+		rc = decode_read_file_resp(
+				response_msg,
+				payload_len,
+				&completion_code,
+				&resp_length,
+				&file_data_offset);
+		if (rc != PLDM_SUCCESS || completion_code != PLDM_SUCCESS) {
+			prlog(PR_ERR, "Decode ReadFileResp Error, rc: %d, cc: %d\n",
+				      rc, completion_code);
+			free(tx);
+			free(response_msg);
+			return OPAL_PARAMETER;
+		}
+
+		if (resp_length == 0) {
+			free(response_msg);
+			break;
+		}
+
+		memcpy(curr_buf,
+		       ((struct pldm_msg *)response_msg)->payload + file_data_offset,
+		       resp_length);
+
+		total_read += resp_length;
+		curr_buf += resp_length;
+		free(response_msg);
+
+		prlog(PR_TRACE, "%s - file_handle: %d, resp_length: 0x%x, total_read: 0x%llx\n",
+			__func__, file_handle, resp_length, total_read);
+
+		if (total_read >= len)
+			break;
+		else if (resp_length != file_req.length) {
+			/* end of file */
+			break;
+		} else if (MAX_TRANSFER_SIZE_BYTES > (len - total_read))
+			file_req.length = len - total_read;
+	}
+
+	free(tx);
+	return OPAL_SUCCESS;
+}
+
+int pldm_file_io_read_file(uint32_t file_handle, uint32_t file_length,
+			   uint32_t pos, void *buf, uint64_t len)
+{
+	if (!file_io_ready)
+		return OPAL_HARDWARE;
+
+	return read_file_req(file_handle, file_length, pos, buf, len);
+}
+
 /*
  * Send/receive a PLDM GetFileTable request message.
  * The file table contains the list of files available and
diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h
index 270cfd62e..ef0157690 100644
--- a/core/pldm/pldm.h
+++ b/core/pldm/pldm.h
@@ -52,6 +52,8 @@  int pldm_responder_handle_request(struct pldm_rx_data *rx);
 int pldm_responder_init(void);
 
 /* Requester support */
+int pldm_file_io_read_file(uint32_t file_handle, uint32_t file_length,
+			   uint32_t pos, void *buf, uint64_t len);
 int pldm_file_io_init(void);
 
 int pldm_fru_get_bmc_version(void *bv, int len);