diff --git a/Makefile.am b/Makefile.am
index 011e686..f850a29 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -129,7 +129,7 @@ pdbg_LDADD = libpdbg.la libccan.a \
 pdbg_LDFLAGS = -Wl,--whole-archive,-lpdbg,--no-whole-archive
 
 lib_LTLIBRARIES = libpdbg.la
-noinst_LTLIBRARIES = libcronus.la
+noinst_LTLIBRARIES = libcronus.la libsbefifo.la
 
 libcronus_la_SOURCES = \
 	libcronus/buffer.c \
@@ -142,6 +142,22 @@ libcronus_la_SOURCES = \
 	libcronus/request.c \
 	libcronus/scom.c
 
+libsbefifo_la_SOURCES = \
+	libsbefifo/cmd_array.c \
+	libsbefifo/cmd_control.c \
+	libsbefifo/cmd_generic.c \
+	libsbefifo/cmd_instruction.c \
+	libsbefifo/cmd_memory.c \
+	libsbefifo/cmd_mpipl.c \
+	libsbefifo/cmd_register.c \
+	libsbefifo/cmd_ring.c \
+	libsbefifo/cmd_scom.c \
+	libsbefifo/connect.c \
+	libsbefifo/ffdc.c \
+	libsbefifo/libsbefifo.h \
+	libsbefifo/operation.c \
+	libsbefifo/sbefifo_private.h
+
 libpdbg_la_SOURCES = \
 	$(DT_sources) \
 	libpdbg/adu.c \
diff --git a/libsbefifo/cmd_array.c b/libsbefifo/cmd_array.c
new file mode 100644
index 0000000..c5f5eec
--- /dev/null
+++ b/libsbefifo/cmd_array.c
@@ -0,0 +1,100 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_control_fast_array(struct sbefifo_context *sctx, uint16_t target_type, uint8_t chiplet_id, uint8_t mode, uint64_t clock_cycle)
+{
+	uint8_t *out;
+	uint32_t msg[3];
+	uint32_t cmd, out_len;
+	uint32_t target;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_ARRAY | SBEFIFO_CMD_FAST_ARRAY;
+	target = ((uint32_t)target_type << 16) |
+		 ((uint32_t)chiplet_id << 8) |
+		 ((uint32_t)(mode & 0x3));
+
+	msg[0] = htobe32(3);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(target);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 3 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
+
+int sbefifo_control_trace_array(struct sbefifo_context *sctx, uint16_t target_type, uint8_t chiplet_id, uint16_t array_id, uint16_t operation, uint8_t **trace_data, uint32_t *trace_data_len)
+{
+	uint8_t *out;
+	uint32_t msg[4];
+	uint32_t cmd, out_len;
+	uint32_t target, oper;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_ARRAY | SBEFIFO_CMD_TRACE_ARRAY;
+	target = ((uint32_t)target_type << 16) | ((uint32_t)chiplet_id);
+	oper = ((uint32_t)array_id << 16) | ((uint32_t)operation);
+
+	msg[0] = htobe32(4);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(target);
+	msg[3] = htobe32(oper);
+
+	out_len = 16 * 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 4 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len < 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	*trace_data_len = 4 * be32toh(*(uint32_t *) &out[out_len-4]);
+
+	if (out_len != *trace_data_len + 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	*trace_data = malloc(*trace_data_len);
+	if (! *trace_data) {
+		free(out);
+		return ENOMEM;
+	}
+
+	memcpy(*trace_data, out, *trace_data_len);
+
+	free(out);
+	return 0;
+}
diff --git a/libsbefifo/cmd_control.c b/libsbefifo/cmd_control.c
new file mode 100644
index 0000000..abbfd73
--- /dev/null
+++ b/libsbefifo/cmd_control.c
@@ -0,0 +1,50 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_istep_execute(struct sbefifo_context *sctx, uint8_t major, uint8_t minor)
+{
+	uint8_t *out;
+	uint32_t msg[3];
+	uint32_t cmd, step, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_CONTROL | SBEFIFO_CMD_EXECUTE_ISTEP;
+	step = (major << 16) | minor;
+
+	msg[0] = htobe32(3);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(step);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 3 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
diff --git a/libsbefifo/cmd_generic.c b/libsbefifo/cmd_generic.c
new file mode 100644
index 0000000..f912e92
--- /dev/null
+++ b/libsbefifo/cmd_generic.c
@@ -0,0 +1,169 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_get_ffdc(struct sbefifo_context *sctx, uint8_t **ffdc, uint32_t *ffdc_len)
+{
+	uint8_t *out;
+	uint32_t msg[2];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_GENERIC | SBEFIFO_CMD_GET_FFDC;
+
+	msg[0] = htobe32(2);	// number of words
+	msg[1] = htobe32(cmd);
+
+	/* We don't know how much data to expect, let's assume it's less than 32K */
+	out_len = 0x8000;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 2 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	*ffdc_len = out_len;
+	if (out_len > 0) {
+		*ffdc = malloc(out_len);
+		if (! *ffdc) {
+			free(out);
+			return ENOMEM;
+		}
+		memcpy(*ffdc, out, out_len);
+
+		free(out);
+	} else {
+		*ffdc = NULL;
+	}
+
+	return 0;
+}
+
+int sbefifo_get_capabilities(struct sbefifo_context *sctx, uint32_t *version, char **commit_id, uint32_t **caps, uint32_t *caps_count)
+{
+	uint8_t *out;
+	uint32_t msg[2];
+	uint32_t cmd, out_len;
+	uint32_t i;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_GENERIC | SBEFIFO_CMD_GET_CAPABILITY;
+
+	msg[0] = htobe32(2);	// number of words
+	msg[1] = htobe32(cmd);
+
+	out_len = 23 * 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 2 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 23 * 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	*version = be32toh(*(uint32_t *) &out[0]);
+
+	*commit_id = malloc(9);
+	if (! *commit_id) {
+		free(out);
+		return ENOMEM;
+	}
+	memcpy(*commit_id, &out[4], 8);
+	(*commit_id)[8] = '\0';
+
+	*caps = malloc(20 * 4);
+	if (! *caps) {
+		free(out);
+		return ENOMEM;
+	}
+
+	*caps_count = 20;
+	for (i=0; i<20; i++)
+		(*caps)[i] = be32toh(*(uint32_t *) &out[12+i*4]);
+
+	free(out);
+	return 0;
+}
+
+int sbefifo_get_frequencies(struct sbefifo_context *sctx, uint32_t **freq, uint32_t *freq_count)
+{
+	uint8_t *out;
+	uint32_t msg[2];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_GENERIC | SBEFIFO_CMD_GET_FREQUENCY;
+
+	msg[0] = htobe32(2);	// number of words
+	msg[1] = htobe32(cmd);
+
+	out_len = 8 * 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 2 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	*freq_count = out_len / 4;
+	if (*freq_count > 0) {
+		uint32_t i;
+
+		*freq = malloc(*freq_count * 4);
+		if (! *freq) {
+			free(out);
+			return ENOMEM;
+		}
+
+		for (i=0; i<*freq_count; i++)
+			(*freq)[i] = be32toh(*(uint32_t *) &out[i*4]);
+
+		free(out);
+	} else {
+		*freq = NULL;
+	}
+
+	return 0;
+}
+
+int sbefifo_quiesce(struct sbefifo_context *sctx)
+{
+	uint8_t *out;
+	uint32_t msg[2];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_GENERIC | SBEFIFO_CMD_GET_FREQUENCY;
+
+	msg[0] = htobe32(2);	// number of words
+	msg[1] = htobe32(cmd);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 2 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
diff --git a/libsbefifo/cmd_instruction.c b/libsbefifo/cmd_instruction.c
new file mode 100644
index 0000000..5185982
--- /dev/null
+++ b/libsbefifo/cmd_instruction.c
@@ -0,0 +1,54 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_control_insn(struct sbefifo_context *sctx, uint8_t core_id, uint8_t thread_id, uint8_t thread_op, uint8_t mode)
+{
+	uint8_t *out;
+	uint32_t msg[3];
+	uint32_t cmd, out_len;
+	uint32_t oper;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_INSTRUCTION | SBEFIFO_CMD_CONTROL_INSN;
+	oper = ((uint32_t)(mode & 0xf) << 16) |
+		((uint32_t)(core_id & 0xff) << 8) |
+		((uint32_t)(thread_id & 0xf) << 4) |
+		((uint32_t)(thread_op & 0xf));
+
+	msg[0] = htobe32(3);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(oper);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 3 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
diff --git a/libsbefifo/cmd_memory.c b/libsbefifo/cmd_memory.c
new file mode 100644
index 0000000..b20767f
--- /dev/null
+++ b/libsbefifo/cmd_memory.c
@@ -0,0 +1,243 @@
+/* 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 <endian.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_mem_get(struct sbefifo_context *sctx, uint64_t addr, uint32_t size, uint16_t flags, uint8_t **data)
+{
+	uint8_t *out;
+	uint64_t start_addr, end_addr;
+	uint32_t msg[6];
+	uint32_t cmd, out_len;
+	uint32_t align, offset, len, extra_bytes, i, j;
+	int rc;
+	bool do_tag = false, do_ecc = false;
+
+	if (flags & SBEFIFO_MEMORY_FLAG_PROC) {
+		align = 8;
+
+		if (flags & SBEFIFO_MEMORY_FLAG_ECC_REQ)
+			do_ecc = true;
+
+		if (flags & SBEFIFO_MEMORY_FLAG_TAG_REQ)
+			do_tag = true;
+
+	} else if (flags & SBEFIFO_MEMORY_FLAG_PBA) {
+		align = 128;
+	} else {
+		return EINVAL;
+	}
+
+	start_addr = addr & (~(uint64_t)(align-1));
+	end_addr = (addr + size + (align-1)) & (~(uint64_t)(align-1));
+
+	if (end_addr - start_addr > 0xffffffff)
+		return EINVAL;
+
+	offset = addr - start_addr;
+	len = end_addr - start_addr;
+
+	extra_bytes = 0;
+	if (do_tag)
+		extra_bytes = len / 8;
+
+	if (do_ecc)
+		extra_bytes = len / 8;
+
+	cmd = SBEFIFO_CMD_CLASS_MEMORY | SBEFIFO_CMD_GET_MEMORY;
+
+	msg[0] = htobe32(6);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(flags);
+	msg[3] = htobe32(start_addr >> 32);
+	msg[4] = htobe32(start_addr & 0xffffffff);
+	msg[5] = htobe32(len);
+
+	out_len = len + extra_bytes + 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 6 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != len + extra_bytes + 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	len = be32toh(*(uint32_t *) &out[out_len-4]);
+	*data = malloc(len);
+	if (! *data) {
+		free(out);
+		return ENOMEM;
+	}
+
+	i = 0;
+	j = 0;
+	while (i < len) {
+		memcpy((void *)&(*data)[j], (void *)&out[i], 8);
+		i += 8;
+		j += 8;
+
+		if (do_tag)
+			i++;
+
+		if (do_ecc)
+			i++;
+	}
+	if (i < len)
+		memcpy((void *)&(*data)[j], (void *)&out[i], len - i);
+
+	memmove(*data, *data + offset, size);
+
+	free(out);
+	return 0;
+}
+
+int sbefifo_mem_put(struct sbefifo_context *sctx, uint64_t addr, uint8_t *data, uint32_t data_len, uint16_t flags)
+{
+	uint8_t *out;
+	uint32_t nwords = (data_len+3)/4;
+	uint32_t msg[6+nwords];
+	uint32_t cmd, out_len;
+	uint32_t align;
+	int rc;
+
+	if (flags & SBEFIFO_MEMORY_FLAG_PROC)
+		align = 8;
+	else if (flags & SBEFIFO_MEMORY_FLAG_PBA)
+		align = 128;
+	else
+		return EINVAL;
+
+	if (addr & (align-1))
+		return EINVAL;
+
+	cmd = SBEFIFO_CMD_CLASS_MEMORY | SBEFIFO_CMD_PUT_MEMORY;
+
+	msg[0] = htobe32(6 + nwords); // number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(flags);
+	msg[3] = htobe32(addr >> 32);
+	msg[4] = htobe32(addr & 0xffffffff);
+	msg[5] = htobe32(data_len);
+	memcpy(&msg[6], data, data_len);
+
+	out_len = 1 * 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, (6+nwords) * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	free(out);
+	return 0;
+}
+
+int sbefifo_occsram_get(struct sbefifo_context *sctx, uint32_t addr, uint32_t size, uint8_t mode, uint8_t **data, uint32_t *data_len)
+{
+	uint8_t *out;
+	uint32_t start_addr, end_addr;
+	uint32_t msg[5];
+	uint32_t cmd, out_len;
+	uint32_t align, offset, len;
+	int rc;
+
+	align = 8;
+	start_addr = addr & (~(uint32_t)(align-1));
+	end_addr = (addr + size + (align-1)) & (~(uint32_t)(align-1));
+
+	offset = addr - start_addr;
+	len = end_addr - start_addr;
+
+	cmd = SBEFIFO_CMD_CLASS_MEMORY | SBEFIFO_CMD_GET_OCCSRAM;
+
+	msg[0] = htobe32(5);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(mode);
+	msg[3] = htobe32(start_addr);
+	msg[4] = htobe32(len);
+
+	out_len = len + 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 5 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != len + 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	*data_len = be32toh(*(uint32_t *) &out[out_len-4]);
+	*data = malloc(*data_len);
+	if (! *data) {
+		free(out);
+		return ENOMEM;
+	}
+	memcpy(*data, out + offset, size);
+
+	free(out);
+	return 0;
+}
+
+int sbefifo_occsram_put(struct sbefifo_context *sctx, uint32_t addr, uint8_t *data, uint32_t data_len, uint8_t mode)
+{
+	uint8_t *out;
+	uint32_t nwords = (data_len+3)/4;
+	uint32_t msg[5+nwords];
+	uint32_t cmd, out_len;
+	uint32_t align;
+	int rc;
+
+	align = 8;
+
+	if (addr & (align-1))
+		return EINVAL;
+
+	if (data_len & (align-1))
+		return EINVAL;
+
+	cmd = SBEFIFO_CMD_CLASS_MEMORY | SBEFIFO_CMD_PUT_OCCSRAM;
+
+	msg[0] = htobe32(5 + nwords); // number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(mode);
+	msg[3] = htobe32(addr);
+	msg[4] = htobe32(data_len);
+	memcpy(&msg[6], data, data_len);
+
+	out_len = 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, (5+nwords) * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	free(out);
+	return 0;
+}
diff --git a/libsbefifo/cmd_mpipl.c b/libsbefifo/cmd_mpipl.c
new file mode 100644
index 0000000..b5f9ea5
--- /dev/null
+++ b/libsbefifo/cmd_mpipl.c
@@ -0,0 +1,102 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_mpipl_enter(struct sbefifo_context *sctx)
+{
+	uint8_t *out;
+	uint32_t msg[2];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_MPIPL | SBEFIFO_CMD_ENTER_MPIPL;
+
+	msg[0] = htobe32(2);	// number of words
+	msg[1] = htobe32(cmd);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 2 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
+
+int sbefifo_mpipl_continue(struct sbefifo_context *sctx)
+{
+	uint8_t *out;
+	uint32_t msg[2];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_MPIPL | SBEFIFO_CMD_CONTINUE_MPIPL;
+
+	msg[0] = htobe32(2);	// number of words
+	msg[1] = htobe32(cmd);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 2 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
+
+int sbefifo_mpipl_stopclocks(struct sbefifo_context *sctx, uint16_t target_type, uint8_t chiplet_id)
+{
+	uint8_t *out;
+	uint32_t msg[3];
+	uint32_t cmd, out_len;
+	uint32_t target;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_GENERIC | SBEFIFO_CMD_STOP_CLOCKS;
+	target = ((uint32_t)target_type << 16) | chiplet_id;
+
+	msg[0] = htobe32(3);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(target);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 3 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
diff --git a/libsbefifo/cmd_register.c b/libsbefifo/cmd_register.c
new file mode 100644
index 0000000..201ceb5
--- /dev/null
+++ b/libsbefifo/cmd_register.c
@@ -0,0 +1,115 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_register_get(struct sbefifo_context *sctx, uint8_t core_id, uint8_t thread_id, uint8_t reg_type, uint8_t *reg_id, uint8_t reg_count, uint64_t **value)
+{
+	uint8_t *out;
+	uint32_t msg[3+reg_count];
+	uint32_t cmd, out_len;
+	uint32_t r, i;
+	int rc;
+
+	if (reg_count == 0 || reg_count > 64)
+		return EINVAL;
+
+	cmd = SBEFIFO_CMD_CLASS_REGISTER | SBEFIFO_CMD_GET_REGISTER;
+	r = ((uint32_t)(core_id & 0xff) << 16) |
+	    ((uint32_t)(thread_id & 0x3) << 12) |
+	    ((uint32_t)(reg_type & 0x3) << 8) |
+	    ((uint32_t)(reg_count & 0xff));
+
+	msg[0] = htobe32(3+reg_count);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(r);
+	for (i=0; i<reg_count; i++) {
+		msg[3+i] = htobe32(reg_id[i] & 0xff);
+	}
+
+	out_len = reg_count * 8;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, (3+reg_count) * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != reg_count * 8) {
+		free(out);
+		return EPROTO;
+	}
+
+	*value = malloc(reg_count * 8);
+	if (! *value) {
+		free(out);
+		return ENOMEM;
+	}
+
+	for (i=0; i<reg_count; i++) {
+		uint32_t val1, val2;
+
+		val1 = be32toh(*(uint32_t *) &out[i*4]);
+		val2 = be32toh(*(uint32_t *) &out[i*4+4]);
+
+		(*value)[i] = ((uint64_t)val1 << 32) | (uint64_t)val2;
+	}
+
+	free(out);
+	return 0;
+}
+
+int sbefifo_register_put(struct sbefifo_context *sctx, uint8_t core_id, uint8_t thread_id, uint8_t reg_type, uint8_t *reg_id, uint8_t reg_count, uint64_t *value)
+{
+	uint8_t *out;
+	uint32_t msg[3+(3*reg_count)];
+	uint32_t cmd, out_len;
+	uint32_t r, i;
+	int rc;
+
+	if (reg_count == 0 || reg_count > 64)
+		return EINVAL;
+
+	cmd = SBEFIFO_CMD_CLASS_REGISTER | SBEFIFO_CMD_PUT_REGISTER;
+	r = ((uint32_t)(core_id & 0xff) << 16) |
+	    ((uint32_t)(thread_id & 0x3) << 12) |
+	    ((uint32_t)(reg_type & 0x3) << 8) |
+	    ((uint32_t)(reg_count & 0xff));
+
+	msg[0] = htobe32(3 + 3*reg_count);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(r);
+	for (i=0; i<reg_count; i++) {
+		msg[3+i*3] = htobe32(reg_id[i] & 0xff);
+		msg[3+i*3+1] = htobe32(value[i] >> 32);
+		msg[3+i*3+2] = htobe32(value[i] & 0xffffffff);
+	}
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, (3+3*reg_count) * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
diff --git a/libsbefifo/cmd_ring.c b/libsbefifo/cmd_ring.c
new file mode 100644
index 0000000..70478e3
--- /dev/null
+++ b/libsbefifo/cmd_ring.c
@@ -0,0 +1,119 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_ring_get(struct sbefifo_context *sctx, uint32_t ring_addr, uint32_t ring_len_bits, uint16_t flags, uint8_t **ring_data, uint32_t *ring_len)
+{
+	uint8_t *out;
+	uint32_t msg[5];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_RING | SBEFIFO_CMD_GET_RING;
+
+	msg[0] = htobe32(5);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(ring_addr);
+	msg[3] = htobe32(ring_len_bits);
+	msg[4] = htobe32(flags);
+
+	/* multiples of 64 bits */
+	out_len = (ring_len_bits + 63) / 8;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 5 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len*8 < ring_len_bits) {
+		free(out);
+		return EPROTO;
+	}
+
+	*ring_len = be32toh(*(uint32_t *) &out[out_len-4]);
+	*ring_data = malloc(*ring_len);
+	if (! *ring_data) {
+		free(out);
+		return ENOMEM;
+	}
+	memcpy(*ring_data, out, *ring_len);
+
+	free(out);
+	return 0;
+}
+
+int sbefifo_ring_put(struct sbefifo_context *sctx, uint16_t ring_mode, uint8_t *ring_data, uint32_t ring_data_len)
+{
+	uint8_t *out;
+	uint32_t nwords = (ring_data_len + 3) / 4;
+	uint32_t msg[3+nwords];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_RING | SBEFIFO_CMD_PUT_RING;
+
+	msg[0] = htobe32(3 + nwords); // number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(ring_mode);
+	memcpy(&msg[3], ring_data, ring_data_len);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, (3+nwords) * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
+
+int sbefifo_ring_put_from_image(struct sbefifo_context *sctx, uint16_t target, uint8_t chiplet_id, uint16_t ring_id, uint16_t ring_mode)
+{
+	uint8_t *out;
+	uint32_t msg[3];
+	uint32_t cmd, out_len;
+	uint32_t target_word, ring_word;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_RING | SBEFIFO_CMD_PUT_RING_IMAGE;
+	target_word = ((uint32_t)target << 16) | (uint32_t)chiplet_id;
+	ring_word = ((uint32_t)ring_id << 16) | (uint32_t)ring_mode;
+
+	msg[0] = htobe32(3);	// number of words
+	msg[1] = htobe32(target_word);
+	msg[2] = htobe32(ring_word);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 3 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
diff --git a/libsbefifo/cmd_scom.c b/libsbefifo/cmd_scom.c
new file mode 100644
index 0000000..cc236ca
--- /dev/null
+++ b/libsbefifo/cmd_scom.c
@@ -0,0 +1,147 @@
+/* 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 <endian.h>
+#include <errno.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_scom_get(struct sbefifo_context *sctx, uint64_t addr, uint64_t *value)
+{
+	uint8_t *out;
+	uint32_t msg[4];
+	uint32_t cmd, out_len;
+	uint32_t val1, val2;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_SCOM | SBEFIFO_CMD_GET_SCOM;
+
+	msg[0] = htobe32(4);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(addr >> 32);
+	msg[3] = htobe32(addr & 0xffffffff);
+
+	out_len = 2 * 4;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 4 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 2 * 4) {
+		free(out);
+		return EPROTO;
+	}
+
+	val1 = be32toh(*(uint32_t *) &out[0]);
+	val2 = be32toh(*(uint32_t *) &out[4]);
+	free(out);
+
+	*value = ((uint64_t)val1 << 32) | (uint64_t)val2;
+
+	return 0;
+}
+
+int sbefifo_scom_put(struct sbefifo_context *sctx, uint64_t addr, uint64_t value)
+{
+	uint8_t *out;
+	uint32_t msg[6];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_SCOM | SBEFIFO_CMD_PUT_SCOM;
+
+	msg[0] = htobe32(6);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(addr >> 32);
+	msg[3] = htobe32(addr & 0xffffffff);
+	msg[2] = htobe32(value >> 32);
+	msg[3] = htobe32(value & 0xffffffff);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 6 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
+
+int sbefifo_scom_modify(struct sbefifo_context *sctx, uint64_t addr, uint64_t value, uint8_t operand)
+{
+	uint8_t *out;
+	uint32_t msg[7];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_SCOM | SBEFIFO_CMD_MODIFY_SCOM;
+
+	msg[0] = htobe32(7);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(operand);
+	msg[3] = htobe32(addr >> 32);
+	msg[4] = htobe32(addr & 0xffffffff);
+	msg[5] = htobe32(value >> 32);
+	msg[6] = htobe32(value & 0xffffffff);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 7 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
+
+int sbefifo_scom_put_mask(struct sbefifo_context *sctx, uint64_t addr, uint64_t value, uint64_t mask)
+{
+	uint8_t *out;
+	uint32_t msg[8];
+	uint32_t cmd, out_len;
+	int rc;
+
+	cmd = SBEFIFO_CMD_CLASS_SCOM | SBEFIFO_CMD_PUT_SCOM_MASK;
+
+	msg[0] = htobe32(8);	// number of words
+	msg[1] = htobe32(cmd);
+	msg[2] = htobe32(addr >> 32);
+	msg[3] = htobe32(addr & 0xffffffff);
+	msg[4] = htobe32(value >> 32);
+	msg[5] = htobe32(value & 0xffffffff);
+	msg[6] = htobe32(mask >> 32);
+	msg[7] = htobe32(mask & 0xffffffff);
+
+	out_len = 0;
+	rc = sbefifo_operation(sctx, (uint8_t *)msg, 8 * 4, cmd, &out, &out_len);
+	if (rc)
+		return rc;
+
+	if (out_len != 0) {
+		free(out);
+		return EPROTO;
+	}
+
+	return 0;
+}
diff --git a/libsbefifo/connect.c b/libsbefifo/connect.c
new file mode 100644
index 0000000..08194e1
--- /dev/null
+++ b/libsbefifo/connect.c
@@ -0,0 +1,74 @@
+/* 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 <fcntl.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "libsbefifo.h"
+#include "sbefifo_private.h"
+
+int sbefifo_connect(const char *fifo_path, struct sbefifo_context **out)
+{
+	struct sbefifo_context *sctx;
+	int fd, rc;
+
+	sctx = malloc(sizeof(struct sbefifo_context));
+	if (!sctx) {
+		fprintf(stderr, "Memory allocation error\n");
+		return ENOMEM;
+	}
+
+	*sctx = (struct sbefifo_context) {
+		.fd = -1,
+	};
+
+	fd = open(fifo_path, O_RDWR | O_SYNC);
+	if (fd < 0) {
+		rc = errno;
+		fprintf(stderr, "Error opening fifo %s\n", fifo_path);
+		free(sctx);
+		return rc;
+	}
+
+	sctx->fd = fd;
+
+	*out = sctx;
+	return 0;
+}
+
+void sbefifo_disconnect(struct sbefifo_context *sctx)
+{
+	if (sctx->fd != -1)
+		close(sctx->fd);
+
+	if (sctx->ffdc)
+		free(sctx->ffdc);
+
+	free(sctx);
+}
+
+void sbefifo_debug(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+}
diff --git a/libsbefifo/ffdc.c b/libsbefifo/ffdc.c
new file mode 100644
index 0000000..f29afc1
--- /dev/null
+++ b/libsbefifo/ffdc.c
@@ -0,0 +1,151 @@
+/* Copyright 2016 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 "sbefifo_private.h"
+
+void sbefifo_ffdc_clear(struct sbefifo_context *sctx)
+{
+	sctx->status = 0;
+
+	if (sctx->ffdc) {
+		free(sctx->ffdc);
+		sctx->ffdc = NULL;
+		sctx->ffdc_len = 0;
+	}
+}
+
+void sbefifo_ffdc_set(struct sbefifo_context *sctx, uint32_t status, uint8_t *ffdc, uint32_t ffdc_len)
+{
+	sctx->status = status;
+
+	sctx->ffdc = malloc(ffdc_len);
+	if (!sctx->ffdc) {
+		fprintf(stderr, "Memory allocation error\n");
+		return;
+	}
+
+	memcpy(sctx->ffdc, ffdc, ffdc_len);
+	sctx->ffdc_len = ffdc_len;
+}
+
+uint32_t sbefifo_ffdc_get(struct sbefifo_context *sctx, const uint8_t **ffdc, uint32_t *ffdc_len)
+{
+	*ffdc = sctx->ffdc;
+	*ffdc_len = sctx->ffdc_len;
+
+	return sctx->status;
+}
+
+static int sbefifo_ffdc_get_uint32(struct sbefifo_context *sctx, uint32_t offset, uint32_t *value)
+{
+	uint32_t v;
+
+	if (offset + 4 > sctx->ffdc_len)
+		return -1;
+
+	memcpy(&v, sctx->ffdc + offset, 4);
+	*value = be32toh(v);
+
+	return 0;
+}
+
+static int sbefifo_ffdc_dump_pkg(struct sbefifo_context *sctx, uint32_t offset)
+{
+	uint32_t offset2 = offset;
+	uint32_t header, value;
+	uint16_t magic, len_words;
+	int i, rc;
+
+	rc = sbefifo_ffdc_get_uint32(sctx, offset2, &header);
+	if (rc < 0)
+		return -1;
+	offset2 += 4;
+
+	/*
+	 * FFDC package structure
+	 *
+	 *             +----------+----------+----------+----------+
+	 *             |  Byte 0  |  Byte 1  |  Byte 2  |  Byte  3 |
+	 *  +----------+----------+----------+----------+----------+
+	 *  |  word 0  |        magic        | length in words (N) |
+	 *  +----------+---------------------+---------------------+
+	 *  |  word 1  |      sequence id    |       command       |
+	 *  +----------+---------------------+---------------------+
+	 *  |  word 2  |              return code                  |
+	 *  +----------+-------------------------------------------+
+	 *  |  word 3  |            FFDC Data - word 0             |
+	 *  +----------+-------------------------------------------+
+	 *  |  word 4  |            FFDC Data - word 1             |
+	 *  +----------+-------------------------------------------+
+	 *  |    ...   |                    ...                    |
+	 *  +----------+-------------------------------------------+
+	 *  |  word N  |            FFDC Data - word N-3           |
+	 *  +----------+----------+----------+----------+----------+
+	 */
+
+	magic = header >> 16;
+	if (magic != 0xffdc) {
+		fprintf(stderr, "sbefifo: ffdc expected 0xffdc, got 0x%04x\n", magic);
+		return -1;
+	}
+
+	len_words = header & 0xffff;
+
+	rc = sbefifo_ffdc_get_uint32(sctx, offset2, &value);
+	if (rc < 0)
+		return -1;
+	offset2 += 4;
+
+	printf("FFDC: Sequence = %u\n", value >> 16);
+	printf("FFDC: Command = 0x%08x\n", value & 0xffff);
+
+	rc = sbefifo_ffdc_get_uint32(sctx, offset2, &value);
+	if (rc < 0)
+		return -1;
+	offset2 += 4;
+
+	printf("FFDC: RC = 0x%08x\n", value);
+
+	for (i=0; i<len_words-3; i++) {
+		rc = sbefifo_ffdc_get_uint32(sctx, offset2, &value);
+		if (rc < 0)
+			return -1;
+		offset2 += 4;
+
+		printf("FFDC: Data: 0x%08x\n", value);
+	}
+
+	return offset2 - offset;
+}
+
+void sbefifo_ffdc_dump(struct sbefifo_context *sctx)
+{
+	uint32_t offset = 0;
+
+	while (offset < sctx->ffdc_len) {
+		int n;
+
+		n = sbefifo_ffdc_dump_pkg(sctx, offset);
+		if (n <= 0)
+			break;
+
+		offset += n;
+	}
+}
diff --git a/libsbefifo/libsbefifo.h b/libsbefifo/libsbefifo.h
new file mode 100644
index 0000000..84b0169
--- /dev/null
+++ b/libsbefifo/libsbefifo.h
@@ -0,0 +1,116 @@
+/* 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 __LIBSBEFIFO_H__
+#define __LIBSBEFIFO_H__
+
+#include <stdint.h>
+
+#define SBEFIFO_PRI_SUCCESS           0x00000000
+#define SBEFIFO_PRI_INVALID_COMMAND   0x00010000
+#define SBEFIFO_PRI_INVALID_DATA      0x00020000
+#define SBEFIFO_PRI_SEQUENCE_ERROR    0x00030000
+#define SBEFIFO_PRI_INTERNAL_ERROR    0x00040000
+#define SBEFIFO_PRI_UNKNOWN_ERROR     0x00FE0000
+
+#define SBEFIFO_SEC_SUCCESS               0x0000
+#define SBEFIFO_SEC_INVALID_CMD_CLASS     0x0001
+#define SBEFIFO_SEC_INVALID_CMD           0x0002
+#define SBEFIFO_SEC_INVALID_ADDRESS       0x0003
+#define SBEFIFO_SEC_INVALID_TARGET        0x0004
+#define SBEFIFO_SEC_INVALID_CHIPLET       0x0005
+#define SBEFIFO_SEC_TARGET_NOT_PRESENT    0x0006
+#define SBEFIFO_SEC_TARGET_NOT_FUNCTIONAL 0x0007
+#define SBEFIFO_SEC_CMD_NOT_ALLOWED       0x0008
+#define SBEFIFO_SEC_INVALID_FUNCTION      0x0009
+#define SBEFIFO_SEC_GENERIC_FAILURE       0x000A
+#define SBEFIFO_SEC_INVALID_ACCESS        0x000B
+#define SBEFIFO_SEC_SBE_OS_FAIL           0x000C
+#define SBEFIFO_SEC_SBE_ACCESS_FAIL       0x000D
+#define SBEFIFO_SEC_MISSING_DATA          0x000E
+#define SBEFIFO_SEC_EXTRA_DATA            0x000F
+#define SBEFIFO_SEC_HW_TIMEOUT            0x0010
+#define SBEFIFO_SEC_PIB_ERROR             0x0011
+#define SBEFIFO_SEC_PARITY_ERROR          0x0012
+
+struct sbefifo_context;
+
+int sbefifo_connect(const char *fifo_path, struct sbefifo_context **out);
+void sbefifo_disconnect(struct sbefifo_context *sctx);
+
+uint32_t sbefifo_ffdc_get(struct sbefifo_context *sctx, const uint8_t **ffdc, uint32_t *ffdc_len);
+void sbefifo_ffdc_dump(struct sbefifo_context *sctx);
+
+int sbefifo_istep_execute(struct sbefifo_context *sctx, uint8_t major, uint8_t minor);
+
+#define SBEFIFO_SCOM_OPERAND_NONE        0
+#define SBEFIFO_SCOM_OPERAND_OR          1
+#define SBEFIFO_SCOM_OPERAND_AND         2
+#define SBEFIFO_SCOM_OPERAND_XOR         3
+
+int sbefifo_scom_get(struct sbefifo_context *sctx, uint64_t addr, uint64_t *value);
+int sbefifo_scom_put(struct sbefifo_context *sctx, uint64_t addr, uint64_t value);
+int sbefifo_scom_modify(struct sbefifo_context *sctx, uint64_t addr, uint64_t value, uint8_t operand);
+int sbefifo_scom_put_mask(struct sbefifo_context *sctx, uint64_t addr, uint64_t value, uint64_t mask);
+
+int sbefifo_ring_get(struct sbefifo_context *sctx, uint32_t ring_addr, uint32_t ring_len_bits, uint16_t flags, uint8_t **ring_data, uint32_t *ring_len);
+int sbefifo_ring_put(struct sbefifo_context *sctx, uint16_t ring_mode, uint8_t *ring_data, uint32_t ring_data_len);
+int sbefifo_ring_put_from_image(struct sbefifo_context *sctx, uint16_t target, uint8_t chiplet_id, uint16_t ring_id, uint16_t ring_mode);
+
+#define SBEFIFO_MEMORY_FLAG_PROC         0x0001
+#define SBEFIFO_MEMORY_FLAG_PBA          0x0002
+#define SBEFIFO_MEMORY_FLAG_AUTO_INCR    0x0004
+#define SBEFIFO_MEMORY_FLAG_ECC_REQ      0x0008
+#define SBEFIFO_MEMORY_FLAG_TAG_REQ      0x0010
+#define SBEFIFO_MEMORY_FLAG_FAST_MODE    0x0020
+#define SBEFIFO_MEMORY_FLAG_LCO_MODE     0x0040 // only for mem_put
+#define SBEFIFO_MEMORY_FLAG_CI           0x0080
+#define SBEFIFO_MEMORY_FLAG_PASSTHRU     0x0100
+#define SBEFIFO_MEMORY_FLAG_CACHEINJECT  0x0200 // only for mem_put
+
+int sbefifo_mem_get(struct sbefifo_context *sctx, uint64_t addr, uint32_t size, uint16_t flags, uint8_t **data);
+int sbefifo_mem_put(struct sbefifo_context *sctx, uint64_t addr, uint8_t *data, uint32_t len, uint16_t flags);
+int sbefifo_occsram_get(struct sbefifo_context *sctx, uint32_t addr, uint32_t size, uint8_t mode, uint8_t **data, uint32_t *data_len);
+int sbefifo_occsram_put(struct sbefifo_context *sctx, uint32_t addr, uint8_t *data, uint32_t data_len, uint8_t mode);
+
+#define SBEFIFO_REGISTER_TYPE_GPR	0x0
+#define SBEFIFO_REGISTER_TYPE_SPR	0x1
+#define SBEFIFO_REGISTER_TYPE_FPR	0x2
+
+int sbefifo_register_get(struct sbefifo_context *sctx, uint8_t core_id, uint8_t thread_id, uint8_t reg_type, uint8_t *reg_id, uint8_t reg_count, uint64_t **value);
+int sbefifo_register_put(struct sbefifo_context *sctx, uint8_t core_id, uint8_t thread_id, uint8_t reg_type, uint8_t *reg_id, uint8_t reg_count, uint64_t *value);
+
+int sbefifo_control_fast_array(struct sbefifo_context *sctx, uint16_t target_type, uint8_t chiplet_id, uint8_t mode, uint64_t clock_cycle);
+int sbefifo_control_trace_array(struct sbefifo_context *sctx, uint16_t target_type, uint8_t chiplet_id, uint16_t array_id, uint16_t operation, uint8_t **trace_data, uint32_t *trace_data_len);
+
+#define SBEFIFO_INSN_OP_START            0x0
+#define SBEFIFO_INSN_OP_STOP             0x1
+#define SBEFIFO_INSN_OP_STEP             0x2
+#define SBEFIFO_INSN_OP_SRESET           0x3
+
+int sbefifo_control_insn(struct sbefifo_context *sctx, uint8_t core_id, uint8_t thread_id, uint8_t thread_op, uint8_t mode);
+
+int sbefifo_get_ffdc(struct sbefifo_context *sctx, uint8_t **ffdc, uint32_t *ffdc_len);
+int sbefifo_get_capabilities(struct sbefifo_context *sctx, uint32_t *version, char **commit_id, uint32_t **caps, uint32_t *caps_count);
+int sbefifo_get_frequencies(struct sbefifo_context *sctx, uint32_t **freq, uint32_t *freq_count);
+int sbefifo_quiesce(struct sbefifo_context *sctx);
+
+int sbefifo_mpipl_enter(struct sbefifo_context *sctx);
+int sbefifo_mpipl_continue(struct sbefifo_context *sctx);
+int sbefifo_mpipl_stopclocks(struct sbefifo_context *sctx, uint16_t target_type, uint8_t chiplet_id);
+
+
+#endif /* __LIBSBEFIFO_H__ */
diff --git a/libsbefifo/operation.c b/libsbefifo/operation.c
new file mode 100644
index 0000000..43418a1
--- /dev/null
+++ b/libsbefifo/operation.c
@@ -0,0 +1,149 @@
+/* Copyright 2016 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 "sbefifo_private.h"
+
+static int sbefifo_read(struct sbefifo_context *sctx, void *buf, size_t *buflen)
+{
+	ssize_t n;
+
+	assert(*buflen > 0);
+
+	n = read(sctx->fd, buf, *buflen);
+	if (n < 0)
+		return errno;
+
+	*buflen = n;
+	return 0;
+}
+
+static int sbefifo_write(struct sbefifo_context *sctx, void *buf, size_t buflen)
+{
+	ssize_t n;
+
+	assert(buflen > 0);
+
+	n = write(sctx->fd, buf, buflen);
+	if (n < 0)
+		return errno;
+
+	if (n != buflen)
+		return EIO;
+
+	return 0;
+}
+
+int sbefifo_operation(struct sbefifo_context *sctx,
+		      uint8_t *msg, uint32_t msg_len, uint16_t cmd,
+		      uint8_t **out, uint32_t *out_len)
+{
+	uint8_t *buf;
+	size_t buflen;
+	uint32_t offset_word, header_word, status_word;
+	uint32_t offset;
+	int rc;
+
+	assert(msg);
+	assert(msg_len > 0);
+
+	sbefifo_ffdc_clear(sctx);
+
+	/*
+	 * Allocate extra memory for FFDC (SBEFIFO_MAX_FFDC_SIZE = 0x2000)
+	 * Use *out_len as a hint to expected reply length
+	 */
+	buflen = (*out_len + 0x2000 + 3) & ~(uint32_t)3;
+	buf = malloc(buflen);
+	if (!buf)
+		return ENOMEM;
+
+	LOG("request: cmd=%08x, len=%u\n", cmd, msg_len);
+
+	rc = sbefifo_write(sctx, msg, msg_len);
+	if (rc) {
+		LOG("write: cmd=%08x, rc=%d\n", cmd, rc);
+		return rc;
+	}
+
+	rc = sbefifo_read(sctx, buf, &buflen);
+	if (rc) {
+		LOG("read: cmd=%08x, buflen=%zu, rc=%d\n", cmd, buflen, rc);
+		return rc;
+	}
+
+	/*
+	 * At least 3 words are expected in response
+	 *   - header word
+	 *   - status word
+	 *   - header offset word
+	 */
+	if (buflen < 3 * 4) {
+		LOG("reply: cmd=%08x, len=%u\n", cmd, buflen);
+		rc = EPROTO;
+		goto fail;
+	}
+
+	/* Last word is header offset (in words) */
+	offset_word = be32toh(*(uint32_t *) &buf[buflen-4]);
+	offset = buflen - (offset_word * 4);
+
+	*out_len = offset;
+
+	header_word = be32toh(*(uint32_t *) &buf[offset]);
+	offset += 4;
+
+	status_word = be32toh(*(uint32_t *) &buf[offset]);
+	offset += 4;
+
+	if (header_word != (0xc0de0000 | cmd)) {
+		LOG("reply: cmd=%08x, len=%u, header=%08x\n", cmd, buflen, header_word);
+		rc = EPROTO;
+		goto fail;
+	}
+
+	LOG("reply: cmd=%08x, len=%u, status=%08x\n", cmd, buflen, status_word);
+
+	if (status_word) {
+		sbefifo_ffdc_set(sctx, status_word, buf + offset, buflen - offset-4);
+		rc = 201;
+		goto fail;
+	}
+
+	if (*out_len > 0) {
+		*out = malloc(*out_len);
+		if (! *out) {
+			rc = ENOMEM;
+			goto fail;
+		}
+		memcpy(*out, buf, *out_len);
+	} else {
+		*out = NULL;
+	}
+
+	free(buf);
+	return 0;
+
+fail:
+	free(buf);
+	return rc;
+}
diff --git a/libsbefifo/sbefifo_private.h b/libsbefifo/sbefifo_private.h
new file mode 100644
index 0000000..87416b7
--- /dev/null
+++ b/libsbefifo/sbefifo_private.h
@@ -0,0 +1,88 @@
+/* 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 __SBEFIFO_PRIVATE_H__
+#define __SBEFIFO_PRIVATE_H__
+
+#include <stdint.h>
+
+#define SBEFIFO_CMD_CLASS_CONTROL        0xA100
+#define   SBEFIFO_CMD_EXECUTE_ISTEP        0x01
+
+#define SBEFIFO_CMD_CLASS_SCOM           0xA200
+#define   SBEFIFO_CMD_GET_SCOM             0x01
+#define   SBEFIFO_CMD_PUT_SCOM             0x02
+#define   SBEFIFO_CMD_MODIFY_SCOM          0x03
+#define   SBEFIFO_CMD_PUT_SCOM_MASK        0x04
+#define   SBEFIFO_CMD_MULTI_SCOM           0x05
+
+#define SBEFIFO_CMD_CLASS_RING           0xA300
+#define   SBEFIFO_CMD_GET_RING             0x01
+#define   SBEFIFO_CMD_PUT_RING             0x02
+#define   SBEFIFO_CMD_PUT_RING_IMAGE       0x03
+
+#define SBEFIFO_CMD_CLASS_MEMORY         0xA400
+#define   SBEFIFO_CMD_GET_MEMORY           0x01
+#define   SBEFIFO_CMD_PUT_MEMORY           0x02
+#define   SBEFIFO_CMD_GET_OCCSRAM          0x03
+#define   SBEFIFO_CMD_PUT_OCCSRAM          0x04
+
+#define SBEFIFO_CMD_CLASS_REGISTER       0xA500
+#define   SBEFIFO_CMD_GET_REGISTER         0x01
+#define   SBEFIFO_CMD_PUT_REGISTER         0x02
+
+#define SBEFIFO_CMD_CLASS_ARRAY          0xA600
+#define   SBEFIFO_CMD_FAST_ARRAY           0x01
+#define   SBEFIFO_CMD_TRACE_ARRAY          0x02
+
+#define SBEFIFO_CMD_CLASS_INSTRUCTION    0xA700
+#define   SBEFIFO_CMD_CONTROL_INSN         0x01
+
+#define SBEFIFO_CMD_CLASS_GENERIC        0xA800
+#define   SBEFIFO_CMD_GET_FFDC             0x01
+#define   SBEFIFO_CMD_GET_CAPABILITY       0x02
+#define   SBEFIFO_CMD_GET_FREQUENCY        0x03
+#define   SBEFIFO_CMD_QUIESCE              0x05
+
+#define SBEFIFO_CMD_CLASS_MPIPL          0xA900
+#define SBEFIFO_CMD_ENTER_MPIPL            0x01
+#define SBEFIFO_CMD_CONTINUE_MPIPL         0x02
+#define SBEFIFO_CMD_STOP_CLOCKS            0x03
+
+struct sbefifo_context {
+	int fd;
+
+	uint32_t status;
+	uint8_t *ffdc;
+	uint32_t ffdc_len;
+};
+
+void sbefifo_debug(const char *fmt, ...);
+
+void sbefifo_ffdc_clear(struct sbefifo_context *sctx);
+void sbefifo_ffdc_set(struct sbefifo_context *sctx, uint32_t status, uint8_t *ffdc, uint32_t ffdc_len);
+
+int sbefifo_operation(struct sbefifo_context *sctx,
+		      uint8_t *msg, uint32_t msg_len, uint16_t cmd,
+		      uint8_t **out, uint32_t *out_len);
+
+#ifdef LIBSBEFIFO_DEBUG
+#define LOG(fmt, args...)	sbefifo_debug(fmt, ##args)
+#else
+#define LOG(fmt, args...)
+#endif
+
+#endif /* __SBEFIFO_PRIVATE_H__ */
