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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Synchronous loop-back test program
30 * For installation verification of synchronous lines and facilities
33 #include <sys/types.h>
35 #include <sys/ioctl.h>
44 #include <sys/stream.h>
45 #include <sys/stropts.h>
47 #include <sys/ser_sync.h>
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
);
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 */
65 static int verbose
= 0;
67 static char *yesno
[] = {
74 static char *txnames
[] = {
84 static char *rxnames
[] = {
94 #define MAXPACKET 4096
97 main(int argc
, char **argv
)
100 char dnambuf
[MAXPATHLEN
], *cp
;
101 char device
[DLPI_LINKNAME_MAX
];
103 struct strioctl sioc
;
105 char *devstr
= "/dev/";
112 while (argc
> 0 && argv
[0][0] == '-')
113 switch (argv
[0][1]) {
114 case 'c': /* rec count */
117 reccount
= atoi(argv
[1]);
122 if (sscanf(argv
[1], "%x", (uint_t
*)&data
) != 1)
127 case 'l': /* rec length */
130 reclen
= atoi(argv
[1]);
134 case 's': /* line speed */
137 speed
= atoi(argv
[1]);
141 case 't': /* test type */
144 looptype
= atoi(argv
[1]);
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",
169 dfd
= open(dnambuf
, O_RDWR
);
171 (void) fprintf(stderr
, "syncloop: cannot open %s\n", dnambuf
);
177 while (*cp
) /* find the end of the name */
181 (void) fprintf(stderr
,
182 "syncloop: %s missing minor device number\n", portname
);
186 if (strlen(portname
) >= DLPI_LINKNAME_MAX
) {
187 (void) fprintf(stderr
,
188 "syncloop: invalid device name (too long) %s\n",
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
));
199 (void) dlpi_parselink(portname
, device
, &ppa
);
201 if (reclen
< 0 || reclen
> MAXPACKET
) {
202 (void) printf("invalid packet length: %d\n", reclen
);
205 (void) printf("[ Data device: %s | Control device: %s, ppa=%u ]\n",
206 dnambuf
, device
, ppa
);
210 sioc
.ic_cmd
= S_IOCGETMODE
;
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
);
220 while (looptype
< 1 || looptype
> 4) {
221 (void) printf("Enter test type:\n");
222 (void) printf("1: Internal Test\n");
224 " (internal data loop, internal clocking)\n");
225 (void) printf("2: Test using loopback plugs\n");
227 " (external data loop, internal clocking)\n");
228 (void) printf("3: Test using local or remote modem loopback\n");
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
);
238 if ((sm
.sm_txclock
!= TXC_IS_BAUD
) ||
239 (sm
.sm_rxclock
!= RXC_IS_BAUD
))
241 sm
.sm_txclock
= TXC_IS_BAUD
;
242 sm
.sm_rxclock
= RXC_IS_BAUD
;
243 if ((sm
.sm_config
& CONN_LPBK
) == 0)
245 sm
.sm_config
|= CONN_LPBK
;
248 if ((sm
.sm_txclock
!= TXC_IS_BAUD
) ||
249 (sm
.sm_rxclock
!= RXC_IS_RXC
))
251 sm
.sm_txclock
= TXC_IS_BAUD
;
252 sm
.sm_rxclock
= RXC_IS_RXC
;
253 if ((sm
.sm_config
& CONN_LPBK
) != 0)
255 sm
.sm_config
&= ~CONN_LPBK
;
258 if ((sm
.sm_txclock
!= TXC_IS_TXC
) ||
259 (sm
.sm_rxclock
!= RXC_IS_RXC
))
261 sm
.sm_txclock
= TXC_IS_TXC
;
262 sm
.sm_rxclock
= RXC_IS_RXC
;
263 if ((sm
.sm_config
& CONN_LPBK
) != 0)
265 sm
.sm_config
&= ~CONN_LPBK
;
271 sm
.sm_baudrate
= speed
;
273 sioc
.ic_cmd
= S_IOCSETMODE
;
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
);
286 sioc
.ic_cmd
= S_IOCGETMODE
;
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
);
296 (void) printf("speed=%d, loopback=%s, nrzi=%s, txc=%s, rxc=%s\n",
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
]);
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");
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
;
331 (void) printf("[ checking for quiet line ]\n");
335 while (poll(&pfd
, 1, short_time
) == 1) {
336 (void) read(dfd
, bigbuf
, sizeof (bigbuf
));
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");
350 struct strioctl sioc
;
351 struct sl_stats start_stats
, end_stats
;
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
;
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");
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",
374 pollret
= poll(&pfd
, 1, long_time
);
375 if (pollret
< 0) perror("poll");
377 (void) printf("poll: nothing to read.\n");
379 len
= read(dfd
, bigbuf
, reclen
);
380 if (len
== reclen
&& memcmp(packet
, bigbuf
, len
) == 0)
381 return; /* success */
383 (void) printf("len %d should be %d\n",
387 printhex(bigbuf
, len
);
388 (void) printf("\nshould be ");
389 printhex(packet
, reclen
);
395 (void) printf("Loopback has TOTALLY FAILED - ");
396 (void) printf("no packets returned after 5 attempts\n");
397 sioc
.ic_cmd
= S_IOCGETSTATS
;
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");
405 if (start_stats
.opack
== end_stats
.opack
)
407 "No packets transmitted - no transmit clock present\n");
414 struct strioctl sioc
;
415 struct sl_stats start_stats
, end_stats
;
416 struct timeval start_time
, end_time
;
424 (void) printf("[ Trying many packets ]\n");
425 sioc
.ic_cmd
= S_IOCGETSTATS
;
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");
433 (void) gettimeofday(&start_time
, 0);
434 end_time
= start_time
;
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
);
445 while (pollret
= poll(&pfd
, 1, zero_time
)) {
449 (void) lseek(dfd
, (long)0, 0);
450 len
= read(dfd
, bigbuf
, reclen
);
452 memcmp(packet
, bigbuf
, len
) != 0) {
453 (void) printf("len %d should be %d\n",
457 printhex(bigbuf
, len
);
458 (void) printf("\nshould be ");
459 printhex(packet
, reclen
);
465 (void) gettimeofday(&end_time
, 0);
469 pfd
.events
= POLLIN
|POLLOUT
;
470 pollret
= poll(&pfd
, 1, long_time
);
474 (void) printf("poll: nothing to read or write.\n");
476 if (pfd
.revents
& POLLOUT
) {
477 (void) write(dfd
, packet
, reclen
);
479 } else if (!(pfd
.revents
& POLLIN
)) {
480 (void) printf("OUTPUT HAS LOCKED UP!!!\n");
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
);
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
);
498 printhex(bigbuf
, len
);
499 (void) printf("\nshould be ");
500 printhex(packet
, reclen
);
506 (void) gettimeofday(&end_time
, 0);
508 (void) printf("\r %d \n", incount
);
510 (void) printf("%d packets with wrong data received!\n",
512 sioc
.ic_cmd
= S_IOCGETSTATS
;
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");
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
);
543 speed
= 8 * incount
* (4 + reclen
) / secs
;
544 (void) printf("estimated line speed = %d bps\n", (int)speed
);
549 printhex(char *cp
, int len
)
551 char c
, *hex
= "0123456789ABCDEF";
554 for (i
= 0; i
< len
; i
++) {
556 (void) putchar(hex
[(c
>> 4) & 0xF]);
557 (void) putchar(hex
[c
& 0xF]);