1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Synchronous loop-back test program 30 * For installation verification of synchronous lines and facilities 31 */ 32 33 #include <sys/types.h> 34 #include <ctype.h> 35 #include <sys/ioctl.h> 36 #include <fcntl.h> 37 #include <sys/time.h> 38 #include <sys/file.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <unistd.h> 42 #include <string.h> 43 #include <errno.h> 44 #include <sys/stream.h> 45 #include <sys/stropts.h> 46 #include <sys/poll.h> 47 #include <sys/ser_sync.h> 48 #include <libdlpi.h> 49 50 static void Usage(void); 51 static void quiet_period(void); 52 static void first_packet(); 53 static void many_packets(); 54 static void printhex(char *cp, int len); 55 56 static unsigned int speed = 9600; 57 static int reccount = 100; 58 static int reclen = 100; 59 static char loopstr[MAX_INPUT]; 60 static int looptype = 0; 61 static int loopchange = 0; 62 static int clockchange = 0; 63 static int cfd, dfd; /* control and data descriptors */ 64 static int data = -1; 65 static int verbose = 0; 66 67 static char *yesno[] = { 68 "no", 69 "yes", 70 "silent", 71 0, 72 }; 73 74 static char *txnames[] = { 75 "txc", 76 "rxc", 77 "baud", 78 "pll", 79 "sysclk", 80 "-txc", 81 0, 82 }; 83 84 static char *rxnames[] = { 85 "rxc", 86 "txc", 87 "baud", 88 "pll", 89 "sysclk", 90 "-rxc", 91 0, 92 }; 93 94 #define MAXPACKET 4096 95 96 int 97 main(int argc, char **argv) 98 { 99 char *portname; 100 char dnambuf[MAXPATHLEN], *cp; 101 char device[DLPI_LINKNAME_MAX]; 102 struct scc_mode sm; 103 struct strioctl sioc; 104 uint_t ppa; 105 char *devstr = "/dev/"; 106 int devstrlen; 107 int retval; 108 dlpi_handle_t dh; 109 110 argc--; 111 argv++; 112 while (argc > 0 && argv[0][0] == '-') 113 switch (argv[0][1]) { 114 case 'c': /* rec count */ 115 if (argc < 2) 116 Usage(); 117 reccount = atoi(argv[1]); 118 argc -= 2; 119 argv += 2; 120 break; 121 case 'd': 122 if (sscanf(argv[1], "%x", (uint_t *)&data) != 1) 123 Usage(); 124 argc -= 2; 125 argv += 2; 126 break; 127 case 'l': /* rec length */ 128 if (argc < 2) 129 Usage(); 130 reclen = atoi(argv[1]); 131 argc -= 2; 132 argv += 2; 133 break; 134 case 's': /* line speed */ 135 if (argc < 2) 136 Usage(); 137 speed = atoi(argv[1]); 138 argc -= 2; 139 argv += 2; 140 break; 141 case 't': /* test type */ 142 if (argc < 2) 143 Usage(); 144 looptype = atoi(argv[1]); 145 argc -= 2; 146 argv += 2; 147 break; 148 case 'v': 149 verbose = 1; 150 argc--; 151 argv++; 152 break; 153 } 154 if (argc != 1) 155 Usage(); 156 portname = argv[0]; 157 158 devstrlen = strlen(devstr); 159 if (strncmp(devstr, portname, devstrlen) != 0) { 160 if (snprintf(dnambuf, sizeof (dnambuf), "%s%s", devstr, 161 portname) >= sizeof (dnambuf)) { 162 (void) fprintf(stderr, 163 "syncloop: invalid device name (too long) %s\n", 164 portname); 165 exit(1); 166 } 167 } 168 169 dfd = open(dnambuf, O_RDWR); 170 if (dfd < 0) { 171 (void) fprintf(stderr, "syncloop: cannot open %s\n", dnambuf); 172 perror(dnambuf); 173 exit(1); 174 } 175 176 cp = portname; 177 while (*cp) /* find the end of the name */ 178 cp++; 179 cp--; 180 if (!isdigit(*cp)) { 181 (void) fprintf(stderr, 182 "syncloop: %s missing minor device number\n", portname); 183 exit(1); 184 } 185 186 if (strlen(portname) >= DLPI_LINKNAME_MAX) { 187 (void) fprintf(stderr, 188 "syncloop: invalid device name (too long) %s\n", 189 portname); 190 exit(1); 191 } 192 193 if ((retval = dlpi_open(portname, &dh, DLPI_SERIAL)) != DLPI_SUCCESS) { 194 (void) fprintf(stderr, "syncloop: dlpi_open %s: %s\n", portname, 195 dlpi_strerror(retval)); 196 exit(1); 197 } 198 199 (void) dlpi_parselink(portname, device, &ppa); 200 201 if (reclen < 0 || reclen > MAXPACKET) { 202 (void) printf("invalid packet length: %d\n", reclen); 203 exit(1); 204 } 205 (void) printf("[ Data device: %s | Control device: %s, ppa=%u ]\n", 206 dnambuf, device, ppa); 207 208 cfd = dlpi_fd(dh); 209 210 sioc.ic_cmd = S_IOCGETMODE; 211 sioc.ic_timout = -1; 212 sioc.ic_len = sizeof (struct scc_mode); 213 sioc.ic_dp = (char *)&sm; 214 if (ioctl(cfd, I_STR, &sioc) < 0) { 215 perror("S_IOCGETMODE"); 216 (void) fprintf(stderr, "syncloop: can't get sync mode info " 217 "for %s\n", portname); 218 exit(1); 219 } 220 while (looptype < 1 || looptype > 4) { 221 (void) printf("Enter test type:\n"); 222 (void) printf("1: Internal Test\n"); 223 (void) printf( 224 " (internal data loop, internal clocking)\n"); 225 (void) printf("2: Test using loopback plugs\n"); 226 (void) printf( 227 " (external data loop, internal clocking)\n"); 228 (void) printf("3: Test using local or remote modem loopback\n"); 229 (void) printf( 230 " (external data loop, external clocking)\n"); 231 (void) printf("4: Other, previously set, special mode\n"); 232 (void) printf("> "); (void) fflush(stdout); 233 (void) fgets(loopstr, sizeof (loopstr), stdin); 234 (void) sscanf(loopstr, "%d", &looptype); 235 } 236 switch (looptype) { 237 case 1: 238 if ((sm.sm_txclock != TXC_IS_BAUD) || 239 (sm.sm_rxclock != RXC_IS_BAUD)) 240 clockchange++; 241 sm.sm_txclock = TXC_IS_BAUD; 242 sm.sm_rxclock = RXC_IS_BAUD; 243 if ((sm.sm_config & CONN_LPBK) == 0) 244 loopchange++; 245 sm.sm_config |= CONN_LPBK; 246 break; 247 case 2: 248 if ((sm.sm_txclock != TXC_IS_BAUD) || 249 (sm.sm_rxclock != RXC_IS_RXC)) 250 clockchange++; 251 sm.sm_txclock = TXC_IS_BAUD; 252 sm.sm_rxclock = RXC_IS_RXC; 253 if ((sm.sm_config & CONN_LPBK) != 0) 254 loopchange++; 255 sm.sm_config &= ~CONN_LPBK; 256 break; 257 case 3: 258 if ((sm.sm_txclock != TXC_IS_TXC) || 259 (sm.sm_rxclock != RXC_IS_RXC)) 260 clockchange++; 261 sm.sm_txclock = TXC_IS_TXC; 262 sm.sm_rxclock = RXC_IS_RXC; 263 if ((sm.sm_config & CONN_LPBK) != 0) 264 loopchange++; 265 sm.sm_config &= ~CONN_LPBK; 266 break; 267 case 4: 268 goto no_params; 269 } 270 271 sm.sm_baudrate = speed; 272 273 sioc.ic_cmd = S_IOCSETMODE; 274 sioc.ic_timout = -1; 275 sioc.ic_len = sizeof (struct scc_mode); 276 sioc.ic_dp = (char *)&sm; 277 if (ioctl(cfd, I_STR, &sioc) < 0) { 278 perror("S_IOCSETMODE"); 279 (void) fprintf(stderr, 280 "syncloop: can't set sync mode info for %s\n", portname); 281 exit(1); 282 } 283 284 no_params: 285 /* report state */ 286 sioc.ic_cmd = S_IOCGETMODE; 287 sioc.ic_timout = -1; 288 sioc.ic_len = sizeof (struct scc_mode); 289 sioc.ic_dp = (char *)&sm; 290 if (ioctl(cfd, I_STR, &sioc) < 0) { 291 perror("S_IOCGETMODE"); 292 (void) fprintf(stderr, "syncloop: can't get sync mode info " 293 "for %s\n", portname); 294 exit(1); 295 } 296 (void) printf("speed=%d, loopback=%s, nrzi=%s, txc=%s, rxc=%s\n", 297 sm.sm_baudrate, 298 yesno[((int)(sm.sm_config & CONN_LPBK) > 0)], 299 yesno[((int)(sm.sm_config & CONN_NRZI) > 0)], 300 txnames[sm.sm_txclock], 301 rxnames[sm.sm_rxclock]); 302 303 quiet_period(); 304 first_packet(); 305 many_packets(); 306 return (0); 307 } 308 309 static void 310 Usage() 311 { 312 (void) printf("Usage: syncloop [ options ] portname\n"); 313 (void) printf("Options: -c packet_count\n"); 314 (void) printf(" -l packet_length\n"); 315 (void) printf(" -s line_speed\n"); 316 (void) printf(" -t test_type\n"); 317 (void) printf(" -d hex_data_byte\n"); 318 exit(1); 319 } 320 321 static int zero_time = 0; 322 static int short_time = 1000; 323 static int long_time = 4000; 324 static char bigbuf[4096]; 325 static char packet[MAXPACKET]; 326 static struct pollfd pfd; 327 328 static void 329 quiet_period() 330 { 331 (void) printf("[ checking for quiet line ]\n"); 332 pfd.fd = dfd; 333 pfd.events = POLLIN; 334 pfd.revents = 0; 335 while (poll(&pfd, 1, short_time) == 1) { 336 (void) read(dfd, bigbuf, sizeof (bigbuf)); 337 } 338 if (poll(&pfd, 1, long_time) == 1) { 339 (void) printf("packet received but none sent!\n"); 340 (void) printf("quiesce other end before starting syncloop\n"); 341 exit(1); 342 } 343 } 344 345 static void 346 first_packet() 347 { 348 int i, len; 349 int pollret; 350 struct strioctl sioc; 351 struct sl_stats start_stats, end_stats; 352 353 for (i = 0; i < reclen; i++) 354 packet[i] = (data == -1) ? rand() : data; 355 (void) printf("[ Trying first packet ]\n"); 356 sioc.ic_cmd = S_IOCGETSTATS; 357 sioc.ic_timout = -1; 358 sioc.ic_len = sizeof (struct sl_stats); 359 sioc.ic_dp = (char *)&start_stats; 360 if (ioctl(cfd, I_STR, &sioc) < 0) { 361 perror("S_IOCGETSTATS"); 362 exit(1); 363 } 364 365 for (i = 0; i < 5; i++) { 366 if (write(dfd, packet, reclen) != reclen) { 367 (void) fprintf(stderr, 368 "packet write failed, errno %d\n", 369 errno); 370 exit(1); 371 } 372 pfd.fd = dfd; 373 pfd.events = POLLIN; 374 pollret = poll(&pfd, 1, long_time); 375 if (pollret < 0) perror("poll"); 376 if (pollret == 0) 377 (void) printf("poll: nothing to read.\n"); 378 if (pollret == 1) { 379 len = read(dfd, bigbuf, reclen); 380 if (len == reclen && memcmp(packet, bigbuf, len) == 0) 381 return; /* success */ 382 else { 383 (void) printf("len %d should be %d\n", 384 len, reclen); 385 if (verbose) { 386 (void) printf(" "); 387 printhex(bigbuf, len); 388 (void) printf("\nshould be "); 389 printhex(packet, reclen); 390 (void) printf("\n"); 391 } 392 } 393 } 394 } 395 (void) printf("Loopback has TOTALLY FAILED - "); 396 (void) printf("no packets returned after 5 attempts\n"); 397 sioc.ic_cmd = S_IOCGETSTATS; 398 sioc.ic_timout = -1; 399 sioc.ic_len = sizeof (struct sl_stats); 400 sioc.ic_dp = (char *)&end_stats; 401 if (ioctl(cfd, I_STR, &sioc) < 0) { 402 perror("S_IOCGETSTATS"); 403 exit(1); 404 } 405 if (start_stats.opack == end_stats.opack) 406 (void) printf( 407 "No packets transmitted - no transmit clock present\n"); 408 exit(1); 409 } 410 411 static void 412 many_packets() 413 { 414 struct strioctl sioc; 415 struct sl_stats start_stats, end_stats; 416 struct timeval start_time, end_time; 417 int baddata = 0; 418 float secs, speed; 419 int i, len; 420 int incount = 0; 421 long prev_sec = -1; 422 int pollret; 423 424 (void) printf("[ Trying many packets ]\n"); 425 sioc.ic_cmd = S_IOCGETSTATS; 426 sioc.ic_timout = -1; 427 sioc.ic_len = sizeof (struct sl_stats); 428 sioc.ic_dp = (char *)&start_stats; 429 if (ioctl(cfd, I_STR, &sioc) < 0) { 430 perror("S_IOCGETSTATS"); 431 exit(1); 432 } 433 (void) gettimeofday(&start_time, 0); 434 end_time = start_time; 435 436 i = 0; 437 while (i < reccount) { 438 if (end_time.tv_sec != prev_sec) { 439 prev_sec = end_time.tv_sec; 440 (void) printf("\r %d ", incount); 441 (void) fflush(stdout); 442 } 443 pfd.fd = dfd; 444 pfd.events = POLLIN; 445 while (pollret = poll(&pfd, 1, zero_time)) { 446 if (pollret < 0) 447 perror("poll"); 448 else { 449 (void) lseek(dfd, (long)0, 0); 450 len = read(dfd, bigbuf, reclen); 451 if (len != reclen || 452 memcmp(packet, bigbuf, len) != 0) { 453 (void) printf("len %d should be %d\n", 454 len, reclen); 455 if (verbose) { 456 (void) printf(" "); 457 printhex(bigbuf, len); 458 (void) printf("\nshould be "); 459 printhex(packet, reclen); 460 (void) printf("\n"); 461 } 462 baddata++; 463 } 464 incount++; 465 (void) gettimeofday(&end_time, 0); 466 } 467 } 468 pfd.fd = dfd; 469 pfd.events = POLLIN|POLLOUT; 470 pollret = poll(&pfd, 1, long_time); 471 if (pollret < 0) 472 perror("poll"); 473 if (pollret == 0) 474 (void) printf("poll: nothing to read or write.\n"); 475 if (pollret == 1) { 476 if (pfd.revents & POLLOUT) { 477 (void) write(dfd, packet, reclen); 478 i++; 479 } else if (!(pfd.revents & POLLIN)) { 480 (void) printf("OUTPUT HAS LOCKED UP!!!\n"); 481 break; 482 } 483 } 484 } 485 pfd.fd = dfd; 486 pfd.events = POLLIN; 487 while ((incount < reccount) && (poll(&pfd, 1, long_time) == 1)) { 488 if (end_time.tv_sec != prev_sec) { 489 prev_sec = end_time.tv_sec; 490 (void) printf("\r %d ", incount); 491 (void) fflush(stdout); 492 } 493 len = read(dfd, bigbuf, reclen); 494 if (len != reclen || memcmp(packet, bigbuf, len) != 0) { 495 (void) printf("len %d should be %d\n", len, reclen); 496 if (verbose) { 497 (void) printf(" "); 498 printhex(bigbuf, len); 499 (void) printf("\nshould be "); 500 printhex(packet, reclen); 501 (void) printf("\n"); 502 } 503 baddata++; 504 } 505 incount++; 506 (void) gettimeofday(&end_time, 0); 507 } 508 (void) printf("\r %d \n", incount); 509 if (baddata) 510 (void) printf("%d packets with wrong data received!\n", 511 baddata); 512 sioc.ic_cmd = S_IOCGETSTATS; 513 sioc.ic_timout = -1; 514 sioc.ic_len = sizeof (struct sl_stats); 515 sioc.ic_dp = (char *)&end_stats; 516 if (ioctl(cfd, I_STR, &sioc) < 0) { 517 perror("S_IOCGETSTATS"); 518 exit(1); 519 } 520 end_stats.ipack -= start_stats.ipack; 521 end_stats.opack -= start_stats.opack; 522 end_stats.abort -= start_stats.abort; 523 end_stats.crc -= start_stats.crc; 524 end_stats.overrun -= start_stats.overrun; 525 end_stats.underrun -= start_stats.underrun; 526 end_stats.ierror -= start_stats.ierror; 527 end_stats.oerror -= start_stats.oerror; 528 if (reccount > end_stats.opack) 529 (void) printf("%d packets lost in outbound queueing\n", 530 reccount - end_stats.opack); 531 if (incount < end_stats.ipack && incount < reccount) 532 (void) printf("%d packets lost in inbound queueing\n", 533 end_stats.ipack - incount); 534 (void) printf("%d packets sent, %d received\n", reccount, incount); 535 (void) printf("CRC errors Aborts Overruns Underruns "); 536 (void) printf(" In <-Drops-> Out\n%9d %9d %9d %9d %12d %12d\n", 537 end_stats.crc, end_stats.abort, 538 end_stats.overrun, end_stats.underrun, 539 end_stats.ierror, end_stats.oerror); 540 secs = (float)(end_time.tv_usec - start_time.tv_usec) / 1000000.0; 541 secs += (float)(end_time.tv_sec - start_time.tv_sec); 542 if (secs) { 543 speed = 8 * incount * (4 + reclen) / secs; 544 (void) printf("estimated line speed = %d bps\n", (int)speed); 545 } 546 } 547 548 static void 549 printhex(char *cp, int len) 550 { 551 char c, *hex = "0123456789ABCDEF"; 552 int i; 553 554 for (i = 0; i < len; i++) { 555 c = *cp++; 556 (void) putchar(hex[(c >> 4) & 0xF]); 557 (void) putchar(hex[c & 0xF]); 558 } 559 } 560