1/*
2 * Copyright (c) 2001-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 */
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/types.h>
33#include <sys/sysctl.h>
34#include <sys/ioctl.h>
35#include <sys/socket.h>
36#include <sys/queue.h>
37#include <net/if.h>
38#include <net/if_mib.h>
39#include <net/if_types.h>
40#include <net/if_atm.h>
41#include <net/if_media.h>
42#include <netnatm/natm.h>
43#include <dev/utopia/utopia.h>
44#include <dev/utopia/suni.h>
45#include <dev/utopia/idtphy.h>
46
47#include "atmconfig.h"
48#include "private.h"
49#include "diag.h"
50
51static void diag_list(int, char *[]);
52static void diag_config(int, char *[]);
53static void diag_vcc(int, char *[]);
54static void diag_phy_show(int, char *[]);
55static void diag_phy_set(int, char *[]);
56static void diag_phy_print(int, char *[]);
57static void diag_phy_stats(int, char *[]);
58static void diag_stats(int, char *[]);
59
60static const struct cmdtab diag_phy_tab[] = {
61	{ "show",	NULL, 		diag_phy_show },
62	{ "set",	NULL, 		diag_phy_set },
63	{ "stats",	NULL,		diag_phy_stats },
64	{ "print",	NULL,		diag_phy_print },
65	{ NULL,		NULL,		NULL },
66};
67
68const struct cmdtab diag_tab[] = {
69	{ "list",	NULL,		diag_list },
70	{ "config",	NULL,		diag_config },
71	{ "phy",	diag_phy_tab,	NULL },
72	{ "stats",	NULL,		diag_stats },
73	{ "vcc",	NULL,		diag_vcc },
74	{ NULL, 	NULL, 		NULL }
75};
76
77static const struct utopia_print suni_lite[] = { SUNI_PRINT_LITE };
78static const struct utopia_print suni_ultra[] = { SUNI_PRINT_ULTRA };
79static const struct utopia_print suni_622[] = { SUNI_PRINT_622 };
80static const struct utopia_print idt77105[] = { IDTPHY_PRINT_77105 };
81static const struct utopia_print idt77155[] = { IDTPHY_PRINT_77155 };
82
83static const struct {
84	const struct utopia_print *tab;
85	u_int len;
86	u_int type;
87} phy_print[] = {
88	{ suni_lite, sizeof(suni_lite) / sizeof(suni_lite[0]),
89	  UTP_TYPE_SUNI_LITE },
90	{ suni_ultra, sizeof(suni_ultra) / sizeof(suni_ultra[0]),
91	  UTP_TYPE_SUNI_ULTRA },
92	{ suni_622, sizeof(suni_622) / sizeof(suni_622[0]),
93	  UTP_TYPE_SUNI_622 },
94	{ idt77105, sizeof(idt77105) / sizeof(idt77105[0]),
95	  UTP_TYPE_IDT77105 },
96	{ idt77155, sizeof(idt77155) / sizeof(idt77155[0]),
97	  UTP_TYPE_IDT77155 },
98};
99
100static const u_int utopia_addreg[] = { UTP_REG_ADD };
101
102/*
103 * Driver statistics printing
104 */
105static const char *const print_stats_pca200e[] = {
106	"cmd_queue_full:",
107	"get_stat_errors:",
108	"clr_stat_errors:",
109	"get_prom_errors:",
110	"suni_reg_errors:",
111	"tx_queue_full:",
112	"tx_queue_almost_full:",
113	"tx_pdu2big:",
114	"tx_too_many_segs:",
115	"tx_retry:",
116	"fix_empty:",
117	"fix_addr_copy:",
118	"fix_addr_noext:",
119	"fix_addr_ext:",
120	"fix_len_noext:",
121	"fix_len_copy:",
122	"fix_len:",
123	"rx_badvc:",
124	"rx_closed:",
125	NULL
126};
127static const char *const print_stats_he[] = {
128	"tdprq_full:",
129	"hbuf_error:",
130	"crc_error:",
131	"len_error:",
132	"flow_closed:",
133	"flow_drop:",
134	"tpd_no_mem:",
135	"rx_seg:",
136	"empty_hbuf:",
137	"short_aal5:",
138	"badlen_aal5:",
139	"bug_bad_isw:",
140	"bug_no_irq_upd:",
141	"itype_tbrq:",
142	"itype_tpd:",
143	"itype_rbps:",
144	"itype_rbpl:",
145	"itype_rbrq:",
146	"itype_rbrqt:",
147	"itype_unknown:",
148	"itype_phys:",
149	"itype_err:",
150	"defrag:",
151	"mcc:",
152	"oec:",
153	"dcc:",
154	"cec:",
155	"no_rcv_mbuf:",
156	NULL
157};
158static const char *const print_stats_eni[] = {
159	"ttrash:",
160	"mfixaddr:",
161	"mfixlen:",
162	"mfixfail:",
163	"txmbovr:",
164	"dmaovr:",
165	"txoutspace:",
166	"txdtqout:",
167	"launch:",
168	"hwpull:",
169	"swadd:",
170	"rxqnotus:",
171	"rxqus:",
172	"rxdrqout:",
173	"rxmbufout:",
174	"txnomap:",
175	"vtrash:",
176	"otrash:",
177	NULL
178};
179
180static const char *const print_stats_idt77211[] = {
181	"need_copy:",
182	"copy_failed:",
183	"out_of_tbds:",
184	"no_txmaps:",
185	"tx_load_err:",
186	"tx_qfull:",
187	NULL
188};
189static const char *const print_stats_idt77252[] = {
190	"raw_cells:",
191	"raw_no_vcc:",
192	"raw_no_buf:",
193	"tx_qfull:",
194	"tx_out_of_tbds:",
195	"tx_out_of_maps:",
196	"tx_load_err:",
197	NULL
198};
199static const char *const print_stats_virtual[] = {
200	"dummy:",
201	NULL
202};
203static const char *const *const print_stats[] = {
204	[ATM_DEVICE_UNKNOWN] =		NULL,
205	[ATM_DEVICE_PCA200E] =		print_stats_pca200e,
206	[ATM_DEVICE_HE155] =		print_stats_he,
207	[ATM_DEVICE_HE622] =		print_stats_he,
208	[ATM_DEVICE_ENI155P] =		print_stats_eni,
209	[ATM_DEVICE_ADP155P] =		print_stats_eni,
210	[ATM_DEVICE_FORELE25] =		print_stats_idt77211,
211	[ATM_DEVICE_FORELE155] =	print_stats_idt77211,
212	[ATM_DEVICE_NICSTAR25] =	print_stats_idt77211,
213	[ATM_DEVICE_NICSTAR155] =	print_stats_idt77211,
214	[ATM_DEVICE_IDTABR25] =		print_stats_idt77252,
215	[ATM_DEVICE_IDTABR155] =	print_stats_idt77252,
216	[ATM_DEVICE_PROATM25] =		print_stats_idt77252,
217	[ATM_DEVICE_PROATM155] =	print_stats_idt77252,
218	[ATM_DEVICE_VIRTUAL] =		print_stats_virtual,
219};
220
221struct diagif_list diagif_list = TAILQ_HEAD_INITIALIZER(diagif_list);
222
223/*
224 * Fetch a phy sysctl
225 */
226static int
227phy_fetch(const char *ifname, const char *var, void *val, size_t len,
228    int err_fatal)
229{
230	char *str;
231
232	if (asprintf(&str, "hw.atm.%s.phy_%s", ifname, var) == -1)
233		err(1, NULL);
234	if (sysctlbyname(str, val, &len, NULL, 0) == -1) {
235		if (err_fatal || errno != ENOENT)
236			err(1, "%s", str);
237		free(str);
238		return (-1);
239	}
240	free(str);
241	return (0);
242}
243
244/*
245 * Fetch the list of all ATM network interfaces and their MIBs.
246 */
247void
248diagif_fetch(void)
249{
250	size_t len;
251	int count;
252	int name[6];
253	struct ifmibdata mib;
254	struct ifatm_mib atm;
255	int idx;
256	struct diagif *d;
257
258	while ((d = TAILQ_FIRST(&diagif_list)) != NULL) {
259		if (d->vtab != NULL)
260			free(d->vtab);
261		TAILQ_REMOVE(&diagif_list, d, link);
262		free(d);
263	}
264
265	len = sizeof(count);
266	if (sysctlbyname("net.link.generic.system.ifcount", &count, &len,
267	    NULL, 0) == -1)
268		err(1, "ifcount");
269
270	name[0] = CTL_NET;
271	name[1] = PF_LINK;
272	name[2] = NETLINK_GENERIC;
273	name[3] = IFMIB_IFDATA;
274
275	for (idx = 1; idx <= count; idx++) {
276		name[4] = idx;
277		name[5] = IFDATA_GENERAL;
278		len = sizeof(mib);
279		if (sysctl(name, 6, &mib, &len, NULL, 0) == -1)
280			err(1, "interface %d: general mib", idx);
281		if (mib.ifmd_data.ifi_type == IFT_ATM) {
282			name[5] = IFDATA_LINKSPECIFIC;
283			len = sizeof(atm);
284			if (sysctl(name, 6, &atm, &len, NULL, 0) == -1)
285				err(1, "interface %d: ATM mib", idx);
286
287			d = malloc(sizeof(*d));
288			if (d == NULL)
289				err(1, NULL);
290			bzero(d, sizeof(*d));
291			d->mib = atm;
292			d->index = idx;
293			strcpy(d->ifname, mib.ifmd_name);
294			TAILQ_INSERT_TAIL(&diagif_list, d, link);
295
296			if (phy_fetch(d->ifname, "type", &d->phy_type,
297			    sizeof(d->phy_type), 0) == 0) {
298				d->phy_present = 1;
299				phy_fetch(d->ifname, "loopback",
300				    &d->phy_loopback,
301				    sizeof(d->phy_loopback), 1);
302				phy_fetch(d->ifname, "name", &d->phy_name,
303				    sizeof(d->phy_name), 1);
304				phy_fetch(d->ifname, "state", &d->phy_state,
305				    sizeof(d->phy_state), 1);
306				phy_fetch(d->ifname, "carrier", &d->phy_carrier,
307				    sizeof(d->phy_carrier), 1);
308			}
309		}
310	}
311}
312
313/*
314 * "<radix><bit>STRING\011<mask><pattern>STRING\012<mask><radix>STRING"
315 */
316static char *
317printb8(uint32_t val, const char *descr)
318{
319	static char buffer[1000];
320	char *ptr;
321	int tmp = 0;
322	u_char mask, pattern;
323
324	if (*descr++ == '\010')
325		sprintf(buffer, "%#o", val);
326	else
327		sprintf(buffer, "%#x", val);
328	ptr = buffer + strlen(buffer);
329
330	*ptr++ = '<';
331	while (*descr) {
332		if (*descr == '\11') {
333			descr++;
334			mask = *descr++;
335			pattern = *descr++;
336			if ((val & mask) == pattern) {
337				if (tmp++)
338					*ptr++ = ',';
339				while (*descr >= ' ')
340					*ptr++ = *descr++;
341			} else {
342				while (*descr >= ' ')
343					descr++;
344			}
345		} else if (*descr == '\12') {
346			descr++;
347			mask = *descr++;
348			pattern = *descr++;
349			if (tmp++)
350				*ptr++ = ',';
351			while (*descr >= ' ')
352				*ptr++ = *descr++;
353			*ptr++ = '=';
354			if (pattern == 8)
355				sprintf(ptr, "%#o",
356				    (val & mask) >> (ffs(mask)-1));
357			else if (pattern == 10)
358				sprintf(ptr, "%u",
359				    (val & mask) >> (ffs(mask)-1));
360			else
361				sprintf(ptr, "%#x",
362				    (val & mask) >> (ffs(mask)-1));
363			ptr += strlen(ptr);
364		} else {
365			if (val & (1 << (*descr++ - 1))) {
366				if (tmp++)
367					*ptr++ = ',';
368				while (*descr >= ' ')
369					*ptr++ = *descr++;
370			} else {
371				while (*descr >= ' ')
372					descr++;
373			}
374		}
375	}
376	*ptr++ = '>';
377	*ptr++ = '\0';
378
379	return (buffer);
380}
381
382/*
383 * "<radix><bit>STRING<bit>STRING"
384 */
385static char *
386printb(uint32_t val, const char *descr)
387{
388	static char buffer[1000];
389	char *ptr;
390	int tmp = 0;
391
392	if (*descr++ == '\010')
393		sprintf(buffer, "%#o", val);
394	else
395		sprintf(buffer, "%#x", val);
396	ptr = buffer + strlen(buffer);
397
398	*ptr++ = '<';
399	while (*descr) {
400		if (val & (1 << (*descr++ - 1))) {
401			if (tmp++)
402				*ptr++ = ',';
403			while (*descr > ' ')
404				*ptr++ = *descr++;
405		} else {
406			while (*descr > ' ')
407				descr++;
408		}
409	}
410	*ptr++ = '>';
411	*ptr++ = '\0';
412
413	return (buffer);
414}
415
416
417static void
418diag_loop(int argc, char *argv[], const char *text,
419    void (*func)(const struct diagif *))
420{
421	int i;
422	struct diagif *aif;
423
424	heading_init();
425	if (argc > 0) {
426		for (i = 0; i < argc; i++) {
427			TAILQ_FOREACH(aif, &diagif_list, link) {
428				if (strcmp(argv[i], aif->ifname) == 0) {
429					heading("%s", text);
430					(*func)(aif);
431					break;
432				}
433			}
434			if (aif == NULL)
435				warnx("%s: no such ATM interface", argv[i]);
436		}
437	} else {
438		TAILQ_FOREACH(aif, &diagif_list, link) {
439			heading("%s", text);
440			(*func)(aif);
441		}
442	}
443}
444
445/*
446 * Print the config line for the given interface
447 */
448static void
449config_line1(const struct diagif *aif)
450{
451	printf("%-6u%-9s%-8u%-5u%-6u%-5u%-6u%02x:%02x:%02x:%02x:%02x:%02x\n",
452	    aif->index, aif->ifname, aif->mib.pcr, (1 << aif->mib.vpi_bits) - 1,
453	    (1 << aif->mib.vci_bits) - 1, aif->mib.max_vpcs, aif->mib.max_vccs,
454	    aif->mib.esi[0], aif->mib.esi[1], aif->mib.esi[2],
455	    aif->mib.esi[3], aif->mib.esi[4], aif->mib.esi[5]);
456}
457
458static void
459config_line2(const struct diagif *aif)
460{
461	u_int d, i;
462
463	static const struct {
464		const char *dev;
465		const char *vendor;
466	} devs[] = {
467		ATM_DEVICE_NAMES
468	};
469	static const struct {
470		u_int	media;
471		const char *const name;
472	} medias[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
473
474	for (i = 0; medias[i].name; i++)
475		if (aif->mib.media == medias[i].media)
476			break;
477
478	if ((d = aif->mib.device) >= sizeof(devs) / sizeof(devs[0]))
479		d = 0;
480
481	printf("%-6u%-9s%-12.11s%-13.12s%-8u%-6x%-6x %s\n", aif->index,
482	    aif->ifname, devs[d].vendor, devs[d].dev, aif->mib.serial,
483	    aif->mib.hw_version, aif->mib.sw_version,
484	    medias[i].name ? medias[i].name : "unknown");
485}
486
487static void
488diag_config(int argc, char *argv[])
489{
490	int opt;
491
492	static int hardware;
493	static int atm;
494
495	static const struct option opts[] = {
496	    { "hardware", OPT_SIMPLE, &hardware },
497	    { "atm", OPT_SIMPLE, &atm },
498	    { NULL, 0, NULL }
499	};
500
501	static const char config_text1[] =
502	    "Interface              Max        Max\n"
503	    "Index Name     PCR     VPI  VCI   VPCs VCCs  ESI\n";
504	static const char config_text2[] =
505	    "Interface                                       Version\n"
506	    "Index Name     Vendor      Card         "
507	    "Serial  HW    SW     Media\n";
508
509	while ((opt = parse_options(&argc, &argv, opts)) != -1)
510		switch (opt) {
511		}
512
513	diagif_fetch();
514	if (TAILQ_EMPTY(&diagif_list))
515		errx(1, "no ATM interfaces found");
516
517	if (!atm && !hardware)
518		atm = 1;
519
520	if (atm)
521		diag_loop(argc, argv, config_text1, config_line1);
522	if (hardware)
523		diag_loop(argc, argv, config_text2, config_line2);
524
525}
526
527static void
528diag_list(int argc, char *argv[])
529{
530	int opt;
531	struct diagif *aif;
532
533	static const struct option opts[] = {
534	    { NULL, 0, NULL }
535	};
536
537	while ((opt = parse_options(&argc, &argv, opts)) != -1)
538		switch (opt) {
539		}
540
541	if (argc > 0)
542		errx(1, "no arguments required for 'diag list'");
543
544	diagif_fetch();
545	if (TAILQ_EMPTY(&diagif_list))
546		errx(1, "no ATM interfaces found");
547
548	TAILQ_FOREACH(aif, &diagif_list, link)
549		printf("%s ", aif->ifname);
550	printf("\n");
551}
552
553/*
554 * Print the config line for the given interface
555 */
556static void
557phy_show_line(const struct diagif *aif)
558{
559	printf("%-6u%-9s", aif->index, aif->ifname);
560	if (aif->phy_present)
561		printf("%-5u%-25s0x%-9x", aif->phy_type,
562		    aif->phy_name, aif->phy_loopback);
563	printf("\n");
564}
565
566static void
567diag_phy_show(int argc, char *argv[])
568{
569	int opt;
570
571	static const struct option opts[] = {
572	    { NULL, 0, NULL }
573	};
574
575	static const char phy_show_text[] =
576	    "Interface      Phy\n"
577	    "Index Name     Type Name                     Loopback State\n";
578
579	while ((opt = parse_options(&argc, &argv, opts)) != -1)
580		switch (opt) {
581		}
582
583	diagif_fetch();
584	if (TAILQ_EMPTY(&diagif_list))
585		errx(1, "no ATM interfaces found");
586
587	diag_loop(argc, argv, phy_show_text, phy_show_line);
588}
589
590/*
591 * Make sure the interface exists and has a phy
592 */
593static struct diagif *
594diagif_get_phy(const char *arg)
595{
596	struct diagif *aif;
597
598	diagif_fetch();
599	TAILQ_FOREACH(aif, &diagif_list, link)
600		if (strcmp(aif->ifname, arg) == 0)
601			break;
602	if (aif == NULL)
603		errx(1, "no such interface: %s", arg);
604	if (!aif->phy_present)
605		errx(1, "interface %s has no phy", arg);
606
607	return (aif);
608}
609
610static void
611diag_phy_set(int argc, char *argv[])
612{
613	int opt;
614	uint8_t reg[3];
615	u_long res;
616	char *end;
617	char *str;
618
619	static const struct option opts[] = {
620	    { NULL, 0, NULL }
621	};
622
623	while ((opt = parse_options(&argc, &argv, opts)) != -1)
624		switch (opt) {
625		}
626
627	if (argc != 4)
628		errx(1, "missing arguments for 'diag phy set'");
629
630	errno = 0;
631	res = strtoul(argv[1], &end, 0);
632	if (errno != 0)
633		err(1, "register number");
634	if (*end != '\0')
635		errx(1, "malformed register number '%s'", argv[1]);
636	if (res > 0xff)
637		errx(1, "register number too large");
638	reg[0] = res;
639
640	errno = 0;
641	res = strtoul(argv[2], &end, 0);
642	if (errno != 0)
643		err(1, "mask");
644	if (*end != '\0')
645		errx(1, "malformed mask '%s'", argv[1]);
646	if (res > 0xff)
647		errx(1, "mask too large");
648	reg[1] = res;
649
650	errno = 0;
651	res = strtoul(argv[3], &end, 0);
652	if (errno != 0)
653		err(1, "value");
654	if (*end != '\0')
655		errx(1, "malformed value '%s'", argv[1]);
656	if (res > 0xff)
657		errx(1, "value too large");
658	reg[2] = res;
659
660	(void)diagif_get_phy(argv[0]);
661
662	if (asprintf(&str, "hw.atm.%s.phy_regs", argv[0]) == -1)
663		err(1, NULL);
664
665	if (sysctlbyname(str, NULL, NULL, reg, 3 * sizeof(uint8_t)))
666		err(1, "%s", str);
667
668	free(str);
669}
670
671static void
672diag_phy_print(int argc, char *argv[])
673{
674	int opt;
675	char *str;
676	size_t len, len1;
677	uint8_t *regs;
678	u_int type, i;
679	const struct utopia_print *p;
680
681	static int numeric;
682
683	static const struct option opts[] = {
684	    { "numeric", OPT_SIMPLE, &numeric },
685	    { NULL, 0, NULL }
686	};
687
688	while ((opt = parse_options(&argc, &argv, opts)) != -1)
689		switch (opt) {
690		}
691
692	if (argc != 1)
693		errx(1, "need device name for 'diag phy print'");
694
695	(void)diagif_get_phy(argv[0]);
696
697	if (asprintf(&str, "hw.atm.%s.phy_regs", argv[0]) == -1)
698		err(1, NULL);
699	len = 0;
700	if (sysctlbyname(str, NULL, &len, NULL, 0))
701		err(1, "'%s' not found", str);
702
703	regs = malloc(len);
704	if (regs == NULL)
705		err(1, NULL);
706
707	if (sysctlbyname(str, regs, &len, NULL, 0))
708		err(1, "'%s' not found", str);
709	free(str);
710
711	if (numeric) {
712		for (i = 0; i < len; i++) {
713			if (i % 16 == 0)
714				printf("%02x: ", i);
715			if (i % 16 == 8)
716				printf(" ");
717			printf(" %02x", regs[i]);
718			if (i % 16 == 15)
719				printf("\n");
720		}
721		if (i % 16 != 0)
722			printf("\n");
723	} else {
724		if (asprintf(&str, "hw.atm.%s.phy_type", argv[0]) == -1)
725			err(1, NULL);
726		len1 = sizeof(type);
727		if (sysctlbyname(str, &type, &len1, NULL, 0))
728			err(1, "'%s' not found", str);
729		free(str);
730
731		for (i = 0; i < sizeof(phy_print) / sizeof(phy_print[0]); i++)
732			if (type == phy_print[i].type)
733				break;
734		if (i == sizeof(phy_print) / sizeof(phy_print[0]))
735			errx(1, "unknown PHY chip type %u\n", type);
736
737		for (p = phy_print[i].tab;
738		    p < phy_print[i].tab + phy_print[i].len;
739		    p++) {
740			if (p->reg + utopia_addreg[p->type] > len)
741				/* don't have this register */
742				continue;
743
744			printf("%s:%*s", p->name, 40 - (int)strlen(p->name),"");
745
746			switch (p->type) {
747
748			  case UTP_REGT_BITS:
749				printf("%s\n", printb8(regs[p->reg], p->fmt));
750				break;
751
752			  case UTP_REGT_INT8:
753				printf("%#x\n", regs[p->reg]);
754				break;
755
756			  case UTP_REGT_INT10BITS:
757				printf("%#x %s\n", regs[p->reg] |
758				    ((regs[p->reg + 1] & 0x3) << 8),
759				    printb8(regs[p->reg + 1], p->fmt));
760				break;
761
762			  case UTP_REGT_INT12:
763				printf("%#x\n", regs[p->reg] |
764				    ((regs[p->reg + 1] & 0xf) << 8));
765				break;
766
767			  case UTP_REGT_INT16:
768				printf("%#x\n", regs[p->reg] |
769				    (regs[p->reg + 1] << 8));
770				break;
771
772			  case UTP_REGT_INT19:
773				printf("%#x\n", regs[p->reg] |
774				    (regs[p->reg + 1] << 8) |
775				    ((regs[p->reg + 2] & 0x7) << 16));
776				break;
777
778			  case UTP_REGT_INT20:
779				printf("%#x\n", regs[p->reg] |
780				    (regs[p->reg + 1] << 8) |
781				    ((regs[p->reg + 2] & 0xf) << 16));
782				break;
783
784			  case UTP_REGT_INT21:
785				printf("%#x\n", regs[p->reg] |
786				    (regs[p->reg + 1] << 8) |
787				    ((regs[p->reg + 2] & 0x1f) << 16));
788				break;
789
790			  default:
791				abort();
792			}
793		}
794	}
795	free(regs);
796}
797
798static void
799diag_phy_stats(int argc, char *argv[])
800{
801	int opt;
802	size_t len;
803	char *str;
804	struct utopia_stats1 stats1;
805	u_int foo;
806
807	static int clear;
808
809	static const struct option opts[] = {
810	    { "clear", OPT_SIMPLE, &clear },
811	    { NULL, 0, NULL }
812	};
813
814	while ((opt = parse_options(&argc, &argv, opts)) != -1)
815		switch (opt) {
816		}
817
818	if (argc != 1)
819		errx(1, "need device name for 'diag phy stats'");
820
821	(void)diagif_get_phy(argv[0]);
822
823	if (asprintf(&str, "hw.atm.%s.phy_stats", argv[0]) == -1)
824		err(1, NULL);
825
826	len = sizeof(stats1);
827	if (sysctlbyname(str, &stats1, &len,
828	    clear ? &foo : NULL, clear ? sizeof(foo) : 0))
829		err(1, "'%s' not found", str);
830	if (len < sizeof(stats1.version))
831		errx(1, "phy statistics too short %zu", len);
832
833	switch (stats1.version) {
834
835	  case 1:
836		if (len != sizeof(stats1))
837			errx(1, "bad phy stats length %zu (expecting %zu)",
838			    len, sizeof(stats1));
839		break;
840
841	  default:
842		errx(1, "unknown phy stats version %u", stats1.version);
843	}
844
845	free(str);
846
847	printf("rx_sbip:	%llu\n", (unsigned long long)stats1.rx_sbip);
848	printf("rx_lbip:	%llu\n", (unsigned long long)stats1.rx_lbip);
849	printf("rx_lfebe:	%llu\n", (unsigned long long)stats1.rx_lfebe);
850	printf("rx_pbip:	%llu\n", (unsigned long long)stats1.rx_pbip);
851	printf("rx_pfebe:	%llu\n", (unsigned long long)stats1.rx_pfebe);
852	printf("rx_cells:	%llu\n", (unsigned long long)stats1.rx_cells);
853	printf("rx_corr:	%llu\n", (unsigned long long)stats1.rx_corr);
854	printf("rx_uncorr:	%llu\n", (unsigned long long)stats1.rx_uncorr);
855	printf("rx_symerr:	%llu\n", (unsigned long long)stats1.rx_symerr);
856	printf("tx_cells:	%llu\n", (unsigned long long)stats1.tx_cells);
857}
858
859/*
860 * Fetch the table of open vccs
861 */
862void
863diagif_fetch_vcc(struct diagif *aif, int fd)
864{
865	struct ifreq ifr;
866
867	if (aif->vtab != NULL)
868		return;
869
870	strncpy(ifr.ifr_name, aif->ifname, IFNAMSIZ);
871	ifr.ifr_name[IFNAMSIZ - 1] = '\0';
872
873	aif->vtab = malloc(sizeof(*aif->vtab) + sizeof(aif->vtab->vccs[0]) *
874	    aif->mib.max_vccs);
875	if (aif->vtab == NULL)
876		err(1, NULL);
877	ifr.ifr_data = (caddr_t)aif->vtab;
878
879	if (ioctl(fd, SIOCATMGVCCS, &ifr) == -1)
880		err(1, "SIOCATMGVCCS");
881}
882
883/*
884 * Print the VCC table for this interface.
885 */
886static void
887print_channel(const struct diagif *aif)
888{
889	const struct atmio_vcc *v;
890
891	static const char *const aal_tab[] = {
892		[ATMIO_AAL_0] = "0",
893		[ATMIO_AAL_34] = "3/4",
894		[ATMIO_AAL_5] = "5",
895		[ATMIO_AAL_RAW] = "raw",
896	};
897	static const char *const traffic_tab[] = {
898		[ATMIO_TRAFFIC_UBR] = "ubr",
899		[ATMIO_TRAFFIC_CBR] = "cbr",
900		[ATMIO_TRAFFIC_ABR] = "abr",
901		[ATMIO_TRAFFIC_VBR] = "vbr",
902	};
903
904	for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) {
905		printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname,
906		    v->vpi, v->vci);
907
908		if (v->aal >= sizeof(aal_tab)/sizeof(aal_tab[0]) ||
909		    aal_tab[v->aal] == NULL)
910			printf("bad ");
911		else
912			printf("%-4s", aal_tab[v->aal]);
913
914		if (v->traffic >= sizeof(traffic_tab)/sizeof(traffic_tab[0]) ||
915		    traffic_tab[v->traffic] == NULL)
916			printf("bad     ");
917		else
918			printf("%-8s", traffic_tab[v->traffic]);
919
920		printf("%-6u%-6u%s\n", v->rmtu, v->tmtu,
921		    printb(v->flags, ATMIO_FLAGS));
922	}
923}
924
925/*
926 * Print the VCC table for this interface, traffic parameters.
927 */
928static void
929print_traffic(const struct diagif *aif)
930{
931	const struct atmio_vcc *v;
932
933	for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) {
934		printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname,
935		    v->vpi, v->vci);
936
937		switch (v->traffic) {
938
939		  case ATMIO_TRAFFIC_CBR:
940			printf("%u", v->tparam.pcr);
941			break;
942
943		  case ATMIO_TRAFFIC_UBR:
944			printf("%-8u                %u", v->tparam.pcr,
945			    v->tparam.mcr);
946			break;
947
948		  case ATMIO_TRAFFIC_VBR:
949			printf("%-8u%-8u%-8u", v->tparam.pcr, v->tparam.scr,
950			    v->tparam.mbs);
951			break;
952
953		  case ATMIO_TRAFFIC_ABR:
954			printf("%-8u                %-8u",
955			    v->tparam.pcr, v->tparam.mcr);
956			break;
957		}
958		printf("\n");
959	}
960}
961
962/*
963 * Print the VCC table for this interface, ABR traffic parameters.
964 */
965static void
966print_abr(const struct diagif *aif)
967{
968	const struct atmio_vcc *v;
969
970	for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) {
971		printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname,
972		    v->vpi, v->vci);
973
974		if (v->traffic == ATMIO_TRAFFIC_ABR) {
975			printf("%-8u%-8u%-4u%-4u%-5u%-5u%-5u%u",
976			    v->tparam.icr, v->tparam.tbe, v->tparam.nrm,
977			    v->tparam.trm, v->tparam.adtf, v->tparam.rif,
978			    v->tparam.rdf, v->tparam.cdf);
979		}
980		printf("\n");
981	}
982}
983
984static void
985diag_vcc_loop(void (*func)(const struct diagif *), const char *text,
986    int argc, char *argv[], int fd)
987{
988	struct diagif *aif;
989
990	heading_init();
991	if (argc == 0) {
992		TAILQ_FOREACH(aif, &diagif_list, link) {
993			diagif_fetch_vcc(aif, fd);
994			if (aif->vtab->count != 0) {
995				heading("%s", text);
996				(*func)(aif);
997			}
998		}
999
1000	} else {
1001		for (optind = 0; optind < argc; optind++) {
1002			TAILQ_FOREACH(aif, &diagif_list, link)
1003				if (strcmp(aif->ifname, argv[optind]) == 0) {
1004					diagif_fetch_vcc(aif, fd);
1005					if (aif->vtab->count != 0) {
1006						heading("%s", text);
1007						(*func)(aif);
1008					}
1009					break;
1010				}
1011			if (aif == NULL)
1012				warnx("no such interface '%s'", argv[optind]);
1013		}
1014	}
1015}
1016
1017static void
1018diag_vcc(int argc, char *argv[])
1019{
1020	int opt, fd;
1021
1022	static int channel, traffic, abr;
1023	static const struct option opts[] = {
1024	    { "abr", OPT_SIMPLE, &abr },
1025	    { "channel", OPT_SIMPLE, &channel },
1026	    { "traffic", OPT_SIMPLE, &traffic },
1027	    { NULL, 0, NULL }
1028	};
1029	static const char head_channel[] =
1030	    "Interface\n"
1031	    "Index Name     VPI VCI   AAL Traffic RxMTU TxMTU Flags\n";
1032	static const char head_traffic[] =
1033	    "Interface                Traffic parameters\n"
1034	    "Index Name     VPI VCI   PCR     SCR     MBS     MCR\n";
1035	static const char head_abr[] =
1036	    "Interface                ABR traffic parameters\n"
1037	    "Index Name     VPI VCI   ICR     TBE     NRM TRM ADTF RIF  RDF  "
1038	    "CDF\n";
1039
1040	while ((opt = parse_options(&argc, &argv, opts)) != -1)
1041		switch (opt) {
1042		}
1043
1044	fd = socket(PF_NATM, SOCK_STREAM, PROTO_NATMAAL5);
1045	if (fd < 0)
1046		err(1, "socket");
1047
1048	diagif_fetch();
1049	if (TAILQ_EMPTY(&diagif_list))
1050		errx(1, "no ATM interfaces found");
1051
1052	if (!channel && !traffic && !abr)
1053		channel = 1;
1054
1055	if (channel)
1056		diag_vcc_loop(print_channel, head_channel, argc, argv, fd);
1057	if (traffic)
1058		diag_vcc_loop(print_traffic, head_traffic, argc, argv, fd);
1059	if (abr)
1060		diag_vcc_loop(print_abr, head_abr, argc, argv, fd);
1061}
1062
1063/*
1064 * Print driver-internal statistics
1065 */
1066static void
1067diag_stats(int argc, char *argv[])
1068{
1069	int opt;
1070	char *str;
1071	size_t len;
1072	uint32_t *stats;
1073	struct diagif *aif;
1074	u_int i;
1075
1076	static const struct option opts[] = {
1077	    { NULL, 0, NULL }
1078	};
1079
1080	while ((opt = parse_options(&argc, &argv, opts)) != -1)
1081		switch (opt) {
1082		}
1083
1084	if (argc != 1)
1085		errx(1, "need one arg for 'diag stats'");
1086
1087	diagif_fetch();
1088	TAILQ_FOREACH(aif, &diagif_list, link)
1089		if (strcmp(aif->ifname, argv[0]) == 0)
1090			break;
1091
1092	if (aif == NULL)
1093		errx(1, "interface '%s' not found", argv[0]);
1094
1095	if (asprintf(&str, "hw.atm.%s.istats", argv[0]) == -1)
1096		err(1, NULL);
1097	len = 0;
1098	if (sysctlbyname(str, NULL, &len, NULL, 0))
1099		err(1, "'%s' not found", str);
1100
1101	stats = malloc(len);
1102	if (stats == NULL)
1103		err(1, NULL);
1104
1105	if (sysctlbyname(str, stats, &len, NULL, 0))
1106		err(1, "'%s' not found", str);
1107	free(str);
1108
1109	if (aif->mib.device >= sizeof(print_stats) / sizeof(print_stats[0]) ||
1110	    print_stats[aif->mib.device] == NULL)
1111		errx(1, "unknown stats format (%u)", aif->mib.device);
1112
1113	for (i = 0; print_stats[aif->mib.device][i] != NULL; i++) {
1114		if (i * sizeof(uint32_t) >= len)
1115			errx(1, "debug info too short (version mismatch?)");
1116		printf("%-22s%u\n", print_stats[aif->mib.device][i], stats[i]);
1117	}
1118	free(stats);
1119
1120	if (i != len / sizeof(uint32_t))
1121		errx(1, "debug info too long (version mismatch?)");
1122}
1123