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