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