1 /* -*- mode: c; c-basic-offset: 2 -*- */
4 * nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
5 * Copyright (C) 2002-2006 Kristian Høgsberg
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.
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.
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.
27 #include <sys/ioctl.h>
38 #include "nosy-user.h"
39 #include "nosy-dump.h"
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
49 print_packet(uint32_t *data, size_t length);
51 decode_link_packet(struct link_packet *packet, size_t length,
52 int include_flags, int exclude_flags);
55 sig_t sys_sigint_handler;
57 static char *option_nosy_device = "/dev/nosy";
58 static char *option_view = "packet";
59 static char *option_output = NULL;
60 static char *option_input = NULL;
61 static int option_hex;
62 static int option_iso;
63 static int option_cycle_start;
64 static int option_version;
65 static int option_verbose;
73 static const struct poptOption options[] = {
77 argInfo: POPT_ARG_STRING,
78 arg: &option_nosy_device,
79 descrip: "Path to nosy device.",
84 argInfo: POPT_ARG_STRING,
86 descrip: "Specify view of bus traffic: packet, transaction or stats.",
92 argInfo: POPT_ARG_NONE,
94 descrip: "Print each packet in hex.",
98 argInfo: POPT_ARG_NONE,
100 descrip: "Print iso packets.",
103 longName: "cycle-start",
104 argInfo: POPT_ARG_NONE,
105 arg: &option_cycle_start,
106 descrip: "Print cycle start packets.",
111 argInfo: POPT_ARG_NONE,
112 arg: &option_verbose,
113 descrip: "Verbose packet view.",
118 argInfo: POPT_ARG_STRING,
120 descrip: "Log to output file.",
121 argDescrip: "FILENAME"
126 argInfo: POPT_ARG_STRING,
128 descrip: "Decode log from file.",
129 argDescrip: "FILENAME"
133 argInfo: POPT_ARG_NONE,
134 arg: &option_version,
135 descrip: "Specify print version info.",
142 sigint_handler(int signal_num)
146 /* Allow all Ctrl-C's except the first to interrupt the program in
149 signal(SIGINT, SIG_DFL);
154 subaction_create(uint32_t *data, size_t length)
156 struct subaction *sa;
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];
162 memcpy (&sa->packet, data, length);
168 subaction_destroy(struct subaction *sa)
173 struct list pending_transaction_list =
174 { &pending_transaction_list, &pending_transaction_list };
176 struct link_transaction *
177 link_transaction_lookup(int request_node, int response_node, int tlabel)
179 struct link_transaction *t;
181 list_for_each_entry(t, &pending_transaction_list, link) {
182 if (t->request_node == request_node &&
183 t->response_node == response_node &&
188 t = malloc(sizeof *t);
189 t->request_node = request_node;
190 t->response_node = response_node;
192 list_init(&t->request_list);
193 list_init(&t->response_list);
195 list_append(&pending_transaction_list, &t->link);
201 link_transaction_destroy(struct link_transaction *t)
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);
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);
218 struct protocol_decoder {
220 int (*decode)(struct link_transaction *t);
223 static struct protocol_decoder protocol_decoders[] = {
224 { "FCP", decode_fcp }
228 handle_transaction(struct link_transaction *t)
230 struct subaction *sa;
234 printf("BUG in handle_transaction\n");
238 for (i = 0; i < array_length(protocol_decoders); i++)
239 if (protocol_decoders[i].decode(t))
242 /* HACK: decode only fcp right now. */
245 decode_link_packet(&t->request->packet, t->request->length,
246 PACKET_FIELD_TRANSACTION, 0);
248 decode_link_packet(&t->response->packet, t->request->length,
249 PACKET_FIELD_TRANSACTION, 0);
251 printf("[no response]");
253 if (option_verbose) {
254 list_for_each_entry(sa, &t->request_list, link)
255 print_packet((uint32_t *) &sa->packet, sa->length);
256 list_for_each_entry(sa, &t->response_list, link)
257 print_packet((uint32_t *) &sa->packet, sa->length);
261 link_transaction_destroy(t);
265 clear_pending_transaction_list(void)
267 struct link_transaction *t;
269 while (!list_empty(&pending_transaction_list)) {
270 t = list_head(&pending_transaction_list, struct link_transaction, link);
271 list_remove(&t->link);
272 link_transaction_destroy(t);
273 /* print unfinished transactions */
277 static const char * const tcode_names[] = {
278 "write_quadlet_request",
279 "write_block_request",
282 "read_quadlet_request",
283 "read_block_request",
284 "read_quadlet_response",
285 "read_block_response",
292 static const char * const ack_names[] = {
311 static const char * const rcode_names[] = {
322 static const char * const retry_names[] = {
340 struct packet_field *fields;
344 struct packet_field {
345 const char *name; /* Short name for field. */
346 int offset; /* Location of field, specified in bits.
347 * Negative means from end of packet */
348 int width; /* Width of field, 0 means use data_length. */
349 int flags; /* Show options. */
350 const char * const *value_names;
353 #define COMMON_REQUEST_FIELDS \
354 { "dest", 0, 16, PACKET_FIELD_TRANSACTION }, \
356 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
357 { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names }, \
358 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
359 { "src", 32, 16, PACKET_FIELD_TRANSACTION }, \
360 { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
362 #define COMMON_RESPONSE_FIELDS \
365 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
366 { "tcode", 24, 4, 0, tcode_names }, \
367 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
369 { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
371 struct packet_field read_quadlet_request_fields[] = {
372 COMMON_REQUEST_FIELDS,
373 { "crc", 96, 32, PACKET_FIELD_DETAIL },
374 { "ack", 156, 4, 0, ack_names }
377 struct packet_field read_quadlet_response_fields[] = {
378 COMMON_RESPONSE_FIELDS,
379 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
380 { "crc", 128, 32, PACKET_FIELD_DETAIL },
381 { "ack", 188, 4, 0, ack_names }
384 struct packet_field read_block_request_fields[] = {
385 COMMON_REQUEST_FIELDS,
386 { "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
387 { "extended_tcode", 112, 16 },
388 { "crc", 128, 32, PACKET_FIELD_DETAIL },
389 { "ack", 188, 4, 0, ack_names },
392 struct packet_field block_response_fields[] = {
393 COMMON_RESPONSE_FIELDS,
394 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
395 { "extended_tcode", 112, 16 },
396 { "crc", 128, 32, PACKET_FIELD_DETAIL },
397 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
398 { "crc", -64, 32, PACKET_FIELD_DETAIL },
399 { "ack", -4, 4, 0, ack_names }
402 struct packet_field write_quadlet_request_fields[] = {
403 COMMON_REQUEST_FIELDS,
404 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
405 { "ack", -4, 4, 0, ack_names }
408 struct packet_field block_request_fields[] = {
409 COMMON_REQUEST_FIELDS,
410 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
411 { "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
412 { "crc", 128, 32, PACKET_FIELD_DETAIL },
413 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
414 { "crc", -64, 32, PACKET_FIELD_DETAIL },
415 { "ack", -4, 4, 0, ack_names }
418 struct packet_field write_response_fields[] = {
419 COMMON_RESPONSE_FIELDS,
420 { "reserved", 64, 32, PACKET_FIELD_DETAIL },
421 { "ack", -4, 4, 0, ack_names }
424 struct packet_field iso_data_fields[] = {
425 { "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
427 { "channel", 18, 6 },
428 { "tcode", 24, 4, 0, tcode_names },
430 { "crc", 32, 32, PACKET_FIELD_DETAIL },
432 { "crc", -64, 32, PACKET_FIELD_DETAIL },
433 { "ack", -4, 4, 0, ack_names }
436 static struct packet_info packet_info[] = {
438 .name = "write_quadlet_request",
439 .type = PACKET_REQUEST,
440 .response_tcode = TCODE_WRITE_RESPONSE,
441 .fields = write_quadlet_request_fields,
442 .field_count = array_length(write_quadlet_request_fields)
445 .name = "write_block_request",
446 .type = PACKET_REQUEST,
447 .response_tcode = TCODE_WRITE_RESPONSE,
448 .fields = block_request_fields,
449 .field_count = array_length(block_request_fields)
452 .name = "write_response",
453 .type = PACKET_RESPONSE,
454 .fields = write_response_fields,
455 .field_count = array_length(write_response_fields)
459 .type = PACKET_RESERVED,
462 .name = "read_quadlet_request",
463 .type = PACKET_REQUEST,
464 .response_tcode = TCODE_READ_QUADLET_RESPONSE,
465 .fields = read_quadlet_request_fields,
466 .field_count = array_length(read_quadlet_request_fields)
469 .name = "read_block_request",
470 .type = PACKET_REQUEST,
471 .response_tcode = TCODE_READ_BLOCK_RESPONSE,
472 .fields = read_block_request_fields,
473 .field_count = array_length(read_block_request_fields)
476 .name = "read_quadlet_response",
477 .type = PACKET_RESPONSE,
478 .fields = read_quadlet_response_fields,
479 .field_count = array_length(read_quadlet_response_fields)
482 .name = "read_block_response",
483 .type = PACKET_RESPONSE,
484 .fields = block_response_fields,
485 .field_count = array_length(block_response_fields)
488 .name = "cycle_start",
489 .type = PACKET_OTHER,
490 .fields = write_quadlet_request_fields,
491 .field_count = array_length(write_quadlet_request_fields)
494 .name = "lock_request",
495 .type = PACKET_REQUEST,
496 .fields = block_request_fields,
497 .field_count = array_length(block_request_fields)
501 .type = PACKET_OTHER,
502 .fields = iso_data_fields,
503 .field_count = array_length(iso_data_fields)
506 .name = "lock_response",
507 .type = PACKET_RESPONSE,
508 .fields = block_response_fields,
509 .field_count = array_length(block_response_fields)
514 handle_packet(uint32_t *data, size_t length)
517 printf("bus reset\r\n");
518 clear_pending_transaction_list();
520 else if (length > sizeof(struct phy_packet)) {
521 struct link_packet *p = (struct link_packet *) data;
522 struct subaction *sa, *prev;
523 struct link_transaction *t;
525 switch (packet_info[p->common.tcode].type) {
527 t = link_transaction_lookup(p->common.source, p->common.destination,
529 sa = subaction_create(data, length);
532 if (!list_empty(&t->request_list)) {
533 prev = list_tail(&t->request_list, struct subaction, link);
535 if (!ACK_BUSY(prev->ack)) {
536 /* error, we should only see ack_busy_* before the
537 * ack_pending/ack_complete -- this is an ack_pending
538 * instead (ack_complete would have finished the
542 if (prev->packet.common.tcode != sa->packet.common.tcode ||
543 prev->packet.common.tlabel != sa->packet.common.tlabel)
545 /* error, these should match for retries. */;
548 list_append(&t->request_list, &sa->link);
552 if (p->common.tcode != TCODE_WRITE_QUADLET &&
553 p->common.tcode != TCODE_WRITE_BLOCK)
554 /* error, unified transactions only allowed for write */;
555 list_remove(&t->link);
556 handle_transaction(t);
562 list_remove(&t->link);
563 handle_transaction(t);
567 /* request subaction phase over, wait for response. */
573 /* ok, wait for retry. */
574 /* check that retry protocol is respected. */
579 case PACKET_RESPONSE:
580 t = link_transaction_lookup(p->common.destination, p->common.source,
582 if (list_empty(&t->request_list)) {
583 /* unsolicited response */
586 sa = subaction_create(data, length);
589 if (!list_empty(&t->response_list)) {
590 prev = list_tail(&t->response_list, struct subaction, link);
592 if (!ACK_BUSY(prev->ack))
593 /* error, we should only see ack_busy_* before the
594 * ack_pending/ack_complete */;
596 if (prev->packet.common.tcode != sa->packet.common.tcode ||
597 prev->packet.common.tlabel != sa->packet.common.tlabel)
598 /* use memcmp() instead? */
599 /* error, these should match for retries. */;
602 prev = list_tail(&t->request_list, struct subaction, link);
603 if (prev->ack != ACK_PENDING) {
604 /* error, should not get response unless last request got
608 if (packet_info[prev->packet.common.tcode].response_tcode !=
609 sa->packet.common.tcode) {
610 /* error, tcode mismatch */
614 list_append(&t->response_list, &sa->link);
621 list_remove(&t->link);
622 handle_transaction(t);
623 /* transaction complete, remove t from pending list. */
627 /* error for responses. */
633 /* no problem, wait for next retry */
640 case PACKET_RESERVED:
648 unsigned int get_bits(struct link_packet *packet, int offset, int width)
650 uint32_t *data = (uint32_t *) packet;
651 uint32_t index, shift, mask;
653 index = offset / 32 + 1;
654 shift = 32 - (offset & 31) - width;
655 mask = width == 32 ? ~0 : (1 << width) - 1;
657 return (data[index] >> shift) & mask;
660 #if __BYTE_ORDER == __LITTLE_ENDIAN
661 #define byte_index(i) ((i) ^ 3)
662 #elif __BYTE_ORDER == __BIG_ENDIAN
663 #define byte_index(i) (i)
665 #error unsupported byte order.
668 void dump_data(unsigned char *data, int length)
675 print_length = length;
677 for (i = 0; i < print_length; i++)
679 (i % 4 == 0 && i != 0) ? " " : "",
680 data[byte_index(i)]);
682 if (print_length < length)
683 printf(" (%d more bytes)", length - print_length);
687 decode_link_packet(struct link_packet *packet, size_t length,
688 int include_flags, int exclude_flags)
690 struct packet_info *pi;
694 pi = &packet_info[packet->common.tcode];
696 for (i = 0; i < pi->field_count; i++) {
697 struct packet_field *f = &pi->fields[i];
700 if (f->flags & exclude_flags)
702 if (include_flags && !(f->flags & include_flags))
706 offset = length * 8 + f->offset - 32;
710 if (f->value_names != NULL) {
713 bits = get_bits(packet, offset, f->width);
714 printf("%s", f->value_names[bits]);
716 else if (f->width == 0) {
717 printf("%s=[", f->name);
718 dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
722 unsigned long long bits;
723 int high_width, low_width;
725 if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
726 /* Bit field spans quadlet boundary. */
727 high_width = ((offset + 31) & ~31) - offset;
728 low_width = f->width - high_width;
730 bits = get_bits(packet, offset, high_width);
731 bits = (bits << low_width) |
732 get_bits(packet, offset + high_width, low_width);
735 bits = get_bits(packet, offset, f->width);
737 printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
739 if (f->flags & PACKET_FIELD_DATA_LENGTH)
743 if (i < pi->field_count - 1)
749 print_packet(uint32_t *data, size_t length)
753 printf("%6u ", data[0]);
757 else if (length < sizeof(struct phy_packet)) {
758 printf("short packet: ");
759 for (i = 1; i < length / 4; i++)
760 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
764 else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
765 struct phy_packet *pp = (struct phy_packet *) data;
767 /* phy packet are 3 quadlets: the 1 quadlet payload,
768 * the bitwise inverse of the payload and the snoop
771 switch (pp->common.identifier) {
772 case PHY_PACKET_CONFIGURATION:
773 if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
774 printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
777 printf("phy config:");
778 if (pp->phy_config.set_root)
779 printf(" set_root_id=%02x", pp->phy_config.root_id);
780 if (pp->phy_config.set_gap_count)
781 printf(" set_gap_count=%d", pp->phy_config.gap_count);
785 case PHY_PACKET_LINK_ON:
786 printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
789 case PHY_PACKET_SELF_ID:
790 if (pp->self_id.extended) {
791 printf("extended self id: phy_id=%02x, seq=%d",
792 pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
795 static const char * const speed_names[] = {
796 "S100", "S200", "S400", "BETA"
798 printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
800 (pp->self_id.link_active ? "active" : "not active"),
801 pp->self_id.gap_count,
802 speed_names[pp->self_id.phy_speed],
803 (pp->self_id.contender ? ", irm contender" : ""),
804 (pp->self_id.initiated_reset ? ", initiator" : ""));
809 printf("unknown phy packet: ");
810 for (i = 1; i < length / 4; i++)
811 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
817 struct link_packet *packet = (struct link_packet *) data;
819 decode_link_packet(packet, length, 0,
820 option_verbose ? 0 : PACKET_FIELD_DETAIL);
825 dump_data((unsigned char *) data + 4, length - 4);
832 #define HIDE_CURSOR "\033[?25l"
833 #define SHOW_CURSOR "\033[?25h"
834 #define CLEAR "\033[H\033[2J"
837 print_stats(uint32_t *data, size_t length)
839 static int bus_reset_count, short_packet_count, phy_packet_count;
840 static int tcode_count[16];
841 static struct timeval last_update;
847 else if (length < sizeof(struct phy_packet))
848 short_packet_count++;
849 else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
852 struct link_packet *packet = (struct link_packet *) data;
853 tcode_count[packet->common.tcode]++;
856 gettimeofday(&now, NULL);
857 if (now.tv_sec <= last_update.tv_sec &&
858 now.tv_usec < last_update.tv_usec + 500000)
862 printf(CLEAR HIDE_CURSOR
863 " bus resets : %8d\n"
864 " short packets : %8d\n"
865 " phy packets : %8d\n",
866 bus_reset_count, short_packet_count, phy_packet_count);
868 for (i = 0; i < array_length(packet_info); i++)
869 if (packet_info[i].type != PACKET_RESERVED)
870 printf(" %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
871 printf(SHOW_CURSOR "\n");
874 struct termios saved_attributes;
877 reset_input_mode (void)
879 tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
883 set_input_mode (void)
885 struct termios tattr;
887 /* Make sure stdin is a terminal. */
888 if (!isatty(STDIN_FILENO)) {
889 fprintf(stderr, "Not a terminal.\n");
893 /* Save the terminal attributes so we can restore them later. */
894 tcgetattr(STDIN_FILENO, &saved_attributes);
895 atexit(reset_input_mode);
897 /* Set the funny terminal modes. */
898 tcgetattr(STDIN_FILENO, &tattr);
899 tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
900 tattr.c_cc[VMIN] = 1;
901 tattr.c_cc[VTIME] = 0;
902 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
905 int main(int argc, const char *argv[])
908 FILE *output = NULL, *input = NULL;
913 struct pollfd pollfds[2];
915 sys_sigint_handler = signal(SIGINT, sigint_handler);
917 con = poptGetContext(NULL, argc, argv, options, 0);
918 retval = poptGetNextOpt(con);
920 poptPrintUsage(con, stdout, 0);
924 if (option_version) {
925 printf("dump tool for nosy sniffer, version %s\n", VERSION);
929 if (__BYTE_ORDER != __LITTLE_ENDIAN)
930 fprintf(stderr, "warning: nosy has only been tested on little "
931 "endian machines\n");
933 if (option_input != NULL) {
934 input = fopen(option_input, "r");
936 fprintf(stderr, "Could not open %s, %m\n", option_input);
941 fd = open(option_nosy_device, O_RDWR);
943 fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
949 if (strcmp(option_view, "transaction") == 0)
950 view = VIEW_TRANSACTION;
951 else if (strcmp(option_view, "stats") == 0)
957 output = fopen(option_output, "w");
958 if (output == NULL) {
959 fprintf(stderr, "Could not open %s, %m\n", option_output);
964 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
967 uint32_t buf[128 * 1024];
973 filter &= ~(1 <<TCODE_ISO_DATA);
974 if (!option_cycle_start)
975 filter &= ~(1 << TCODE_CYCLE_START);
976 if (view == VIEW_STATS)
977 filter = ~(1 << TCODE_CYCLE_START);
979 ioctl(fd, NOSY_IOC_FILTER, filter);
981 ioctl(fd, NOSY_IOC_START);
984 pollfds[0].events = POLLIN;
985 pollfds[1].fd = STDIN_FILENO;
986 pollfds[1].events = POLLIN;
990 if (fread(&length, sizeof length, 1, input) != 1)
992 fread(buf, 1, length, input);
995 poll(pollfds, 2, -1);
996 if (pollfds[1].revents) {
997 read(STDIN_FILENO, &c, sizeof c);
1006 if (pollfds[0].revents)
1007 length = read(fd, buf, sizeof buf);
1012 if (output != NULL) {
1013 fwrite(&length, sizeof length, 1, output);
1014 fwrite(buf, 1, length, output);
1018 case VIEW_TRANSACTION:
1019 handle_packet(buf, length);
1022 print_packet(buf, length);
1025 print_stats(buf, length);
1031 poptPrintUsage(con, stdout, 0);
1038 poptFreeContext(con);