aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-22 05:58:05 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-07-27 05:04:11 -0400
commit9f6d3c4b76314c40c866a935d78c80fd284768bd (patch)
treeccb994e8ebe7a36b8bed804c79ce9f117455f041
parentaed69d2b79bb5af008526998e466da6d0eac7ae5 (diff)
tools/firewire: add userspace front-end of nosy
This adds nosy-dump, the userspace part of nosy, the IEEE 1394 traffic sniffer for Texas Instruments PCILynx/ PCILynx2 based cards. Author is Kristian Høgsberg. The files added here are taken from git://anongit.freedesktop.org/~krh/nosy commit ee29be97 (2009-11-10) with the following changes by Stefan Richter: - Parts pertaining to the kernel module removed from Makefile. - dist target removed from the Makefile. - Mentioned nosy-dump in the Kconfig help to nosy's kernel component. - Add copyright notice to nosy-dump.c. This is a duplicate of the respective notice in the kernel component nosy.c except for a time span of 2002 - 2006, according to Kristian's git log. "git shortlog decode-fcp.c list.h nosy-dump.[ch]" from nosy's git repository: Jonathan Woithe (1): Save logs on Ctrl-C Kristian Høgsberg (11): Pull over nosy from mercurial repo. Remove some fields from default view, add logging feature. Use infinite time out for poll(), mark more detail fields. Fix byte ordering macro. Add decoding of iso data and lock packets. Add flag to indicate data length field. Add cycle start packet decoding, add --iso and --cycle-start flags. Distinguish between phy-packets and 0-length iso data. Fix transaction and stats view. Add simple AV/C decoder. Don't break down on big payloads. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Acked-by: Kristian Høgsberg <krh@bitplanet.net>
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/firewire/Kconfig3
-rw-r--r--tools/firewire/Makefile19
-rw-r--r--tools/firewire/decode-fcp.c239
-rw-r--r--tools/firewire/list.h62
-rw-r--r--tools/firewire/nosy-dump.c1037
-rw-r--r--tools/firewire/nosy-dump.h292
7 files changed, 1652 insertions, 1 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index d329b053a718..70c9938f3f3e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2256,6 +2256,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
2256S: Maintained 2256S: Maintained
2257F: drivers/firewire/ 2257F: drivers/firewire/
2258F: include/linux/firewire*.h 2258F: include/linux/firewire*.h
2259F: tools/firewire/
2259 2260
2260FIRMWARE LOADER (request_firmware) 2261FIRMWARE LOADER (request_firmware)
2261S: Orphan 2262S: Orphan
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index c4edc34d128b..fcf3ea28340b 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -85,7 +85,8 @@ config FIREWIRE_NOSY
85 Apple Power Mac G3 blue & white (onboard controller). 85 Apple Power Mac G3 blue & white (onboard controller).
86 86
87 To compile this driver as a module, say M here: The module will be 87 To compile this driver as a module, say M here: The module will be
88 called nosy. 88 called nosy. Source code of a userspace interface to nosy, called
89 nosy-dump, can be found in tools/firewire/ of the kernel sources.
89 90
90 If unsure, say N. 91 If unsure, say N.
91 92
diff --git a/tools/firewire/Makefile b/tools/firewire/Makefile
new file mode 100644
index 000000000000..6afcdc21c7c9
--- /dev/null
+++ b/tools/firewire/Makefile
@@ -0,0 +1,19 @@
1version = 0.3
2prefix = /usr
3
4CC = gcc
5
6all : nosy-dump
7
8nosy-dump : CFLAGS = -Wall -O2 -g
9nosy-dump : CPPFLAGS = -DVERSION=\"$(version)\" -I../../drivers/firewire
10nosy-dump : LDFLAGS = -g
11nosy-dump : LDLIBS = -lpopt
12
13nosy-dump : nosy-dump.o decode-fcp.o
14
15clean :
16 rm -rf *.o nosy-dump
17
18install :
19 install nosy-dump $(prefix)/bin/nosy-dump
diff --git a/tools/firewire/decode-fcp.c b/tools/firewire/decode-fcp.c
new file mode 100644
index 000000000000..cb9a31b37530
--- /dev/null
+++ b/tools/firewire/decode-fcp.c
@@ -0,0 +1,239 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include "list.h"
4#include "nosy-dump.h"
5
6#define CSR_FCP_COMMAND 0xfffff0000b00ull
7#define CSR_FCP_RESPONSE 0xfffff0000d00ull
8
9static const char * const ctype_names[16] = {
10 "control",
11 "status",
12 "specific inquiry",
13 "notify",
14 "general inquiry",
15 "(reserved 0x05)",
16 "(reserved 0x06)",
17 "(reserved 0x07)",
18 "not implemented",
19 "accepted",
20 "rejected",
21 "in transition",
22 "stable",
23 "changed",
24 "(reserved 0x0e)",
25 "interim"
26};
27
28static const char * const subunit_type_names[32] = {
29 "monitor",
30 "audio",
31 "printer",
32 "disc",
33 "tape recorder/player",
34 "tuner",
35 "ca",
36 "camera",
37 "(reserved 0x08)",
38 "panel",
39 "bulletin board",
40 "camera storage",
41 "(reserved 0x0c)",
42 "(reserved 0x0d)",
43 "(reserved 0x0e)",
44 "(reserved 0x0f)",
45 "(reserved 0x10)",
46 "(reserved 0x11)",
47 "(reserved 0x12)",
48 "(reserved 0x13)",
49 "(reserved 0x14)",
50 "(reserved 0x15)",
51 "(reserved 0x16)",
52 "(reserved 0x17)",
53 "(reserved 0x18)",
54 "(reserved 0x19)",
55 "(reserved 0x1a)",
56 "(reserved 0x1b)",
57 "vendor unique",
58 "all subunit types",
59 "subunit_type extended to next byte",
60 "unit"
61};
62
63struct avc_enum {
64 int value;
65 const char *name;
66};
67
68struct avc_field {
69 const char *name; /* Short name for field. */
70 int offset; /* Location of field, specified in bits.
71 * Negative means from end of packet */
72 int width; /* Width of field, 0 means use data_length. */
73 struct avc_enum *names;
74};
75
76struct avc_opcode_info {
77 const char *name;
78 struct avc_field fields[8];
79};
80
81struct avc_enum power_field_names[] = {
82 { 0x70, "on" },
83 { 0x60, "off" },
84 { }
85};
86
87static const struct avc_opcode_info opcode_info[256] = {
88
89 /* TA Document 1999026
90 * AV/C Digital Interface Command Set General Specification
91 * Version 4.0 */
92 [0xb2] =
93 { "power", {
94 { "state", 0, 8, power_field_names }
95 }
96 },
97 [0x30] =
98 { "unit info", {
99 { "foo", 0, 8 },
100 { "unit_type", 8, 5 },
101 { "unit", 13, 3 },
102 { "company id", 16, 24 },
103 }
104 },
105 [0x31] = { "subunit info" },
106 [0x01] = { "reserve" },
107 [0xb0] = { "version" },
108 [0x00] = { "vendor dependent" },
109
110 [0x02] = { "plug info" },
111 [0x12] = { "channel usage" },
112 [0x24] = { "connect" },
113 [0x20] = { "connect av" },
114 [0x22] = { "connections" },
115 [0x11] = { "digital input" },
116 [0x10] = { "digital output" },
117 [0x25] = { "disconnect" },
118 [0x21] = { "disconnect av" },
119 [0x19] = { "input plug signal format" },
120 [0x18] = { "output plug signal format" },
121 [0x1f] = { "general bus setup" },
122
123 /* TA Document 1999025
124 * AV/C Descriptor Mechanism Specification Version 1.0 */
125 [0x0c] = { "create descriptor" },
126 [0x08] = { "open descriptor" },
127 [0x09] = { "read descriptor" },
128 [0x0a] = { "write descriptor" },
129 [0x05] = { "open info block" },
130 [0x06] = { "read info block" },
131 [0x07] = { "write info block" },
132 [0x0b] = { "search descriptor" },
133 [0x0d] = { "object number select" },
134
135 /* TA Document 1999015
136 * AV/C Command Set for Rate Control of Isochronous Data Flow 1.0 */
137 [0xb3] = { "rate", {
138 { "subfunction", 0, 8 },
139 { "result", 8, 8 },
140 { "plug_type", 16, 8 },
141 { "plug_id", 16, 8 },
142 }
143 },
144
145 /* TA Document 1999008
146 * AV/C Audio Subunit Specification 1.0 */
147 [0xb8] = { "function block" },
148
149 /* TA Document 2001001
150 * AV/C Panel Subunit Specification 1.1 */
151 [0x7d] = { "gui update" },
152 [0x7e] = { "push gui data" },
153 [0x7f] = { "user action" },
154 [0x7c] = { "pass through" },
155
156 /* */
157 [0x26] = { "asynchronous connection" },
158};
159
160struct avc_frame {
161 unsigned int operand0 : 8;
162 unsigned int opcode : 8;
163 unsigned int subunit_id : 3;
164 unsigned int subunit_type : 5;
165 unsigned int ctype : 4;
166 unsigned int cts : 4;
167};
168
169static void
170decode_avc(struct link_transaction *t)
171{
172 struct avc_frame *frame = (struct avc_frame *) t->request->packet.write_block.data;
173 const struct avc_opcode_info *info;
174 const char *name;
175 char buffer[32];
176 int i;
177
178 info = &opcode_info[frame->opcode];
179 if (info->name == NULL) {
180 snprintf(buffer, sizeof buffer, "(unknown opcode 0x%02x)", frame->opcode);
181 name = buffer;
182 } else {
183 name = info->name;
184 }
185
186 printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s",
187 ctype_names[frame->ctype], subunit_type_names[frame->subunit_type],
188 frame->subunit_id, name);
189
190 for (i = 0; info->fields[i].name != NULL; i++) {
191 printf(", %s", info->fields[i].name);
192 }
193
194 printf("\n");
195}
196
197
198int
199decode_fcp(struct link_transaction *t)
200{
201 struct avc_frame *frame = (struct avc_frame *) t->request->packet.write_block.data;
202 unsigned long long offset;
203
204 offset = ((unsigned long long) t->request->packet.common.offset_high << 32) |
205 t->request->packet.common.offset_low;
206
207 if (t->request->packet.common.tcode != TCODE_WRITE_BLOCK)
208 return 0;
209
210 if (offset == CSR_FCP_COMMAND || offset == CSR_FCP_RESPONSE) {
211 switch (frame->cts) {
212 case 0x00:
213 decode_avc(t);
214 break;
215 case 0x01:
216 printf("cal fcp frame (cts=0x01)\n");
217 break;
218 case 0x02:
219 printf("ehs fcp frame (cts=0x02)\n");
220 break;
221 case 0x03:
222 printf("havi fcp frame (cts=0x03)\n");
223 break;
224 case 0x0e:
225 printf("vendor specific fcp frame (cts=0x0e)\n");
226 break;
227 case 0x0f:
228 printf("extended cts\n");
229 break;
230 default:
231 printf("reserved fcp frame (ctx=0x%02x)\n", frame->cts);
232 break;
233 }
234 return 1;
235 }
236
237 return 0;
238}
239
diff --git a/tools/firewire/list.h b/tools/firewire/list.h
new file mode 100644
index 000000000000..fa119dd371fe
--- /dev/null
+++ b/tools/firewire/list.h
@@ -0,0 +1,62 @@
1struct list {
2 struct list *next, *prev;
3};
4
5static inline void
6list_init(struct list *list)
7{
8 list->next = list;
9 list->prev = list;
10}
11
12static inline int
13list_empty(struct list *list)
14{
15 return list->next == list;
16}
17
18static inline void
19list_insert(struct list *link, struct list *new_link)
20{
21 new_link->prev = link->prev;
22 new_link->next = link;
23 new_link->prev->next = new_link;
24 new_link->next->prev = new_link;
25}
26
27static inline void
28list_append(struct list *list, struct list *new_link)
29{
30 list_insert((struct list *)list, new_link);
31}
32
33static inline void
34list_prepend(struct list *list, struct list *new_link)
35{
36 list_insert(list->next, new_link);
37}
38
39static inline void
40list_remove(struct list *link)
41{
42 link->prev->next = link->next;
43 link->next->prev = link->prev;
44}
45
46#define list_entry(link, type, member) \
47 ((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
48
49#define list_head(list, type, member) \
50 list_entry((list)->next, type, member)
51
52#define list_tail(list, type, member) \
53 list_entry((list)->prev, type, member)
54
55#define list_next(elm, member) \
56 list_entry((elm)->member.next, typeof(*elm), member)
57
58#define list_for_each_entry(pos, list, member) \
59 for (pos = list_head(list, typeof(*pos), member); \
60 &pos->member != (list); \
61 pos = list_next(pos, member))
62
diff --git a/tools/firewire/nosy-dump.c b/tools/firewire/nosy-dump.c
new file mode 100644
index 000000000000..64e5ea438928
--- /dev/null
+++ b/tools/firewire/nosy-dump.c
@@ -0,0 +1,1037 @@
1/* -*- mode: c; c-basic-offset: 2 -*- */
2
3/*
4 * nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
5 * Copyright (C) 2002-2006 Kristian Høgsberg
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/ioctl.h>
28#include <sys/time.h>
29#include <endian.h>
30#include <popt.h>
31#include <poll.h>
32#include <byteswap.h>
33#include <termios.h>
34
35#include <signal.h>
36
37#include "list.h"
38#include "nosy-user.h"
39#include "nosy-dump.h"
40
41enum {
42 PACKET_FIELD_DETAIL = 0x01,
43 PACKET_FIELD_DATA_LENGTH = 0x02,
44 /* Marks the fields we print in transaction view. */
45 PACKET_FIELD_TRANSACTION = 0x04
46};
47
48static void
49print_packet(unsigned long *data, size_t length);
50static void
51decode_link_packet(struct link_packet *packet, size_t length,
52 int include_flags, int exclude_flags);
53
54static int run = 1;
55sig_t sys_sigint_handler;
56
57static char *option_nosy_device = "/dev/nosy";
58static char *option_view = "packet";
59static char *option_output = NULL;
60static char *option_input = NULL;
61static int option_hex;
62static int option_iso;
63static int option_cycle_start;
64static int option_version;
65static int option_verbose;
66
67enum {
68 VIEW_TRANSACTION,
69 VIEW_PACKET,
70 VIEW_STATS
71};
72
73static const struct poptOption options[] = {
74 {
75 longName: "device",
76 shortName: 'd',
77 argInfo: POPT_ARG_STRING,
78 arg: &option_nosy_device,
79 descrip: "Path to nosy device.",
80 argDescrip: "DEVICE"
81 },
82 {
83 longName: "view",
84 argInfo: POPT_ARG_STRING,
85 arg: &option_view,
86 descrip: "Specify view of bus traffic: packet, transaction or stats.",
87 argDescrip: "VIEW"
88 },
89 {
90 longName: "hex",
91 shortName: 'x',
92 argInfo: POPT_ARG_NONE,
93 arg: &option_hex,
94 descrip: "Print each packet in hex.",
95 },
96 {
97 longName: "iso",
98 argInfo: POPT_ARG_NONE,
99 arg: &option_iso,
100 descrip: "Print iso packets.",
101 },
102 {
103 longName: "cycle-start",
104 argInfo: POPT_ARG_NONE,
105 arg: &option_cycle_start,
106 descrip: "Print cycle start packets.",
107 },
108 {
109 longName: "verbose",
110 shortName: 'v',
111 argInfo: POPT_ARG_NONE,
112 arg: &option_verbose,
113 descrip: "Verbose packet view.",
114 },
115 {
116 longName: "output",
117 shortName: 'o',
118 argInfo: POPT_ARG_STRING,
119 arg: &option_output,
120 descrip: "Log to output file.",
121 argDescrip: "FILENAME"
122 },
123 {
124 longName: "input",
125 shortName: 'i',
126 argInfo: POPT_ARG_STRING,
127 arg: &option_input,
128 descrip: "Decode log from file.",
129 argDescrip: "FILENAME"
130 },
131 {
132 longName: "version",
133 argInfo: POPT_ARG_NONE,
134 arg: &option_version,
135 descrip: "Specify print version info.",
136 },
137 POPT_AUTOHELP
138 POPT_TABLEEND
139};
140
141void
142sigint_handler(int signal_num)
143{
144 if (run == 1) {
145 run = 0;
146 /* Allow all Ctrl-C's except the first to interrupt the program in
147 * the usual way.
148 */
149 signal(SIGINT, SIG_DFL);
150 }
151}
152
153struct subaction *
154subaction_create(unsigned long *data, size_t length)
155{
156 struct subaction *sa;
157
158 /* we put the ack in the subaction struct for easy access. */
159 sa = malloc(sizeof *sa - sizeof sa->packet + length);
160 sa->ack = data[length / 4 - 1];
161 sa->length = length;
162 memcpy (&sa->packet, data, length);
163
164 return sa;
165}
166
167void
168subaction_destroy(struct subaction *sa)
169{
170 free(sa);
171}
172
173struct list pending_transaction_list =
174 { &pending_transaction_list, &pending_transaction_list };
175
176struct link_transaction *
177link_transaction_lookup(int request_node, int response_node, int tlabel)
178{
179 struct link_transaction *t;
180
181 list_for_each_entry(t, &pending_transaction_list, link) {
182 if (t->request_node == request_node &&
183 t->response_node == response_node &&
184 t->tlabel == tlabel)
185 return t;
186 }
187
188 t = malloc(sizeof *t);
189 t->request_node = request_node;
190 t->response_node = response_node;
191 t->tlabel = tlabel;
192 list_init(&t->request_list);
193 list_init(&t->response_list);
194
195 list_append(&pending_transaction_list, &t->link);
196
197 return t;
198}
199
200void
201link_transaction_destroy(struct link_transaction *t)
202{
203 while (!list_empty(&t->request_list)) {
204 struct subaction *sa = list_head(&t->request_list, struct subaction, link);
205 list_remove(&sa->link);
206 subaction_destroy(sa);
207 }
208
209 while (!list_empty(&t->response_list)) {
210 struct subaction *sa = list_head(&t->response_list, struct subaction, link);
211 list_remove(&sa->link);
212 subaction_destroy(sa);
213 }
214
215 free(t);
216}
217
218struct protocol_decoder {
219 const char *name;
220 int (*decode)(struct link_transaction *t);
221};
222
223static struct protocol_decoder protocol_decoders[] = {
224 { "FCP", decode_fcp }
225};
226
227void
228handle_transaction(struct link_transaction *t)
229{
230 struct subaction *sa;
231 int i;
232
233 for (i = 0; i < array_length(protocol_decoders); i++)
234 if (protocol_decoders[i].decode(t))
235 break;
236
237 /* HACK: decode only fcp right now. */
238 return;
239
240 decode_link_packet(&t->request->packet, t->request->length,
241 PACKET_FIELD_TRANSACTION, 0);
242 if (t->response)
243 decode_link_packet(&t->response->packet, t->request->length,
244 PACKET_FIELD_TRANSACTION, 0);
245 else
246 printf("[no response]");
247
248 if (option_verbose) {
249 list_for_each_entry(sa, &t->request_list, link)
250 print_packet((unsigned long *) &sa->packet, sa->length);
251 list_for_each_entry(sa, &t->response_list, link)
252 print_packet((unsigned long *) &sa->packet, sa->length);
253 }
254 printf("\r\n");
255
256 link_transaction_destroy(t);
257}
258
259void
260clear_pending_transaction_list(void)
261{
262 struct link_transaction *t;
263
264 while (!list_empty(&pending_transaction_list)) {
265 t = list_head(&pending_transaction_list, struct link_transaction, link);
266 list_remove(&t->link);
267 link_transaction_destroy(t);
268 /* print unfinished transactions */
269 }
270}
271
272static const char * const tcode_names[] = {
273 "write_quadlet_request",
274 "write_block_request",
275 "write_response",
276 "reserved",
277 "read_quadlet_request",
278 "read_block_request",
279 "read_quadlet_response",
280 "read_block_response",
281 "cycle_start",
282 "lock_request",
283 "iso_data",
284 "lock_response"
285};
286
287static const char * const ack_names[] = {
288 "no ack",
289 "ack_complete",
290 "ack_pending",
291 "reserved (0x03)",
292 "ack_busy_x",
293 "ack_busy_a",
294 "ack_busy_b",
295 "reserved (0x07)",
296 "reserved (0x08)",
297 "reserved (0x09)",
298 "reserved (0x0a)",
299 "reserved (0x0b)",
300 "reserved (0x0c)",
301 "ack_data_error",
302 "ack_type_error",
303 "reserved (0x0f)",
304};
305
306static const char * const rcode_names[] = {
307 "complete",
308 "reserved (0x01)",
309 "reserved (0x02)",
310 "reserved (0x03)",
311 "conflict_error",
312 "data_error",
313 "type_error",
314 "address_error",
315};
316
317static const char * const retry_names[] = {
318 "retry_1",
319 "retry_x",
320 "retry_a",
321 "retry_b",
322};
323
324enum {
325 PACKET_RESERVED,
326 PACKET_REQUEST,
327 PACKET_RESPONSE,
328 PACKET_OTHER,
329};
330
331struct packet_info {
332 const char *name;
333 int type;
334 int response_tcode;
335 struct packet_field *fields;
336 int field_count;
337};
338
339struct packet_field {
340 const char *name; /* Short name for field. */
341 int offset; /* Location of field, specified in bits.
342 * Negative means from end of packet */
343 int width; /* Width of field, 0 means use data_length. */
344 int flags; /* Show options. */
345 const char * const *value_names;
346};
347
348#define COMMON_REQUEST_FIELDS \
349 { "dest", 0, 16, PACKET_FIELD_TRANSACTION }, \
350 { "tl", 16, 6 }, \
351 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
352 { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names }, \
353 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
354 { "src", 32, 16, PACKET_FIELD_TRANSACTION }, \
355 { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
356
357#define COMMON_RESPONSE_FIELDS \
358 { "dest", 0, 16 }, \
359 { "tl", 16, 6 }, \
360 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
361 { "tcode", 24, 4, 0, tcode_names }, \
362 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
363 { "src", 32, 16 }, \
364 { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
365
366struct packet_field read_quadlet_request_fields[] = {
367 COMMON_REQUEST_FIELDS,
368 { "crc", 96, 32, PACKET_FIELD_DETAIL },
369 { "ack", 156, 4, 0, ack_names }
370};
371
372struct packet_field read_quadlet_response_fields[] = {
373 COMMON_RESPONSE_FIELDS,
374 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
375 { "crc", 128, 32, PACKET_FIELD_DETAIL },
376 { "ack", 188, 4, 0, ack_names }
377};
378
379struct packet_field read_block_request_fields[] = {
380 COMMON_REQUEST_FIELDS,
381 { "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
382 { "extended_tcode", 112, 16 },
383 { "crc", 128, 32, PACKET_FIELD_DETAIL },
384 { "ack", 188, 4, 0, ack_names },
385};
386
387struct packet_field block_response_fields[] = {
388 COMMON_RESPONSE_FIELDS,
389 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
390 { "extended_tcode", 112, 16 },
391 { "crc", 128, 32, PACKET_FIELD_DETAIL },
392 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
393 { "crc", -64, 32, PACKET_FIELD_DETAIL },
394 { "ack", -4, 4, 0, ack_names }
395};
396
397struct packet_field write_quadlet_request_fields[] = {
398 COMMON_REQUEST_FIELDS,
399 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
400 { "ack", -4, 4, 0, ack_names }
401};
402
403struct packet_field block_request_fields[] = {
404 COMMON_REQUEST_FIELDS,
405 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
406 { "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
407 { "crc", 128, 32, PACKET_FIELD_DETAIL },
408 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
409 { "crc", -64, 32, PACKET_FIELD_DETAIL },
410 { "ack", -4, 4, 0, ack_names }
411};
412
413struct packet_field write_response_fields[] = {
414 COMMON_RESPONSE_FIELDS,
415 { "reserved", 64, 32, PACKET_FIELD_DETAIL },
416 { "ack", -4, 4, 0, ack_names }
417};
418
419struct packet_field iso_data_fields[] = {
420 { "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
421 { "tag", 16, 2 },
422 { "channel", 18, 6 },
423 { "tcode", 24, 4, 0, tcode_names },
424 { "sy", 28, 4 },
425 { "crc", 32, 32, PACKET_FIELD_DETAIL },
426 { "data", 64, 0 },
427 { "crc", -64, 32, PACKET_FIELD_DETAIL },
428 { "ack", -4, 4, 0, ack_names }
429};
430
431static struct packet_info packet_info[] = {
432 {
433 .name = "write_quadlet_request",
434 .type = PACKET_REQUEST,
435 .response_tcode = TCODE_WRITE_RESPONSE,
436 .fields = write_quadlet_request_fields,
437 .field_count = array_length(write_quadlet_request_fields)
438 },
439 {
440 .name = "write_block_request",
441 .type = PACKET_REQUEST,
442 .response_tcode = TCODE_WRITE_RESPONSE,
443 .fields = block_request_fields,
444 .field_count = array_length(block_request_fields)
445 },
446 {
447 .name = "write_response",
448 .type = PACKET_RESPONSE,
449 .fields = write_response_fields,
450 .field_count = array_length(write_response_fields)
451 },
452 {
453 .name = "reserved",
454 .type = PACKET_RESERVED,
455 },
456 {
457 .name = "read_quadlet_request",
458 .type = PACKET_REQUEST,
459 .response_tcode = TCODE_READ_QUADLET_RESPONSE,
460 .fields = read_quadlet_request_fields,
461 .field_count = array_length(read_quadlet_request_fields)
462 },
463 {
464 .name = "read_block_request",
465 .type = PACKET_REQUEST,
466 .response_tcode = TCODE_READ_BLOCK_RESPONSE,
467 .fields = read_block_request_fields,
468 .field_count = array_length(read_block_request_fields)
469 },
470 {
471 .name = "read_quadlet_response",
472 .type = PACKET_RESPONSE,
473 .fields = read_quadlet_response_fields,
474 .field_count = array_length(read_quadlet_response_fields)
475 },
476 {
477 .name = "read_block_response",
478 .type = PACKET_RESPONSE,
479 .fields = block_response_fields,
480 .field_count = array_length(block_response_fields)
481 },
482 {
483 .name = "cycle_start",
484 .type = PACKET_OTHER,
485 .fields = write_quadlet_request_fields,
486 .field_count = array_length(write_quadlet_request_fields)
487 },
488 {
489 .name = "lock_request",
490 .type = PACKET_REQUEST,
491 .fields = block_request_fields,
492 .field_count = array_length(block_request_fields)
493 },
494 {
495 .name = "iso_data",
496 .type = PACKET_OTHER,
497 .fields = iso_data_fields,
498 .field_count = array_length(iso_data_fields)
499 },
500 {
501 .name = "lock_response",
502 .type = PACKET_RESPONSE,
503 .fields = block_response_fields,
504 .field_count = array_length(block_response_fields)
505 }
506};
507
508int
509handle_packet(unsigned long *data, size_t length)
510{
511 if (length == 0) {
512 printf("bus reset\r\n");
513 clear_pending_transaction_list();
514 }
515 else if (length > sizeof(struct phy_packet)) {
516 struct link_packet *p = (struct link_packet *) data;
517 struct subaction *sa, *prev;
518 struct link_transaction *t;
519
520 switch (packet_info[p->common.tcode].type) {
521 case PACKET_REQUEST:
522 t = link_transaction_lookup(p->common.source, p->common.destination,
523 p->common.tlabel);
524 sa = subaction_create(data, length);
525 t->request = sa;
526
527 if (!list_empty(&t->request_list)) {
528 prev = list_tail(&t->request_list, struct subaction, link);
529
530 if (!ACK_BUSY(prev->ack)) {
531 /* error, we should only see ack_busy_* before the
532 * ack_pending/ack_complete -- this is an ack_pending
533 * instead (ack_complete would have finished the
534 * transaction). */
535 }
536
537 if (prev->packet.common.tcode != sa->packet.common.tcode ||
538 prev->packet.common.tlabel != sa->packet.common.tlabel)
539 /* memcmp() ? */
540 /* error, these should match for retries. */;
541 }
542
543 list_append(&t->request_list, &sa->link);
544
545 switch (sa->ack) {
546 case ACK_COMPLETE:
547 if (p->common.tcode != TCODE_WRITE_QUADLET &&
548 p->common.tcode != TCODE_WRITE_BLOCK)
549 /* error, unified transactions only allowed for write */;
550 list_remove(&t->link);
551 handle_transaction(t);
552 break;
553
554 case ACK_NO_ACK:
555 case ACK_DATA_ERROR:
556 case ACK_TYPE_ERROR:
557 list_remove(&t->link);
558 handle_transaction(t);
559 break;
560
561 case ACK_PENDING:
562 /* request subaction phase over, wait for response. */
563 break;
564
565 case ACK_BUSY_X:
566 case ACK_BUSY_A:
567 case ACK_BUSY_B:
568 /* ok, wait for retry. */
569 /* check that retry protocol is respected. */
570 break;
571 }
572 break;
573
574 case PACKET_RESPONSE:
575 t = link_transaction_lookup(p->common.destination, p->common.source,
576 p->common.tlabel);
577 if (list_empty(&t->request_list)) {
578 /* unsolicited response */
579 }
580
581 sa = subaction_create(data, length);
582 t->response = sa;
583
584 if (!list_empty(&t->response_list)) {
585 prev = list_tail(&t->response_list, struct subaction, link);
586
587 if (!ACK_BUSY(prev->ack))
588 /* error, we should only see ack_busy_* before the
589 * ack_pending/ack_complete */;
590
591 if (prev->packet.common.tcode != sa->packet.common.tcode ||
592 prev->packet.common.tlabel != sa->packet.common.tlabel)
593 /* use memcmp() instead? */
594 /* error, these should match for retries. */;
595 }
596 else {
597 prev = list_tail(&t->request_list, struct subaction, link);
598 if (prev->ack != ACK_PENDING) {
599 /* error, should not get response unless last request got
600 * ack_pending. */
601 }
602
603 if (packet_info[prev->packet.common.tcode].response_tcode !=
604 sa->packet.common.tcode) {
605 /* error, tcode mismatch */
606 }
607 }
608
609 list_append(&t->response_list, &sa->link);
610
611 switch (sa->ack) {
612 case ACK_COMPLETE:
613 case ACK_NO_ACK:
614 case ACK_DATA_ERROR:
615 case ACK_TYPE_ERROR:
616 list_remove(&t->link);
617 handle_transaction(t);
618 /* transaction complete, remove t from pending list. */
619 break;
620
621 case ACK_PENDING:
622 /* error for responses. */
623 break;
624
625 case ACK_BUSY_X:
626 case ACK_BUSY_A:
627 case ACK_BUSY_B:
628 /* no problem, wait for next retry */
629 break;
630 }
631
632 break;
633
634 case PACKET_OTHER:
635 case PACKET_RESERVED:
636 return 0;
637 }
638 }
639
640 return 1;
641}
642
643unsigned int get_bits(struct link_packet *packet, int offset, int width)
644{
645 unsigned long *data = (unsigned long *) packet;
646 unsigned long index, shift, mask;
647
648 index = offset / 32 + 1;
649 shift = 32 - (offset & 31) - width;
650 mask = width == 32 ? ~0 : (1 << width) - 1;
651
652 return (data[index] >> shift) & mask;
653}
654
655#if __BYTE_ORDER == __LITTLE_ENDIAN
656#define byte_index(i) ((i) ^ 3)
657#elif __BYTE_ORDER == __BIG_ENDIAN
658#define byte_index(i) (i)
659#else
660#error unsupported byte order.
661#endif
662
663void dump_data(unsigned char *data, int length)
664{
665 int i, print_length;
666
667 if (length > 128)
668 print_length = 128;
669 else
670 print_length = length;
671
672 for (i = 0; i < print_length; i++)
673 printf("%s%02hhx",
674 (i % 4 == 0 && i != 0) ? " " : "",
675 data[byte_index(i)]);
676
677 if (print_length < length)
678 printf(" (%d more bytes)", length - print_length);
679}
680
681static void
682decode_link_packet(struct link_packet *packet, size_t length,
683 int include_flags, int exclude_flags)
684{
685 struct packet_info *pi;
686 int data_length = 0;
687 int i;
688
689 pi = &packet_info[packet->common.tcode];
690
691 for (i = 0; i < pi->field_count; i++) {
692 struct packet_field *f = &pi->fields[i];
693 int offset;
694
695 if (f->flags & exclude_flags)
696 continue;
697 if (include_flags && !(f->flags & include_flags))
698 continue;
699
700 if (f->offset < 0)
701 offset = length * 8 + f->offset - 32;
702 else
703 offset = f->offset;
704
705 if (f->value_names != NULL) {
706 unsigned long bits;
707
708 bits = get_bits(packet, offset, f->width);
709 printf("%s", f->value_names[bits]);
710 }
711 else if (f->width == 0) {
712 printf("%s=[", f->name);
713 dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
714 printf("]");
715 }
716 else {
717 unsigned long long bits;
718 int high_width, low_width;
719
720 if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
721 /* Bit field spans quadlet boundary. */
722 high_width = ((offset + 31) & ~31) - offset;
723 low_width = f->width - high_width;
724
725 bits = get_bits(packet, offset, high_width);
726 bits = (bits << low_width) |
727 get_bits(packet, offset + high_width, low_width);
728 }
729 else
730 bits = get_bits(packet, offset, f->width);
731
732 printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
733
734 if (f->flags & PACKET_FIELD_DATA_LENGTH)
735 data_length = bits;
736 }
737
738 if (i < pi->field_count - 1)
739 printf(", ");
740 }
741}
742
743static void
744print_packet(unsigned long *data, size_t length)
745{
746 int i;
747
748 printf("%6lu ", data[0]);
749
750 if (length == 4)
751 printf("bus reset");
752 else if (length < sizeof(struct phy_packet)) {
753 printf("short packet: ");
754 for (i = 1; i < length / 4; i++)
755 printf("%s%08lx", i == 0 ? "[" : " ", data[i]);
756 printf("]");
757
758 }
759 else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
760 struct phy_packet *pp = (struct phy_packet *) data;
761
762 /* phy packet are 3 quadlets: the 1 quadlet payload,
763 * the bitwise inverse of the payload and the snoop
764 * mode ack */
765
766 switch (pp->common.identifier) {
767 case PHY_PACKET_CONFIGURATION:
768 if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
769 printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
770 }
771 else {
772 printf("phy config:");
773 if (pp->phy_config.set_root)
774 printf(" set_root_id=%02x", pp->phy_config.root_id);
775 if (pp->phy_config.set_gap_count)
776 printf(" set_gap_count=%d", pp->phy_config.gap_count);
777 }
778 break;
779
780 case PHY_PACKET_LINK_ON:
781 printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
782 break;
783
784 case PHY_PACKET_SELF_ID:
785 if (pp->self_id.extended) {
786 printf("extended self id: phy_id=%02x, seq=%d",
787 pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
788 }
789 else {
790 static const char * const speed_names[] = {
791 "S100", "S200", "S400", "BETA"
792 };
793 printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
794 pp->self_id.phy_id,
795 (pp->self_id.link_active ? "active" : "not active"),
796 pp->self_id.gap_count,
797 speed_names[pp->self_id.phy_speed],
798 (pp->self_id.contender ? ", irm contender" : ""),
799 (pp->self_id.initiated_reset ? ", initiator" : ""));
800
801 }
802 break;
803 default:
804 printf("unknown phy packet: ");
805 for (i = 1; i < length / 4; i++)
806 printf("%s%08lx", i == 0 ? "[" : " ", data[i]);
807 printf("]");
808 break;
809 }
810 }
811 else {
812 struct link_packet *packet = (struct link_packet *) data;
813
814 decode_link_packet(packet, length, 0,
815 option_verbose ? 0 : PACKET_FIELD_DETAIL);
816 }
817
818 if (option_hex) {
819 printf(" [");
820 dump_data((unsigned char *) data + 4, length - 4);
821 printf("]");
822 }
823
824 printf("\r\n");
825}
826
827#define HIDE_CURSOR "\033[?25l"
828#define SHOW_CURSOR "\033[?25h"
829#define CLEAR "\033[H\033[2J"
830
831static void
832print_stats(unsigned long *data, size_t length)
833{
834 static int bus_reset_count, short_packet_count, phy_packet_count;
835 static int tcode_count[16];
836 static struct timeval last_update;
837 struct timeval now;
838 int i;
839
840 if (length == 0)
841 bus_reset_count++;
842 else if (length < sizeof(struct phy_packet))
843 short_packet_count++;
844 else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
845 phy_packet_count++;
846 else {
847 struct link_packet *packet = (struct link_packet *) data;
848 tcode_count[packet->common.tcode]++;
849 }
850
851 gettimeofday(&now, NULL);
852 if (now.tv_sec <= last_update.tv_sec &&
853 now.tv_usec < last_update.tv_usec + 500000)
854 return;
855
856 last_update = now;
857 printf(CLEAR HIDE_CURSOR
858 " bus resets : %8d\n"
859 " short packets : %8d\n"
860 " phy packets : %8d\n",
861 bus_reset_count, short_packet_count, phy_packet_count);
862
863 for (i = 0; i < array_length(packet_info); i++)
864 if (packet_info[i].type != PACKET_RESERVED)
865 printf(" %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
866 printf(SHOW_CURSOR "\n");
867}
868
869struct termios saved_attributes;
870
871void
872reset_input_mode (void)
873{
874 tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
875}
876
877void
878set_input_mode (void)
879{
880 struct termios tattr;
881
882 /* Make sure stdin is a terminal. */
883 if (!isatty(STDIN_FILENO)) {
884 fprintf(stderr, "Not a terminal.\n");
885 exit(EXIT_FAILURE);
886 }
887
888 /* Save the terminal attributes so we can restore them later. */
889 tcgetattr(STDIN_FILENO, &saved_attributes);
890 atexit(reset_input_mode);
891
892 /* Set the funny terminal modes. */
893 tcgetattr(STDIN_FILENO, &tattr);
894 tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
895 tattr.c_cc[VMIN] = 1;
896 tattr.c_cc[VTIME] = 0;
897 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
898}
899
900int main(int argc, const char *argv[])
901{
902 int fd = -1;
903 FILE *output = NULL, *input = NULL;
904 poptContext con;
905 int retval;
906 int view;
907 char c;
908 struct pollfd pollfds[2];
909
910 sys_sigint_handler = signal(SIGINT, sigint_handler);
911
912 con = poptGetContext(NULL, argc, argv, options, 0);
913 retval = poptGetNextOpt(con);
914 if (retval < -1) {
915 poptPrintUsage(con, stdout, 0);
916 return -1;
917 }
918
919 if (option_version) {
920 printf("dump tool for nosy sniffer, version %s\n", VERSION);
921 return 0;
922 }
923
924 if (__BYTE_ORDER != __LITTLE_ENDIAN)
925 fprintf(stderr, "warning: nosy has only been tested on little "
926 "endian machines\n");
927
928 if (option_input != NULL) {
929 input = fopen(option_input, "r");
930 if (input == NULL) {
931 fprintf(stderr, "Could not open %s, %m\n", option_input);
932 return -1;
933 }
934 }
935 else {
936 fd = open(option_nosy_device, O_RDWR);
937 if (fd < 0) {
938 fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
939 return -1;
940 }
941 set_input_mode();
942 }
943
944 if (strcmp(option_view, "transaction") == 0)
945 view = VIEW_TRANSACTION;
946 else if (strcmp(option_view, "stats") == 0)
947 view = VIEW_STATS;
948 else
949 view = VIEW_PACKET;
950
951 if (option_output) {
952 output = fopen(option_output, "w");
953 if (output == NULL) {
954 fprintf(stderr, "Could not open %s, %m\n", option_output);
955 return -1;
956 }
957 }
958
959 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
960
961 if (1) {
962 unsigned long buf[128 * 1024];
963 unsigned int filter;
964 int length;
965
966 filter = ~0;
967 if (!option_iso)
968 filter &= ~(1 <<TCODE_ISO_DATA);
969 if (!option_cycle_start)
970 filter &= ~(1 << TCODE_CYCLE_START);
971
972 if (view == VIEW_STATS)
973 ioctl(fd, NOSY_IOC_FILTER, ~(1 << TCODE_CYCLE_START));
974 else
975 ioctl(fd, NOSY_IOC_FILTER, filter);
976
977 ioctl(fd, NOSY_IOC_START);
978
979 pollfds[0].fd = fd;
980 pollfds[0].events = POLLIN;
981 pollfds[1].fd = STDIN_FILENO;
982 pollfds[1].events = POLLIN;
983
984 while (run) {
985 if (input != NULL) {
986 if (fread(&length, sizeof length, 1, input) != 1)
987 return 0;
988 fread(buf, 1, length, input);
989 }
990 else {
991 poll(pollfds, 2, -1);
992 if (pollfds[1].revents) {
993 read(STDIN_FILENO, &c, sizeof c);
994 switch (c) {
995 case 'q':
996 if (output != NULL)
997 fclose(output);
998 return 0;
999 }
1000 }
1001
1002 if (pollfds[0].revents)
1003 length = read(fd, buf, sizeof buf);
1004 else
1005 continue;
1006 }
1007
1008 if (output != NULL) {
1009 fwrite(&length, sizeof length, 1, output);
1010 fwrite(buf, 1, length, output);
1011 }
1012
1013 switch (view) {
1014 case VIEW_TRANSACTION:
1015 handle_packet(buf, length);
1016 break;
1017 case VIEW_PACKET:
1018 print_packet(buf, length);
1019 break;
1020 case VIEW_STATS:
1021 print_stats(buf, length);
1022 break;
1023 }
1024 }
1025 }
1026 else
1027 poptPrintUsage(con, stdout, 0);
1028
1029 if (output != NULL)
1030 fclose(output);
1031
1032 close(fd);
1033
1034 poptFreeContext(con);
1035
1036 return 0;
1037}
diff --git a/tools/firewire/nosy-dump.h b/tools/firewire/nosy-dump.h
new file mode 100644
index 000000000000..d8bcb61ab954
--- /dev/null
+++ b/tools/firewire/nosy-dump.h
@@ -0,0 +1,292 @@
1#ifndef __nosy_dump_h__
2#define __nosy_dump_h__
3
4#define array_length(array) (sizeof(array) / sizeof(array[0]))
5
6#define TCODE_WRITE_QUADLET 0x0
7#define TCODE_WRITE_BLOCK 0x1
8#define TCODE_WRITE_RESPONSE 0x2
9#define TCODE_READ_QUADLET 0x4
10#define TCODE_READ_BLOCK 0x5
11#define TCODE_READ_QUADLET_RESPONSE 0x6
12#define TCODE_READ_BLOCK_RESPONSE 0x7
13#define TCODE_CYCLE_START 0x8
14#define TCODE_LOCK_REQUEST 0x9
15#define TCODE_ISO_DATA 0xa
16#define TCODE_LOCK_RESPONSE 0xb
17#define TCODE_PHY_PACKET 0x10
18
19#define ACK_NO_ACK 0x0
20#define ACK_COMPLETE 0x1
21#define ACK_PENDING 0x2
22#define ACK_BUSY_X 0x4
23#define ACK_BUSY_A 0x5
24#define ACK_BUSY_B 0x6
25#define ACK_DATA_ERROR 0xd
26#define ACK_TYPE_ERROR 0xe
27
28#define ACK_DONE(a) ((a >> 2) == 0)
29#define ACK_BUSY(a) ((a >> 2) == 1)
30#define ACK_ERROR(a) ((a >> 2) == 3)
31
32#define SPEED_100 0x0
33#define SPEED_200 0x1
34#define SPEED_400 0x2
35
36struct phy_packet {
37 unsigned long timestamp;
38
39 union {
40 struct {
41 unsigned int zero : 24;
42 unsigned int phy_id : 6;
43 unsigned int identifier : 2;
44 } common, link_on;
45 struct {
46 unsigned int zero : 16;
47 unsigned int gap_count : 6;
48 unsigned int set_gap_count : 1;
49 unsigned int set_root : 1;
50 unsigned int root_id : 6;
51 unsigned int identifier : 2;
52 } phy_config;
53 struct {
54 unsigned int more_packets : 1;
55 unsigned int initiated_reset : 1;
56 unsigned int port2 : 2;
57 unsigned int port1 : 2;
58 unsigned int port0 : 2;
59 unsigned int power_class : 3;
60 unsigned int contender : 1;
61 unsigned int phy_delay : 2;
62 unsigned int phy_speed : 2;
63 unsigned int gap_count : 6;
64 unsigned int link_active : 1;
65 unsigned int extended : 1;
66 unsigned int phy_id : 6;
67 unsigned int identifier : 2;
68 } self_id;
69
70 struct {
71 unsigned int more_packets : 1;
72 unsigned int reserved1 : 1;
73 unsigned int porth : 2;
74 unsigned int portg : 2;
75 unsigned int portf : 2;
76 unsigned int porte : 2;
77 unsigned int portd : 2;
78 unsigned int portc : 2;
79 unsigned int portb : 2;
80 unsigned int porta : 2;
81 unsigned int reserved0 : 2;
82 unsigned int sequence : 3;
83 unsigned int extended : 1;
84 unsigned int phy_id : 6;
85 unsigned int identifier : 2;
86 } ext_self_id;
87 };
88
89 unsigned long inverted;
90 unsigned long ack;
91};
92
93#define PHY_PACKET_CONFIGURATION 0x00
94#define PHY_PACKET_LINK_ON 0x01
95#define PHY_PACKET_SELF_ID 0x02
96
97struct link_packet {
98 unsigned long timestamp;
99
100 union {
101 struct {
102 unsigned int priority : 4;
103 unsigned int tcode : 4;
104 unsigned int rt : 2;
105 unsigned int tlabel : 6;
106 unsigned int destination : 16;
107
108 unsigned int offset_high : 16;
109 unsigned int source : 16;
110
111 unsigned long offset_low;
112 } common;
113
114 struct {
115 unsigned int priority : 4;
116 unsigned int tcode : 4;
117 unsigned int rt : 2;
118 unsigned int tlabel : 6;
119 unsigned int destination : 16;
120
121 unsigned int offset_high : 16;
122 unsigned int source : 16;
123
124 unsigned long offset_low;
125
126 unsigned long crc;
127 } read_quadlet;
128
129 struct {
130 unsigned int priority : 4;
131 unsigned int tcode : 4;
132 unsigned int rt : 2;
133 unsigned int tlabel : 6;
134 unsigned int destination : 16;
135
136 unsigned int reserved0 : 12;
137 unsigned int rcode : 4;
138 unsigned int source : 16;
139
140 unsigned long reserved1;
141
142 unsigned long data;
143
144 unsigned long crc;
145 } read_quadlet_response;
146
147 struct {
148 unsigned int priority : 4;
149 unsigned int tcode : 4;
150 unsigned int rt : 2;
151 unsigned int tlabel : 6;
152 unsigned int destination : 16;
153
154 unsigned int offset_high : 16;
155 unsigned int source : 16;
156
157 unsigned long offset_low;
158
159 unsigned int extended_tcode : 16;
160 unsigned int data_length : 16;
161
162 unsigned long crc;
163 } read_block;
164
165 struct {
166 unsigned int priority : 4;
167 unsigned int tcode : 4;
168 unsigned int rt : 2;
169 unsigned int tlabel : 6;
170 unsigned int destination : 16;
171
172 unsigned int reserved0 : 12;
173 unsigned int rcode : 4;
174 unsigned int source : 16;
175
176 unsigned long reserved1;
177
178 unsigned int extended_tcode : 16;
179 unsigned int data_length : 16;
180
181 unsigned long crc;
182
183 unsigned long data[0];
184
185 /* crc and ack follows. */
186
187 } read_block_response;
188
189 struct {
190 unsigned int priority : 4;
191 unsigned int tcode : 4;
192 unsigned int rt : 2;
193 unsigned int tlabel : 6;
194 unsigned int destination : 16;
195
196 unsigned int offset_high : 16;
197 unsigned int source : 16;
198
199 unsigned long offset_low;
200
201 unsigned long data;
202
203 unsigned long crc;
204
205 } write_quadlet;
206
207 struct {
208 unsigned int priority : 4;
209 unsigned int tcode : 4;
210 unsigned int rt : 2;
211 unsigned int tlabel : 6;
212 unsigned int destination : 16;
213
214 unsigned int offset_high : 16;
215 unsigned int source : 16;
216
217 unsigned int offset_low : 32;
218
219 unsigned int extended_tcode : 16;
220 unsigned int data_length : 16;
221
222 unsigned long crc;
223 unsigned long data[0];
224
225 /* crc and ack follows. */
226
227 } write_block;
228
229 struct {
230 unsigned int priority : 4;
231 unsigned int tcode : 4;
232 unsigned int rt : 2;
233 unsigned int tlabel : 6;
234 unsigned int destination : 16;
235
236 unsigned int reserved0 : 12;
237 unsigned int rcode : 4;
238 unsigned int source : 16;
239
240 unsigned long reserved1;
241
242 unsigned long crc;
243 } write_response;
244
245 struct {
246 unsigned int priority : 4;
247 unsigned int tcode : 4;
248 unsigned int rt : 2;
249 unsigned int tlabel : 6;
250 unsigned int destination : 16;
251
252 unsigned int offset_high : 16;
253 unsigned int source : 16;
254
255 unsigned long offset_low;
256
257 unsigned long data;
258
259 unsigned long crc;
260 } cycle_start;
261
262 struct {
263 unsigned int sy : 4;
264 unsigned int tcode : 4;
265 unsigned int channel : 6;
266 unsigned int tag : 2;
267 unsigned int data_length : 16;
268
269 unsigned long crc;
270 } iso_data;
271
272 };
273
274};
275
276struct subaction {
277 unsigned long ack;
278 size_t length;
279 struct list link;
280 struct link_packet packet;
281};
282
283struct link_transaction {
284 int request_node, response_node, tlabel;
285 struct subaction *request, *response;
286 struct list request_list, response_list;
287 struct list link;
288};
289
290int decode_fcp(struct link_transaction *t);
291
292#endif /* __nosy_dump_h__ */