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