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