nosy-dump.c (25065B)
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 26enum { 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 33static void print_packet(uint32_t *data, size_t length); 34static void decode_link_packet(struct link_packet *packet, size_t length, 35 int include_flags, int exclude_flags); 36static int run = 1; 37sig_t sys_sigint_handler; 38 39static char *option_nosy_device = "/dev/nosy"; 40static char *option_view = "packet"; 41static char *option_output; 42static char *option_input; 43static int option_hex; 44static int option_iso; 45static int option_cycle_start; 46static int option_version; 47static int option_verbose; 48 49enum { 50 VIEW_TRANSACTION, 51 VIEW_PACKET, 52 VIEW_STATS, 53}; 54 55static 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. */ 124static void 125sigint_handler(int signal_num) 126{ 127 if (run == 1) { 128 run = 0; 129 signal(SIGINT, SIG_DFL); 130 } 131} 132 133static struct subaction * 134subaction_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 149static void 150subaction_destroy(struct subaction *sa) 151{ 152 free(sa); 153} 154 155static struct list pending_transaction_list = { 156 &pending_transaction_list, &pending_transaction_list 157}; 158 159static struct link_transaction * 160link_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 185static void 186link_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 203struct protocol_decoder { 204 const char *name; 205 int (*decode)(struct link_transaction *t); 206}; 207 208static const struct protocol_decoder protocol_decoders[] = { 209 { "FCP", decode_fcp } 210}; 211 212static void 213handle_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 249static void 250clear_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 263static 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 272static 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 283static 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 290static const char * const retry_names[] = { 291 [0x0] = "retry_1", 292 [0x1] = "retry_x", 293 [0x2] = "retry_a", 294 [0x3] = "retry_b", 295}; 296 297enum { 298 PACKET_RESERVED, 299 PACKET_REQUEST, 300 PACKET_RESPONSE, 301 PACKET_OTHER, 302}; 303 304struct 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 312struct 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 339static 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 345static 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 352static 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 360static 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 370static 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 376static 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 386static 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 392static 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 404static 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 481static int 482handle_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 546static int 547handle_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 618static int 619handle_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 643static unsigned int 644get_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 664static void 665dump_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 683static void 684decode_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 743static void 744print_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=%d", 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=%d", 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=%d, 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 826static void 827print_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 864static struct termios saved_attributes; 865 866static void 867reset_input_mode(void) 868{ 869 tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes); 870} 871 872static void 873set_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 895int 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}