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