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
main(int argc,char ** argv)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
Usage()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
quiet_period()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
first_packet()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
many_packets()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
printhex(char * cp,int len)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