--- old/usr/src/cmd/mdb/common/mdb/mdb_ctf.c	Tue Aug 20 09:24:06 2019
+++ new/usr/src/cmd/mdb/common/mdb/mdb_ctf.c	Tue Aug 20 09:24:06 2019
@@ -24,7 +24,7 @@
  */
 /*
  * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
- * Copyright (c) 2015, Joyent, Inc.  All rights reserved.
+ * Copyright (c) 2018, Joyent, Inc.
  */
 
 #include <mdb/mdb_ctf.h>
@@ -1236,8 +1236,9 @@
 	    "member %s of type %s", name, mp->m_tgtname);
 
 	if (mdb_ctf_member_info(mp->m_tgtid, name, &tgtoff, &tgtmid) != 0) {
-		mdb_ctf_warn(mp->m_flags,
-		    "could not find %s\n", tgtname);
+		if (mp->m_flags & MDB_CTF_VREAD_IGNORE_ABSENT)
+			return (0);
+		mdb_ctf_warn(mp->m_flags, "could not find %s\n", tgtname);
 		return (set_errno(EMDB_CTFNOMEMB));
 	}
 
@@ -1612,12 +1613,11 @@
  * Warning: it will therefore only work with enums are only used to store
  * legitimate enum values (not several values or-ed together).
  *
- * By default, if mdb_ctf_vread() can not find any members or enum values,
- * it will print a descriptive message (with mdb_warn()) and fail.
- * Passing MDB_CTF_VREAD_QUIET in 'flags' will suppress the warning message.
- * Additional flags can be used to ignore specific types of translation
- * failure, but should be used with caution, because they will silently leave
- * the caller's buffer uninitialized.
+ * Flags values:
+ *
+ * MDB_CTF_VREAD_QUIET: keep quiet about failures
+ * MDB_CTF_VREAD_IGNORE_ABSENT: ignore any member that couldn't be found in the
+ * target struct; be careful not to use an uninitialized result.
  */
 int
 mdb_ctf_vread(void *modbuf, const char *target_typename,
@@ -1630,6 +1630,7 @@
 	mdb_ctf_id_t tgtid;
 	mdb_ctf_id_t modid;
 	mdb_module_t *mod;
+	int ret;
 
 	if ((mod = mdb_get_module()) == NULL || (mfp = mod->mod_ctfp) == NULL) {
 		mdb_ctf_warn(flags, "no ctf data found for mdb module %s\n",
@@ -1662,15 +1663,20 @@
 		return (-1); /* errno is set for us */
 	}
 
-	tgtbuf = mdb_alloc(size, UM_SLEEP | UM_GC);
+	tgtbuf = mdb_alloc(size, UM_SLEEP);
 
 	if (mdb_vread(tgtbuf, size, addr) < 0) {
 		mdb_ctf_warn(flags, "couldn't read %s from %p\n",
 		    target_typename, addr);
+		mdb_free(tgtbuf, size);
 		return (-1); /* errno is set for us */
 	}
 
-	return (vread_helper(modid, modbuf, tgtid, tgtbuf, NULL, flags));
+	ret = vread_helper(modid, modbuf, tgtid, tgtbuf, NULL, flags);
+
+	mdb_free(tgtbuf, size);
+
+	return (ret);
 }
 
 /*
--- old/usr/src/cmd/mdb/common/mdb/mdb_ctf.h	Tue Aug 20 09:24:06 2019
+++ new/usr/src/cmd/mdb/common/mdb/mdb_ctf.h	Tue Aug 20 09:24:06 2019
@@ -24,7 +24,7 @@
  */
 /*
  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
- * Copyright (c) 2015, Joyent, Inc.
+ * Copyright 2018 Joyent, Inc.
  */
 
 #ifndef	_MDB_CTF_H
@@ -142,6 +142,7 @@
     int, mdb_ctf_id_t *, ulong_t *);
 
 #define	MDB_CTF_VREAD_QUIET		0x100
+#define	MDB_CTF_VREAD_IGNORE_ABSENT	0x200
 
 extern int mdb_ctf_vread(void *, const char *, const char *,
     uintptr_t, uint_t);
--- old/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile	Tue Aug 20 09:24:07 2019
+++ new/usr/src/cmd/mdb/i86pc/modules/unix/amd64/Makefile	Tue Aug 20 09:24:07 2019
@@ -22,12 +22,12 @@
 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# Copyright 2016 Joyent, Inc.
+# Copyright 2018 Joyent, Inc.
 
 MODULE = unix.so
 MDBTGT = kvm
 
-MODSRCS = unix.c i86mmu.c
+MODSRCS = unix.c i86mmu.c xcall.c
 MODASMSRCS = unix_sup.s
 
 include ../../../../../Makefile.cmd
--- old/usr/src/cmd/mdb/i86pc/modules/unix/unix.c	Tue Aug 20 09:24:07 2019
+++ new/usr/src/cmd/mdb/i86pc/modules/unix/unix.c	Tue Aug 20 09:24:07 2019
@@ -802,7 +802,7 @@
 
 /*ARGSUSED*/
 static int
-scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+scalehrtime_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
 	uint32_t nsec_scale;
 	hrtime_t tsc = addr, hrt, tsc_last, base, mult = 1;
@@ -904,7 +904,7 @@
  */
 /*ARGSUSED*/
 static int
-x86_featureset_cmd(uintptr_t addr, uint_t flags, int argc,
+x86_featureset_dcmd(uintptr_t addr, uint_t flags, int argc,
     const mdb_arg_t *argv)
 {
 	void *fset;
@@ -1035,6 +1035,9 @@
 }
 #endif
 
+extern void xcall_help(void);
+extern int xcall_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
+
 static const mdb_dcmd_t dcmds[] = {
 	{ "gate_desc", ":", "dump a gate descriptor", gate_desc },
 	{ "idt", ":[-v]", "dump an IDT", idt },
@@ -1058,9 +1061,10 @@
 	    mfntopfn_dcmd },
 	{ "memseg_list", ":", "show memseg list", memseg_list },
 	{ "scalehrtime", ":[-a|-r]", "scale an unscaled high-res time",
-	    scalehrtime_cmd, scalehrtime_help },
+	    scalehrtime_dcmd, scalehrtime_help },
 	{ "x86_featureset", NULL, "dump the x86_featureset vector",
-		x86_featureset_cmd },
+		x86_featureset_dcmd },
+	{ "xcall", ":", "print CPU cross-call state", xcall_dcmd, xcall_help },
 #ifdef _KMDB
 	{ "sysregs", NULL, "dump system registers", sysregs_dcmd },
 #endif
--- /dev/null	Tue Aug 20 09:24:08 2019
+++ new/usr/src/cmd/mdb/i86pc/modules/unix/xcall.c	Tue Aug 20 09:24:08 2019
@@ -0,0 +1,237 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
+#include <mdb/mdb_modapi.h>
+#include <mdb/mdb_ctf.h>
+#include <sys/cpuvar.h>
+#include <sys/x_call.h>
+
+typedef struct {
+		uint32_t xc_work_cnt;
+		struct xc_msg *xc_curmsg;
+		struct xc_msg *xc_msgbox;
+		xc_data_t xc_data;
+} mdb_xcall_machcpu_t;
+
+typedef struct {
+	processorid_t cpu_id;
+	mdb_xcall_machcpu_t cpu_m;
+} mdb_xcall_cpu_t;
+
+typedef struct {
+	uint_t xd_flags;
+	processorid_t xd_cpu_id;
+	size_t xd_msg_index;
+	struct xc_msg xd_msgs[NCPU];
+} xcall_data_t;
+
+void
+xcall_help(void)
+{
+	mdb_printf(
+	    "Print all active cross-calls where the given CPU is the master.\n"
+	    "The PEND column is ->xc_work_cnt, the pending message count -\n"
+	    "this includes both master and slave messages.  For each\n"
+	    "cross call, the message type and the slave CPU ID are shown.\n");
+}
+
+static int
+cpu_id_to_addr(processorid_t cpun, uintptr_t *addrp)
+{
+	uintptr_t addr;
+	GElf_Sym sym;
+
+	if (mdb_lookup_by_name("cpu", &sym) == -1) {
+		mdb_warn("failed to find symbol for 'cpu'");
+		return (-1);
+	}
+
+	if (cpun * sizeof (uintptr_t) > sym.st_size)
+		return (-1);
+
+	addr = (uintptr_t)sym.st_value + cpun * sizeof (uintptr_t);
+
+	if (mdb_vread(&addr, sizeof (addr), addr) == -1) {
+		mdb_warn("failed to read cpu[%lu]", cpun);
+		return (-1);
+	}
+
+	if (addr != (uintptr_t)NULL) {
+		*addrp = addr;
+		return (0);
+	}
+
+	return (-1);
+}
+
+static int
+xcall_copy_msg(struct xc_msg *msg, xcall_data_t *data, boolean_t current)
+{
+	if (data->xd_msg_index >= NCPU) {
+		mdb_warn("ran out of msg space: %lu >= %lu\n",
+		    data->xd_msg_index, NCPU);
+		return (-1);
+	}
+
+	bcopy(msg, &data->xd_msgs[data->xd_msg_index], sizeof (*msg));
+
+	/*
+	 * As we don't use .xc_next, store 'current' there.
+	 */
+	data->xd_msgs[data->xd_msg_index].xc_next = (void *)(uintptr_t)current;
+	data->xd_msg_index++;
+	return (0);
+}
+
+static int
+xcall_get_msgs(uintptr_t addr, const void *wdata, void *priv)
+{
+	_NOTE(ARGUNUSED(wdata));
+	xcall_data_t *data = priv;
+	mdb_xcall_cpu_t xcpu = { 0, };
+	struct xc_msg msg;
+	uintptr_t msgaddr;
+
+	if (mdb_ctf_vread(&xcpu, "unix`cpu_t", "mdb_xcall_cpu_t",
+	    addr, MDB_CTF_VREAD_IGNORE_ABSENT) == -1)
+		return (WALK_ERR);
+
+	if (xcpu.cpu_m.xc_curmsg != NULL) {
+		msgaddr = (uintptr_t)xcpu.cpu_m.xc_curmsg;
+
+		if (mdb_vread(&msg, sizeof (msg), msgaddr) != sizeof (msg))
+			return (WALK_ERR);
+
+		if (msg.xc_master == data->xd_cpu_id) {
+			if (data->xd_flags & DCMD_PIPE_OUT)
+				mdb_printf("%p\n", msgaddr);
+			else if (xcall_copy_msg(&msg, data, B_TRUE) != 0)
+				return (WALK_ERR);
+		}
+	}
+
+	for (msgaddr = (uintptr_t)xcpu.cpu_m.xc_msgbox;
+	    msgaddr != (uintptr_t)NULL; msgaddr = (uintptr_t)msg.xc_next) {
+		if (mdb_vread(&msg, sizeof (msg), msgaddr) != sizeof (msg))
+			return (WALK_ERR);
+
+		if (msg.xc_master != data->xd_cpu_id)
+			continue;
+
+		if (data->xd_flags & DCMD_PIPE_OUT)
+			mdb_printf("%p\n", msgaddr);
+		else if (xcall_copy_msg(&msg, data, B_FALSE) != 0)
+			return (WALK_ERR);
+	}
+
+	return (WALK_NEXT);
+}
+
+static int
+print_xcall_msg(struct xc_msg *msg)
+{
+	boolean_t current = (boolean_t)msg->xc_next;
+	char indent[] = "        ";
+	const char *cmd;
+
+	switch (msg->xc_command) {
+		case XC_MSG_ASYNC: cmd = "ASYNC"; break;
+		case XC_MSG_CALL: cmd = "CALL"; break;
+		case XC_MSG_SYNC: cmd = "SYNC"; break;
+		case XC_MSG_FREE:cmd = "FREE"; break;
+		case XC_MSG_WAITING: cmd = "WAITING"; break;
+		case XC_MSG_RELEASED: cmd = "RELEASED"; break;
+		case XC_MSG_DONE: cmd = "DONE"; break;
+		default: cmd = "?"; break;
+	}
+
+	mdb_printf("%s %s%-*s %-6u\n", indent, current ? "*" : "",
+	    9 - current, cmd, msg->xc_slave);
+	return (0);
+}
+
+/*
+ * Show all xcall messages where the master is the given CPU.
+ *
+ * As non-free messages can be on the slave's ->xc_msgbox or ->xc_curmsg, we
+ * need to walk across all of them to find each message where ->xc_master
+ * is our CPU ID.
+ */
+int
+xcall_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	mdb_xcall_cpu_t xcpu = { 0, };
+	xcall_data_t data = { 0, };
+
+	if (mdb_getopts(argc, argv, NULL) != argc)
+		return (DCMD_USAGE);
+
+	/*
+	 * Yep, this will re-collect all the messages each time.  Shrug.
+	 */
+	if (!(flags & DCMD_ADDRSPEC)) {
+		if (mdb_pwalk_dcmd("cpu", "xcall", argc, argv, 0) == -1) {
+			mdb_warn("can't walk CPUs");
+			return (DCMD_ERR);
+		}
+
+		return (DCMD_OK);
+	}
+
+	if (addr < NCPU && cpu_id_to_addr((processorid_t)addr, &addr) != 0) {
+		mdb_warn("invalid CPU ID %lu\n", addr);
+		return (DCMD_ERR);
+	}
+
+	if (mdb_ctf_vread(&xcpu, "unix`cpu_t", "mdb_xcall_cpu_t",
+	    addr, MDB_CTF_VREAD_IGNORE_ABSENT) == -1) {
+		mdb_warn("couldn't read cpu 0x%lx", addr);
+		return (DCMD_ERR);
+	}
+
+	data.xd_cpu_id = xcpu.cpu_id;
+	data.xd_flags = flags;
+
+	if (mdb_pwalk("cpu", xcall_get_msgs, &data, (uintptr_t)NULL) == -1) {
+		mdb_warn("can't walk CPUs");
+		return (DCMD_ERR);
+	}
+
+	if (flags & DCMD_PIPE_OUT)
+		return (DCMD_OK);
+
+	if (DCMD_HDRSPEC(flags))
+		mdb_printf("%<u>%3s %4s %s%</u>\n", "CPU", "PEND", "HANDLER");
+
+	if (data.xd_msg_index == 0) {
+		mdb_printf("%3d %4d -\n",
+		    xcpu.cpu_id, xcpu.cpu_m.xc_work_cnt);
+		return (DCMD_OK);
+	}
+
+	mdb_printf("%3d %4d %a(%a, %a, %a)\n",
+	    xcpu.cpu_id, xcpu.cpu_m.xc_work_cnt,
+	    xcpu.cpu_m.xc_data.xc_func, xcpu.cpu_m.xc_data.xc_a1,
+	    xcpu.cpu_m.xc_data.xc_a2, xcpu.cpu_m.xc_data.xc_a3);
+
+	if (!(flags & DCMD_PIPE_OUT))
+		mdb_printf("         %<u>%-9s %-6s%</u>\n", "COMMAND", "SLAVE");
+
+	for (size_t i = 0; i < data.xd_msg_index; i++) {
+		if (print_xcall_msg(&data.xd_msgs[i]) != 0)
+			return (DCMD_ERR);
+	}
+
+	return (DCMD_OK);
+}
--- old/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile	Tue Aug 20 09:24:08 2019
+++ new/usr/src/cmd/mdb/i86xpv/modules/unix/amd64/Makefile	Tue Aug 20 09:24:08 2019
@@ -22,12 +22,12 @@
 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# Copyright 2016 Joyent, Inc.
+# Copyright 2018 Joyent, Inc.
 
 MODULE = unix.so
 MDBTGT = kvm
 
-MODSRCS = unix.c i86mmu.c
+MODSRCS = unix.c i86mmu.c xcall.c
 MODASMSRCS = unix_sup.s
 
 include ../../../../../Makefile.cmd
--- old/usr/src/uts/i86pc/os/x_call.c	Tue Aug 20 09:24:08 2019
+++ new/usr/src/uts/i86pc/os/x_call.c	Tue Aug 20 09:24:08 2019
@@ -25,6 +25,7 @@
 /*
  * Copyright (c) 2010, Intel Corporation.
  * All rights reserved.
+ * Copyright 2018 Joyent, Inc.
  */
 
 #include <sys/types.h>
@@ -79,40 +80,31 @@
  * on a different Virtual Address at the same time. The old code required
  * N squared IPIs. With this method, depending on timing, it could happen
  * with just N IPIs.
- */
-
-/*
- * The default is to not enable collecting counts of IPI information, since
- * the updating of shared cachelines could cause excess bus traffic.
- */
-uint_t xc_collect_enable = 0;
-uint64_t xc_total_cnt = 0;	/* total #IPIs sent for cross calls */
-uint64_t xc_multi_cnt = 0;	/* # times we piggy backed on another IPI */
-
-/*
- * Values for message states. Here are the normal transitions. A transition
- * of "->" happens in the slave cpu and "=>" happens in the master cpu as
- * the messages are passed back and forth.
  *
+ * Here are the normal transitions for XC_MSG_* values in ->xc_command. A
+ * transition of "->" happens in the slave cpu and "=>" happens in the master
+ * cpu as the messages are passed back and forth.
+ *
  * FREE => ASYNC ->                       DONE => FREE
  * FREE => CALL ->                        DONE => FREE
  * FREE => SYNC -> WAITING => RELEASED -> DONE => FREE
  *
- * The interesing one above is ASYNC. You might ask, why not go directly
- * to FREE, instead of DONE. If it did that, it might be possible to exhaust
+ * The interesting one above is ASYNC. You might ask, why not go directly
+ * to FREE, instead of DONE? If it did that, it might be possible to exhaust
  * the master's xc_free list if a master can generate ASYNC messages faster
  * then the slave can process them. That could be handled with more complicated
  * handling. However since nothing important uses ASYNC, I've not bothered.
  */
-#define	XC_MSG_FREE	(0)	/* msg in xc_free queue */
-#define	XC_MSG_ASYNC	(1)	/* msg in slave xc_msgbox */
-#define	XC_MSG_CALL	(2)	/* msg in slave xc_msgbox */
-#define	XC_MSG_SYNC	(3)	/* msg in slave xc_msgbox */
-#define	XC_MSG_WAITING	(4)	/* msg in master xc_msgbox or xc_waiters */
-#define	XC_MSG_RELEASED	(5)	/* msg in slave xc_msgbox */
-#define	XC_MSG_DONE	(6)	/* msg in master xc_msgbox */
 
 /*
+ * The default is to not enable collecting counts of IPI information, since
+ * the updating of shared cachelines could cause excess bus traffic.
+ */
+uint_t xc_collect_enable = 0;
+uint64_t xc_total_cnt = 0;	/* total #IPIs sent for cross calls */
+uint64_t xc_multi_cnt = 0;	/* # times we piggy backed on another IPI */
+
+/*
  * We allow for one high priority message at a time to happen in the system.
  * This is used for panic, kmdb, etc., so no locking is done.
  */
@@ -121,13 +113,6 @@
 static xc_data_t xc_priority_data;
 
 /*
- * Wrappers to avoid C compiler warnings due to volatile. The atomic bit
- * operations don't accept volatile bit vectors - which is a bit silly.
- */
-#define	XC_BT_SET(vector, b)	BT_ATOMIC_SET((ulong_t *)(vector), (b))
-#define	XC_BT_CLEAR(vector, b)	BT_ATOMIC_CLEAR((ulong_t *)(vector), (b))
-
-/*
  * Decrement a CPU's work count
  */
 static void
@@ -193,6 +178,20 @@
 }
 
 /*
+ * Extract the next message from the CPU's queue, and place the message in
+ * .xc_curmsg.  The latter is solely to make debugging (and ::xcall) more
+ * useful.
+ */
+static xc_msg_t *
+xc_get(void)
+{
+	struct machcpu *mcpup = &CPU->cpu_m;
+	xc_msg_t *msg = xc_extract(&mcpup->xc_msgbox);
+	mcpup->xc_curmsg = msg;
+	return (msg);
+}
+
+/*
  * Initialize the machcpu fields used for cross calls
  */
 static uint_t xc_initialized = 0;
@@ -328,8 +327,7 @@
 		/*
 		 * We may have to wait for a message to arrive.
 		 */
-		for (msg = NULL; msg == NULL;
-		    msg = xc_extract(&mcpup->xc_msgbox)) {
+		for (msg = NULL; msg == NULL; msg = xc_get()) {
 
 			/*
 			 * Alway check for and handle a priority message.
@@ -339,7 +337,7 @@
 				a1 = xc_priority_data.xc_a1;
 				a2 = xc_priority_data.xc_a2;
 				a3 = xc_priority_data.xc_a3;
-				XC_BT_CLEAR(xc_priority_set, CPU->cpu_id);
+				BT_ATOMIC_CLEAR(xc_priority_set, CPU->cpu_id);
 				xc_decrement(mcpup);
 				func(a1, a2, a3);
 				if (mcpup->xc_work_cnt == 0)
@@ -443,6 +441,8 @@
 			panic("bad message 0x%p in msgbox", (void *)msg);
 			break;
 		}
+
+		CPU->cpu_m.xc_curmsg = NULL;
 	}
 	return (rc);
 }
@@ -581,7 +581,7 @@
 		 * ahead.
 		 */
 		if (BT_TEST(xc_priority_set, c)) {
-			XC_BT_CLEAR(xc_priority_set, c);
+			BT_ATOMIC_CLEAR(xc_priority_set, c);
 			if (cpup->cpu_m.xc_work_cnt > 0)
 				xc_decrement(&cpup->cpu_m);
 		}
@@ -607,7 +607,7 @@
 		    cpup == CPU)
 			continue;
 		(void) xc_increment(&cpup->cpu_m);
-		XC_BT_SET(xc_priority_set, c);
+		BT_ATOMIC_SET(xc_priority_set, c);
 		send_dirint(c, XC_HI_PIL);
 		for (i = 0; i < 10; ++i) {
 			(void) atomic_cas_ptr(&cpup->cpu_m.xc_msgbox,
--- old/usr/src/uts/i86pc/sys/machcpuvar.h	Tue Aug 20 09:24:09 2019
+++ new/usr/src/uts/i86pc/sys/machcpuvar.h	Tue Aug 20 09:24:09 2019
@@ -152,7 +152,7 @@
  *
  * There are CTASSERTs in os/intr.c that verify this all works out.
  */
-#define	MACHCPU_SIZE	(1568 + 688)
+#define	MACHCPU_SIZE	(1568 + 696)
 #define	MACHCPU_PAD	(MMU_PAGESIZE - MACHCPU_SIZE)
 #define	MACHCPU_PAD2	(MMU_PAGESIZE - 16 - 3 * sizeof (struct kpti_frame))
 
@@ -161,6 +161,7 @@
 	 * x_call fields - used for interprocessor cross calls
 	 */
 	struct xc_msg	*xc_msgbox;
+	struct xc_msg	*xc_curmsg;
 	struct xc_msg	*xc_free;
 	xc_data_t	xc_data;
 	uint32_t	xc_wait_cnt;
--- old/usr/src/uts/i86pc/sys/x_call.h	Tue Aug 20 09:24:09 2019
+++ new/usr/src/uts/i86pc/sys/x_call.h	Tue Aug 20 09:24:09 2019
@@ -22,6 +22,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright 2018 Joyent, Inc.
  */
 
 #ifndef	_SYS_X_CALL_H
@@ -33,6 +34,14 @@
 
 #ifndef _ASM
 
+#define	XC_MSG_FREE	(0)	/* msg in xc_free queue */
+#define	XC_MSG_ASYNC	(1)	/* msg in slave xc_msgbox */
+#define	XC_MSG_CALL	(2)	/* msg in slave xc_msgbox */
+#define	XC_MSG_SYNC	(3)	/* msg in slave xc_msgbox */
+#define	XC_MSG_WAITING	(4)	/* msg in master xc_msgbox or xc_waiters */
+#define	XC_MSG_RELEASED	(5)	/* msg in slave xc_msgbox */
+#define	XC_MSG_DONE	(6)	/* msg in master xc_msgbox */
+
 typedef uintptr_t xc_arg_t;
 typedef int (*xc_func_t)(xc_arg_t, xc_arg_t, xc_arg_t);
 
@@ -52,13 +61,8 @@
  */
 typedef struct xc_msg {
 	uint8_t		xc_command;
-#ifdef __amd64
 	uint16_t	xc_master;
 	uint16_t	xc_slave;
-#else
-	uint8_t		xc_master;
-	uint8_t		xc_slave;
-#endif
 	struct xc_msg	*xc_next;
 } xc_msg_t;
 
