Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/firewire/nosy-dump.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
4
* Copyright (C) 2002-2006 Kristian Høgsberg
5
*/
6
7
#include <byteswap.h>
8
#include <endian.h>
9
#include <fcntl.h>
10
#include <linux/firewire-constants.h>
11
#include <poll.h>
12
#include <popt.h>
13
#include <signal.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <sys/ioctl.h>
18
#include <sys/time.h>
19
#include <termios.h>
20
#include <unistd.h>
21
22
#include "list.h"
23
#include "nosy-dump.h"
24
#include "nosy-user.h"
25
26
enum {
27
PACKET_FIELD_DETAIL = 0x01,
28
PACKET_FIELD_DATA_LENGTH = 0x02,
29
/* Marks the fields we print in transaction view. */
30
PACKET_FIELD_TRANSACTION = 0x04,
31
};
32
33
static void print_packet(uint32_t *data, size_t length);
34
static void decode_link_packet(struct link_packet *packet, size_t length,
35
int include_flags, int exclude_flags);
36
static int run = 1;
37
sig_t sys_sigint_handler;
38
39
static char *option_nosy_device = "/dev/nosy";
40
static char *option_view = "packet";
41
static char *option_output;
42
static char *option_input;
43
static int option_hex;
44
static int option_iso;
45
static int option_cycle_start;
46
static int option_version;
47
static int option_verbose;
48
49
enum {
50
VIEW_TRANSACTION,
51
VIEW_PACKET,
52
VIEW_STATS,
53
};
54
55
static const struct poptOption options[] = {
56
{
57
.longName = "device",
58
.shortName = 'd',
59
.argInfo = POPT_ARG_STRING,
60
.arg = &option_nosy_device,
61
.descrip = "Path to nosy device.",
62
.argDescrip = "DEVICE"
63
},
64
{
65
.longName = "view",
66
.argInfo = POPT_ARG_STRING,
67
.arg = &option_view,
68
.descrip = "Specify view of bus traffic: packet, transaction or stats.",
69
.argDescrip = "VIEW"
70
},
71
{
72
.longName = "hex",
73
.shortName = 'x',
74
.argInfo = POPT_ARG_NONE,
75
.arg = &option_hex,
76
.descrip = "Print each packet in hex.",
77
},
78
{
79
.longName = "iso",
80
.argInfo = POPT_ARG_NONE,
81
.arg = &option_iso,
82
.descrip = "Print iso packets.",
83
},
84
{
85
.longName = "cycle-start",
86
.argInfo = POPT_ARG_NONE,
87
.arg = &option_cycle_start,
88
.descrip = "Print cycle start packets.",
89
},
90
{
91
.longName = "verbose",
92
.shortName = 'v',
93
.argInfo = POPT_ARG_NONE,
94
.arg = &option_verbose,
95
.descrip = "Verbose packet view.",
96
},
97
{
98
.longName = "output",
99
.shortName = 'o',
100
.argInfo = POPT_ARG_STRING,
101
.arg = &option_output,
102
.descrip = "Log to output file.",
103
.argDescrip = "FILENAME"
104
},
105
{
106
.longName = "input",
107
.shortName = 'i',
108
.argInfo = POPT_ARG_STRING,
109
.arg = &option_input,
110
.descrip = "Decode log from file.",
111
.argDescrip = "FILENAME"
112
},
113
{
114
.longName = "version",
115
.argInfo = POPT_ARG_NONE,
116
.arg = &option_version,
117
.descrip = "Specify print version info.",
118
},
119
POPT_AUTOHELP
120
POPT_TABLEEND
121
};
122
123
/* Allow all ^C except the first to interrupt the program in the usual way. */
124
static void
125
sigint_handler(int signal_num)
126
{
127
if (run == 1) {
128
run = 0;
129
signal(SIGINT, SIG_DFL);
130
}
131
}
132
133
static struct subaction *
134
subaction_create(uint32_t *data, size_t length)
135
{
136
struct subaction *sa;
137
138
/* we put the ack in the subaction struct for easy access. */
139
sa = malloc(sizeof *sa - sizeof sa->packet + length);
140
if (!sa)
141
exit(EXIT_FAILURE);
142
sa->ack = data[length / 4 - 1];
143
sa->length = length;
144
memcpy(&sa->packet, data, length);
145
146
return sa;
147
}
148
149
static void
150
subaction_destroy(struct subaction *sa)
151
{
152
free(sa);
153
}
154
155
static struct list pending_transaction_list = {
156
&pending_transaction_list, &pending_transaction_list
157
};
158
159
static struct link_transaction *
160
link_transaction_lookup(int request_node, int response_node, int tlabel)
161
{
162
struct link_transaction *t;
163
164
list_for_each_entry(t, &pending_transaction_list, link) {
165
if (t->request_node == request_node &&
166
t->response_node == response_node &&
167
t->tlabel == tlabel)
168
return t;
169
}
170
171
t = malloc(sizeof *t);
172
if (!t)
173
exit(EXIT_FAILURE);
174
t->request_node = request_node;
175
t->response_node = response_node;
176
t->tlabel = tlabel;
177
list_init(&t->request_list);
178
list_init(&t->response_list);
179
180
list_append(&pending_transaction_list, &t->link);
181
182
return t;
183
}
184
185
static void
186
link_transaction_destroy(struct link_transaction *t)
187
{
188
struct subaction *sa;
189
190
while (!list_empty(&t->request_list)) {
191
sa = list_head(&t->request_list, struct subaction, link);
192
list_remove(&sa->link);
193
subaction_destroy(sa);
194
}
195
while (!list_empty(&t->response_list)) {
196
sa = list_head(&t->response_list, struct subaction, link);
197
list_remove(&sa->link);
198
subaction_destroy(sa);
199
}
200
free(t);
201
}
202
203
struct protocol_decoder {
204
const char *name;
205
int (*decode)(struct link_transaction *t);
206
};
207
208
static const struct protocol_decoder protocol_decoders[] = {
209
{ "FCP", decode_fcp }
210
};
211
212
static void
213
handle_transaction(struct link_transaction *t)
214
{
215
struct subaction *sa;
216
int i;
217
218
if (!t->request) {
219
printf("BUG in handle_transaction\n");
220
return;
221
}
222
223
for (i = 0; i < array_length(protocol_decoders); i++)
224
if (protocol_decoders[i].decode(t))
225
break;
226
227
/* HACK: decode only fcp right now. */
228
return;
229
230
decode_link_packet(&t->request->packet, t->request->length,
231
PACKET_FIELD_TRANSACTION, 0);
232
if (t->response)
233
decode_link_packet(&t->response->packet, t->request->length,
234
PACKET_FIELD_TRANSACTION, 0);
235
else
236
printf("[no response]");
237
238
if (option_verbose) {
239
list_for_each_entry(sa, &t->request_list, link)
240
print_packet((uint32_t *) &sa->packet, sa->length);
241
list_for_each_entry(sa, &t->response_list, link)
242
print_packet((uint32_t *) &sa->packet, sa->length);
243
}
244
printf("\r\n");
245
246
link_transaction_destroy(t);
247
}
248
249
static void
250
clear_pending_transaction_list(void)
251
{
252
struct link_transaction *t;
253
254
while (!list_empty(&pending_transaction_list)) {
255
t = list_head(&pending_transaction_list,
256
struct link_transaction, link);
257
list_remove(&t->link);
258
link_transaction_destroy(t);
259
/* print unfinished transactions */
260
}
261
}
262
263
static const char * const tcode_names[] = {
264
[0x0] = "write_quadlet_request", [0x6] = "read_quadlet_response",
265
[0x1] = "write_block_request", [0x7] = "read_block_response",
266
[0x2] = "write_response", [0x8] = "cycle_start",
267
[0x3] = "reserved", [0x9] = "lock_request",
268
[0x4] = "read_quadlet_request", [0xa] = "iso_data",
269
[0x5] = "read_block_request", [0xb] = "lock_response",
270
};
271
272
static const char * const ack_names[] = {
273
[0x0] = "no ack", [0x8] = "reserved (0x08)",
274
[0x1] = "ack_complete", [0x9] = "reserved (0x09)",
275
[0x2] = "ack_pending", [0xa] = "reserved (0x0a)",
276
[0x3] = "reserved (0x03)", [0xb] = "reserved (0x0b)",
277
[0x4] = "ack_busy_x", [0xc] = "reserved (0x0c)",
278
[0x5] = "ack_busy_a", [0xd] = "ack_data_error",
279
[0x6] = "ack_busy_b", [0xe] = "ack_type_error",
280
[0x7] = "reserved (0x07)", [0xf] = "reserved (0x0f)",
281
};
282
283
static const char * const rcode_names[] = {
284
[0x0] = "complete", [0x4] = "conflict_error",
285
[0x1] = "reserved (0x01)", [0x5] = "data_error",
286
[0x2] = "reserved (0x02)", [0x6] = "type_error",
287
[0x3] = "reserved (0x03)", [0x7] = "address_error",
288
};
289
290
static const char * const retry_names[] = {
291
[0x0] = "retry_1",
292
[0x1] = "retry_x",
293
[0x2] = "retry_a",
294
[0x3] = "retry_b",
295
};
296
297
enum {
298
PACKET_RESERVED,
299
PACKET_REQUEST,
300
PACKET_RESPONSE,
301
PACKET_OTHER,
302
};
303
304
struct packet_info {
305
const char *name;
306
int type;
307
int response_tcode;
308
const struct packet_field *fields;
309
int field_count;
310
};
311
312
struct packet_field {
313
const char *name; /* Short name for field. */
314
int offset; /* Location of field, specified in bits; */
315
/* negative means from end of packet. */
316
int width; /* Width of field, 0 means use data_length. */
317
int flags; /* Show options. */
318
const char * const *value_names;
319
};
320
321
#define COMMON_REQUEST_FIELDS \
322
{ "dest", 0, 16, PACKET_FIELD_TRANSACTION }, \
323
{ "tl", 16, 6 }, \
324
{ "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
325
{ "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names }, \
326
{ "pri", 28, 4, PACKET_FIELD_DETAIL }, \
327
{ "src", 32, 16, PACKET_FIELD_TRANSACTION }, \
328
{ "offs", 48, 48, PACKET_FIELD_TRANSACTION }
329
330
#define COMMON_RESPONSE_FIELDS \
331
{ "dest", 0, 16 }, \
332
{ "tl", 16, 6 }, \
333
{ "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
334
{ "tcode", 24, 4, 0, tcode_names }, \
335
{ "pri", 28, 4, PACKET_FIELD_DETAIL }, \
336
{ "src", 32, 16 }, \
337
{ "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
338
339
static const struct packet_field read_quadlet_request_fields[] = {
340
COMMON_REQUEST_FIELDS,
341
{ "crc", 96, 32, PACKET_FIELD_DETAIL },
342
{ "ack", 156, 4, 0, ack_names },
343
};
344
345
static const struct packet_field read_quadlet_response_fields[] = {
346
COMMON_RESPONSE_FIELDS,
347
{ "data", 96, 32, PACKET_FIELD_TRANSACTION },
348
{ "crc", 128, 32, PACKET_FIELD_DETAIL },
349
{ "ack", 188, 4, 0, ack_names },
350
};
351
352
static const struct packet_field read_block_request_fields[] = {
353
COMMON_REQUEST_FIELDS,
354
{ "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
355
{ "extended_tcode", 112, 16 },
356
{ "crc", 128, 32, PACKET_FIELD_DETAIL },
357
{ "ack", 188, 4, 0, ack_names },
358
};
359
360
static const struct packet_field block_response_fields[] = {
361
COMMON_RESPONSE_FIELDS,
362
{ "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
363
{ "extended_tcode", 112, 16 },
364
{ "crc", 128, 32, PACKET_FIELD_DETAIL },
365
{ "data", 160, 0, PACKET_FIELD_TRANSACTION },
366
{ "crc", -64, 32, PACKET_FIELD_DETAIL },
367
{ "ack", -4, 4, 0, ack_names },
368
};
369
370
static const struct packet_field write_quadlet_request_fields[] = {
371
COMMON_REQUEST_FIELDS,
372
{ "data", 96, 32, PACKET_FIELD_TRANSACTION },
373
{ "ack", -4, 4, 0, ack_names },
374
};
375
376
static const struct packet_field block_request_fields[] = {
377
COMMON_REQUEST_FIELDS,
378
{ "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
379
{ "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
380
{ "crc", 128, 32, PACKET_FIELD_DETAIL },
381
{ "data", 160, 0, PACKET_FIELD_TRANSACTION },
382
{ "crc", -64, 32, PACKET_FIELD_DETAIL },
383
{ "ack", -4, 4, 0, ack_names },
384
};
385
386
static const struct packet_field write_response_fields[] = {
387
COMMON_RESPONSE_FIELDS,
388
{ "reserved", 64, 32, PACKET_FIELD_DETAIL },
389
{ "ack", -4, 4, 0, ack_names },
390
};
391
392
static const struct packet_field iso_data_fields[] = {
393
{ "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
394
{ "tag", 16, 2 },
395
{ "channel", 18, 6 },
396
{ "tcode", 24, 4, 0, tcode_names },
397
{ "sy", 28, 4 },
398
{ "crc", 32, 32, PACKET_FIELD_DETAIL },
399
{ "data", 64, 0 },
400
{ "crc", -64, 32, PACKET_FIELD_DETAIL },
401
{ "ack", -4, 4, 0, ack_names },
402
};
403
404
static const struct packet_info packet_info[] = {
405
{
406
.name = "write_quadlet_request",
407
.type = PACKET_REQUEST,
408
.response_tcode = TCODE_WRITE_RESPONSE,
409
.fields = write_quadlet_request_fields,
410
.field_count = array_length(write_quadlet_request_fields)
411
},
412
{
413
.name = "write_block_request",
414
.type = PACKET_REQUEST,
415
.response_tcode = TCODE_WRITE_RESPONSE,
416
.fields = block_request_fields,
417
.field_count = array_length(block_request_fields)
418
},
419
{
420
.name = "write_response",
421
.type = PACKET_RESPONSE,
422
.fields = write_response_fields,
423
.field_count = array_length(write_response_fields)
424
},
425
{
426
.name = "reserved",
427
.type = PACKET_RESERVED,
428
},
429
{
430
.name = "read_quadlet_request",
431
.type = PACKET_REQUEST,
432
.response_tcode = TCODE_READ_QUADLET_RESPONSE,
433
.fields = read_quadlet_request_fields,
434
.field_count = array_length(read_quadlet_request_fields)
435
},
436
{
437
.name = "read_block_request",
438
.type = PACKET_REQUEST,
439
.response_tcode = TCODE_READ_BLOCK_RESPONSE,
440
.fields = read_block_request_fields,
441
.field_count = array_length(read_block_request_fields)
442
},
443
{
444
.name = "read_quadlet_response",
445
.type = PACKET_RESPONSE,
446
.fields = read_quadlet_response_fields,
447
.field_count = array_length(read_quadlet_response_fields)
448
},
449
{
450
.name = "read_block_response",
451
.type = PACKET_RESPONSE,
452
.fields = block_response_fields,
453
.field_count = array_length(block_response_fields)
454
},
455
{
456
.name = "cycle_start",
457
.type = PACKET_OTHER,
458
.fields = write_quadlet_request_fields,
459
.field_count = array_length(write_quadlet_request_fields)
460
},
461
{
462
.name = "lock_request",
463
.type = PACKET_REQUEST,
464
.fields = block_request_fields,
465
.field_count = array_length(block_request_fields)
466
},
467
{
468
.name = "iso_data",
469
.type = PACKET_OTHER,
470
.fields = iso_data_fields,
471
.field_count = array_length(iso_data_fields)
472
},
473
{
474
.name = "lock_response",
475
.type = PACKET_RESPONSE,
476
.fields = block_response_fields,
477
.field_count = array_length(block_response_fields)
478
},
479
};
480
481
static int
482
handle_request_packet(uint32_t *data, size_t length)
483
{
484
struct link_packet *p = (struct link_packet *) data;
485
struct subaction *sa, *prev;
486
struct link_transaction *t;
487
488
t = link_transaction_lookup(p->common.source, p->common.destination,
489
p->common.tlabel);
490
sa = subaction_create(data, length);
491
t->request = sa;
492
493
if (!list_empty(&t->request_list)) {
494
prev = list_tail(&t->request_list,
495
struct subaction, link);
496
497
if (!ACK_BUSY(prev->ack)) {
498
/*
499
* error, we should only see ack_busy_* before the
500
* ack_pending/ack_complete -- this is an ack_pending
501
* instead (ack_complete would have finished the
502
* transaction).
503
*/
504
}
505
506
if (prev->packet.common.tcode != sa->packet.common.tcode ||
507
prev->packet.common.tlabel != sa->packet.common.tlabel) {
508
/* memcmp() ? */
509
/* error, these should match for retries. */
510
}
511
}
512
513
list_append(&t->request_list, &sa->link);
514
515
switch (sa->ack) {
516
case ACK_COMPLETE:
517
if (p->common.tcode != TCODE_WRITE_QUADLET_REQUEST &&
518
p->common.tcode != TCODE_WRITE_BLOCK_REQUEST)
519
/* error, unified transactions only allowed for write */;
520
list_remove(&t->link);
521
handle_transaction(t);
522
break;
523
524
case ACK_NO_ACK:
525
case ACK_DATA_ERROR:
526
case ACK_TYPE_ERROR:
527
list_remove(&t->link);
528
handle_transaction(t);
529
break;
530
531
case ACK_PENDING:
532
/* request subaction phase over, wait for response. */
533
break;
534
535
case ACK_BUSY_X:
536
case ACK_BUSY_A:
537
case ACK_BUSY_B:
538
/* ok, wait for retry. */
539
/* check that retry protocol is respected. */
540
break;
541
}
542
543
return 1;
544
}
545
546
static int
547
handle_response_packet(uint32_t *data, size_t length)
548
{
549
struct link_packet *p = (struct link_packet *) data;
550
struct subaction *sa, *prev;
551
struct link_transaction *t;
552
553
t = link_transaction_lookup(p->common.destination, p->common.source,
554
p->common.tlabel);
555
if (list_empty(&t->request_list)) {
556
/* unsolicited response */
557
}
558
559
sa = subaction_create(data, length);
560
t->response = sa;
561
562
if (!list_empty(&t->response_list)) {
563
prev = list_tail(&t->response_list, struct subaction, link);
564
565
if (!ACK_BUSY(prev->ack)) {
566
/*
567
* error, we should only see ack_busy_* before the
568
* ack_pending/ack_complete
569
*/
570
}
571
572
if (prev->packet.common.tcode != sa->packet.common.tcode ||
573
prev->packet.common.tlabel != sa->packet.common.tlabel) {
574
/* use memcmp() instead? */
575
/* error, these should match for retries. */
576
}
577
} else {
578
prev = list_tail(&t->request_list, struct subaction, link);
579
if (prev->ack != ACK_PENDING) {
580
/*
581
* error, should not get response unless last request got
582
* ack_pending.
583
*/
584
}
585
586
if (packet_info[prev->packet.common.tcode].response_tcode !=
587
sa->packet.common.tcode) {
588
/* error, tcode mismatch */
589
}
590
}
591
592
list_append(&t->response_list, &sa->link);
593
594
switch (sa->ack) {
595
case ACK_COMPLETE:
596
case ACK_NO_ACK:
597
case ACK_DATA_ERROR:
598
case ACK_TYPE_ERROR:
599
list_remove(&t->link);
600
handle_transaction(t);
601
/* transaction complete, remove t from pending list. */
602
break;
603
604
case ACK_PENDING:
605
/* error for responses. */
606
break;
607
608
case ACK_BUSY_X:
609
case ACK_BUSY_A:
610
case ACK_BUSY_B:
611
/* no problem, wait for next retry */
612
break;
613
}
614
615
return 1;
616
}
617
618
static int
619
handle_packet(uint32_t *data, size_t length)
620
{
621
if (length == 0) {
622
printf("bus reset\r\n");
623
clear_pending_transaction_list();
624
} else if (length > sizeof(struct phy_packet)) {
625
struct link_packet *p = (struct link_packet *) data;
626
627
switch (packet_info[p->common.tcode].type) {
628
case PACKET_REQUEST:
629
return handle_request_packet(data, length);
630
631
case PACKET_RESPONSE:
632
return handle_response_packet(data, length);
633
634
case PACKET_OTHER:
635
case PACKET_RESERVED:
636
return 0;
637
}
638
}
639
640
return 1;
641
}
642
643
static unsigned int
644
get_bits(struct link_packet *packet, int offset, int width)
645
{
646
uint32_t *data = (uint32_t *) packet;
647
uint32_t index, shift, mask;
648
649
index = offset / 32 + 1;
650
shift = 32 - (offset & 31) - width;
651
mask = width == 32 ? ~0 : (1 << width) - 1;
652
653
return (data[index] >> shift) & mask;
654
}
655
656
#if __BYTE_ORDER == __LITTLE_ENDIAN
657
#define byte_index(i) ((i) ^ 3)
658
#elif __BYTE_ORDER == __BIG_ENDIAN
659
#define byte_index(i) (i)
660
#else
661
#error unsupported byte order.
662
#endif
663
664
static void
665
dump_data(unsigned char *data, int length)
666
{
667
int i, print_length;
668
669
if (length > 128)
670
print_length = 128;
671
else
672
print_length = length;
673
674
for (i = 0; i < print_length; i++)
675
printf("%s%02hhx",
676
(i % 4 == 0 && i != 0) ? " " : "",
677
data[byte_index(i)]);
678
679
if (print_length < length)
680
printf(" (%d more bytes)", length - print_length);
681
}
682
683
static void
684
decode_link_packet(struct link_packet *packet, size_t length,
685
int include_flags, int exclude_flags)
686
{
687
const struct packet_info *pi;
688
int data_length = 0;
689
int i;
690
691
pi = &packet_info[packet->common.tcode];
692
693
for (i = 0; i < pi->field_count; i++) {
694
const struct packet_field *f = &pi->fields[i];
695
int offset;
696
697
if (f->flags & exclude_flags)
698
continue;
699
if (include_flags && !(f->flags & include_flags))
700
continue;
701
702
if (f->offset < 0)
703
offset = length * 8 + f->offset - 32;
704
else
705
offset = f->offset;
706
707
if (f->value_names != NULL) {
708
uint32_t bits;
709
710
bits = get_bits(packet, offset, f->width);
711
printf("%s", f->value_names[bits]);
712
} else if (f->width == 0) {
713
printf("%s=[", f->name);
714
dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
715
printf("]");
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
} else {
729
bits = get_bits(packet, offset, f->width);
730
}
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
743
static void
744
print_packet(uint32_t *data, size_t length)
745
{
746
int i;
747
748
printf("%6u ", 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%08x", i == 0 ? "[" : " ", data[i]);
756
printf("]");
757
758
} else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
759
struct phy_packet *pp = (struct phy_packet *) data;
760
761
/* phy packet are 3 quadlets: the 1 quadlet payload,
762
* the bitwise inverse of the payload and the snoop
763
* mode ack */
764
765
switch (pp->common.identifier) {
766
case PHY_PACKET_CONFIGURATION:
767
if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
768
printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
769
} else {
770
printf("phy config:");
771
if (pp->phy_config.set_root)
772
printf(" set_root_id=%02x", pp->phy_config.root_id);
773
if (pp->phy_config.set_gap_count)
774
printf(" set_gap_count=%u", pp->phy_config.gap_count);
775
}
776
break;
777
778
case PHY_PACKET_LINK_ON:
779
printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
780
break;
781
782
case PHY_PACKET_SELF_ID:
783
if (pp->self_id.extended) {
784
printf("extended self id: phy_id=%02x, seq=%u",
785
pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
786
} else {
787
static const char * const speed_names[] = {
788
"S100", "S200", "S400", "BETA"
789
};
790
printf("self id: phy_id=%02x, link %s, gap_count=%u speed=%s%s%s",
791
pp->self_id.phy_id,
792
(pp->self_id.link_active ? "active" : "not active"),
793
pp->self_id.gap_count,
794
speed_names[pp->self_id.phy_speed],
795
(pp->self_id.contender ? ", irm contender" : ""),
796
(pp->self_id.initiated_reset ? ", initiator" : ""));
797
}
798
break;
799
default:
800
printf("unknown phy packet: ");
801
for (i = 1; i < length / 4; i++)
802
printf("%s%08x", i == 0 ? "[" : " ", data[i]);
803
printf("]");
804
break;
805
}
806
} else {
807
struct link_packet *packet = (struct link_packet *) data;
808
809
decode_link_packet(packet, length, 0,
810
option_verbose ? 0 : PACKET_FIELD_DETAIL);
811
}
812
813
if (option_hex) {
814
printf(" [");
815
dump_data((unsigned char *) data + 4, length - 4);
816
printf("]");
817
}
818
819
printf("\r\n");
820
}
821
822
#define HIDE_CURSOR "\033[?25l"
823
#define SHOW_CURSOR "\033[?25h"
824
#define CLEAR "\033[H\033[2J"
825
826
static void
827
print_stats(uint32_t *data, size_t length)
828
{
829
static int bus_reset_count, short_packet_count, phy_packet_count;
830
static int tcode_count[16];
831
static struct timeval last_update;
832
struct timeval now;
833
int i;
834
835
if (length == 0)
836
bus_reset_count++;
837
else if (length < sizeof(struct phy_packet))
838
short_packet_count++;
839
else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
840
phy_packet_count++;
841
else {
842
struct link_packet *packet = (struct link_packet *) data;
843
tcode_count[packet->common.tcode]++;
844
}
845
846
gettimeofday(&now, NULL);
847
if (now.tv_sec <= last_update.tv_sec &&
848
now.tv_usec < last_update.tv_usec + 500000)
849
return;
850
851
last_update = now;
852
printf(CLEAR HIDE_CURSOR
853
" bus resets : %8d\n"
854
" short packets : %8d\n"
855
" phy packets : %8d\n",
856
bus_reset_count, short_packet_count, phy_packet_count);
857
858
for (i = 0; i < array_length(packet_info); i++)
859
if (packet_info[i].type != PACKET_RESERVED)
860
printf(" %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
861
printf(SHOW_CURSOR "\n");
862
}
863
864
static struct termios saved_attributes;
865
866
static void
867
reset_input_mode(void)
868
{
869
tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
870
}
871
872
static void
873
set_input_mode(void)
874
{
875
struct termios tattr;
876
877
/* Make sure stdin is a terminal. */
878
if (!isatty(STDIN_FILENO)) {
879
fprintf(stderr, "Not a terminal.\n");
880
exit(EXIT_FAILURE);
881
}
882
883
/* Save the terminal attributes so we can restore them later. */
884
tcgetattr(STDIN_FILENO, &saved_attributes);
885
atexit(reset_input_mode);
886
887
/* Set the funny terminal modes. */
888
tcgetattr(STDIN_FILENO, &tattr);
889
tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
890
tattr.c_cc[VMIN] = 1;
891
tattr.c_cc[VTIME] = 0;
892
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
893
}
894
895
int main(int argc, const char *argv[])
896
{
897
uint32_t buf[128 * 1024];
898
uint32_t filter;
899
int length, retval, view;
900
int fd = -1;
901
FILE *output = NULL, *input = NULL;
902
poptContext con;
903
char c;
904
struct pollfd pollfds[2];
905
906
sys_sigint_handler = signal(SIGINT, sigint_handler);
907
908
con = poptGetContext(NULL, argc, argv, options, 0);
909
retval = poptGetNextOpt(con);
910
if (retval < -1) {
911
poptPrintUsage(con, stdout, 0);
912
return -1;
913
}
914
915
if (option_version) {
916
printf("dump tool for nosy sniffer, version %s\n", VERSION);
917
return 0;
918
}
919
920
if (__BYTE_ORDER != __LITTLE_ENDIAN)
921
fprintf(stderr, "warning: nosy has only been tested on little "
922
"endian machines\n");
923
924
if (option_input != NULL) {
925
input = fopen(option_input, "r");
926
if (input == NULL) {
927
fprintf(stderr, "Could not open %s, %m\n", option_input);
928
return -1;
929
}
930
} else {
931
fd = open(option_nosy_device, O_RDWR);
932
if (fd < 0) {
933
fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
934
return -1;
935
}
936
set_input_mode();
937
}
938
939
if (strcmp(option_view, "transaction") == 0)
940
view = VIEW_TRANSACTION;
941
else if (strcmp(option_view, "stats") == 0)
942
view = VIEW_STATS;
943
else
944
view = VIEW_PACKET;
945
946
if (option_output) {
947
output = fopen(option_output, "w");
948
if (output == NULL) {
949
fprintf(stderr, "Could not open %s, %m\n", option_output);
950
return -1;
951
}
952
}
953
954
setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
955
956
filter = ~0;
957
if (!option_iso)
958
filter &= ~(1 << TCODE_STREAM_DATA);
959
if (!option_cycle_start)
960
filter &= ~(1 << TCODE_CYCLE_START);
961
if (view == VIEW_STATS)
962
filter = ~(1 << TCODE_CYCLE_START);
963
964
ioctl(fd, NOSY_IOC_FILTER, filter);
965
966
ioctl(fd, NOSY_IOC_START);
967
968
pollfds[0].fd = fd;
969
pollfds[0].events = POLLIN;
970
pollfds[1].fd = STDIN_FILENO;
971
pollfds[1].events = POLLIN;
972
973
while (run) {
974
if (input != NULL) {
975
if (fread(&length, sizeof length, 1, input) != 1)
976
return 0;
977
fread(buf, 1, length, input);
978
} else {
979
poll(pollfds, 2, -1);
980
if (pollfds[1].revents) {
981
read(STDIN_FILENO, &c, sizeof c);
982
switch (c) {
983
case 'q':
984
if (output != NULL)
985
fclose(output);
986
return 0;
987
}
988
}
989
990
if (pollfds[0].revents)
991
length = read(fd, buf, sizeof buf);
992
else
993
continue;
994
}
995
996
if (output != NULL) {
997
fwrite(&length, sizeof length, 1, output);
998
fwrite(buf, 1, length, output);
999
}
1000
1001
switch (view) {
1002
case VIEW_TRANSACTION:
1003
handle_packet(buf, length);
1004
break;
1005
case VIEW_PACKET:
1006
print_packet(buf, length);
1007
break;
1008
case VIEW_STATS:
1009
print_stats(buf, length);
1010
break;
1011
}
1012
}
1013
1014
if (output != NULL)
1015
fclose(output);
1016
1017
close(fd);
1018
1019
poptFreeContext(con);
1020
1021
return 0;
1022
}
1023
1024