0001
0002
0003
0004
0005
0006
0007 #include <byteswap.h>
0008 #include <endian.h>
0009 #include <fcntl.h>
0010 #include <linux/firewire-constants.h>
0011 #include <poll.h>
0012 #include <popt.h>
0013 #include <signal.h>
0014 #include <stdio.h>
0015 #include <stdlib.h>
0016 #include <string.h>
0017 #include <sys/ioctl.h>
0018 #include <sys/time.h>
0019 #include <termios.h>
0020 #include <unistd.h>
0021
0022 #include "list.h"
0023 #include "nosy-dump.h"
0024 #include "nosy-user.h"
0025
0026 enum {
0027 PACKET_FIELD_DETAIL = 0x01,
0028 PACKET_FIELD_DATA_LENGTH = 0x02,
0029
0030 PACKET_FIELD_TRANSACTION = 0x04,
0031 };
0032
0033 static void print_packet(uint32_t *data, size_t length);
0034 static void decode_link_packet(struct link_packet *packet, size_t length,
0035 int include_flags, int exclude_flags);
0036 static int run = 1;
0037 sig_t sys_sigint_handler;
0038
0039 static char *option_nosy_device = "/dev/nosy";
0040 static char *option_view = "packet";
0041 static char *option_output;
0042 static char *option_input;
0043 static int option_hex;
0044 static int option_iso;
0045 static int option_cycle_start;
0046 static int option_version;
0047 static int option_verbose;
0048
0049 enum {
0050 VIEW_TRANSACTION,
0051 VIEW_PACKET,
0052 VIEW_STATS,
0053 };
0054
0055 static const struct poptOption options[] = {
0056 {
0057 .longName = "device",
0058 .shortName = 'd',
0059 .argInfo = POPT_ARG_STRING,
0060 .arg = &option_nosy_device,
0061 .descrip = "Path to nosy device.",
0062 .argDescrip = "DEVICE"
0063 },
0064 {
0065 .longName = "view",
0066 .argInfo = POPT_ARG_STRING,
0067 .arg = &option_view,
0068 .descrip = "Specify view of bus traffic: packet, transaction or stats.",
0069 .argDescrip = "VIEW"
0070 },
0071 {
0072 .longName = "hex",
0073 .shortName = 'x',
0074 .argInfo = POPT_ARG_NONE,
0075 .arg = &option_hex,
0076 .descrip = "Print each packet in hex.",
0077 },
0078 {
0079 .longName = "iso",
0080 .argInfo = POPT_ARG_NONE,
0081 .arg = &option_iso,
0082 .descrip = "Print iso packets.",
0083 },
0084 {
0085 .longName = "cycle-start",
0086 .argInfo = POPT_ARG_NONE,
0087 .arg = &option_cycle_start,
0088 .descrip = "Print cycle start packets.",
0089 },
0090 {
0091 .longName = "verbose",
0092 .shortName = 'v',
0093 .argInfo = POPT_ARG_NONE,
0094 .arg = &option_verbose,
0095 .descrip = "Verbose packet view.",
0096 },
0097 {
0098 .longName = "output",
0099 .shortName = 'o',
0100 .argInfo = POPT_ARG_STRING,
0101 .arg = &option_output,
0102 .descrip = "Log to output file.",
0103 .argDescrip = "FILENAME"
0104 },
0105 {
0106 .longName = "input",
0107 .shortName = 'i',
0108 .argInfo = POPT_ARG_STRING,
0109 .arg = &option_input,
0110 .descrip = "Decode log from file.",
0111 .argDescrip = "FILENAME"
0112 },
0113 {
0114 .longName = "version",
0115 .argInfo = POPT_ARG_NONE,
0116 .arg = &option_version,
0117 .descrip = "Specify print version info.",
0118 },
0119 POPT_AUTOHELP
0120 POPT_TABLEEND
0121 };
0122
0123
0124 static void
0125 sigint_handler(int signal_num)
0126 {
0127 if (run == 1) {
0128 run = 0;
0129 signal(SIGINT, SIG_DFL);
0130 }
0131 }
0132
0133 static struct subaction *
0134 subaction_create(uint32_t *data, size_t length)
0135 {
0136 struct subaction *sa;
0137
0138
0139 sa = malloc(sizeof *sa - sizeof sa->packet + length);
0140 if (!sa)
0141 exit(EXIT_FAILURE);
0142 sa->ack = data[length / 4 - 1];
0143 sa->length = length;
0144 memcpy(&sa->packet, data, length);
0145
0146 return sa;
0147 }
0148
0149 static void
0150 subaction_destroy(struct subaction *sa)
0151 {
0152 free(sa);
0153 }
0154
0155 static struct list pending_transaction_list = {
0156 &pending_transaction_list, &pending_transaction_list
0157 };
0158
0159 static struct link_transaction *
0160 link_transaction_lookup(int request_node, int response_node, int tlabel)
0161 {
0162 struct link_transaction *t;
0163
0164 list_for_each_entry(t, &pending_transaction_list, link) {
0165 if (t->request_node == request_node &&
0166 t->response_node == response_node &&
0167 t->tlabel == tlabel)
0168 return t;
0169 }
0170
0171 t = malloc(sizeof *t);
0172 if (!t)
0173 exit(EXIT_FAILURE);
0174 t->request_node = request_node;
0175 t->response_node = response_node;
0176 t->tlabel = tlabel;
0177 list_init(&t->request_list);
0178 list_init(&t->response_list);
0179
0180 list_append(&pending_transaction_list, &t->link);
0181
0182 return t;
0183 }
0184
0185 static void
0186 link_transaction_destroy(struct link_transaction *t)
0187 {
0188 struct subaction *sa;
0189
0190 while (!list_empty(&t->request_list)) {
0191 sa = list_head(&t->request_list, struct subaction, link);
0192 list_remove(&sa->link);
0193 subaction_destroy(sa);
0194 }
0195 while (!list_empty(&t->response_list)) {
0196 sa = list_head(&t->response_list, struct subaction, link);
0197 list_remove(&sa->link);
0198 subaction_destroy(sa);
0199 }
0200 free(t);
0201 }
0202
0203 struct protocol_decoder {
0204 const char *name;
0205 int (*decode)(struct link_transaction *t);
0206 };
0207
0208 static const struct protocol_decoder protocol_decoders[] = {
0209 { "FCP", decode_fcp }
0210 };
0211
0212 static void
0213 handle_transaction(struct link_transaction *t)
0214 {
0215 struct subaction *sa;
0216 int i;
0217
0218 if (!t->request) {
0219 printf("BUG in handle_transaction\n");
0220 return;
0221 }
0222
0223 for (i = 0; i < array_length(protocol_decoders); i++)
0224 if (protocol_decoders[i].decode(t))
0225 break;
0226
0227
0228 return;
0229
0230 decode_link_packet(&t->request->packet, t->request->length,
0231 PACKET_FIELD_TRANSACTION, 0);
0232 if (t->response)
0233 decode_link_packet(&t->response->packet, t->request->length,
0234 PACKET_FIELD_TRANSACTION, 0);
0235 else
0236 printf("[no response]");
0237
0238 if (option_verbose) {
0239 list_for_each_entry(sa, &t->request_list, link)
0240 print_packet((uint32_t *) &sa->packet, sa->length);
0241 list_for_each_entry(sa, &t->response_list, link)
0242 print_packet((uint32_t *) &sa->packet, sa->length);
0243 }
0244 printf("\r\n");
0245
0246 link_transaction_destroy(t);
0247 }
0248
0249 static void
0250 clear_pending_transaction_list(void)
0251 {
0252 struct link_transaction *t;
0253
0254 while (!list_empty(&pending_transaction_list)) {
0255 t = list_head(&pending_transaction_list,
0256 struct link_transaction, link);
0257 list_remove(&t->link);
0258 link_transaction_destroy(t);
0259
0260 }
0261 }
0262
0263 static const char * const tcode_names[] = {
0264 [0x0] = "write_quadlet_request", [0x6] = "read_quadlet_response",
0265 [0x1] = "write_block_request", [0x7] = "read_block_response",
0266 [0x2] = "write_response", [0x8] = "cycle_start",
0267 [0x3] = "reserved", [0x9] = "lock_request",
0268 [0x4] = "read_quadlet_request", [0xa] = "iso_data",
0269 [0x5] = "read_block_request", [0xb] = "lock_response",
0270 };
0271
0272 static const char * const ack_names[] = {
0273 [0x0] = "no ack", [0x8] = "reserved (0x08)",
0274 [0x1] = "ack_complete", [0x9] = "reserved (0x09)",
0275 [0x2] = "ack_pending", [0xa] = "reserved (0x0a)",
0276 [0x3] = "reserved (0x03)", [0xb] = "reserved (0x0b)",
0277 [0x4] = "ack_busy_x", [0xc] = "reserved (0x0c)",
0278 [0x5] = "ack_busy_a", [0xd] = "ack_data_error",
0279 [0x6] = "ack_busy_b", [0xe] = "ack_type_error",
0280 [0x7] = "reserved (0x07)", [0xf] = "reserved (0x0f)",
0281 };
0282
0283 static const char * const rcode_names[] = {
0284 [0x0] = "complete", [0x4] = "conflict_error",
0285 [0x1] = "reserved (0x01)", [0x5] = "data_error",
0286 [0x2] = "reserved (0x02)", [0x6] = "type_error",
0287 [0x3] = "reserved (0x03)", [0x7] = "address_error",
0288 };
0289
0290 static const char * const retry_names[] = {
0291 [0x0] = "retry_1",
0292 [0x1] = "retry_x",
0293 [0x2] = "retry_a",
0294 [0x3] = "retry_b",
0295 };
0296
0297 enum {
0298 PACKET_RESERVED,
0299 PACKET_REQUEST,
0300 PACKET_RESPONSE,
0301 PACKET_OTHER,
0302 };
0303
0304 struct packet_info {
0305 const char *name;
0306 int type;
0307 int response_tcode;
0308 const struct packet_field *fields;
0309 int field_count;
0310 };
0311
0312 struct packet_field {
0313 const char *name;
0314 int offset;
0315
0316 int width;
0317 int flags;
0318 const char * const *value_names;
0319 };
0320
0321 #define COMMON_REQUEST_FIELDS \
0322 { "dest", 0, 16, PACKET_FIELD_TRANSACTION }, \
0323 { "tl", 16, 6 }, \
0324 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
0325 { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names }, \
0326 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
0327 { "src", 32, 16, PACKET_FIELD_TRANSACTION }, \
0328 { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
0329
0330 #define COMMON_RESPONSE_FIELDS \
0331 { "dest", 0, 16 }, \
0332 { "tl", 16, 6 }, \
0333 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
0334 { "tcode", 24, 4, 0, tcode_names }, \
0335 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
0336 { "src", 32, 16 }, \
0337 { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
0338
0339 static const struct packet_field read_quadlet_request_fields[] = {
0340 COMMON_REQUEST_FIELDS,
0341 { "crc", 96, 32, PACKET_FIELD_DETAIL },
0342 { "ack", 156, 4, 0, ack_names },
0343 };
0344
0345 static const struct packet_field read_quadlet_response_fields[] = {
0346 COMMON_RESPONSE_FIELDS,
0347 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
0348 { "crc", 128, 32, PACKET_FIELD_DETAIL },
0349 { "ack", 188, 4, 0, ack_names },
0350 };
0351
0352 static const struct packet_field read_block_request_fields[] = {
0353 COMMON_REQUEST_FIELDS,
0354 { "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
0355 { "extended_tcode", 112, 16 },
0356 { "crc", 128, 32, PACKET_FIELD_DETAIL },
0357 { "ack", 188, 4, 0, ack_names },
0358 };
0359
0360 static const struct packet_field block_response_fields[] = {
0361 COMMON_RESPONSE_FIELDS,
0362 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
0363 { "extended_tcode", 112, 16 },
0364 { "crc", 128, 32, PACKET_FIELD_DETAIL },
0365 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
0366 { "crc", -64, 32, PACKET_FIELD_DETAIL },
0367 { "ack", -4, 4, 0, ack_names },
0368 };
0369
0370 static const struct packet_field write_quadlet_request_fields[] = {
0371 COMMON_REQUEST_FIELDS,
0372 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
0373 { "ack", -4, 4, 0, ack_names },
0374 };
0375
0376 static const struct packet_field block_request_fields[] = {
0377 COMMON_REQUEST_FIELDS,
0378 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
0379 { "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
0380 { "crc", 128, 32, PACKET_FIELD_DETAIL },
0381 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
0382 { "crc", -64, 32, PACKET_FIELD_DETAIL },
0383 { "ack", -4, 4, 0, ack_names },
0384 };
0385
0386 static const struct packet_field write_response_fields[] = {
0387 COMMON_RESPONSE_FIELDS,
0388 { "reserved", 64, 32, PACKET_FIELD_DETAIL },
0389 { "ack", -4, 4, 0, ack_names },
0390 };
0391
0392 static const struct packet_field iso_data_fields[] = {
0393 { "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
0394 { "tag", 16, 2 },
0395 { "channel", 18, 6 },
0396 { "tcode", 24, 4, 0, tcode_names },
0397 { "sy", 28, 4 },
0398 { "crc", 32, 32, PACKET_FIELD_DETAIL },
0399 { "data", 64, 0 },
0400 { "crc", -64, 32, PACKET_FIELD_DETAIL },
0401 { "ack", -4, 4, 0, ack_names },
0402 };
0403
0404 static const struct packet_info packet_info[] = {
0405 {
0406 .name = "write_quadlet_request",
0407 .type = PACKET_REQUEST,
0408 .response_tcode = TCODE_WRITE_RESPONSE,
0409 .fields = write_quadlet_request_fields,
0410 .field_count = array_length(write_quadlet_request_fields)
0411 },
0412 {
0413 .name = "write_block_request",
0414 .type = PACKET_REQUEST,
0415 .response_tcode = TCODE_WRITE_RESPONSE,
0416 .fields = block_request_fields,
0417 .field_count = array_length(block_request_fields)
0418 },
0419 {
0420 .name = "write_response",
0421 .type = PACKET_RESPONSE,
0422 .fields = write_response_fields,
0423 .field_count = array_length(write_response_fields)
0424 },
0425 {
0426 .name = "reserved",
0427 .type = PACKET_RESERVED,
0428 },
0429 {
0430 .name = "read_quadlet_request",
0431 .type = PACKET_REQUEST,
0432 .response_tcode = TCODE_READ_QUADLET_RESPONSE,
0433 .fields = read_quadlet_request_fields,
0434 .field_count = array_length(read_quadlet_request_fields)
0435 },
0436 {
0437 .name = "read_block_request",
0438 .type = PACKET_REQUEST,
0439 .response_tcode = TCODE_READ_BLOCK_RESPONSE,
0440 .fields = read_block_request_fields,
0441 .field_count = array_length(read_block_request_fields)
0442 },
0443 {
0444 .name = "read_quadlet_response",
0445 .type = PACKET_RESPONSE,
0446 .fields = read_quadlet_response_fields,
0447 .field_count = array_length(read_quadlet_response_fields)
0448 },
0449 {
0450 .name = "read_block_response",
0451 .type = PACKET_RESPONSE,
0452 .fields = block_response_fields,
0453 .field_count = array_length(block_response_fields)
0454 },
0455 {
0456 .name = "cycle_start",
0457 .type = PACKET_OTHER,
0458 .fields = write_quadlet_request_fields,
0459 .field_count = array_length(write_quadlet_request_fields)
0460 },
0461 {
0462 .name = "lock_request",
0463 .type = PACKET_REQUEST,
0464 .fields = block_request_fields,
0465 .field_count = array_length(block_request_fields)
0466 },
0467 {
0468 .name = "iso_data",
0469 .type = PACKET_OTHER,
0470 .fields = iso_data_fields,
0471 .field_count = array_length(iso_data_fields)
0472 },
0473 {
0474 .name = "lock_response",
0475 .type = PACKET_RESPONSE,
0476 .fields = block_response_fields,
0477 .field_count = array_length(block_response_fields)
0478 },
0479 };
0480
0481 static int
0482 handle_request_packet(uint32_t *data, size_t length)
0483 {
0484 struct link_packet *p = (struct link_packet *) data;
0485 struct subaction *sa, *prev;
0486 struct link_transaction *t;
0487
0488 t = link_transaction_lookup(p->common.source, p->common.destination,
0489 p->common.tlabel);
0490 sa = subaction_create(data, length);
0491 t->request = sa;
0492
0493 if (!list_empty(&t->request_list)) {
0494 prev = list_tail(&t->request_list,
0495 struct subaction, link);
0496
0497 if (!ACK_BUSY(prev->ack)) {
0498
0499
0500
0501
0502
0503
0504 }
0505
0506 if (prev->packet.common.tcode != sa->packet.common.tcode ||
0507 prev->packet.common.tlabel != sa->packet.common.tlabel) {
0508
0509
0510 }
0511 }
0512
0513 list_append(&t->request_list, &sa->link);
0514
0515 switch (sa->ack) {
0516 case ACK_COMPLETE:
0517 if (p->common.tcode != TCODE_WRITE_QUADLET_REQUEST &&
0518 p->common.tcode != TCODE_WRITE_BLOCK_REQUEST)
0519 ;
0520 list_remove(&t->link);
0521 handle_transaction(t);
0522 break;
0523
0524 case ACK_NO_ACK:
0525 case ACK_DATA_ERROR:
0526 case ACK_TYPE_ERROR:
0527 list_remove(&t->link);
0528 handle_transaction(t);
0529 break;
0530
0531 case ACK_PENDING:
0532
0533 break;
0534
0535 case ACK_BUSY_X:
0536 case ACK_BUSY_A:
0537 case ACK_BUSY_B:
0538
0539
0540 break;
0541 }
0542
0543 return 1;
0544 }
0545
0546 static int
0547 handle_response_packet(uint32_t *data, size_t length)
0548 {
0549 struct link_packet *p = (struct link_packet *) data;
0550 struct subaction *sa, *prev;
0551 struct link_transaction *t;
0552
0553 t = link_transaction_lookup(p->common.destination, p->common.source,
0554 p->common.tlabel);
0555 if (list_empty(&t->request_list)) {
0556
0557 }
0558
0559 sa = subaction_create(data, length);
0560 t->response = sa;
0561
0562 if (!list_empty(&t->response_list)) {
0563 prev = list_tail(&t->response_list, struct subaction, link);
0564
0565 if (!ACK_BUSY(prev->ack)) {
0566
0567
0568
0569
0570 }
0571
0572 if (prev->packet.common.tcode != sa->packet.common.tcode ||
0573 prev->packet.common.tlabel != sa->packet.common.tlabel) {
0574
0575
0576 }
0577 } else {
0578 prev = list_tail(&t->request_list, struct subaction, link);
0579 if (prev->ack != ACK_PENDING) {
0580
0581
0582
0583
0584 }
0585
0586 if (packet_info[prev->packet.common.tcode].response_tcode !=
0587 sa->packet.common.tcode) {
0588
0589 }
0590 }
0591
0592 list_append(&t->response_list, &sa->link);
0593
0594 switch (sa->ack) {
0595 case ACK_COMPLETE:
0596 case ACK_NO_ACK:
0597 case ACK_DATA_ERROR:
0598 case ACK_TYPE_ERROR:
0599 list_remove(&t->link);
0600 handle_transaction(t);
0601
0602 break;
0603
0604 case ACK_PENDING:
0605
0606 break;
0607
0608 case ACK_BUSY_X:
0609 case ACK_BUSY_A:
0610 case ACK_BUSY_B:
0611
0612 break;
0613 }
0614
0615 return 1;
0616 }
0617
0618 static int
0619 handle_packet(uint32_t *data, size_t length)
0620 {
0621 if (length == 0) {
0622 printf("bus reset\r\n");
0623 clear_pending_transaction_list();
0624 } else if (length > sizeof(struct phy_packet)) {
0625 struct link_packet *p = (struct link_packet *) data;
0626
0627 switch (packet_info[p->common.tcode].type) {
0628 case PACKET_REQUEST:
0629 return handle_request_packet(data, length);
0630
0631 case PACKET_RESPONSE:
0632 return handle_response_packet(data, length);
0633
0634 case PACKET_OTHER:
0635 case PACKET_RESERVED:
0636 return 0;
0637 }
0638 }
0639
0640 return 1;
0641 }
0642
0643 static unsigned int
0644 get_bits(struct link_packet *packet, int offset, int width)
0645 {
0646 uint32_t *data = (uint32_t *) packet;
0647 uint32_t index, shift, mask;
0648
0649 index = offset / 32 + 1;
0650 shift = 32 - (offset & 31) - width;
0651 mask = width == 32 ? ~0 : (1 << width) - 1;
0652
0653 return (data[index] >> shift) & mask;
0654 }
0655
0656 #if __BYTE_ORDER == __LITTLE_ENDIAN
0657 #define byte_index(i) ((i) ^ 3)
0658 #elif __BYTE_ORDER == __BIG_ENDIAN
0659 #define byte_index(i) (i)
0660 #else
0661 #error unsupported byte order.
0662 #endif
0663
0664 static void
0665 dump_data(unsigned char *data, int length)
0666 {
0667 int i, print_length;
0668
0669 if (length > 128)
0670 print_length = 128;
0671 else
0672 print_length = length;
0673
0674 for (i = 0; i < print_length; i++)
0675 printf("%s%02hhx",
0676 (i % 4 == 0 && i != 0) ? " " : "",
0677 data[byte_index(i)]);
0678
0679 if (print_length < length)
0680 printf(" (%d more bytes)", length - print_length);
0681 }
0682
0683 static void
0684 decode_link_packet(struct link_packet *packet, size_t length,
0685 int include_flags, int exclude_flags)
0686 {
0687 const struct packet_info *pi;
0688 int data_length = 0;
0689 int i;
0690
0691 pi = &packet_info[packet->common.tcode];
0692
0693 for (i = 0; i < pi->field_count; i++) {
0694 const struct packet_field *f = &pi->fields[i];
0695 int offset;
0696
0697 if (f->flags & exclude_flags)
0698 continue;
0699 if (include_flags && !(f->flags & include_flags))
0700 continue;
0701
0702 if (f->offset < 0)
0703 offset = length * 8 + f->offset - 32;
0704 else
0705 offset = f->offset;
0706
0707 if (f->value_names != NULL) {
0708 uint32_t bits;
0709
0710 bits = get_bits(packet, offset, f->width);
0711 printf("%s", f->value_names[bits]);
0712 } else if (f->width == 0) {
0713 printf("%s=[", f->name);
0714 dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
0715 printf("]");
0716 } else {
0717 unsigned long long bits;
0718 int high_width, low_width;
0719
0720 if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
0721
0722 high_width = ((offset + 31) & ~31) - offset;
0723 low_width = f->width - high_width;
0724
0725 bits = get_bits(packet, offset, high_width);
0726 bits = (bits << low_width) |
0727 get_bits(packet, offset + high_width, low_width);
0728 } else {
0729 bits = get_bits(packet, offset, f->width);
0730 }
0731
0732 printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
0733
0734 if (f->flags & PACKET_FIELD_DATA_LENGTH)
0735 data_length = bits;
0736 }
0737
0738 if (i < pi->field_count - 1)
0739 printf(", ");
0740 }
0741 }
0742
0743 static void
0744 print_packet(uint32_t *data, size_t length)
0745 {
0746 int i;
0747
0748 printf("%6u ", data[0]);
0749
0750 if (length == 4) {
0751 printf("bus reset");
0752 } else if (length < sizeof(struct phy_packet)) {
0753 printf("short packet: ");
0754 for (i = 1; i < length / 4; i++)
0755 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
0756 printf("]");
0757
0758 } else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
0759 struct phy_packet *pp = (struct phy_packet *) data;
0760
0761
0762
0763
0764
0765 switch (pp->common.identifier) {
0766 case PHY_PACKET_CONFIGURATION:
0767 if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
0768 printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
0769 } else {
0770 printf("phy config:");
0771 if (pp->phy_config.set_root)
0772 printf(" set_root_id=%02x", pp->phy_config.root_id);
0773 if (pp->phy_config.set_gap_count)
0774 printf(" set_gap_count=%d", pp->phy_config.gap_count);
0775 }
0776 break;
0777
0778 case PHY_PACKET_LINK_ON:
0779 printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
0780 break;
0781
0782 case PHY_PACKET_SELF_ID:
0783 if (pp->self_id.extended) {
0784 printf("extended self id: phy_id=%02x, seq=%d",
0785 pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
0786 } else {
0787 static const char * const speed_names[] = {
0788 "S100", "S200", "S400", "BETA"
0789 };
0790 printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
0791 pp->self_id.phy_id,
0792 (pp->self_id.link_active ? "active" : "not active"),
0793 pp->self_id.gap_count,
0794 speed_names[pp->self_id.phy_speed],
0795 (pp->self_id.contender ? ", irm contender" : ""),
0796 (pp->self_id.initiated_reset ? ", initiator" : ""));
0797 }
0798 break;
0799 default:
0800 printf("unknown phy packet: ");
0801 for (i = 1; i < length / 4; i++)
0802 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
0803 printf("]");
0804 break;
0805 }
0806 } else {
0807 struct link_packet *packet = (struct link_packet *) data;
0808
0809 decode_link_packet(packet, length, 0,
0810 option_verbose ? 0 : PACKET_FIELD_DETAIL);
0811 }
0812
0813 if (option_hex) {
0814 printf(" [");
0815 dump_data((unsigned char *) data + 4, length - 4);
0816 printf("]");
0817 }
0818
0819 printf("\r\n");
0820 }
0821
0822 #define HIDE_CURSOR "\033[?25l"
0823 #define SHOW_CURSOR "\033[?25h"
0824 #define CLEAR "\033[H\033[2J"
0825
0826 static void
0827 print_stats(uint32_t *data, size_t length)
0828 {
0829 static int bus_reset_count, short_packet_count, phy_packet_count;
0830 static int tcode_count[16];
0831 static struct timeval last_update;
0832 struct timeval now;
0833 int i;
0834
0835 if (length == 0)
0836 bus_reset_count++;
0837 else if (length < sizeof(struct phy_packet))
0838 short_packet_count++;
0839 else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
0840 phy_packet_count++;
0841 else {
0842 struct link_packet *packet = (struct link_packet *) data;
0843 tcode_count[packet->common.tcode]++;
0844 }
0845
0846 gettimeofday(&now, NULL);
0847 if (now.tv_sec <= last_update.tv_sec &&
0848 now.tv_usec < last_update.tv_usec + 500000)
0849 return;
0850
0851 last_update = now;
0852 printf(CLEAR HIDE_CURSOR
0853 " bus resets : %8d\n"
0854 " short packets : %8d\n"
0855 " phy packets : %8d\n",
0856 bus_reset_count, short_packet_count, phy_packet_count);
0857
0858 for (i = 0; i < array_length(packet_info); i++)
0859 if (packet_info[i].type != PACKET_RESERVED)
0860 printf(" %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
0861 printf(SHOW_CURSOR "\n");
0862 }
0863
0864 static struct termios saved_attributes;
0865
0866 static void
0867 reset_input_mode(void)
0868 {
0869 tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
0870 }
0871
0872 static void
0873 set_input_mode(void)
0874 {
0875 struct termios tattr;
0876
0877
0878 if (!isatty(STDIN_FILENO)) {
0879 fprintf(stderr, "Not a terminal.\n");
0880 exit(EXIT_FAILURE);
0881 }
0882
0883
0884 tcgetattr(STDIN_FILENO, &saved_attributes);
0885 atexit(reset_input_mode);
0886
0887
0888 tcgetattr(STDIN_FILENO, &tattr);
0889 tattr.c_lflag &= ~(ICANON|ECHO);
0890 tattr.c_cc[VMIN] = 1;
0891 tattr.c_cc[VTIME] = 0;
0892 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
0893 }
0894
0895 int main(int argc, const char *argv[])
0896 {
0897 uint32_t buf[128 * 1024];
0898 uint32_t filter;
0899 int length, retval, view;
0900 int fd = -1;
0901 FILE *output = NULL, *input = NULL;
0902 poptContext con;
0903 char c;
0904 struct pollfd pollfds[2];
0905
0906 sys_sigint_handler = signal(SIGINT, sigint_handler);
0907
0908 con = poptGetContext(NULL, argc, argv, options, 0);
0909 retval = poptGetNextOpt(con);
0910 if (retval < -1) {
0911 poptPrintUsage(con, stdout, 0);
0912 return -1;
0913 }
0914
0915 if (option_version) {
0916 printf("dump tool for nosy sniffer, version %s\n", VERSION);
0917 return 0;
0918 }
0919
0920 if (__BYTE_ORDER != __LITTLE_ENDIAN)
0921 fprintf(stderr, "warning: nosy has only been tested on little "
0922 "endian machines\n");
0923
0924 if (option_input != NULL) {
0925 input = fopen(option_input, "r");
0926 if (input == NULL) {
0927 fprintf(stderr, "Could not open %s, %m\n", option_input);
0928 return -1;
0929 }
0930 } else {
0931 fd = open(option_nosy_device, O_RDWR);
0932 if (fd < 0) {
0933 fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
0934 return -1;
0935 }
0936 set_input_mode();
0937 }
0938
0939 if (strcmp(option_view, "transaction") == 0)
0940 view = VIEW_TRANSACTION;
0941 else if (strcmp(option_view, "stats") == 0)
0942 view = VIEW_STATS;
0943 else
0944 view = VIEW_PACKET;
0945
0946 if (option_output) {
0947 output = fopen(option_output, "w");
0948 if (output == NULL) {
0949 fprintf(stderr, "Could not open %s, %m\n", option_output);
0950 return -1;
0951 }
0952 }
0953
0954 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
0955
0956 filter = ~0;
0957 if (!option_iso)
0958 filter &= ~(1 << TCODE_STREAM_DATA);
0959 if (!option_cycle_start)
0960 filter &= ~(1 << TCODE_CYCLE_START);
0961 if (view == VIEW_STATS)
0962 filter = ~(1 << TCODE_CYCLE_START);
0963
0964 ioctl(fd, NOSY_IOC_FILTER, filter);
0965
0966 ioctl(fd, NOSY_IOC_START);
0967
0968 pollfds[0].fd = fd;
0969 pollfds[0].events = POLLIN;
0970 pollfds[1].fd = STDIN_FILENO;
0971 pollfds[1].events = POLLIN;
0972
0973 while (run) {
0974 if (input != NULL) {
0975 if (fread(&length, sizeof length, 1, input) != 1)
0976 return 0;
0977 fread(buf, 1, length, input);
0978 } else {
0979 poll(pollfds, 2, -1);
0980 if (pollfds[1].revents) {
0981 read(STDIN_FILENO, &c, sizeof c);
0982 switch (c) {
0983 case 'q':
0984 if (output != NULL)
0985 fclose(output);
0986 return 0;
0987 }
0988 }
0989
0990 if (pollfds[0].revents)
0991 length = read(fd, buf, sizeof buf);
0992 else
0993 continue;
0994 }
0995
0996 if (output != NULL) {
0997 fwrite(&length, sizeof length, 1, output);
0998 fwrite(buf, 1, length, output);
0999 }
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 }