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