[Pdbg] [PATCH 1/6] libcronus: Add a library to talk to cronus server on BMC

Amitay Isaacs amitay at ozlabs.org
Wed Jul 3 19:13:49 AEST 2019


Signed-off-by: Amitay Isaacs <amitay at ozlabs.org>
---
 Makefile.am                   |  12 +++
 libcronus/buffer.c            | 180 ++++++++++++++++++++++++++++++++++
 libcronus/buffer.h            |  56 +++++++++++
 libcronus/cfam.c              | 173 ++++++++++++++++++++++++++++++++
 libcronus/connect.c           | 144 +++++++++++++++++++++++++++
 libcronus/instruction.h       | 167 +++++++++++++++++++++++++++++++
 libcronus/libcronus.h         |  45 +++++++++
 libcronus/libcronus_private.h |  53 ++++++++++
 libcronus/request.c           | 160 ++++++++++++++++++++++++++++++
 libcronus/scom.c              | 174 ++++++++++++++++++++++++++++++++
 10 files changed, 1164 insertions(+)
 create mode 100644 libcronus/buffer.c
 create mode 100644 libcronus/buffer.h
 create mode 100644 libcronus/cfam.c
 create mode 100644 libcronus/connect.c
 create mode 100644 libcronus/instruction.h
 create mode 100644 libcronus/libcronus.h
 create mode 100644 libcronus/libcronus_private.h
 create mode 100644 libcronus/request.c
 create mode 100644 libcronus/scom.c

diff --git a/Makefile.am b/Makefile.am
index e155583..71918aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -126,6 +126,18 @@ pdbg_LDADD = libpdbg.la libccan.a \
 	-L.libs -lrt
 
 lib_LTLIBRARIES = libpdbg.la
+noinst_LTLIBRARIES = libcronus.la
+
+libcronus_la_SOURCES = \
+	libcronus/buffer.c \
+	libcronus/buffer.h \
+	libcronus/cfam.c \
+	libcronus/connect.c \
+	libcronus/instruction.h \
+	libcronus/libcronus.h \
+	libcronus/libcronus_private.h \
+	libcronus/request.c \
+	libcronus/scom.c
 
 libpdbg_la_SOURCES = \
 	$(DT_sources) \
diff --git a/libcronus/buffer.c b/libcronus/buffer.c
new file mode 100644
index 0000000..b96ca9c
--- /dev/null
+++ b/libcronus/buffer.c
@@ -0,0 +1,180 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <endian.h>
+
+#include "buffer.h"
+
+int cbuf_new(struct cronus_buffer *cbuf, size_t size)
+{
+	cbuf->ptr = malloc(size);
+	if (!cbuf->ptr)
+		return ENOMEM;
+
+	cbuf->size = size;
+	cbuf->offset = 0;
+
+	return 0;
+}
+
+int cbuf_new_from_buf(struct cronus_buffer *cbuf, uint8_t *ptr, size_t size)
+{
+	int ret;
+
+	ret = cbuf_new(cbuf, size);
+	if (ret)
+		return ret;
+
+	memcpy(cbuf->ptr, ptr, size);
+	return 0;
+}
+
+void cbuf_free(struct cronus_buffer *cbuf)
+{
+	free(cbuf->ptr);
+}
+
+void cbuf_init(struct cronus_buffer *cbuf, uint8_t *ptr, size_t size)
+{
+	*cbuf = (struct cronus_buffer) {
+		.ptr = ptr,
+		.size = size,
+	};
+}
+
+uint8_t *cbuf_ptr(struct cronus_buffer *cbuf)
+{
+	return cbuf->ptr + cbuf->offset;
+}
+
+size_t cbuf_offset(struct cronus_buffer *cbuf)
+{
+	return cbuf->offset;
+}
+
+size_t cbuf_size(struct cronus_buffer *cbuf)
+{
+	return cbuf->size;
+}
+
+uint8_t *cbuf_finish(struct cronus_buffer *cbuf, size_t *length)
+{
+	*length = cbuf->offset;
+	return cbuf->ptr;
+}
+
+static void cbuf_check_offset(struct cronus_buffer *cbuf, size_t count)
+{
+	assert(cbuf->offset + count <= cbuf->size);
+}
+
+void cbuf_write(struct cronus_buffer *cbuf, uint8_t *bytes, size_t count)
+{
+	cbuf_check_offset(cbuf, count);
+
+	memcpy(cbuf->ptr + cbuf->offset, bytes, count);
+	cbuf->offset += count;
+}
+
+void cbuf_read(struct cronus_buffer *cbuf, uint8_t *bytes, size_t count)
+{
+	cbuf_check_offset(cbuf, count);
+
+	memcpy(bytes, cbuf->ptr + cbuf->offset, count);
+	cbuf->offset += count;
+}
+
+void cbuf_write_uint8(struct cronus_buffer *cbuf, uint8_t value)
+{
+	cbuf_write(cbuf, &value, 1);
+}
+
+void cbuf_read_uint8(struct cronus_buffer *cbuf, uint8_t *value)
+{
+	cbuf_read(cbuf, value, 1);
+}
+
+void cbuf_write_uint16(struct cronus_buffer *cbuf, uint16_t value)
+{
+	uint16_t data = htobe16(value);
+
+	cbuf_write(cbuf, (uint8_t *)&data, 2);
+}
+
+void cbuf_read_uint16(struct cronus_buffer *cbuf, uint16_t *value)
+{
+	uint16_t data;
+
+	cbuf_read(cbuf, (uint8_t *)&data, 2);
+	*value = be16toh(data);
+}
+
+void cbuf_write_uint32(struct cronus_buffer *cbuf, uint32_t value)
+{
+	uint32_t data = htobe32(value);
+
+	cbuf_write(cbuf, (uint8_t *)&data, 4);
+}
+
+void cbuf_read_uint32(struct cronus_buffer *cbuf, uint32_t *value)
+{
+	uint32_t data;
+
+	cbuf_read(cbuf, (uint8_t *)&data, 4);
+	*value = be32toh(data);
+}
+
+void cbuf_write_uint64(struct cronus_buffer *cbuf, uint64_t value)
+{
+	uint64_t data = htobe64(value);
+
+	cbuf_write(cbuf, (uint8_t *)&data, 8);
+}
+
+void cbuf_read_uint64(struct cronus_buffer *cbuf, uint64_t *value)
+{
+	uint64_t data;
+
+	cbuf_read(cbuf, (uint8_t *)&data, 8);
+	*value = be64toh(data);
+}
+
+void cbuf_dump(struct cronus_buffer *cbuf, const char *prefix)
+{
+	size_t len;
+	unsigned int i;
+
+	if (!prefix)
+		prefix = "DUMP";
+
+	len = (cbuf->offset > 0) ? cbuf->offset : cbuf->size;
+
+	for (i=0; i<len; i++) {
+		if (i % 16 == 0)
+			fprintf(stderr, "%s: 0x%08x", prefix, i);
+
+		fprintf(stderr, " %02x", cbuf->ptr[i]);
+
+		if ((i+1) % 16 == 0)
+			fprintf(stderr, "\n");
+	}
+	fprintf(stderr, "\n");
+}
diff --git a/libcronus/buffer.h b/libcronus/buffer.h
new file mode 100644
index 0000000..6e10272
--- /dev/null
+++ b/libcronus/buffer.h
@@ -0,0 +1,56 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LIBCRONUS_BUFFER_H__
+#define __LIBCRONUS_BUFFER_H__
+
+#include <stdint.h>
+
+struct cronus_buffer {
+	uint8_t *ptr;
+	size_t size;
+	size_t offset;
+};
+
+int cbuf_new(struct cronus_buffer *cbuf, size_t size);
+int cbuf_new_from_buf(struct cronus_buffer *cbuf, uint8_t *ptr, size_t size);
+void cbuf_free(struct cronus_buffer *cbuf);
+void cbuf_init(struct cronus_buffer *cbuf, uint8_t *ptr, size_t size);
+
+uint8_t *cbuf_finish(struct cronus_buffer *cbuf, size_t *length);
+
+uint8_t *cbuf_ptr(struct cronus_buffer *cbuf);
+size_t cbuf_offset(struct cronus_buffer *cbuf);
+size_t cbuf_size(struct cronus_buffer *cbuf);
+
+void cbuf_write(struct cronus_buffer *cbuf, uint8_t *bytes, size_t count);
+void cbuf_read(struct cronus_buffer *cbuf, uint8_t *bytes, size_t count);
+
+void cbuf_write_uint8(struct cronus_buffer *cbuf, uint8_t value);
+void cbuf_read_uint8(struct cronus_buffer *cbuf, uint8_t *value);
+
+void cbuf_write_uint16(struct cronus_buffer *cbuf, uint16_t value);
+void cbuf_read_uint16(struct cronus_buffer *cbuf, uint16_t *value);
+
+void cbuf_write_uint32(struct cronus_buffer *cbuf, uint32_t value);
+void cbuf_read_uint32(struct cronus_buffer *cbuf, uint32_t *value);
+
+void cbuf_write_uint64(struct cronus_buffer *cbuf, uint64_t value);
+void cbuf_read_uint64(struct cronus_buffer *cbuf, uint64_t *value);
+
+void cbuf_dump(struct cronus_buffer *cbuf, const char *prefix);
+
+#endif /* __LIBCRONUS_BUFFER_H__ */
diff --git a/libcronus/cfam.c b/libcronus/cfam.c
new file mode 100644
index 0000000..8ad3973
--- /dev/null
+++ b/libcronus/cfam.c
@@ -0,0 +1,173 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "buffer.h"
+#include "instruction.h"
+#include "libcronus_private.h"
+#include "libcronus.h"
+
+int cronus_getcfam(struct cronus_context *cctx,
+		   int pib_index,
+		   uint32_t addr,
+		   uint32_t *value)
+{
+	struct cronus_buffer cbuf_request, cbuf_reply;
+	struct cronus_reply reply;
+	char devstr[4] = "0\0\0\0";
+	uint32_t flags, key;
+	uint32_t capacity, bits;
+	int ret;
+
+	assert(pib_index == 0 || pib_index == 1);
+	devstr[0] = '1' + pib_index;
+
+	ret = cbuf_new(&cbuf_request, 1024);
+	if (ret)
+		return ret;
+
+	key = cronus_key(cctx);
+
+	/* number of commands */
+	cbuf_write_uint32(&cbuf_request, 1);
+
+	/* header */
+	cbuf_write_uint32(&cbuf_request, key);
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_TYPE_FSI);
+	cbuf_write_uint32(&cbuf_request, 7 * sizeof(uint32_t)); // payload size
+
+	flags = INSTRUCTION_FLAG_DEVSTR | \
+		INSTRUCTION_FLAG_CFAM_MAILBOX | \
+		INSTRUCTION_FLAG_NO_PIB_RESET;
+
+	/* payload */
+	cbuf_write_uint32(&cbuf_request, 5);  // version
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_CMD_READSPMEM);
+	cbuf_write_uint32(&cbuf_request, flags);
+	cbuf_write_uint32(&cbuf_request, addr);
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint32_t));  // data size in bits
+	cbuf_write_uint32(&cbuf_request, sizeof(devstr));
+	cbuf_write(&cbuf_request, (uint8_t *)devstr, sizeof(devstr));
+
+	ret = cronus_request(cctx, key, &cbuf_request, &cbuf_reply);
+	if (ret) {
+		fprintf(stderr, "Failed to talk to server\n");
+		return ret;
+	}
+
+	ret = cronus_parse_reply(key, &cbuf_reply, &reply);
+	if (ret) {
+		fprintf(stderr, "Failed to parse reply\n");
+		return ret;
+	}
+
+	cbuf_free(&cbuf_reply);
+
+	if (reply.rc != SERVER_COMMAND_COMPLETE) {
+		fprintf(stderr, "%s\n", reply.error);
+		return EIO;
+	}
+
+	cbuf_init(&cbuf_reply, reply.data, reply.data_len);
+
+	cbuf_read_uint32(&cbuf_reply, &capacity);
+	if (capacity != 0x00000020) {
+		fprintf(stderr, "Invalid capacity 0x%x\n", capacity);
+		return EPROTO;
+	}
+
+	cbuf_read_uint32(&cbuf_reply, &bits);
+	if (bits != 0x00000020) {
+		fprintf(stderr, "Invalid number of bits 0x%x\n", bits);
+		return EPROTO;
+	}
+
+	cbuf_read_uint32(&cbuf_reply, value);
+
+	return 0;
+}
+
+int cronus_putcfam(struct cronus_context *cctx,
+		   int pib_index,
+		   uint32_t addr,
+		   uint32_t value)
+{
+	struct cronus_buffer cbuf_request, cbuf_reply;
+	struct cronus_reply reply;
+	char devstr[4] = "0\0\0\0";
+	uint32_t flags, key;
+	int ret;
+
+	assert(pib_index == 0 || pib_index == 1);
+	devstr[0] = '1' + pib_index;
+
+	ret = cbuf_new(&cbuf_request, 1024);
+	if (ret)
+		return ret;
+
+	key = cronus_key(cctx);
+
+	/* number of commands */
+	cbuf_write_uint32(&cbuf_request, 1);
+
+	/* header */
+	cbuf_write_uint32(&cbuf_request, key);
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_TYPE_FSI);
+	cbuf_write_uint32(&cbuf_request, 11 * sizeof(uint32_t)); // payload size
+
+	flags = INSTRUCTION_FLAG_DEVSTR | \
+		INSTRUCTION_FLAG_CFAM_MAILBOX | \
+		INSTRUCTION_FLAG_NO_PIB_RESET;
+
+	/* payload */
+	cbuf_write_uint32(&cbuf_request, 5);  // version
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_CMD_WRITESPMEM);
+	cbuf_write_uint32(&cbuf_request, flags);
+	cbuf_write_uint32(&cbuf_request, addr);
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint32_t));  // data size in bits
+	cbuf_write_uint32(&cbuf_request, sizeof(devstr));
+	cbuf_write_uint32(&cbuf_request, (1 + 1 + 1) * sizeof(uint32_t)); // size of value
+	cbuf_write(&cbuf_request, (uint8_t *)devstr, sizeof(devstr));
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint32_t)); // capacity in bits
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint32_t)); // length in bits
+	cbuf_write_uint32(&cbuf_request, value);
+
+	ret = cronus_request(cctx, key, &cbuf_request, &cbuf_reply);
+	if (ret) {
+		fprintf(stderr, "Failed to talk to server\n");
+		return ret;
+	}
+
+	ret = cronus_parse_reply(key, &cbuf_reply, &reply);
+	if (ret) {
+		fprintf(stderr, "Failed to parse reply\n");
+		return ret;
+	}
+
+	cbuf_free(&cbuf_request);
+	cbuf_free(&cbuf_reply);
+
+	if (reply.rc != SERVER_COMMAND_COMPLETE) {
+		fprintf(stderr, "%s\n", reply.error);
+		return EIO;
+	}
+
+	return 0;
+}
+
diff --git a/libcronus/connect.c b/libcronus/connect.c
new file mode 100644
index 0000000..f8c9856
--- /dev/null
+++ b/libcronus/connect.c
@@ -0,0 +1,144 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+#include "libcronus_private.h"
+#include "libcronus.h"
+
+static int cronus_wait_for_feedbobo(struct cronus_context *cctx)
+{
+	uint32_t pkt[10];
+	ssize_t n;
+	uint32_t word;
+
+	n = read(cctx->fd, pkt, sizeof(pkt));
+	if (n == -1) {
+		int ret = errno;
+		perror("read");
+		return ret;
+	}
+
+	if (n != 2 * sizeof(uint32_t)) {
+		fprintf(stderr, "Insufficient data from server\n");
+		return EPROTO;
+	}
+
+	word = ntohl(pkt[1]);
+	if ((word & 0xFFFFFFF0) != 0xFEEDB0B0) {
+		fprintf(stderr, "Invalid response 0x%08x from server\n", word);
+		return EPROTO;
+	}
+
+	cctx->server_version = word & 0x0000000F;
+
+	return 0;
+}
+
+int cronus_connect(const char *hostname, struct cronus_context **out)
+{
+	struct cronus_context *cctx;
+	struct addrinfo hints;
+	struct addrinfo *result;
+	struct sockaddr_in addr;
+	extern int h_errno;
+	int fd, ret;
+
+	if (!hostname || !out)
+		return EINVAL;
+
+	hints = (struct addrinfo) {
+		.ai_family = AF_INET,
+	};
+
+	ret = getaddrinfo(hostname, NULL, &hints, &result);
+	if (ret != 0) {
+		herror("getaddrinfo");
+		return EIO;
+	}
+
+	cctx = malloc(sizeof(struct cronus_context));
+	if (!cctx) {
+		fprintf(stderr, "Memory allocation error\n");
+		return ENOMEM;
+	}
+
+	*cctx = (struct cronus_context) {
+		.fd = -1,
+		.key = 0x11111111,
+	};
+
+	addr = *(struct sockaddr_in *)result->ai_addr;
+	addr.sin_port = htons(8192);
+
+	freeaddrinfo(result);
+
+	fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+	if (fd == -1) {
+		ret = errno;
+		perror("socket");
+		return ret;
+	}
+
+	ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret == -1) {
+		ret = errno;
+		perror("connect");
+		close(fd);
+		return ret;
+	}
+
+	cctx->fd = fd;
+
+	ret = cronus_wait_for_feedbobo(cctx);
+	if (ret) {
+		close(fd);
+		return ret;
+	}
+
+	*out = cctx;
+	return 0;
+}
+
+void cronus_disconnect(struct cronus_context *cctx)
+{
+	assert(cctx);
+
+	if (cctx->fd != -1) {
+		close(cctx->fd);
+		cctx->fd = -1;
+	}
+
+	free(cctx);
+}
+
+uint32_t cronus_key(struct cronus_context *cctx)
+{
+	uint32_t key = cctx->key;
+
+	cctx->key += 1;
+
+	return key;
+}
diff --git a/libcronus/instruction.h b/libcronus/instruction.h
new file mode 100644
index 0000000..634d016
--- /dev/null
+++ b/libcronus/instruction.h
@@ -0,0 +1,167 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LIBCRONUS_INSTRUCTION_H__
+#define __LIBCRONUS_INSTRUCTION_H__
+
+/* Instruction types */
+#define INSTRUCTION_TYPE_NOINSTRUCTION	0
+#define INSTRUCTION_TYPE_FSI		1
+#define INSTRUCTION_TYPE_JTAG		2
+#define INSTRUCTION_TYPE_MULTIPLEJTAG	3
+#define INSTRUCTION_TYPE_PSI		4
+#define INSTRUCTION_TYPE_GPIO		5
+#define INSTRUCTION_TYPE_I2C		6
+#define INSTRUCTION_TYPE_VPD		7
+#define INSTRUCTION_TYPE_DMA		8
+#define INSTRUCTION_TYPE_CONTORL	9
+#define INSTRUCTION_TYPE_DMAEXER	10
+#define INSTRUCTION_TYPE_POWR		11
+#define INSTRUCTION_TYPE_FSISTREAM	12
+#define INSTRUCTION_TYPE_SBEFIFO	13
+#define INSTRUCTION_TYPE_GSD2PIB	14
+#define INSTRUCTION_TYPE_FSIMEMPROC	15
+#define INSTRUCTION_TYPE_PNOR		16
+#define INSTRUCTION_TYPE_D2C		17
+
+/* Instruction commands */
+#define INSTRUCTION_CMD_NOCOMMAND		0
+#define INSTRUCTION_CMD_SENDCMD			1
+#define INSTRUCTION_CMD_READ			2
+#define INSTRUCTION_CMD_WRITE			3
+#define INSTRUCTION_CMD_LONGIN			4
+#define INSTRUCTION_CMD_LONGOUT			5
+#define INSTRUCTION_CMD_READ_WRITE		6
+#define INSTRUCTION_CMD_SHIFTOUT		7
+#define INSTRUCTION_CMD_DMAIN			8
+#define INSTRUCTION_CMD_DMAOUT			9
+#define INSTRUCTION_CMD_MISC			10
+#define INSTRUCTION_CMD_TOTAP			11
+#define INSTRUCTION_CMD_READVPD			12
+#define INSTRUCTION_CMD_READSPMEM		13
+#define INSTRUCTION_CMD_WRITESPMEM		14
+#define INSTRUCTION_CMD_SCOMIN			15
+#define INSTRUCTION_CMD_SCOMOUT			16
+#define INSTRUCTION_CMD_WRITEVPD		17
+#define INSTRUCTION_CMD_PSI_RESET		18
+#define INSTRUCTION_CMD_PSI_LINK_CALIB		19
+#define INSTRUCTION_CMD_PSI_EI_REG_READ		20
+#define INSTRUCTION_CMD_PSI_EI_REG_WRITE	21
+#define INSTRUCTION_CMD_PSI_VERIFY		22
+#define INSTRUCTION_CMD_PSI_SCOM_READ		23
+#define INSTRUCTION_CMD_PSI_SCOM_WRITE		24
+#define INSTRUCTION_CMD_PSI_READ		25
+#define INSTRUCTION_CMD_PSI_WRITE		26
+#define INSTRUCTION_CMD_PSI_INIT		27
+#define INSTRUCTION_CMD_PSI_LINK_ENABLE		28
+#define INSTRUCTION_CMD_PSI_SET_SPEED		29
+#define INSTRUCTION_CMD_PSI_LINK_VERIFY		30
+#define INSTRUCTION_CMD_I2CWRITE		31
+#define INSTRUCTION_CMD_I2READ			32
+#define INSTRUCTION_CMD_GPIO_CONFIGPIN		33
+#define INSTRUCTION_CMD_GPIO_READPIN		34
+#define INSTRUCTION_CMD_GPIO_READPINS		35
+#define INSTRUCTION_CMD_GPIO_READLATCH		36
+#define INSTRUCTION_CMD_GPIO_WRITELATCH		37
+#define INSTRUCTION_CMD_GPIO_WRITELATCHES	38
+#define INSTRUCTION_CMD_GPIO_READCONFIG		39
+#define INSTRUCTION_CMD_GPIO_WRITECONFIG	40
+#define INSTRUCTION_CMD_GPIO_WRITECNFGSET	41
+#define INSTRUCTION_CMD_GPIO_WRITECNFGCLR	42
+#define INSTRUCTION_CMD_DMAEXER_START		43
+#define INSTRUCTION_CMD_DMAEXER_REPORT		44
+#define INSTRUCTION_CMD_DMAEXER_STOP		45
+#define INSTRUCTION_CMD_INFO			46
+#define INSTRUCTION_CMD_RUN_CMD			47
+#define INSTRUCTION_CMD_MULTI_ENALBE		48
+#define INSTRUCTION_CMD_AUTH			49
+#define INSTRUCTION_CMD_ADDAUTH			50
+#define INSTRUCTION_CMD_CLEARAUTH		51
+#define INSTRUCTION_CMD_VERSION			52
+#define INSTRUCTION_CMD_FLIGHTRECORDER		53
+#define INSTRUCTION_CMD_EXIT			54
+#define INSTRUCTION_CMD_SCOMIN_MASK		55
+#define INSTRUCTION_CMD_MASK_PERSISTENT		56
+#define INSTRUCTION_CMD_SET_PERSISTENT		57
+#define INSTRUCTION_CMD_GET_PERSISTENT		58
+#define INSTRUCTION_CMD_READKEYWORD		59
+#define INSTRUCTION_CMD_WRITEKEYWORD		60
+#define INSTRUCTION_CMD_FRUSTATUS		61
+#define INSTRUCTION_CMD_CHICDOIPL		62
+#define INSTRUCTION_CMD_ENABLE_MEM_VOLTAGES	63
+#define INSTRUCTION_CMD_DISABLE_MEM_VOLTAGES	64
+#define INSTRUCTION_CMD_SNDISTEPMSG		65
+#define INSTRUCTION_CMD_MBXTRACEENABLE		66
+#define INSTRUCTION_CMD_MBXTRACEDISABLE		67
+#define INSTRUCTION_CMD_MBXTRACEREAD		68
+#define INSTRUCTION_CMD_PUTMEMPBA		69
+#define INSTRUCTION_CMD_GETMEMPBA		70
+#define INSTRUCTION_CMD_BULK_SCOMOUT		71
+#define INSTRUCTION_CMD_BULK_SCOMIN		72
+#define INSTRUCTION_CMD_STREAM_SETUP		73
+#define INSTRUCTION_CMD_STREAM_FINISH		74
+#define INSTRUCTION_CMD_FSPDMAIN		75
+#define INSTRUCTION_CMD_FSPDMAOUT		76
+#define INSTRUCTION_CMD_SUBMIT			77
+#define INSTRUCTION_CMD_REQUEST_RESET		78
+#define INSTRUCTION_CMD_SEND_TAPI_CMD		79
+#define INSTRUCTION_CMD_PUTMEMPROC		80
+#define INSTRUCTION_CMD_GETMEMPROC		81
+#define INSTRUCTION_CMD_PNORGETLIST		82
+#define INSTRUCTION_CMD_PNORGET			83
+#define INSTRUCTION_CMD_PNORPUT			84
+#define INSTRUCTION_CMD_QUERYSP			85
+#define INSTRUCTION_CMD_ADJUST_PROC_VOLTAGES	86
+#define INSTRUCTION_CMD_I2CRESETLIGHT		87
+#define INSTRUCTION_CMD_I2CRESETFULL		88
+#define INSTRUCTION_CMD_PSI_CMU_REG_READ	89
+#define INSTRUCTION_CMD_PSI_CMU_REG_WRITE	90
+#define INSTRUCTION_CMD_GETFILE			91
+
+/* Instruction flags */
+#define INSTRUCTION_FLAG_DEBUG                  0x80000000
+#define INSTRUCTION_FLAG_NOEXECUTE              0x40000000
+#define INSTRUCTION_FLAG_SERVER_DEBUG           0x20000000
+#define INSTRUCTION_FLAG_PERFORMANCE            0x10000000
+#define INSTRUCTION_FLAG_CRC_ENABLE             0x08000000
+#define INSTRUCTION_FLAG_32BIT_CRC              0x04000000
+#define INSTRUCTION_FLAG_16BIT_CRC              0x02000000
+#define INSTRUCTION_FLAG_PERSISTENT_DATA        0x01000000
+#define INSTRUCTION_FLAG_FSI_SCANHEADERCHECK    0x00800000
+#define INSTRUCTION_FLAG_FSI_SCANSETPULSE       0x00400000
+#define INSTRUCTION_FLAG_FSI_USE_DRA            0x00200000
+#define INSTRUCTION_FLAG_FSI_SCANEXTRABCLOCK    0x00100000
+#define INSTRUCTION_FLAG_FSI_SCANVIAPIB         0x00080000
+#define INSTRUCTION_FLAG_FSI_CFAM2_0            0x00040000
+#define INSTRUCTION_FLAG_64BIT_ADDRESS          0x00008000
+#define INSTRUCTION_FLAG_DEVSTR                 0x00004000
+#define INSTRUCTION_FLAG_CFAM_MAILBOX           0x00002000
+#define INSTRUCTION_FLAG_CACHE_INHIBITED        0x00001000
+#define INSTRUCTION_FLAG_SBEFIFO_RESET_ENABLE   0x00000800
+#define INSTRUCTION_FLAG_POWR_DDR4              0x00000400
+#define INSTRUCTION_FLAG_NO_PIB_RESET           0x00000200
+
+/* Result types */
+#define RESULT_TYPE_ECMD_DBUF		0
+#define RESULT_TYPE_INSTRUCTION_STATUS	1
+
+/* Error codes */
+#define ECMD_ERR_CRONUS                         0x02000000 ///< Error came from Cronus
+
+#define SERVER_COMMAND_COMPLETE                 (ECMD_ERR_CRONUS | 0x402000)
+
+
+#endif /* __LIBCRONUS_INSTRUCTION_H__ */
diff --git a/libcronus/libcronus.h b/libcronus/libcronus.h
new file mode 100644
index 0000000..c3b178c
--- /dev/null
+++ b/libcronus/libcronus.h
@@ -0,0 +1,45 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LIBCRONUS_H__
+#define __LIBCRONUS_H__
+
+#include <stdint.h>
+
+struct cronus_context;
+
+int cronus_connect(const char *hostname, struct cronus_context **out);
+void cronus_disconnect(struct cronus_context *cctx);
+
+int cronus_getcfam(struct cronus_context *cctx,
+		   int pib_index,
+		   uint32_t addr,
+		   uint32_t *value);
+int cronus_putcfam(struct cronus_context *cctx,
+		   int pib_index,
+		   uint32_t addr,
+		   uint32_t value);
+
+int cronus_getscom(struct cronus_context *cctx,
+		   int pib_index,
+		   uint64_t addr,
+		   uint64_t *value);
+int cronus_putscom(struct cronus_context *cctx,
+		   int pib_index,
+		   uint64_t addr,
+		   uint64_t value);
+
+#endif /* __LIBCRONUS_H__ */
diff --git a/libcronus/libcronus_private.h b/libcronus/libcronus_private.h
new file mode 100644
index 0000000..9a6c720
--- /dev/null
+++ b/libcronus/libcronus_private.h
@@ -0,0 +1,53 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LIBCRONUS_PRIVATE_H__
+#define __LIBCRONUS_PRIVATE_H__
+
+#include <stdint.h>
+
+#include "buffer.h"
+
+struct cronus_context {
+	int fd;
+	uint32_t key;
+
+	uint32_t server_version;
+};
+
+struct cronus_reply {
+	uint32_t status_version;
+	uint32_t instruction_version;
+	uint32_t rc;
+	uint32_t status_len;
+	uint8_t *status;
+	char *error;
+
+	uint32_t data_len;
+	uint8_t *data;
+};
+
+uint32_t cronus_key(struct cronus_context *cctx);
+
+int cronus_request(struct cronus_context *cctx,
+		   uint32_t key,
+		   struct cronus_buffer *request,
+		   struct cronus_buffer *reply);
+int cronus_parse_reply(uint32_t key,
+		       struct cronus_buffer *cbuf,
+		       struct cronus_reply *reply);
+
+#endif /* __LIBCRONUS_PRIVATE_H__ */
diff --git a/libcronus/request.c b/libcronus/request.c
new file mode 100644
index 0000000..60f928a
--- /dev/null
+++ b/libcronus/request.c
@@ -0,0 +1,160 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "buffer.h"
+#include "instruction.h"
+#include "libcronus_private.h"
+
+int cronus_request(struct cronus_context *cctx,
+		   uint32_t key,
+		   struct cronus_buffer *request,
+		   struct cronus_buffer *reply)
+{
+	uint8_t buf[1024], *ptr;
+	size_t len = 0;
+	ssize_t n;
+	int ret;
+
+	assert(cctx);
+	assert(cctx->fd != -1);
+
+	ptr = cbuf_finish(request, &len);
+	assert(len > 0);
+
+	n = write(cctx->fd, ptr, len);
+	if (n == -1) {
+		ret = errno;
+		perror("write");
+		return ret;
+	}
+	if (n != len) {
+		fprintf(stderr, "Short write (%zu of %zu) to server\n", n, len);
+		return EIO;
+	}
+
+	n = read(cctx->fd, buf, sizeof(buf));
+	if (n == -1) {
+		ret = errno;
+		perror("read");
+		return ret;
+	}
+
+	ret = cbuf_new_from_buf(reply, buf, n);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int cronus_parse_ecmd_dbuf(struct cronus_buffer *cbuf,
+				  uint32_t size,
+				  struct cronus_reply *reply)
+{
+	reply->data = malloc(size);
+	if (!reply->data)
+		return ENOMEM;
+	reply->data_len = size;
+
+	cbuf_read(cbuf, reply->data, reply->data_len);
+	return 0;
+
+}
+
+static int cronus_parse_instruction_status(struct cronus_buffer *cbuf,
+					   uint32_t size,
+					   struct cronus_reply *reply)
+{
+	uint32_t offset;
+
+	if (size < 4 * sizeof(uint32_t))
+		return EPROTO;
+
+	cbuf_read_uint32(cbuf, &reply->status_version);
+	cbuf_read_uint32(cbuf, &reply->instruction_version);
+	cbuf_read_uint32(cbuf, &reply->rc);
+	cbuf_read_uint32(cbuf, &reply->status_len);
+	offset = 4 * sizeof(uint32_t);
+
+	if (size < offset + reply->status_len)
+		return EPROTO;
+
+	reply->status = malloc(reply->status_len);
+	if (!reply->status)
+		return ENOMEM;
+
+	cbuf_read(cbuf, reply->status, reply->status_len);
+	return 0;
+}
+
+int cronus_parse_reply(uint32_t key,
+		       struct cronus_buffer *cbuf,
+		       struct cronus_reply *reply)
+{
+	uint32_t num_replies;
+	int i;
+
+	memset(reply, 0, sizeof(*reply));
+
+	cbuf_read_uint32(cbuf, &num_replies);
+	if (num_replies != 2) {
+		fprintf(stderr, "Invalid number of replies (%u) from server\n", num_replies);
+		return EPROTO;
+	}
+
+	for (i=0; i<num_replies; i++) {
+		uint32_t rkey, type, size;
+		int ret = -1;
+
+		cbuf_read_uint32(cbuf, &rkey);
+		if (rkey != key) {
+			fprintf(stderr, "Wrong key %u, expected %u\n", rkey, key);
+			return EPROTO;
+		}
+
+		cbuf_read_uint32(cbuf, &type);
+		cbuf_read_uint32(cbuf, &size);
+
+		if (type == RESULT_TYPE_ECMD_DBUF) {
+			ret = cronus_parse_ecmd_dbuf(cbuf, size, reply);
+		} else if (type == RESULT_TYPE_INSTRUCTION_STATUS) {
+			ret = cronus_parse_instruction_status(cbuf, size, reply);
+		}
+
+		if (ret != 0)
+			return ret;
+	}
+
+	if (reply->rc != SERVER_COMMAND_COMPLETE) {
+		uint32_t size;
+
+		size = cbuf_size(cbuf) - cbuf_offset(cbuf);
+
+		reply->error = malloc(size);
+		if (!reply->error)
+			return ENOMEM;
+
+		cbuf_read(cbuf, (uint8_t *)reply->error, size);
+	}
+
+	return 0;
+}
diff --git a/libcronus/scom.c b/libcronus/scom.c
new file mode 100644
index 0000000..5679ae5
--- /dev/null
+++ b/libcronus/scom.c
@@ -0,0 +1,174 @@
+/* Copyright 2019 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "buffer.h"
+#include "instruction.h"
+#include "libcronus_private.h"
+#include "libcronus.h"
+
+int cronus_getscom(struct cronus_context *cctx,
+		   int pib_index,
+		   uint64_t addr,
+		   uint64_t *value)
+{
+	struct cronus_buffer cbuf_request, cbuf_reply;
+	struct cronus_reply reply;
+	char devstr[4] = "0\0\0\0";
+	uint32_t flags, key;
+	uint32_t capacity, bits;
+	int ret;
+
+	assert(pib_index == 0 || pib_index == 1);
+	devstr[0] = '1' + pib_index;
+
+	ret = cbuf_new(&cbuf_request, 1024);
+	if (ret)
+		return ret;
+
+	key = cronus_key(cctx);
+
+	/* number of commands */
+	cbuf_write_uint32(&cbuf_request, 1);
+
+	/* header */
+	cbuf_write_uint32(&cbuf_request, key);
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_TYPE_FSI);
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint32_t)); // payload size
+
+	flags = INSTRUCTION_FLAG_64BIT_ADDRESS | \
+		INSTRUCTION_FLAG_DEVSTR | \
+		INSTRUCTION_FLAG_NO_PIB_RESET;
+
+	/* payload */
+	cbuf_write_uint32(&cbuf_request, 5);  // version
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_CMD_SCOMOUT);
+	cbuf_write_uint32(&cbuf_request, flags);
+	cbuf_write_uint64(&cbuf_request, addr);
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint64_t));  // data size in bits
+	cbuf_write_uint32(&cbuf_request, sizeof(devstr));
+	cbuf_write(&cbuf_request, (uint8_t *)devstr, sizeof(devstr));
+
+	ret = cronus_request(cctx, key, &cbuf_request, &cbuf_reply);
+	if (ret) {
+		fprintf(stderr, "Failed to talk to server\n");
+		return ret;
+	}
+
+	ret = cronus_parse_reply(key, &cbuf_reply, &reply);
+	if (ret) {
+		fprintf(stderr, "Failed to parse reply\n");
+		return ret;
+	}
+
+	cbuf_free(&cbuf_request);
+	cbuf_free(&cbuf_reply);
+
+	if (reply.rc != SERVER_COMMAND_COMPLETE) {
+		fprintf(stderr, "%s\n", reply.error);
+		return EIO;
+	}
+
+	cbuf_init(&cbuf_reply, reply.data, reply.data_len);
+
+	cbuf_read_uint32(&cbuf_reply, &capacity);
+	if (capacity != 0x00000040) {
+		fprintf(stderr, "Invalid capacity 0x%x\n", capacity);
+		return EPROTO;
+	}
+
+	cbuf_read_uint32(&cbuf_reply, &bits);
+	if (bits != 0x00000040) {
+		fprintf(stderr, "Invalid number of bits 0x%x\n", bits);
+		return EPROTO;
+	}
+
+	cbuf_read_uint64(&cbuf_reply, value);
+
+	return 0;
+}
+
+int cronus_putscom(struct cronus_context *cctx,
+		   int pib_index,
+		   uint64_t addr,
+		   uint64_t value)
+{
+	struct cronus_buffer cbuf_request, cbuf_reply;
+	struct cronus_reply reply;
+	char devstr[4] = "0\0\0\0";
+	uint32_t flags, key;
+	int ret;
+
+	assert(pib_index == 0 || pib_index == 1);
+	devstr[0] = '1' + pib_index;
+
+	ret = cbuf_new(&cbuf_request, 1024);
+	if (ret)
+		return ret;
+
+	key = cronus_key(cctx);
+
+	/* number of commands */
+	cbuf_write_uint32(&cbuf_request, 1);
+
+	/* header */
+	cbuf_write_uint32(&cbuf_request, key);
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_TYPE_FSI);
+	cbuf_write_uint32(&cbuf_request, 13 * sizeof(uint32_t)); // payload size
+
+	flags = INSTRUCTION_FLAG_64BIT_ADDRESS | \
+		INSTRUCTION_FLAG_DEVSTR | \
+		INSTRUCTION_FLAG_NO_PIB_RESET;
+
+	/* payload */
+	cbuf_write_uint32(&cbuf_request, 5);  // version
+	cbuf_write_uint32(&cbuf_request, INSTRUCTION_CMD_SCOMIN);
+	cbuf_write_uint32(&cbuf_request, flags);
+	cbuf_write_uint64(&cbuf_request, addr);
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint64_t));  // data size in bits
+	cbuf_write_uint32(&cbuf_request, sizeof(devstr));
+	cbuf_write_uint32(&cbuf_request, (1 + 1 + 2) * sizeof(uint32_t)); // size of value
+	cbuf_write(&cbuf_request, (uint8_t *)devstr, sizeof(devstr));
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint64_t)); // capacity in bits
+	cbuf_write_uint32(&cbuf_request, 8 * sizeof(uint64_t)); // length in bits
+	cbuf_write_uint64(&cbuf_request, value);
+
+	ret = cronus_request(cctx, key, &cbuf_request, &cbuf_reply);
+	if (ret) {
+		fprintf(stderr, "Failed to talk to server\n");
+		return ret;
+	}
+
+	ret = cronus_parse_reply(key, &cbuf_reply, &reply);
+	if (ret) {
+		fprintf(stderr, "Failed to parse reply\n");
+		return ret;
+	}
+
+	cbuf_free(&cbuf_request);
+	cbuf_free(&cbuf_reply);
+
+	if (reply.rc != SERVER_COMMAND_COMPLETE) {
+		fprintf(stderr, "%s\n", reply.error);
+		return EIO;
+	}
+
+	return 0;
+}
-- 
2.21.0



More information about the Pdbg mailing list