xref: /openbmc/linux/tools/firewire/nosy-dump.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*1a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29f6d3c4bSStefan Richter /*
39f6d3c4bSStefan Richter  * nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
49f6d3c4bSStefan Richter  * Copyright (C) 2002-2006 Kristian Høgsberg
59f6d3c4bSStefan Richter  */
69f6d3c4bSStefan Richter 
792c16f7eSStefan Richter #include <byteswap.h>
892c16f7eSStefan Richter #include <endian.h>
99f6d3c4bSStefan Richter #include <fcntl.h>
1083ef7c75SStefan Richter #include <linux/firewire-constants.h>
1192c16f7eSStefan Richter #include <poll.h>
1292c16f7eSStefan Richter #include <popt.h>
1392c16f7eSStefan Richter #include <signal.h>
1492c16f7eSStefan Richter #include <stdio.h>
1592c16f7eSStefan Richter #include <stdlib.h>
1692c16f7eSStefan Richter #include <string.h>
179f6d3c4bSStefan Richter #include <sys/ioctl.h>
189f6d3c4bSStefan Richter #include <sys/time.h>
199f6d3c4bSStefan Richter #include <termios.h>
2092c16f7eSStefan Richter #include <unistd.h>
219f6d3c4bSStefan Richter 
229f6d3c4bSStefan Richter #include "list.h"
239f6d3c4bSStefan Richter #include "nosy-dump.h"
2492c16f7eSStefan Richter #include "nosy-user.h"
259f6d3c4bSStefan Richter 
269f6d3c4bSStefan Richter enum {
279f6d3c4bSStefan Richter 	PACKET_FIELD_DETAIL		= 0x01,
289f6d3c4bSStefan Richter 	PACKET_FIELD_DATA_LENGTH	= 0x02,
299f6d3c4bSStefan Richter 	/* Marks the fields we print in transaction view. */
3092c16f7eSStefan Richter 	PACKET_FIELD_TRANSACTION	= 0x04,
319f6d3c4bSStefan Richter };
329f6d3c4bSStefan Richter 
3392c16f7eSStefan Richter static void print_packet(uint32_t *data, size_t length);
3492c16f7eSStefan Richter static void decode_link_packet(struct link_packet *packet, size_t length,
359f6d3c4bSStefan Richter 			       int include_flags, int exclude_flags);
369f6d3c4bSStefan Richter static int run = 1;
379f6d3c4bSStefan Richter sig_t sys_sigint_handler;
389f6d3c4bSStefan Richter 
399f6d3c4bSStefan Richter static char *option_nosy_device = "/dev/nosy";
409f6d3c4bSStefan Richter static char *option_view = "packet";
4192c16f7eSStefan Richter static char *option_output;
4292c16f7eSStefan Richter static char *option_input;
439f6d3c4bSStefan Richter static int option_hex;
449f6d3c4bSStefan Richter static int option_iso;
459f6d3c4bSStefan Richter static int option_cycle_start;
469f6d3c4bSStefan Richter static int option_version;
479f6d3c4bSStefan Richter static int option_verbose;
489f6d3c4bSStefan Richter 
499f6d3c4bSStefan Richter enum {
509f6d3c4bSStefan Richter 	VIEW_TRANSACTION,
519f6d3c4bSStefan Richter 	VIEW_PACKET,
5292c16f7eSStefan Richter 	VIEW_STATS,
539f6d3c4bSStefan Richter };
549f6d3c4bSStefan Richter 
559f6d3c4bSStefan Richter static const struct poptOption options[] = {
569f6d3c4bSStefan Richter 	{
5792c16f7eSStefan Richter 		.longName	= "device",
5892c16f7eSStefan Richter 		.shortName	= 'd',
5992c16f7eSStefan Richter 		.argInfo	= POPT_ARG_STRING,
6092c16f7eSStefan Richter 		.arg		= &option_nosy_device,
6192c16f7eSStefan Richter 		.descrip	= "Path to nosy device.",
6292c16f7eSStefan Richter 		.argDescrip	= "DEVICE"
639f6d3c4bSStefan Richter 	},
649f6d3c4bSStefan Richter 	{
6592c16f7eSStefan Richter 		.longName	= "view",
6692c16f7eSStefan Richter 		.argInfo	= POPT_ARG_STRING,
6792c16f7eSStefan Richter 		.arg		= &option_view,
6892c16f7eSStefan Richter 		.descrip	= "Specify view of bus traffic: packet, transaction or stats.",
6992c16f7eSStefan Richter 		.argDescrip	= "VIEW"
709f6d3c4bSStefan Richter 	},
719f6d3c4bSStefan Richter 	{
7292c16f7eSStefan Richter 		.longName	= "hex",
7392c16f7eSStefan Richter 		.shortName	= 'x',
7492c16f7eSStefan Richter 		.argInfo	= POPT_ARG_NONE,
7592c16f7eSStefan Richter 		.arg		= &option_hex,
7692c16f7eSStefan Richter 		.descrip	= "Print each packet in hex.",
779f6d3c4bSStefan Richter 	},
789f6d3c4bSStefan Richter 	{
7992c16f7eSStefan Richter 		.longName	= "iso",
8092c16f7eSStefan Richter 		.argInfo	= POPT_ARG_NONE,
8192c16f7eSStefan Richter 		.arg		= &option_iso,
8292c16f7eSStefan Richter 		.descrip	= "Print iso packets.",
839f6d3c4bSStefan Richter 	},
849f6d3c4bSStefan Richter 	{
8592c16f7eSStefan Richter 		.longName	= "cycle-start",
8692c16f7eSStefan Richter 		.argInfo	= POPT_ARG_NONE,
8792c16f7eSStefan Richter 		.arg		= &option_cycle_start,
8892c16f7eSStefan Richter 		.descrip	= "Print cycle start packets.",
899f6d3c4bSStefan Richter 	},
909f6d3c4bSStefan Richter 	{
9192c16f7eSStefan Richter 		.longName	= "verbose",
9292c16f7eSStefan Richter 		.shortName	= 'v',
9392c16f7eSStefan Richter 		.argInfo	= POPT_ARG_NONE,
9492c16f7eSStefan Richter 		.arg		= &option_verbose,
9592c16f7eSStefan Richter 		.descrip	= "Verbose packet view.",
969f6d3c4bSStefan Richter 	},
979f6d3c4bSStefan Richter 	{
9892c16f7eSStefan Richter 		.longName	= "output",
9992c16f7eSStefan Richter 		.shortName	= 'o',
10092c16f7eSStefan Richter 		.argInfo	= POPT_ARG_STRING,
10192c16f7eSStefan Richter 		.arg		= &option_output,
10292c16f7eSStefan Richter 		.descrip	= "Log to output file.",
10392c16f7eSStefan Richter 		.argDescrip	= "FILENAME"
1049f6d3c4bSStefan Richter 	},
1059f6d3c4bSStefan Richter 	{
10692c16f7eSStefan Richter 		.longName	= "input",
10792c16f7eSStefan Richter 		.shortName	= 'i',
10892c16f7eSStefan Richter 		.argInfo	= POPT_ARG_STRING,
10992c16f7eSStefan Richter 		.arg		= &option_input,
11092c16f7eSStefan Richter 		.descrip	= "Decode log from file.",
11192c16f7eSStefan Richter 		.argDescrip	= "FILENAME"
1129f6d3c4bSStefan Richter 	},
1139f6d3c4bSStefan Richter 	{
11492c16f7eSStefan Richter 		.longName	= "version",
11592c16f7eSStefan Richter 		.argInfo	= POPT_ARG_NONE,
11692c16f7eSStefan Richter 		.arg		= &option_version,
11792c16f7eSStefan Richter 		.descrip	= "Specify print version info.",
1189f6d3c4bSStefan Richter 	},
1199f6d3c4bSStefan Richter 	POPT_AUTOHELP
1209f6d3c4bSStefan Richter 	POPT_TABLEEND
1219f6d3c4bSStefan Richter };
1229f6d3c4bSStefan Richter 
12392c16f7eSStefan Richter /* Allow all ^C except the first to interrupt the program in the usual way. */
124468066f7SStefan Richter static void
sigint_handler(int signal_num)1259f6d3c4bSStefan Richter sigint_handler(int signal_num)
1269f6d3c4bSStefan Richter {
1279f6d3c4bSStefan Richter 	if (run == 1) {
1289f6d3c4bSStefan Richter 		run = 0;
1299f6d3c4bSStefan Richter 		signal(SIGINT, SIG_DFL);
1309f6d3c4bSStefan Richter 	}
1319f6d3c4bSStefan Richter }
1329f6d3c4bSStefan Richter 
133468066f7SStefan Richter static struct subaction *
subaction_create(uint32_t * data,size_t length)1341bcc69fbSStefan Richter subaction_create(uint32_t *data, size_t length)
1359f6d3c4bSStefan Richter {
1369f6d3c4bSStefan Richter 	struct subaction *sa;
1379f6d3c4bSStefan Richter 
1389f6d3c4bSStefan Richter 	/* we put the ack in the subaction struct for easy access. */
1399f6d3c4bSStefan Richter 	sa = malloc(sizeof *sa - sizeof sa->packet + length);
1406fa79bcaSStefan Richter 	if (!sa)
1416fa79bcaSStefan Richter 		exit(EXIT_FAILURE);
1429f6d3c4bSStefan Richter 	sa->ack = data[length / 4 - 1];
1439f6d3c4bSStefan Richter 	sa->length = length;
1449f6d3c4bSStefan Richter 	memcpy(&sa->packet, data, length);
1459f6d3c4bSStefan Richter 
1469f6d3c4bSStefan Richter 	return sa;
1479f6d3c4bSStefan Richter }
1489f6d3c4bSStefan Richter 
149468066f7SStefan Richter static void
subaction_destroy(struct subaction * sa)1509f6d3c4bSStefan Richter subaction_destroy(struct subaction *sa)
1519f6d3c4bSStefan Richter {
1529f6d3c4bSStefan Richter 	free(sa);
1539f6d3c4bSStefan Richter }
1549f6d3c4bSStefan Richter 
155468066f7SStefan Richter static struct list pending_transaction_list = {
15692c16f7eSStefan Richter 	&pending_transaction_list, &pending_transaction_list
15792c16f7eSStefan Richter };
1589f6d3c4bSStefan Richter 
159468066f7SStefan Richter static struct link_transaction *
link_transaction_lookup(int request_node,int response_node,int tlabel)1609f6d3c4bSStefan Richter link_transaction_lookup(int request_node, int response_node, int tlabel)
1619f6d3c4bSStefan Richter {
1629f6d3c4bSStefan Richter 	struct link_transaction *t;
1639f6d3c4bSStefan Richter 
1649f6d3c4bSStefan Richter 	list_for_each_entry(t, &pending_transaction_list, link) {
1659f6d3c4bSStefan Richter 		if (t->request_node == request_node &&
1669f6d3c4bSStefan Richter 		    t->response_node == response_node &&
1679f6d3c4bSStefan Richter 		    t->tlabel == tlabel)
1689f6d3c4bSStefan Richter 			return t;
1699f6d3c4bSStefan Richter 	}
1709f6d3c4bSStefan Richter 
1719f6d3c4bSStefan Richter 	t = malloc(sizeof *t);
1726fa79bcaSStefan Richter 	if (!t)
1736fa79bcaSStefan Richter 		exit(EXIT_FAILURE);
1749f6d3c4bSStefan Richter 	t->request_node = request_node;
1759f6d3c4bSStefan Richter 	t->response_node = response_node;
1769f6d3c4bSStefan Richter 	t->tlabel = tlabel;
1779f6d3c4bSStefan Richter 	list_init(&t->request_list);
1789f6d3c4bSStefan Richter 	list_init(&t->response_list);
1799f6d3c4bSStefan Richter 
1809f6d3c4bSStefan Richter 	list_append(&pending_transaction_list, &t->link);
1819f6d3c4bSStefan Richter 
1829f6d3c4bSStefan Richter 	return t;
1839f6d3c4bSStefan Richter }
1849f6d3c4bSStefan Richter 
185468066f7SStefan Richter static void
link_transaction_destroy(struct link_transaction * t)1869f6d3c4bSStefan Richter link_transaction_destroy(struct link_transaction *t)
1879f6d3c4bSStefan Richter {
18892c16f7eSStefan Richter 	struct subaction *sa;
18992c16f7eSStefan Richter 
1909f6d3c4bSStefan Richter 	while (!list_empty(&t->request_list)) {
19192c16f7eSStefan Richter 		sa = list_head(&t->request_list, struct subaction, link);
1929f6d3c4bSStefan Richter 		list_remove(&sa->link);
1939f6d3c4bSStefan Richter 		subaction_destroy(sa);
1949f6d3c4bSStefan Richter 	}
1959f6d3c4bSStefan Richter 	while (!list_empty(&t->response_list)) {
19692c16f7eSStefan Richter 		sa = list_head(&t->response_list, struct subaction, link);
1979f6d3c4bSStefan Richter 		list_remove(&sa->link);
1989f6d3c4bSStefan Richter 		subaction_destroy(sa);
1999f6d3c4bSStefan Richter 	}
2009f6d3c4bSStefan Richter 	free(t);
2019f6d3c4bSStefan Richter }
2029f6d3c4bSStefan Richter 
2039f6d3c4bSStefan Richter struct protocol_decoder {
2049f6d3c4bSStefan Richter 	const char *name;
2059f6d3c4bSStefan Richter 	int (*decode)(struct link_transaction *t);
2069f6d3c4bSStefan Richter };
2079f6d3c4bSStefan Richter 
208468066f7SStefan Richter static const struct protocol_decoder protocol_decoders[] = {
2099f6d3c4bSStefan Richter 	{ "FCP", decode_fcp }
2109f6d3c4bSStefan Richter };
2119f6d3c4bSStefan Richter 
212468066f7SStefan Richter static void
handle_transaction(struct link_transaction * t)2139f6d3c4bSStefan Richter handle_transaction(struct link_transaction *t)
2149f6d3c4bSStefan Richter {
2159f6d3c4bSStefan Richter 	struct subaction *sa;
2169f6d3c4bSStefan Richter 	int i;
2179f6d3c4bSStefan Richter 
218a8461c0fSStefan Richter 	if (!t->request) {
219a8461c0fSStefan Richter 		printf("BUG in handle_transaction\n");
220a8461c0fSStefan Richter 		return;
221a8461c0fSStefan Richter 	}
222a8461c0fSStefan Richter 
2239f6d3c4bSStefan Richter 	for (i = 0; i < array_length(protocol_decoders); i++)
2249f6d3c4bSStefan Richter 		if (protocol_decoders[i].decode(t))
2259f6d3c4bSStefan Richter 			break;
2269f6d3c4bSStefan Richter 
2279f6d3c4bSStefan Richter 	/* HACK: decode only fcp right now. */
2289f6d3c4bSStefan Richter 	return;
2299f6d3c4bSStefan Richter 
2309f6d3c4bSStefan Richter 	decode_link_packet(&t->request->packet, t->request->length,
2319f6d3c4bSStefan Richter 			   PACKET_FIELD_TRANSACTION, 0);
2329f6d3c4bSStefan Richter 	if (t->response)
2339f6d3c4bSStefan Richter 		decode_link_packet(&t->response->packet, t->request->length,
2349f6d3c4bSStefan Richter 				   PACKET_FIELD_TRANSACTION, 0);
2359f6d3c4bSStefan Richter 	else
2369f6d3c4bSStefan Richter 		printf("[no response]");
2379f6d3c4bSStefan Richter 
2389f6d3c4bSStefan Richter 	if (option_verbose) {
2399f6d3c4bSStefan Richter 		list_for_each_entry(sa, &t->request_list, link)
2401bcc69fbSStefan Richter 			print_packet((uint32_t *) &sa->packet, sa->length);
2419f6d3c4bSStefan Richter 		list_for_each_entry(sa, &t->response_list, link)
2421bcc69fbSStefan Richter 			print_packet((uint32_t *) &sa->packet, sa->length);
2439f6d3c4bSStefan Richter 	}
2449f6d3c4bSStefan Richter 	printf("\r\n");
2459f6d3c4bSStefan Richter 
2469f6d3c4bSStefan Richter 	link_transaction_destroy(t);
2479f6d3c4bSStefan Richter }
2489f6d3c4bSStefan Richter 
249468066f7SStefan Richter static void
clear_pending_transaction_list(void)2509f6d3c4bSStefan Richter clear_pending_transaction_list(void)
2519f6d3c4bSStefan Richter {
2529f6d3c4bSStefan Richter 	struct link_transaction *t;
2539f6d3c4bSStefan Richter 
2549f6d3c4bSStefan Richter 	while (!list_empty(&pending_transaction_list)) {
25592c16f7eSStefan Richter 		t = list_head(&pending_transaction_list,
25692c16f7eSStefan Richter 			      struct link_transaction, link);
2579f6d3c4bSStefan Richter 		list_remove(&t->link);
2589f6d3c4bSStefan Richter 		link_transaction_destroy(t);
2599f6d3c4bSStefan Richter 		/* print unfinished transactions */
2609f6d3c4bSStefan Richter 	}
2619f6d3c4bSStefan Richter }
2629f6d3c4bSStefan Richter 
2639f6d3c4bSStefan Richter static const char * const tcode_names[] = {
26492c16f7eSStefan Richter 	[0x0] = "write_quadlet_request",	[0x6] = "read_quadlet_response",
26592c16f7eSStefan Richter 	[0x1] = "write_block_request",		[0x7] = "read_block_response",
26692c16f7eSStefan Richter 	[0x2] = "write_response",		[0x8] = "cycle_start",
26792c16f7eSStefan Richter 	[0x3] = "reserved",			[0x9] = "lock_request",
26892c16f7eSStefan Richter 	[0x4] = "read_quadlet_request",		[0xa] = "iso_data",
26992c16f7eSStefan Richter 	[0x5] = "read_block_request",		[0xb] = "lock_response",
2709f6d3c4bSStefan Richter };
2719f6d3c4bSStefan Richter 
2729f6d3c4bSStefan Richter static const char * const ack_names[] = {
27392c16f7eSStefan Richter 	[0x0] = "no ack",			[0x8] = "reserved (0x08)",
27492c16f7eSStefan Richter 	[0x1] = "ack_complete",			[0x9] = "reserved (0x09)",
27592c16f7eSStefan Richter 	[0x2] = "ack_pending",			[0xa] = "reserved (0x0a)",
27692c16f7eSStefan Richter 	[0x3] = "reserved (0x03)",		[0xb] = "reserved (0x0b)",
27792c16f7eSStefan Richter 	[0x4] = "ack_busy_x",			[0xc] = "reserved (0x0c)",
27892c16f7eSStefan Richter 	[0x5] = "ack_busy_a",			[0xd] = "ack_data_error",
27992c16f7eSStefan Richter 	[0x6] = "ack_busy_b",			[0xe] = "ack_type_error",
28092c16f7eSStefan Richter 	[0x7] = "reserved (0x07)",		[0xf] = "reserved (0x0f)",
2819f6d3c4bSStefan Richter };
2829f6d3c4bSStefan Richter 
2839f6d3c4bSStefan Richter static const char * const rcode_names[] = {
28492c16f7eSStefan Richter 	[0x0] = "complete",			[0x4] = "conflict_error",
28592c16f7eSStefan Richter 	[0x1] = "reserved (0x01)",		[0x5] = "data_error",
28692c16f7eSStefan Richter 	[0x2] = "reserved (0x02)",		[0x6] = "type_error",
28792c16f7eSStefan Richter 	[0x3] = "reserved (0x03)",		[0x7] = "address_error",
2889f6d3c4bSStefan Richter };
2899f6d3c4bSStefan Richter 
2909f6d3c4bSStefan Richter static const char * const retry_names[] = {
29192c16f7eSStefan Richter 	[0x0] = "retry_1",
29292c16f7eSStefan Richter 	[0x1] = "retry_x",
29392c16f7eSStefan Richter 	[0x2] = "retry_a",
29492c16f7eSStefan Richter 	[0x3] = "retry_b",
2959f6d3c4bSStefan Richter };
2969f6d3c4bSStefan Richter 
2979f6d3c4bSStefan Richter enum {
2989f6d3c4bSStefan Richter 	PACKET_RESERVED,
2999f6d3c4bSStefan Richter 	PACKET_REQUEST,
3009f6d3c4bSStefan Richter 	PACKET_RESPONSE,
3019f6d3c4bSStefan Richter 	PACKET_OTHER,
3029f6d3c4bSStefan Richter };
3039f6d3c4bSStefan Richter 
3049f6d3c4bSStefan Richter struct packet_info {
3059f6d3c4bSStefan Richter 	const char *name;
3069f6d3c4bSStefan Richter 	int type;
3079f6d3c4bSStefan Richter 	int response_tcode;
308468066f7SStefan Richter 	const struct packet_field *fields;
3099f6d3c4bSStefan Richter 	int field_count;
3109f6d3c4bSStefan Richter };
3119f6d3c4bSStefan Richter 
3129f6d3c4bSStefan Richter struct packet_field {
3139f6d3c4bSStefan Richter 	const char *name; /* Short name for field. */
31492c16f7eSStefan Richter 	int offset;	/* Location of field, specified in bits; */
31592c16f7eSStefan Richter 			/* negative means from end of packet.    */
3169f6d3c4bSStefan Richter 	int width;	/* Width of field, 0 means use data_length. */
3179f6d3c4bSStefan Richter 	int flags;	/* Show options. */
3189f6d3c4bSStefan Richter 	const char * const *value_names;
3199f6d3c4bSStefan Richter };
3209f6d3c4bSStefan Richter 
3219f6d3c4bSStefan Richter #define COMMON_REQUEST_FIELDS						\
3229f6d3c4bSStefan Richter 	{ "dest", 0, 16, PACKET_FIELD_TRANSACTION },			\
3239f6d3c4bSStefan Richter 	{ "tl", 16, 6 },						\
3249f6d3c4bSStefan Richter 	{ "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names },		\
3259f6d3c4bSStefan Richter 	{ "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names },	\
3269f6d3c4bSStefan Richter 	{ "pri", 28, 4, PACKET_FIELD_DETAIL },				\
3279f6d3c4bSStefan Richter 	{ "src", 32, 16, PACKET_FIELD_TRANSACTION },			\
3289f6d3c4bSStefan Richter 	{ "offs", 48, 48, PACKET_FIELD_TRANSACTION }
3299f6d3c4bSStefan Richter 
3309f6d3c4bSStefan Richter #define COMMON_RESPONSE_FIELDS						\
3319f6d3c4bSStefan Richter 	{ "dest", 0, 16 },						\
3329f6d3c4bSStefan Richter 	{ "tl", 16, 6 },						\
3339f6d3c4bSStefan Richter 	{ "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names },		\
3349f6d3c4bSStefan Richter 	{ "tcode", 24, 4, 0, tcode_names },				\
3359f6d3c4bSStefan Richter 	{ "pri", 28, 4, PACKET_FIELD_DETAIL },				\
3369f6d3c4bSStefan Richter 	{ "src", 32, 16 },						\
3379f6d3c4bSStefan Richter 	{ "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
3389f6d3c4bSStefan Richter 
339468066f7SStefan Richter static const struct packet_field read_quadlet_request_fields[] = {
3409f6d3c4bSStefan Richter 	COMMON_REQUEST_FIELDS,
3419f6d3c4bSStefan Richter 	{ "crc", 96, 32, PACKET_FIELD_DETAIL },
34292c16f7eSStefan Richter 	{ "ack", 156, 4, 0, ack_names },
3439f6d3c4bSStefan Richter };
3449f6d3c4bSStefan Richter 
345468066f7SStefan Richter static const struct packet_field read_quadlet_response_fields[] = {
3469f6d3c4bSStefan Richter 	COMMON_RESPONSE_FIELDS,
3479f6d3c4bSStefan Richter 	{ "data", 96, 32, PACKET_FIELD_TRANSACTION },
3489f6d3c4bSStefan Richter 	{ "crc", 128, 32, PACKET_FIELD_DETAIL },
34992c16f7eSStefan Richter 	{ "ack", 188, 4, 0, ack_names },
3509f6d3c4bSStefan Richter };
3519f6d3c4bSStefan Richter 
352468066f7SStefan Richter static const struct packet_field read_block_request_fields[] = {
3539f6d3c4bSStefan Richter 	COMMON_REQUEST_FIELDS,
3549f6d3c4bSStefan Richter 	{ "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
3559f6d3c4bSStefan Richter 	{ "extended_tcode", 112, 16 },
3569f6d3c4bSStefan Richter 	{ "crc", 128, 32, PACKET_FIELD_DETAIL },
3579f6d3c4bSStefan Richter 	{ "ack", 188, 4, 0, ack_names },
3589f6d3c4bSStefan Richter };
3599f6d3c4bSStefan Richter 
360468066f7SStefan Richter static const struct packet_field block_response_fields[] = {
3619f6d3c4bSStefan Richter 	COMMON_RESPONSE_FIELDS,
3629f6d3c4bSStefan Richter 	{ "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
3639f6d3c4bSStefan Richter 	{ "extended_tcode", 112, 16 },
3649f6d3c4bSStefan Richter 	{ "crc", 128, 32, PACKET_FIELD_DETAIL },
3659f6d3c4bSStefan Richter 	{ "data", 160, 0, PACKET_FIELD_TRANSACTION },
3669f6d3c4bSStefan Richter 	{ "crc", -64, 32, PACKET_FIELD_DETAIL },
36792c16f7eSStefan Richter 	{ "ack", -4, 4, 0, ack_names },
3689f6d3c4bSStefan Richter };
3699f6d3c4bSStefan Richter 
370468066f7SStefan Richter static const struct packet_field write_quadlet_request_fields[] = {
3719f6d3c4bSStefan Richter 	COMMON_REQUEST_FIELDS,
3729f6d3c4bSStefan Richter 	{ "data", 96, 32, PACKET_FIELD_TRANSACTION },
37392c16f7eSStefan Richter 	{ "ack", -4, 4, 0, ack_names },
3749f6d3c4bSStefan Richter };
3759f6d3c4bSStefan Richter 
376468066f7SStefan Richter static const struct packet_field block_request_fields[] = {
3779f6d3c4bSStefan Richter 	COMMON_REQUEST_FIELDS,
3789f6d3c4bSStefan Richter 	{ "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
3799f6d3c4bSStefan Richter 	{ "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
3809f6d3c4bSStefan Richter 	{ "crc", 128, 32, PACKET_FIELD_DETAIL },
3819f6d3c4bSStefan Richter 	{ "data", 160, 0, PACKET_FIELD_TRANSACTION },
3829f6d3c4bSStefan Richter 	{ "crc", -64, 32, PACKET_FIELD_DETAIL },
38392c16f7eSStefan Richter 	{ "ack", -4, 4, 0, ack_names },
3849f6d3c4bSStefan Richter };
3859f6d3c4bSStefan Richter 
386468066f7SStefan Richter static const struct packet_field write_response_fields[] = {
3879f6d3c4bSStefan Richter 	COMMON_RESPONSE_FIELDS,
3889f6d3c4bSStefan Richter 	{ "reserved", 64, 32, PACKET_FIELD_DETAIL },
38992c16f7eSStefan Richter 	{ "ack", -4, 4, 0, ack_names },
3909f6d3c4bSStefan Richter };
3919f6d3c4bSStefan Richter 
392468066f7SStefan Richter static const struct packet_field iso_data_fields[] = {
3939f6d3c4bSStefan Richter 	{ "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
3949f6d3c4bSStefan Richter 	{ "tag", 16, 2 },
3959f6d3c4bSStefan Richter 	{ "channel", 18, 6 },
3969f6d3c4bSStefan Richter 	{ "tcode", 24, 4, 0, tcode_names },
3979f6d3c4bSStefan Richter 	{ "sy", 28, 4 },
3989f6d3c4bSStefan Richter 	{ "crc", 32, 32, PACKET_FIELD_DETAIL },
3999f6d3c4bSStefan Richter 	{ "data", 64, 0 },
4009f6d3c4bSStefan Richter 	{ "crc", -64, 32, PACKET_FIELD_DETAIL },
40192c16f7eSStefan Richter 	{ "ack", -4, 4, 0, ack_names },
4029f6d3c4bSStefan Richter };
4039f6d3c4bSStefan Richter 
404468066f7SStefan Richter static const struct packet_info packet_info[] = {
4059f6d3c4bSStefan Richter 	{
4069f6d3c4bSStefan Richter 		.name		= "write_quadlet_request",
4079f6d3c4bSStefan Richter 		.type		= PACKET_REQUEST,
4089f6d3c4bSStefan Richter 		.response_tcode	= TCODE_WRITE_RESPONSE,
4099f6d3c4bSStefan Richter 		.fields		= write_quadlet_request_fields,
4109f6d3c4bSStefan Richter 		.field_count	= array_length(write_quadlet_request_fields)
4119f6d3c4bSStefan Richter 	},
4129f6d3c4bSStefan Richter 	{
4139f6d3c4bSStefan Richter 		.name		= "write_block_request",
4149f6d3c4bSStefan Richter 		.type		= PACKET_REQUEST,
4159f6d3c4bSStefan Richter 		.response_tcode	= TCODE_WRITE_RESPONSE,
4169f6d3c4bSStefan Richter 		.fields		= block_request_fields,
4179f6d3c4bSStefan Richter 		.field_count	= array_length(block_request_fields)
4189f6d3c4bSStefan Richter 	},
4199f6d3c4bSStefan Richter 	{
4209f6d3c4bSStefan Richter 		.name		= "write_response",
4219f6d3c4bSStefan Richter 		.type		= PACKET_RESPONSE,
4229f6d3c4bSStefan Richter 		.fields		= write_response_fields,
4239f6d3c4bSStefan Richter 		.field_count	= array_length(write_response_fields)
4249f6d3c4bSStefan Richter 	},
4259f6d3c4bSStefan Richter 	{
4269f6d3c4bSStefan Richter 		.name		= "reserved",
4279f6d3c4bSStefan Richter 		.type		= PACKET_RESERVED,
4289f6d3c4bSStefan Richter 	},
4299f6d3c4bSStefan Richter 	{
4309f6d3c4bSStefan Richter 		.name		= "read_quadlet_request",
4319f6d3c4bSStefan Richter 		.type		= PACKET_REQUEST,
4329f6d3c4bSStefan Richter 		.response_tcode	= TCODE_READ_QUADLET_RESPONSE,
4339f6d3c4bSStefan Richter 		.fields		= read_quadlet_request_fields,
4349f6d3c4bSStefan Richter 		.field_count	= array_length(read_quadlet_request_fields)
4359f6d3c4bSStefan Richter 	},
4369f6d3c4bSStefan Richter 	{
4379f6d3c4bSStefan Richter 		.name		= "read_block_request",
4389f6d3c4bSStefan Richter 		.type		= PACKET_REQUEST,
4399f6d3c4bSStefan Richter 		.response_tcode	= TCODE_READ_BLOCK_RESPONSE,
4409f6d3c4bSStefan Richter 		.fields		= read_block_request_fields,
4419f6d3c4bSStefan Richter 		.field_count	= array_length(read_block_request_fields)
4429f6d3c4bSStefan Richter 	},
4439f6d3c4bSStefan Richter 	{
4449f6d3c4bSStefan Richter 		.name		= "read_quadlet_response",
4459f6d3c4bSStefan Richter 		.type		= PACKET_RESPONSE,
4469f6d3c4bSStefan Richter 		.fields		= read_quadlet_response_fields,
4479f6d3c4bSStefan Richter 		.field_count	= array_length(read_quadlet_response_fields)
4489f6d3c4bSStefan Richter 	},
4499f6d3c4bSStefan Richter 	{
4509f6d3c4bSStefan Richter 		.name		= "read_block_response",
4519f6d3c4bSStefan Richter 		.type		= PACKET_RESPONSE,
4529f6d3c4bSStefan Richter 		.fields		= block_response_fields,
4539f6d3c4bSStefan Richter 		.field_count	= array_length(block_response_fields)
4549f6d3c4bSStefan Richter 	},
4559f6d3c4bSStefan Richter 	{
4569f6d3c4bSStefan Richter 		.name		= "cycle_start",
4579f6d3c4bSStefan Richter 		.type		= PACKET_OTHER,
4589f6d3c4bSStefan Richter 		.fields		= write_quadlet_request_fields,
4599f6d3c4bSStefan Richter 		.field_count	= array_length(write_quadlet_request_fields)
4609f6d3c4bSStefan Richter 	},
4619f6d3c4bSStefan Richter 	{
4629f6d3c4bSStefan Richter 		.name		= "lock_request",
4639f6d3c4bSStefan Richter 		.type		= PACKET_REQUEST,
4649f6d3c4bSStefan Richter 		.fields		= block_request_fields,
4659f6d3c4bSStefan Richter 		.field_count	= array_length(block_request_fields)
4669f6d3c4bSStefan Richter 	},
4679f6d3c4bSStefan Richter 	{
4689f6d3c4bSStefan Richter 		.name		= "iso_data",
4699f6d3c4bSStefan Richter 		.type		= PACKET_OTHER,
4709f6d3c4bSStefan Richter 		.fields		= iso_data_fields,
4719f6d3c4bSStefan Richter 		.field_count	= array_length(iso_data_fields)
4729f6d3c4bSStefan Richter 	},
4739f6d3c4bSStefan Richter 	{
4749f6d3c4bSStefan Richter 		.name		= "lock_response",
4759f6d3c4bSStefan Richter 		.type		= PACKET_RESPONSE,
4769f6d3c4bSStefan Richter 		.fields		= block_response_fields,
4779f6d3c4bSStefan Richter 		.field_count	= array_length(block_response_fields)
47892c16f7eSStefan Richter 	},
4799f6d3c4bSStefan Richter };
4809f6d3c4bSStefan Richter 
481468066f7SStefan Richter static int
handle_request_packet(uint32_t * data,size_t length)482269fe102SStefan Richter handle_request_packet(uint32_t *data, size_t length)
4839f6d3c4bSStefan Richter {
4849f6d3c4bSStefan Richter 	struct link_packet *p = (struct link_packet *) data;
4859f6d3c4bSStefan Richter 	struct subaction *sa, *prev;
4869f6d3c4bSStefan Richter 	struct link_transaction *t;
4879f6d3c4bSStefan Richter 
4889f6d3c4bSStefan Richter 	t = link_transaction_lookup(p->common.source, p->common.destination,
4899f6d3c4bSStefan Richter 			p->common.tlabel);
4909f6d3c4bSStefan Richter 	sa = subaction_create(data, length);
4919f6d3c4bSStefan Richter 	t->request = sa;
4929f6d3c4bSStefan Richter 
4939f6d3c4bSStefan Richter 	if (!list_empty(&t->request_list)) {
49492c16f7eSStefan Richter 		prev = list_tail(&t->request_list,
49592c16f7eSStefan Richter 				 struct subaction, link);
4969f6d3c4bSStefan Richter 
4979f6d3c4bSStefan Richter 		if (!ACK_BUSY(prev->ack)) {
49892c16f7eSStefan Richter 			/*
49992c16f7eSStefan Richter 			 * error, we should only see ack_busy_* before the
5009f6d3c4bSStefan Richter 			 * ack_pending/ack_complete -- this is an ack_pending
5019f6d3c4bSStefan Richter 			 * instead (ack_complete would have finished the
50292c16f7eSStefan Richter 			 * transaction).
50392c16f7eSStefan Richter 			 */
5049f6d3c4bSStefan Richter 		}
5059f6d3c4bSStefan Richter 
5069f6d3c4bSStefan Richter 		if (prev->packet.common.tcode != sa->packet.common.tcode ||
50792c16f7eSStefan Richter 		    prev->packet.common.tlabel != sa->packet.common.tlabel) {
5089f6d3c4bSStefan Richter 			/* memcmp() ? */
50992c16f7eSStefan Richter 			/* error, these should match for retries. */
51092c16f7eSStefan Richter 		}
5119f6d3c4bSStefan Richter 	}
5129f6d3c4bSStefan Richter 
5139f6d3c4bSStefan Richter 	list_append(&t->request_list, &sa->link);
5149f6d3c4bSStefan Richter 
5159f6d3c4bSStefan Richter 	switch (sa->ack) {
5169f6d3c4bSStefan Richter 	case ACK_COMPLETE:
51783ef7c75SStefan Richter 		if (p->common.tcode != TCODE_WRITE_QUADLET_REQUEST &&
51883ef7c75SStefan Richter 		    p->common.tcode != TCODE_WRITE_BLOCK_REQUEST)
5199f6d3c4bSStefan Richter 			/* error, unified transactions only allowed for write */;
5209f6d3c4bSStefan Richter 		list_remove(&t->link);
5219f6d3c4bSStefan Richter 		handle_transaction(t);
5229f6d3c4bSStefan Richter 		break;
5239f6d3c4bSStefan Richter 
5249f6d3c4bSStefan Richter 	case ACK_NO_ACK:
5259f6d3c4bSStefan Richter 	case ACK_DATA_ERROR:
5269f6d3c4bSStefan Richter 	case ACK_TYPE_ERROR:
5279f6d3c4bSStefan Richter 		list_remove(&t->link);
5289f6d3c4bSStefan Richter 		handle_transaction(t);
5299f6d3c4bSStefan Richter 		break;
5309f6d3c4bSStefan Richter 
5319f6d3c4bSStefan Richter 	case ACK_PENDING:
5329f6d3c4bSStefan Richter 		/* request subaction phase over, wait for response. */
5339f6d3c4bSStefan Richter 		break;
5349f6d3c4bSStefan Richter 
5359f6d3c4bSStefan Richter 	case ACK_BUSY_X:
5369f6d3c4bSStefan Richter 	case ACK_BUSY_A:
5379f6d3c4bSStefan Richter 	case ACK_BUSY_B:
5389f6d3c4bSStefan Richter 		/* ok, wait for retry. */
5399f6d3c4bSStefan Richter 		/* check that retry protocol is respected. */
5409f6d3c4bSStefan Richter 		break;
5419f6d3c4bSStefan Richter 	}
5429f6d3c4bSStefan Richter 
543269fe102SStefan Richter 	return 1;
544269fe102SStefan Richter }
545269fe102SStefan Richter 
546269fe102SStefan Richter static int
handle_response_packet(uint32_t * data,size_t length)547269fe102SStefan Richter handle_response_packet(uint32_t *data, size_t length)
548269fe102SStefan Richter {
549269fe102SStefan Richter 	struct link_packet *p = (struct link_packet *) data;
550269fe102SStefan Richter 	struct subaction *sa, *prev;
551269fe102SStefan Richter 	struct link_transaction *t;
552269fe102SStefan Richter 
5539f6d3c4bSStefan Richter 	t = link_transaction_lookup(p->common.destination, p->common.source,
5549f6d3c4bSStefan Richter 			p->common.tlabel);
5559f6d3c4bSStefan Richter 	if (list_empty(&t->request_list)) {
5569f6d3c4bSStefan Richter 		/* unsolicited response */
5579f6d3c4bSStefan Richter 	}
5589f6d3c4bSStefan Richter 
5599f6d3c4bSStefan Richter 	sa = subaction_create(data, length);
5609f6d3c4bSStefan Richter 	t->response = sa;
5619f6d3c4bSStefan Richter 
5629f6d3c4bSStefan Richter 	if (!list_empty(&t->response_list)) {
5639f6d3c4bSStefan Richter 		prev = list_tail(&t->response_list, struct subaction, link);
5649f6d3c4bSStefan Richter 
56592c16f7eSStefan Richter 		if (!ACK_BUSY(prev->ack)) {
56692c16f7eSStefan Richter 			/*
56792c16f7eSStefan Richter 			 * error, we should only see ack_busy_* before the
56892c16f7eSStefan Richter 			 * ack_pending/ack_complete
56992c16f7eSStefan Richter 			 */
57092c16f7eSStefan Richter 		}
5719f6d3c4bSStefan Richter 
5729f6d3c4bSStefan Richter 		if (prev->packet.common.tcode != sa->packet.common.tcode ||
57392c16f7eSStefan Richter 		    prev->packet.common.tlabel != sa->packet.common.tlabel) {
5749f6d3c4bSStefan Richter 			/* use memcmp() instead? */
57592c16f7eSStefan Richter 			/* error, these should match for retries. */
5769f6d3c4bSStefan Richter 		}
57792c16f7eSStefan Richter 	} else {
5789f6d3c4bSStefan Richter 		prev = list_tail(&t->request_list, struct subaction, link);
5799f6d3c4bSStefan Richter 		if (prev->ack != ACK_PENDING) {
58092c16f7eSStefan Richter 			/*
58192c16f7eSStefan Richter 			 * error, should not get response unless last request got
58292c16f7eSStefan Richter 			 * ack_pending.
58392c16f7eSStefan Richter 			 */
5849f6d3c4bSStefan Richter 		}
5859f6d3c4bSStefan Richter 
5869f6d3c4bSStefan Richter 		if (packet_info[prev->packet.common.tcode].response_tcode !=
5879f6d3c4bSStefan Richter 		    sa->packet.common.tcode) {
5889f6d3c4bSStefan Richter 			/* error, tcode mismatch */
5899f6d3c4bSStefan Richter 		}
5909f6d3c4bSStefan Richter 	}
5919f6d3c4bSStefan Richter 
5929f6d3c4bSStefan Richter 	list_append(&t->response_list, &sa->link);
5939f6d3c4bSStefan Richter 
5949f6d3c4bSStefan Richter 	switch (sa->ack) {
5959f6d3c4bSStefan Richter 	case ACK_COMPLETE:
5969f6d3c4bSStefan Richter 	case ACK_NO_ACK:
5979f6d3c4bSStefan Richter 	case ACK_DATA_ERROR:
5989f6d3c4bSStefan Richter 	case ACK_TYPE_ERROR:
5999f6d3c4bSStefan Richter 		list_remove(&t->link);
6009f6d3c4bSStefan Richter 		handle_transaction(t);
6019f6d3c4bSStefan Richter 		/* transaction complete, remove t from pending list. */
6029f6d3c4bSStefan Richter 		break;
6039f6d3c4bSStefan Richter 
6049f6d3c4bSStefan Richter 	case ACK_PENDING:
6059f6d3c4bSStefan Richter 		/* error for responses. */
6069f6d3c4bSStefan Richter 		break;
6079f6d3c4bSStefan Richter 
6089f6d3c4bSStefan Richter 	case ACK_BUSY_X:
6099f6d3c4bSStefan Richter 	case ACK_BUSY_A:
6109f6d3c4bSStefan Richter 	case ACK_BUSY_B:
6119f6d3c4bSStefan Richter 		/* no problem, wait for next retry */
6129f6d3c4bSStefan Richter 		break;
6139f6d3c4bSStefan Richter 	}
6149f6d3c4bSStefan Richter 
615269fe102SStefan Richter 	return 1;
616269fe102SStefan Richter }
617269fe102SStefan Richter 
618269fe102SStefan Richter static int
handle_packet(uint32_t * data,size_t length)619269fe102SStefan Richter handle_packet(uint32_t *data, size_t length)
620269fe102SStefan Richter {
621269fe102SStefan Richter 	if (length == 0) {
622269fe102SStefan Richter 		printf("bus reset\r\n");
623269fe102SStefan Richter 		clear_pending_transaction_list();
624269fe102SStefan Richter 	} else if (length > sizeof(struct phy_packet)) {
625269fe102SStefan Richter 		struct link_packet *p = (struct link_packet *) data;
626269fe102SStefan Richter 
627269fe102SStefan Richter 		switch (packet_info[p->common.tcode].type) {
628269fe102SStefan Richter 		case PACKET_REQUEST:
629269fe102SStefan Richter 			return handle_request_packet(data, length);
630269fe102SStefan Richter 
631269fe102SStefan Richter 		case PACKET_RESPONSE:
632269fe102SStefan Richter 			return handle_response_packet(data, length);
6339f6d3c4bSStefan Richter 
6349f6d3c4bSStefan Richter 		case PACKET_OTHER:
6359f6d3c4bSStefan Richter 		case PACKET_RESERVED:
6369f6d3c4bSStefan Richter 			return 0;
6379f6d3c4bSStefan Richter 		}
6389f6d3c4bSStefan Richter 	}
6399f6d3c4bSStefan Richter 
6409f6d3c4bSStefan Richter 	return 1;
6419f6d3c4bSStefan Richter }
6429f6d3c4bSStefan Richter 
643468066f7SStefan Richter static unsigned int
get_bits(struct link_packet * packet,int offset,int width)644468066f7SStefan Richter get_bits(struct link_packet *packet, int offset, int width)
6459f6d3c4bSStefan Richter {
6461bcc69fbSStefan Richter 	uint32_t *data = (uint32_t *) packet;
6471bcc69fbSStefan Richter 	uint32_t index, shift, mask;
6489f6d3c4bSStefan Richter 
6499f6d3c4bSStefan Richter 	index = offset / 32 + 1;
6509f6d3c4bSStefan Richter 	shift = 32 - (offset & 31) - width;
6519f6d3c4bSStefan Richter 	mask = width == 32 ? ~0 : (1 << width) - 1;
6529f6d3c4bSStefan Richter 
6539f6d3c4bSStefan Richter 	return (data[index] >> shift) & mask;
6549f6d3c4bSStefan Richter }
6559f6d3c4bSStefan Richter 
6569f6d3c4bSStefan Richter #if __BYTE_ORDER == __LITTLE_ENDIAN
6579f6d3c4bSStefan Richter #define byte_index(i) ((i) ^ 3)
6589f6d3c4bSStefan Richter #elif __BYTE_ORDER == __BIG_ENDIAN
6599f6d3c4bSStefan Richter #define byte_index(i) (i)
6609f6d3c4bSStefan Richter #else
6619f6d3c4bSStefan Richter #error unsupported byte order.
6629f6d3c4bSStefan Richter #endif
6639f6d3c4bSStefan Richter 
664468066f7SStefan Richter static void
dump_data(unsigned char * data,int length)665468066f7SStefan Richter dump_data(unsigned char *data, int length)
6669f6d3c4bSStefan Richter {
6679f6d3c4bSStefan Richter 	int i, print_length;
6689f6d3c4bSStefan Richter 
6699f6d3c4bSStefan Richter 	if (length > 128)
6709f6d3c4bSStefan Richter 		print_length = 128;
6719f6d3c4bSStefan Richter 	else
6729f6d3c4bSStefan Richter 		print_length = length;
6739f6d3c4bSStefan Richter 
6749f6d3c4bSStefan Richter 	for (i = 0; i < print_length; i++)
6759f6d3c4bSStefan Richter 		printf("%s%02hhx",
6769f6d3c4bSStefan Richter 		       (i % 4 == 0 && i != 0) ? " " : "",
6779f6d3c4bSStefan Richter 		       data[byte_index(i)]);
6789f6d3c4bSStefan Richter 
6799f6d3c4bSStefan Richter 	if (print_length < length)
6809f6d3c4bSStefan Richter 		printf(" (%d more bytes)", length - print_length);
6819f6d3c4bSStefan Richter }
6829f6d3c4bSStefan Richter 
6839f6d3c4bSStefan Richter static void
decode_link_packet(struct link_packet * packet,size_t length,int include_flags,int exclude_flags)6849f6d3c4bSStefan Richter decode_link_packet(struct link_packet *packet, size_t length,
6859f6d3c4bSStefan Richter 		   int include_flags, int exclude_flags)
6869f6d3c4bSStefan Richter {
687468066f7SStefan Richter 	const struct packet_info *pi;
6889f6d3c4bSStefan Richter 	int data_length = 0;
6899f6d3c4bSStefan Richter 	int i;
6909f6d3c4bSStefan Richter 
6919f6d3c4bSStefan Richter 	pi = &packet_info[packet->common.tcode];
6929f6d3c4bSStefan Richter 
6939f6d3c4bSStefan Richter 	for (i = 0; i < pi->field_count; i++) {
694468066f7SStefan Richter 		const struct packet_field *f = &pi->fields[i];
6959f6d3c4bSStefan Richter 		int offset;
6969f6d3c4bSStefan Richter 
6979f6d3c4bSStefan Richter 		if (f->flags & exclude_flags)
6989f6d3c4bSStefan Richter 			continue;
6999f6d3c4bSStefan Richter 		if (include_flags && !(f->flags & include_flags))
7009f6d3c4bSStefan Richter 			continue;
7019f6d3c4bSStefan Richter 
7029f6d3c4bSStefan Richter 		if (f->offset < 0)
7039f6d3c4bSStefan Richter 			offset = length * 8 + f->offset - 32;
7049f6d3c4bSStefan Richter 		else
7059f6d3c4bSStefan Richter 			offset = f->offset;
7069f6d3c4bSStefan Richter 
7079f6d3c4bSStefan Richter 		if (f->value_names != NULL) {
7081bcc69fbSStefan Richter 			uint32_t bits;
7099f6d3c4bSStefan Richter 
7109f6d3c4bSStefan Richter 			bits = get_bits(packet, offset, f->width);
7119f6d3c4bSStefan Richter 			printf("%s", f->value_names[bits]);
71292c16f7eSStefan Richter 		} else if (f->width == 0) {
7139f6d3c4bSStefan Richter 			printf("%s=[", f->name);
7149f6d3c4bSStefan Richter 			dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
7159f6d3c4bSStefan Richter 			printf("]");
71692c16f7eSStefan Richter 		} else {
7179f6d3c4bSStefan Richter 			unsigned long long bits;
7189f6d3c4bSStefan Richter 			int high_width, low_width;
7199f6d3c4bSStefan Richter 
7209f6d3c4bSStefan Richter 			if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
7219f6d3c4bSStefan Richter 				/* Bit field spans quadlet boundary. */
7229f6d3c4bSStefan Richter 				high_width = ((offset + 31) & ~31) - offset;
7239f6d3c4bSStefan Richter 				low_width = f->width - high_width;
7249f6d3c4bSStefan Richter 
7259f6d3c4bSStefan Richter 				bits = get_bits(packet, offset, high_width);
7269f6d3c4bSStefan Richter 				bits = (bits << low_width) |
7279f6d3c4bSStefan Richter 					get_bits(packet, offset + high_width, low_width);
72892c16f7eSStefan Richter 			} else {
7299f6d3c4bSStefan Richter 				bits = get_bits(packet, offset, f->width);
73092c16f7eSStefan Richter 			}
7319f6d3c4bSStefan Richter 
7329f6d3c4bSStefan Richter 			printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
7339f6d3c4bSStefan Richter 
7349f6d3c4bSStefan Richter 			if (f->flags & PACKET_FIELD_DATA_LENGTH)
7359f6d3c4bSStefan Richter 				data_length = bits;
7369f6d3c4bSStefan Richter 		}
7379f6d3c4bSStefan Richter 
7389f6d3c4bSStefan Richter 		if (i < pi->field_count - 1)
7399f6d3c4bSStefan Richter 			printf(", ");
7409f6d3c4bSStefan Richter 	}
7419f6d3c4bSStefan Richter }
7429f6d3c4bSStefan Richter 
7439f6d3c4bSStefan Richter static void
print_packet(uint32_t * data,size_t length)7441bcc69fbSStefan Richter print_packet(uint32_t *data, size_t length)
7459f6d3c4bSStefan Richter {
7469f6d3c4bSStefan Richter 	int i;
7479f6d3c4bSStefan Richter 
7481bcc69fbSStefan Richter 	printf("%6u  ", data[0]);
7499f6d3c4bSStefan Richter 
75092c16f7eSStefan Richter 	if (length == 4) {
7519f6d3c4bSStefan Richter 		printf("bus reset");
75292c16f7eSStefan Richter 	} else if (length < sizeof(struct phy_packet)) {
7539f6d3c4bSStefan Richter 		printf("short packet: ");
7549f6d3c4bSStefan Richter 		for (i = 1; i < length / 4; i++)
7551bcc69fbSStefan Richter 			printf("%s%08x", i == 0 ? "[" : " ", data[i]);
7569f6d3c4bSStefan Richter 		printf("]");
7579f6d3c4bSStefan Richter 
75892c16f7eSStefan Richter 	} else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
7599f6d3c4bSStefan Richter 		struct phy_packet *pp = (struct phy_packet *) data;
7609f6d3c4bSStefan Richter 
7619f6d3c4bSStefan Richter 		/* phy packet are 3 quadlets: the 1 quadlet payload,
7629f6d3c4bSStefan Richter 		 * the bitwise inverse of the payload and the snoop
7639f6d3c4bSStefan Richter 		 * mode ack */
7649f6d3c4bSStefan Richter 
7659f6d3c4bSStefan Richter 		switch (pp->common.identifier) {
7669f6d3c4bSStefan Richter 		case PHY_PACKET_CONFIGURATION:
7679f6d3c4bSStefan Richter 			if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
7689f6d3c4bSStefan Richter 				printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
76992c16f7eSStefan Richter 			} else {
7709f6d3c4bSStefan Richter 				printf("phy config:");
7719f6d3c4bSStefan Richter 				if (pp->phy_config.set_root)
7729f6d3c4bSStefan Richter 					printf(" set_root_id=%02x", pp->phy_config.root_id);
7739f6d3c4bSStefan Richter 				if (pp->phy_config.set_gap_count)
7749f6d3c4bSStefan Richter 					printf(" set_gap_count=%d", pp->phy_config.gap_count);
7759f6d3c4bSStefan Richter 			}
7769f6d3c4bSStefan Richter 			break;
7779f6d3c4bSStefan Richter 
7789f6d3c4bSStefan Richter 		case PHY_PACKET_LINK_ON:
7799f6d3c4bSStefan Richter 			printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
7809f6d3c4bSStefan Richter 			break;
7819f6d3c4bSStefan Richter 
7829f6d3c4bSStefan Richter 		case PHY_PACKET_SELF_ID:
7839f6d3c4bSStefan Richter 			if (pp->self_id.extended) {
7849f6d3c4bSStefan Richter 				printf("extended self id: phy_id=%02x, seq=%d",
7859f6d3c4bSStefan Richter 				       pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
78692c16f7eSStefan Richter 			} else {
7879f6d3c4bSStefan Richter 				static const char * const speed_names[] = {
7889f6d3c4bSStefan Richter 					"S100", "S200", "S400", "BETA"
7899f6d3c4bSStefan Richter 				};
7909f6d3c4bSStefan Richter 				printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
7919f6d3c4bSStefan Richter 				       pp->self_id.phy_id,
7929f6d3c4bSStefan Richter 				       (pp->self_id.link_active ? "active" : "not active"),
7939f6d3c4bSStefan Richter 				       pp->self_id.gap_count,
7949f6d3c4bSStefan Richter 				       speed_names[pp->self_id.phy_speed],
7959f6d3c4bSStefan Richter 				       (pp->self_id.contender ? ", irm contender" : ""),
7969f6d3c4bSStefan Richter 				       (pp->self_id.initiated_reset ? ", initiator" : ""));
7979f6d3c4bSStefan Richter 			}
7989f6d3c4bSStefan Richter 			break;
7999f6d3c4bSStefan Richter 		default:
8009f6d3c4bSStefan Richter 			printf("unknown phy packet: ");
8019f6d3c4bSStefan Richter 			for (i = 1; i < length / 4; i++)
8021bcc69fbSStefan Richter 				printf("%s%08x", i == 0 ? "[" : " ", data[i]);
8039f6d3c4bSStefan Richter 			printf("]");
8049f6d3c4bSStefan Richter 			break;
8059f6d3c4bSStefan Richter 		}
80692c16f7eSStefan Richter 	} else {
8079f6d3c4bSStefan Richter 		struct link_packet *packet = (struct link_packet *) data;
8089f6d3c4bSStefan Richter 
8099f6d3c4bSStefan Richter 		decode_link_packet(packet, length, 0,
8109f6d3c4bSStefan Richter 				   option_verbose ? 0 : PACKET_FIELD_DETAIL);
8119f6d3c4bSStefan Richter 	}
8129f6d3c4bSStefan Richter 
8139f6d3c4bSStefan Richter 	if (option_hex) {
8149f6d3c4bSStefan Richter 		printf("  [");
8159f6d3c4bSStefan Richter 		dump_data((unsigned char *) data + 4, length - 4);
8169f6d3c4bSStefan Richter 		printf("]");
8179f6d3c4bSStefan Richter 	}
8189f6d3c4bSStefan Richter 
8199f6d3c4bSStefan Richter 	printf("\r\n");
8209f6d3c4bSStefan Richter }
8219f6d3c4bSStefan Richter 
8229f6d3c4bSStefan Richter #define HIDE_CURSOR	"\033[?25l"
8239f6d3c4bSStefan Richter #define SHOW_CURSOR	"\033[?25h"
8249f6d3c4bSStefan Richter #define CLEAR		"\033[H\033[2J"
8259f6d3c4bSStefan Richter 
8269f6d3c4bSStefan Richter static void
print_stats(uint32_t * data,size_t length)8271bcc69fbSStefan Richter print_stats(uint32_t *data, size_t length)
8289f6d3c4bSStefan Richter {
8299f6d3c4bSStefan Richter 	static int bus_reset_count, short_packet_count, phy_packet_count;
8309f6d3c4bSStefan Richter 	static int tcode_count[16];
8319f6d3c4bSStefan Richter 	static struct timeval last_update;
8329f6d3c4bSStefan Richter 	struct timeval now;
8339f6d3c4bSStefan Richter 	int i;
8349f6d3c4bSStefan Richter 
8359f6d3c4bSStefan Richter 	if (length == 0)
8369f6d3c4bSStefan Richter 		bus_reset_count++;
8379f6d3c4bSStefan Richter 	else if (length < sizeof(struct phy_packet))
8389f6d3c4bSStefan Richter 		short_packet_count++;
8399f6d3c4bSStefan Richter 	else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
8409f6d3c4bSStefan Richter 		phy_packet_count++;
8419f6d3c4bSStefan Richter 	else {
8429f6d3c4bSStefan Richter 		struct link_packet *packet = (struct link_packet *) data;
8439f6d3c4bSStefan Richter 		tcode_count[packet->common.tcode]++;
8449f6d3c4bSStefan Richter 	}
8459f6d3c4bSStefan Richter 
8469f6d3c4bSStefan Richter 	gettimeofday(&now, NULL);
8479f6d3c4bSStefan Richter 	if (now.tv_sec <= last_update.tv_sec &&
8489f6d3c4bSStefan Richter 	    now.tv_usec < last_update.tv_usec + 500000)
8499f6d3c4bSStefan Richter 		return;
8509f6d3c4bSStefan Richter 
8519f6d3c4bSStefan Richter 	last_update = now;
8529f6d3c4bSStefan Richter 	printf(CLEAR HIDE_CURSOR
8539f6d3c4bSStefan Richter 	       "  bus resets              : %8d\n"
8549f6d3c4bSStefan Richter 	       "  short packets           : %8d\n"
8559f6d3c4bSStefan Richter 	       "  phy packets             : %8d\n",
8569f6d3c4bSStefan Richter 	       bus_reset_count, short_packet_count, phy_packet_count);
8579f6d3c4bSStefan Richter 
8589f6d3c4bSStefan Richter 	for (i = 0; i < array_length(packet_info); i++)
8599f6d3c4bSStefan Richter 		if (packet_info[i].type != PACKET_RESERVED)
8609f6d3c4bSStefan Richter 			printf("  %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
8619f6d3c4bSStefan Richter 	printf(SHOW_CURSOR "\n");
8629f6d3c4bSStefan Richter }
8639f6d3c4bSStefan Richter 
864468066f7SStefan Richter static struct termios saved_attributes;
8659f6d3c4bSStefan Richter 
866468066f7SStefan Richter static void
reset_input_mode(void)8679f6d3c4bSStefan Richter reset_input_mode(void)
8689f6d3c4bSStefan Richter {
8699f6d3c4bSStefan Richter 	tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
8709f6d3c4bSStefan Richter }
8719f6d3c4bSStefan Richter 
872468066f7SStefan Richter static void
set_input_mode(void)8739f6d3c4bSStefan Richter set_input_mode(void)
8749f6d3c4bSStefan Richter {
8759f6d3c4bSStefan Richter 	struct termios tattr;
8769f6d3c4bSStefan Richter 
8779f6d3c4bSStefan Richter 	/* Make sure stdin is a terminal. */
8789f6d3c4bSStefan Richter 	if (!isatty(STDIN_FILENO)) {
8799f6d3c4bSStefan Richter 		fprintf(stderr, "Not a terminal.\n");
8809f6d3c4bSStefan Richter 		exit(EXIT_FAILURE);
8819f6d3c4bSStefan Richter 	}
8829f6d3c4bSStefan Richter 
8839f6d3c4bSStefan Richter 	/* Save the terminal attributes so we can restore them later. */
8849f6d3c4bSStefan Richter 	tcgetattr(STDIN_FILENO, &saved_attributes);
8859f6d3c4bSStefan Richter 	atexit(reset_input_mode);
8869f6d3c4bSStefan Richter 
8879f6d3c4bSStefan Richter 	/* Set the funny terminal modes. */
8889f6d3c4bSStefan Richter 	tcgetattr(STDIN_FILENO, &tattr);
8899f6d3c4bSStefan Richter 	tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
8909f6d3c4bSStefan Richter 	tattr.c_cc[VMIN] = 1;
8919f6d3c4bSStefan Richter 	tattr.c_cc[VTIME] = 0;
8929f6d3c4bSStefan Richter 	tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
8939f6d3c4bSStefan Richter }
8949f6d3c4bSStefan Richter 
main(int argc,const char * argv[])8959f6d3c4bSStefan Richter int main(int argc, const char *argv[])
8969f6d3c4bSStefan Richter {
897ddbfe749SStefan Richter 	uint32_t buf[128 * 1024];
898ddbfe749SStefan Richter 	uint32_t filter;
899ddbfe749SStefan Richter 	int length, retval, view;
9009f6d3c4bSStefan Richter 	int fd = -1;
9019f6d3c4bSStefan Richter 	FILE *output = NULL, *input = NULL;
9029f6d3c4bSStefan Richter 	poptContext con;
9039f6d3c4bSStefan Richter 	char c;
9049f6d3c4bSStefan Richter 	struct pollfd pollfds[2];
9059f6d3c4bSStefan Richter 
9069f6d3c4bSStefan Richter 	sys_sigint_handler = signal(SIGINT, sigint_handler);
9079f6d3c4bSStefan Richter 
9089f6d3c4bSStefan Richter 	con = poptGetContext(NULL, argc, argv, options, 0);
9099f6d3c4bSStefan Richter 	retval = poptGetNextOpt(con);
9109f6d3c4bSStefan Richter 	if (retval < -1) {
9119f6d3c4bSStefan Richter 		poptPrintUsage(con, stdout, 0);
9129f6d3c4bSStefan Richter 		return -1;
9139f6d3c4bSStefan Richter 	}
9149f6d3c4bSStefan Richter 
9159f6d3c4bSStefan Richter 	if (option_version) {
9169f6d3c4bSStefan Richter 		printf("dump tool for nosy sniffer, version %s\n", VERSION);
9179f6d3c4bSStefan Richter 		return 0;
9189f6d3c4bSStefan Richter 	}
9199f6d3c4bSStefan Richter 
9209f6d3c4bSStefan Richter 	if (__BYTE_ORDER != __LITTLE_ENDIAN)
9219f6d3c4bSStefan Richter 		fprintf(stderr, "warning: nosy has only been tested on little "
9229f6d3c4bSStefan Richter 			"endian machines\n");
9239f6d3c4bSStefan Richter 
9249f6d3c4bSStefan Richter 	if (option_input != NULL) {
9259f6d3c4bSStefan Richter 		input = fopen(option_input, "r");
9269f6d3c4bSStefan Richter 		if (input == NULL) {
9279f6d3c4bSStefan Richter 			fprintf(stderr, "Could not open %s, %m\n", option_input);
9289f6d3c4bSStefan Richter 			return -1;
9299f6d3c4bSStefan Richter 		}
93092c16f7eSStefan Richter 	} else {
9319f6d3c4bSStefan Richter 		fd = open(option_nosy_device, O_RDWR);
9329f6d3c4bSStefan Richter 		if (fd < 0) {
9339f6d3c4bSStefan Richter 			fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
9349f6d3c4bSStefan Richter 			return -1;
9359f6d3c4bSStefan Richter 		}
9369f6d3c4bSStefan Richter 		set_input_mode();
9379f6d3c4bSStefan Richter 	}
9389f6d3c4bSStefan Richter 
9399f6d3c4bSStefan Richter 	if (strcmp(option_view, "transaction") == 0)
9409f6d3c4bSStefan Richter 		view = VIEW_TRANSACTION;
9419f6d3c4bSStefan Richter 	else if (strcmp(option_view, "stats") == 0)
9429f6d3c4bSStefan Richter 		view = VIEW_STATS;
9439f6d3c4bSStefan Richter 	else
9449f6d3c4bSStefan Richter 		view = VIEW_PACKET;
9459f6d3c4bSStefan Richter 
9469f6d3c4bSStefan Richter 	if (option_output) {
9479f6d3c4bSStefan Richter 		output = fopen(option_output, "w");
9489f6d3c4bSStefan Richter 		if (output == NULL) {
9499f6d3c4bSStefan Richter 			fprintf(stderr, "Could not open %s, %m\n", option_output);
9509f6d3c4bSStefan Richter 			return -1;
9519f6d3c4bSStefan Richter 		}
9529f6d3c4bSStefan Richter 	}
9539f6d3c4bSStefan Richter 
9549f6d3c4bSStefan Richter 	setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
9559f6d3c4bSStefan Richter 
9569f6d3c4bSStefan Richter 	filter = ~0;
9579f6d3c4bSStefan Richter 	if (!option_iso)
95883ef7c75SStefan Richter 		filter &= ~(1 << TCODE_STREAM_DATA);
9599f6d3c4bSStefan Richter 	if (!option_cycle_start)
9609f6d3c4bSStefan Richter 		filter &= ~(1 << TCODE_CYCLE_START);
9619f6d3c4bSStefan Richter 	if (view == VIEW_STATS)
9621bcc69fbSStefan Richter 		filter = ~(1 << TCODE_CYCLE_START);
9631bcc69fbSStefan Richter 
9649f6d3c4bSStefan Richter 	ioctl(fd, NOSY_IOC_FILTER, filter);
9659f6d3c4bSStefan Richter 
9669f6d3c4bSStefan Richter 	ioctl(fd, NOSY_IOC_START);
9679f6d3c4bSStefan Richter 
9689f6d3c4bSStefan Richter 	pollfds[0].fd = fd;
9699f6d3c4bSStefan Richter 	pollfds[0].events = POLLIN;
9709f6d3c4bSStefan Richter 	pollfds[1].fd = STDIN_FILENO;
9719f6d3c4bSStefan Richter 	pollfds[1].events = POLLIN;
9729f6d3c4bSStefan Richter 
9739f6d3c4bSStefan Richter 	while (run) {
9749f6d3c4bSStefan Richter 		if (input != NULL) {
9759f6d3c4bSStefan Richter 			if (fread(&length, sizeof length, 1, input) != 1)
9769f6d3c4bSStefan Richter 				return 0;
9779f6d3c4bSStefan Richter 			fread(buf, 1, length, input);
97892c16f7eSStefan Richter 		} else {
9799f6d3c4bSStefan Richter 			poll(pollfds, 2, -1);
9809f6d3c4bSStefan Richter 			if (pollfds[1].revents) {
9819f6d3c4bSStefan Richter 				read(STDIN_FILENO, &c, sizeof c);
9829f6d3c4bSStefan Richter 				switch (c) {
9839f6d3c4bSStefan Richter 				case 'q':
9849f6d3c4bSStefan Richter 					if (output != NULL)
9859f6d3c4bSStefan Richter 						fclose(output);
9869f6d3c4bSStefan Richter 					return 0;
9879f6d3c4bSStefan Richter 				}
9889f6d3c4bSStefan Richter 			}
9899f6d3c4bSStefan Richter 
9909f6d3c4bSStefan Richter 			if (pollfds[0].revents)
9919f6d3c4bSStefan Richter 				length = read(fd, buf, sizeof buf);
9929f6d3c4bSStefan Richter 			else
9939f6d3c4bSStefan Richter 				continue;
9949f6d3c4bSStefan Richter 		}
9959f6d3c4bSStefan Richter 
9969f6d3c4bSStefan Richter 		if (output != NULL) {
9979f6d3c4bSStefan Richter 			fwrite(&length, sizeof length, 1, output);
9989f6d3c4bSStefan Richter 			fwrite(buf, 1, length, output);
9999f6d3c4bSStefan Richter 		}
10009f6d3c4bSStefan Richter 
10019f6d3c4bSStefan Richter 		switch (view) {
10029f6d3c4bSStefan Richter 		case VIEW_TRANSACTION:
10039f6d3c4bSStefan Richter 			handle_packet(buf, length);
10049f6d3c4bSStefan Richter 			break;
10059f6d3c4bSStefan Richter 		case VIEW_PACKET:
10069f6d3c4bSStefan Richter 			print_packet(buf, length);
10079f6d3c4bSStefan Richter 			break;
10089f6d3c4bSStefan Richter 		case VIEW_STATS:
10099f6d3c4bSStefan Richter 			print_stats(buf, length);
10109f6d3c4bSStefan Richter 			break;
10119f6d3c4bSStefan Richter 		}
10129f6d3c4bSStefan Richter 	}
10139f6d3c4bSStefan Richter 
10149f6d3c4bSStefan Richter 	if (output != NULL)
10159f6d3c4bSStefan Richter 		fclose(output);
10169f6d3c4bSStefan Richter 
10179f6d3c4bSStefan Richter 	close(fd);
10189f6d3c4bSStefan Richter 
10199f6d3c4bSStefan Richter 	poptFreeContext(con);
10209f6d3c4bSStefan Richter 
10219f6d3c4bSStefan Richter 	return 0;
10229f6d3c4bSStefan Richter }
1023