1/*	$NetBSD: eshconfig.c,v 1.9 2009/04/15 05:50:20 lukem Exp $	*/
2
3/*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code contributed to The NetBSD Foundation by Kevin M. Lahey
8 * of the Numerical Aerospace Simulation Facility, NASA Ames Research
9 * Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34#ifndef lint
35__RCSID("$NetBSD: eshconfig.c,v 1.9 2009/04/15 05:50:20 lukem Exp $");
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/socket.h>
40#include <sys/ioctl.h>
41#include <sys/sockio.h>
42#include <fcntl.h>
43
44#include <net/if.h>
45#include <net/if_dl.h>
46#include <net/if_media.h>
47#include <netinet/in.h>
48#include <arpa/inet.h>
49
50#include <ctype.h>
51#include <err.h>
52#include <errno.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <unistd.h>
57
58#include <dev/ic/rrunnerreg.h>
59#include <dev/ic/rrunnervar.h>
60
61/*
62 * Create a simple pair of tables to map possible burst DMA values
63 * to the values required by the RoadRunner.
64 */
65
66struct map_dma {
67	int       value;
68	u_int32_t rr_value;
69};
70
71static struct map_dma read_dma_map[] =  {{0,    RR_PS_READ_DISABLE},
72				  {4,    RR_PS_READ_4},
73				  {16,   RR_PS_READ_16},
74				  {32,   RR_PS_READ_32},
75				  {64,   RR_PS_READ_64},
76				  {128,  RR_PS_READ_128},
77				  {256,  RR_PS_READ_256},
78				  {1024, RR_PS_READ_1024},
79				  {-1,    0}};
80
81static struct map_dma write_dma_map[] = {{0,    RR_PS_WRITE_DISABLE},
82				  {4,    RR_PS_WRITE_4},
83				  {16,   RR_PS_WRITE_16},
84				  {32,   RR_PS_WRITE_32},
85				  {64,   RR_PS_WRITE_64},
86				  {128,  RR_PS_WRITE_128},
87				  {256,  RR_PS_WRITE_256},
88				  {1024, RR_PS_WRITE_1024},
89				  {-1,   0}};
90
91/*
92 * The RunCode is composed of separate segments, each of which has a
93 * starting address in SRAM memory (for running) and in EEPROM
94 * (for storage).
95 */
96
97
98struct rr_seg_descr {
99	u_int32_t	start_addr;
100	u_int32_t	length;
101	u_int32_t	ee_addr;
102};
103
104static u_int32_t	do_map(int, struct map_dma *);
105static void 		eeprom_upload(const char *);
106static void 		eeprom_download(const char *);
107static u_int32_t 	rr_checksum(const u_int32_t *, int);
108static void 		esh_tune(void);
109static void 		esh_tune_eeprom(void);
110static void 		esh_tuning_stats(void);
111static void 		esh_stats(int);
112static void 		esh_reset(void);
113static int 		drvspec_ioctl(char *, int, int, int, caddr_t);
114__dead static void		usage(void);
115
116static char name[30] = "esh0";
117static int s;
118
119#define RR_EE_SIZE 8192
120static u_int32_t eeprom[RR_EE_SIZE];
121static u_int32_t runcode[RR_EE_SIZE];
122
123static struct ifdrv ifd;
124
125/* drvspec_ioctl
126 *
127 * We defined a driver-specific socket ioctl to allow us to tweak
128 * the characteristics of network devices.  This routine will
129 * provide a shortcut to calling this routine, which would otherwise
130 * require lots of costly and annoying setup.
131 */
132
133static int
134drvspec_ioctl(char *lname, int fd, int cmd, int len, caddr_t data)
135{
136	strcpy(ifd.ifd_name, lname);
137	ifd.ifd_cmd = cmd;
138	ifd.ifd_len = len;
139	ifd.ifd_data = data;
140
141	return ioctl(fd, SIOCSDRVSPEC, (caddr_t) &ifd);
142}
143
144static void
145usage(void)
146{
147	fprintf(stderr, "eshconfig -- configure Essential Communications "
148		"HIPPI driver\n");
149	fprintf(stderr, "-b burst size for read\n");
150	fprintf(stderr, "-c burst size for write:\n");
151	fprintf(stderr, "\t0 (no limit), 5, 16, 32, 64, 128, 256, 1024\n");
152	fprintf(stderr, "-d download filename\n");
153	fprintf(stderr, "-e write data to EEPROM\n");
154	fprintf(stderr, "-m minimum bytes DMA per direction\n");
155	fprintf(stderr, "-r bytes before DMA starts for read\n");
156	fprintf(stderr, "-s show statistics (-ss to display only non-zero)\n");
157	fprintf(stderr, "-t show tuning parameters\n");
158	fprintf(stderr, "-u upload filename [not working]\n");
159	fprintf(stderr, "-w bytes before DMA starts for write\n");
160	fprintf(stderr, "-i interrupt delay in usecs\n");
161	fprintf(stderr, "-x reset interface\n");
162	exit(1);
163}
164
165/* do_map
166 *
167 * Map between values for burst DMA sizes and the values expected by
168 * the RoadRunner chip.
169 */
170
171static u_int32_t
172do_map(int value, struct map_dma *map)
173{
174	int i;
175
176	for (i = 0; map[i].value != -1; i++)
177		if (value == map[i].value)
178			return map[i].rr_value;
179
180	return -1;
181}
182
183/* do_map_dma
184 *
185 * Reverse the mapping.
186 */
187
188static int
189do_map_dma(uint32_t value, struct map_dma *map)
190{
191	int i;
192
193	for (i = 0; map[i].value != -1; i++)
194		if (value == map[i].rr_value)
195			return map[i].value;
196
197	return 0;
198}
199
200
201static int dma_thresh_read = -1;
202static int dma_thresh_write = -1;
203static int dma_min_grab = -1;
204static int dma_max_read = -1;
205static int dma_max_write = -1;
206
207static int interrupt_delay = -1;
208
209static int get_stats = 0;
210static int get_tuning_stats = 0;
211static int eeprom_write = 0;
212static char *eeprom_download_filename = NULL;
213static char *eeprom_upload_filename = NULL;
214static int reset = 0;
215
216static struct rr_tuning rr_tune;
217struct rr_eeprom rr_eeprom;
218struct rr_stats rr_stats;
219
220int
221main(int argc, char *argv[])
222{
223	int ch;
224
225	/* Parse command-line options */
226
227	while ((ch = getopt(argc, argv, "b:c:d:ei:m:r:stu:w:x")) != -1) {
228		switch (ch) {
229		case 'b':
230			dma_max_read = atoi(optarg);
231			break;
232		case 'c':
233			dma_max_write = atoi(optarg);
234			break;
235		case 'd':
236			eeprom_download_filename = optarg;
237			break;
238		case 'e':
239			eeprom_write++;
240			break;
241		case 'i':
242			interrupt_delay = atoi(optarg);
243			break;
244		case 'm':
245			dma_min_grab = atoi(optarg);
246			break;
247		case 'r':
248			dma_thresh_read = atoi(optarg);
249			break;
250		case 's':
251			get_stats++;
252			break;
253		case 't':
254			get_tuning_stats++;
255			break;
256		case 'u':
257			eeprom_upload_filename = optarg;
258			break;
259		case 'w':
260			dma_thresh_write = atoi(optarg);
261			break;
262		case 'x':
263			reset = 1;
264			break;
265		default:
266			usage();
267			/* NOTREACHED */
268		}
269	}
270	argc -= optind;
271	argv += optind;
272
273	if (argc > 1)
274		usage();
275	if (argc == 1) {
276		(void) strncpy(name, argv[0], sizeof(name));
277		argc--; argv++;
278	}
279
280	s = socket(AF_INET, SOCK_DGRAM, 0);
281	if (s < 0)
282		err(1, "socket");
283
284	if (eeprom_upload_filename)
285		eeprom_upload(eeprom_upload_filename);
286
287	if (eeprom_download_filename)
288		eeprom_download(eeprom_download_filename);
289
290	if (get_stats) {
291		esh_stats(get_stats);
292	}
293
294    	if (drvspec_ioctl(name, s, EIOCGTUNE, sizeof(struct rr_tuning),
295			  (caddr_t) &rr_tune) < 0) {
296		err(1, "ioctl(EIOCGTUNE)");
297	}
298
299	if (get_tuning_stats) {
300		if (get_stats)
301			printf("\n");
302		esh_tuning_stats();
303	}
304
305	if (eeprom_write || dma_thresh_read != -1 ||
306	    dma_thresh_write != -1 ||
307	    dma_min_grab != -1 ||
308	    dma_max_read != -1 ||
309	    dma_max_write != -1 ||
310	    interrupt_delay != -1) {
311		esh_tune();
312	}
313
314	if (eeprom_write)
315		esh_tune_eeprom();
316
317	if (reset)
318		esh_reset();
319
320	exit(0);
321}
322
323static void
324esh_tune(void)
325{
326	dma_max_read = do_map(dma_max_read, read_dma_map);
327	if (dma_max_read != -1) {
328		rr_tune.rt_pci_state &= ~RR_PS_READ_MASK;
329		rr_tune.rt_pci_state |= dma_max_read;
330	}
331
332	dma_max_write = do_map(dma_max_write, write_dma_map);
333	if (dma_max_write != -1) {
334		rr_tune.rt_pci_state &= ~RR_PS_WRITE_MASK;
335		rr_tune.rt_pci_state |= dma_max_write;
336	}
337
338	if (dma_min_grab != -1) {
339		if ((dma_min_grab & (RR_PS_MIN_DMA_MASK >> RR_PS_MIN_DMA_SHIFT))
340		    != dma_min_grab)
341			usage();
342		rr_tune.rt_pci_state &= ~RR_PS_MIN_DMA_MASK;
343		rr_tune.rt_pci_state |=
344			(dma_min_grab << RR_PS_MIN_DMA_SHIFT);
345	}
346
347	if (dma_thresh_write != -1) {
348		if (dma_thresh_write < 1 || dma_thresh_write > RR_DW_THRESHOLD_MAX)
349			usage();
350		rr_tune.rt_dma_write_state &= ~RR_DW_THRESHOLD_MASK;
351		rr_tune.rt_dma_write_state |=
352			dma_thresh_write << RR_DW_THRESHOLD_SHIFT;
353	}
354
355	if (dma_thresh_read != -1) {
356		if (dma_thresh_read < 1 || dma_thresh_read > RR_DR_THRESHOLD_MAX)
357			usage();
358		rr_tune.rt_dma_read_state &= ~RR_DR_THRESHOLD_MASK;
359		rr_tune.rt_dma_read_state |=
360			dma_thresh_read << RR_DR_THRESHOLD_SHIFT;
361	}
362
363	rr_tune.rt_stats_timer = ESH_STATS_TIMER_DEFAULT;
364
365	if (interrupt_delay != -1)
366		rr_tune.rt_interrupt_timer = interrupt_delay;
367
368	if (drvspec_ioctl(name, s, EIOCSTUNE, sizeof(struct rr_tuning),
369			  (caddr_t) &rr_tune) < 0)
370		err(1, "EIOCSTUNE");
371}
372
373/* esh_tune_eeprom
374 *
375 * Store the current tuning data into the eeprom.
376 */
377
378static void
379esh_tune_eeprom(void)
380{
381#define LAST (RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN)
382#define FIRST (RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN)
383
384	u_int32_t	tuning_data[LAST + 1];
385
386	rr_eeprom.ifr_buffer = tuning_data;
387	rr_eeprom.ifr_length = sizeof(tuning_data);
388	rr_eeprom.ifr_offset = 0;
389
390	if (drvspec_ioctl(name, s, EIOCGEEPROM, sizeof(struct rr_eeprom),
391			  (caddr_t) &rr_eeprom) == -1)
392		err(6, "ioctl to retrieve tuning information from EEPROM");
393
394	tuning_data[RR_EE_PCI_STATE / RR_EE_WORD_LEN] =
395		rr_tune.rt_pci_state;
396	tuning_data[RR_EE_DMA_WRITE_STATE / RR_EE_WORD_LEN] =
397		rr_tune.rt_dma_write_state;
398	tuning_data[RR_EE_DMA_READ_STATE / RR_EE_WORD_LEN] =
399		rr_tune.rt_dma_read_state;
400	tuning_data[RR_EE_INTERRUPT_TIMER / RR_EE_WORD_LEN] = rr_tune.rt_interrupt_timer;
401	tuning_data[RR_EE_STATS_TIMER / RR_EE_WORD_LEN] =
402		ESH_STATS_TIMER_DEFAULT;
403
404	tuning_data[RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN] =
405		rr_checksum(&tuning_data[FIRST], LAST - FIRST);
406
407	rr_eeprom.ifr_buffer = tuning_data;
408	rr_eeprom.ifr_length = sizeof(tuning_data);
409	rr_eeprom.ifr_offset = 0;
410
411	if (drvspec_ioctl(name, s, EIOCSEEPROM, sizeof(struct rr_eeprom),
412			  (caddr_t) &rr_eeprom) == -1)
413		err(7, "ioctl to set tuning information from EEPROM");
414}
415
416/* eeprom_upload
417 *
418 * Upload the EEPROM from the card and store in the data file.
419 */
420
421static void
422eeprom_upload(const char *filename)
423{
424	int fd;
425
426	bzero(eeprom, sizeof(eeprom));
427	if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) < 0)
428		err(4, "Couldn't open %s for output", filename);
429
430	rr_eeprom.ifr_buffer = eeprom;
431	rr_eeprom.ifr_length = sizeof(eeprom);
432	rr_eeprom.ifr_offset = 0;
433
434	if (drvspec_ioctl(name, s, EIOCGEEPROM, sizeof(struct rr_eeprom),
435			  (caddr_t) &rr_eeprom) == -1)
436		err(5, "ioctl to retrieve all of EEPROM");
437
438	write(fd, eeprom, sizeof(eeprom));
439	close(fd);
440}
441
442/* eeprom_download
443 *
444 * Download into eeprom the contents of a file.  The file is made up
445 * of ASCII text;  the first three characters can be ignored, the next
446 * four hex characters define an address, the next two characters can
447 * be ignored, and the final eight hex characters are the data.
448 */
449
450static void
451eeprom_download(const char *filename)
452{
453	FILE *fp;
454	struct rr_seg_descr *segd = NULL, *nsegd;
455	char id[BUFSIZ];
456	char pad[BUFSIZ];
457	char buffer[BUFSIZ];
458	u_int32_t address = 0;
459	u_int32_t last_address = 0;
460	u_int32_t value;
461	u_int32_t length = 0;
462	int segment_start = 0;
463	int seg_table_start;
464	int seg_count_offset;
465	int phase2_start;
466	int phase2_checksum;
467	int in_segment = 0;
468	int segment = 0;
469	int eof = 0;
470	int line = 0;
471	int zero_count = 0;
472	int i;
473
474	/* Clear out eeprom storage space, then read in the value on the card */
475
476	bzero(eeprom, sizeof(eeprom));
477	bzero(runcode, sizeof(runcode));
478
479	rr_eeprom.ifr_buffer = eeprom;
480	rr_eeprom.ifr_length = sizeof(eeprom);
481	rr_eeprom.ifr_offset = 0;
482	if (drvspec_ioctl(name, s, EIOCGEEPROM, sizeof(struct rr_eeprom),
483			  (caddr_t) &rr_eeprom) == -1)
484		err(5, "ioctl to retrieve EEPROM");
485
486	/*
487	 * Open the input file and proceed to read the data file, storing
488	 * the data and counting the number of segments.
489	 */
490
491	if ((fp = fopen(filename, "r")) == NULL)
492		err(2, "fopen");
493
494	do {
495		if (fgets(buffer, sizeof(buffer), fp) == NULL)
496			errx(3, "premature, unmarked end of file, line %d", line);
497		line++;
498
499		if (!strncmp(buffer + 7, "01", 2)) { /* check for EOF marker... */
500			eof = 1;
501		} else {
502			sscanf(buffer, "%3s%4x%2s%8x%2s",
503			       id, &address, pad, &value, pad);
504			if (strcmp(id, ":04") != 0)
505				errx(3, "bad initial id on line %d", line);
506		}
507
508		/*
509		 * Check to see if we terminated a segment;  this happens
510		 * when we are at end of file, or we hit a non-sequential
511		 * address value, or we see three or more zeroes in a row.
512		 */
513
514		if ((length == RR_EE_SEG_SIZE || eof || zero_count >= 3 ||
515		     (last_address && last_address != address - 1)) && in_segment) {
516
517			length -= zero_count;
518			segment_start += length;
519			segd[segment].length = length;
520
521			printf("segment %d, %d words\n", segment, length);
522			last_address = in_segment = zero_count = length = 0;
523			segment++;
524		}
525
526		if (eof)
527			break;
528
529		/* Skip zero values starting a segment */
530
531		if (!in_segment && value == 0)
532			continue;
533		last_address = address;
534
535		/*
536		 * If we haven't started a segment yet, do so now.
537		 * Store away the address at which this code should be placed
538		 * in memory and the address of the code in the EEPROM.
539		 */
540
541		if (!in_segment) {
542			in_segment = 1;
543
544			nsegd = realloc(segd, sizeof(struct rr_seg_descr) * (segment + 1));
545			if (nsegd == NULL)
546				err(6, "couldn't realloc segment descriptor space");
547			segd = nsegd;
548
549			segd[segment].start_addr = address * sizeof(u_int32_t);
550			segd[segment].ee_addr = segment_start;
551		}
552
553		/* Keep track of consecutive zeroes */
554
555		if (in_segment && value == 0)
556			zero_count++;
557		else
558			zero_count = 0;
559
560		/* Store away the actual data */
561
562		runcode[segment_start + length++] = value;
563	} while (!eof);
564	fclose(fp);
565
566	/* Now that we have a segment count, fill in the EEPROM image. */
567
568	seg_count_offset = eeprom[RR_EE_RUNCODE_SEGMENTS / RR_EE_WORD_LEN];
569	seg_count_offset = (seg_count_offset - RR_EE_OFFSET) / RR_EE_WORD_LEN;
570	seg_table_start = seg_count_offset + 1;
571	phase2_checksum = seg_table_start + 3 * segment;
572	phase2_start = eeprom[RR_EE_PHASE2_EE_START / RR_EE_WORD_LEN];
573	phase2_start = (phase2_start - RR_EE_OFFSET) / RR_EE_WORD_LEN;
574
575	printf("segment table start = %x, segments = %d\n",
576	       seg_table_start, eeprom[seg_count_offset]);
577
578	/* We'll fill in anything after the segment count, so clear it */
579
580	bzero(eeprom + seg_count_offset,
581	      sizeof(eeprom) - seg_count_offset * sizeof(eeprom[0]));
582
583	eeprom[seg_count_offset] = segment;
584
585	for (i = 0; i < segment; i++)
586		segd[i].ee_addr = RR_EE_OFFSET +
587			(segd[i].ee_addr + phase2_checksum + 1) * RR_EE_WORD_LEN;
588
589	bcopy(segd, &eeprom[seg_table_start],
590	      sizeof(struct rr_seg_descr) * segment);
591
592	bcopy(runcode, &eeprom[phase2_checksum + 1],
593	      segment_start * sizeof(u_int32_t));
594
595	eeprom[phase2_checksum] = rr_checksum(&eeprom[phase2_start],
596					      phase2_checksum - phase2_start);
597
598	eeprom[segment_start + phase2_checksum + 1] =
599		rr_checksum(&eeprom[phase2_checksum + 1], segment_start);
600
601	printf("phase2 checksum %x, runcode checksum %x\n",
602	       eeprom[phase2_checksum],
603	       eeprom[segment_start + phase2_checksum + 1]);
604
605	rr_eeprom.ifr_buffer = eeprom;
606	rr_eeprom.ifr_length = sizeof(eeprom);
607	rr_eeprom.ifr_offset = 0;
608	if (drvspec_ioctl(name, s, EIOCSEEPROM, sizeof(struct rr_eeprom),
609			  (caddr_t) &rr_eeprom) == -1)
610		err(5, "ioctl to retrieve EEPROM");
611}
612
613/* rr_checksum
614 *
615 * Perform checksum on RunCode.  Length is in words.  Ugh.
616 */
617
618static u_int32_t
619rr_checksum(const u_int32_t *data, int length)
620{
621	u_int32_t checksum = 0;
622
623	while (length--)
624		checksum += *data++;
625
626	checksum = 0 - checksum;
627	return checksum;
628}
629
630static struct stats_values {
631	int	 offset;
632	const char *name;
633} stats_values[] = {
634	{0x04, "receive rings created"},
635	{0x08, "receive rings deleted"},
636	{0x0c, "interrupts"},
637	{0x10, "event overflows"},
638	{0x14, "invalid commands"},
639	{0x18, "DMA read errors"},
640	{0x1c, "DMA write errors"},
641	{0x20, "stats updates per timer"},
642	{0x24, "stats updates per host"},
643	{0x28, "watchdog"},
644	{0x2c, "trace"},
645	{0x30, "link ready sync established"},
646	{0x34, "GLink errors"},
647	{0x38, "alternating flag errors"},
648	{0x3c, "overhead bit 8 synchronized"},
649	{0x40, "remote serial parity errors"},
650	{0x44, "remote parallel parity errors"},
651	{0x48, "remote loopback requested"},
652	{0x50, "transmit connections established"},
653	{0x54, "transmit connections rejected"},
654	{0x58, "transmit connections retried"},
655	{0x5c, "transmit connections timed out"},
656	{0x60, "transmit connections disconnected"},
657	{0x64, "transmit parity errors"},
658	{0x68, "packets sent"},
659	{0x74, "short first burst sent"},
660	{0x80, "transmit data not moving"},
661	{0x90, "receive connections accepted"},
662	{0x94, "receive connections rejected -- bad parity"},
663	{0x98, "receive connections rejected -- 64-bit width"},
664	{0x9c, "receive connections rejected -- buffers low"},
665	{0xa0, "receive connections disconnected"},
666	{0xa4, "receive connections with no data"},
667	{0xa8, "packets received"},
668	{0xb4, "short first burst received"},
669	{0xc0, "receive parity error"},
670	{0xc4, "receive LLRC error"},
671	{0xc8, "receive burst size error"},
672	{0xcc, "receive state error"},
673	{0xd0, "receive ready ULP"},
674	{0xd4, "receive invalid ULP"},
675	{0xd8, "receive packets flow control due to buffer space"},
676	{0xdc, "receive packets flow control due to descriptors"},
677	{0xe0, "receive ring fulls"},
678	{0xe4, "packet length errors"},
679	{0xe8, "packets with checksum error"},
680	{0xec, "packets dropped"},
681	{0xf0, "ring low on space"},
682	{0xf4, "data in ring at close"},
683	{0xf8, "receives to ring not moving data"},
684	{0xfc, "receiver idles"},
685	{0, 0},
686};
687
688static void
689esh_reset(void)
690{
691	if (drvspec_ioctl(name, s, EIOCRESET, 0, 0) < 0)
692		err(1, "ioctl(EIOCRESET)");
693}
694
695static void
696esh_stats(int lget_stats)
697{
698	u_int32_t	*stats;
699	long long value;
700	int offset;
701
702	if (drvspec_ioctl(name, s, EIOCGSTATS, sizeof(struct rr_stats),
703			  (caddr_t) &rr_stats) < 0)
704		err(1, "ioctl(EIOCGTUNE)");
705
706	stats = rr_stats.rs_stats;
707
708	value = (((long long) stats[0x78 / 4]) << 32) | stats[0x7c / 4];
709	if (lget_stats == 1 || value > 0)
710		printf("%12lld bytes sent\n", value);
711	value = ((long long) stats[0xb8 / 4] << 32) | stats[0xbc / 4];
712	if (lget_stats == 1 || value > 0)
713		printf("%12lld bytes received\n", value);
714
715	for (offset = 0; stats_values[offset].offset != 0; offset++) {
716		if (lget_stats == 1 || stats[stats_values[offset].offset / 4] > 0)
717			printf("%12d %s\n", stats[stats_values[offset].offset / 4],
718			       stats_values[offset].name);
719	}
720}
721
722
723static void
724esh_tuning_stats(void)
725{
726	printf("rt_mode_and_status = %x\n",
727	       rr_tune.rt_mode_and_status);
728	printf("rt_conn_retry_count = %x\n",
729	       rr_tune.rt_conn_retry_count);
730	printf("rt_conn_retry_timer = %x\n",
731	       rr_tune.rt_conn_retry_timer);
732	printf("rt_conn_timeout = %x\n", rr_tune.rt_conn_timeout);
733	printf("rt_stats_timer = %x\n", rr_tune.rt_stats_timer);
734	printf("rt_interrupt_timer = %x\n",
735	       rr_tune.rt_interrupt_timer);
736	printf("rt_tx_timeout = %x\n", rr_tune.rt_tx_timeout);
737	printf("rt_rx_timeout = %x\n", rr_tune.rt_rx_timeout);
738	printf("rt_pci_state = %x"
739	       "     min DMA %x  read max %x write max %x\n",
740	       rr_tune.rt_pci_state,
741	       (rr_tune.rt_pci_state & RR_PS_MIN_DMA_MASK)
742	       >> RR_PS_MIN_DMA_SHIFT,
743	       do_map_dma(rr_tune.rt_pci_state & RR_PS_READ_MASK,
744			  read_dma_map),
745	       do_map_dma(rr_tune.rt_pci_state & RR_PS_WRITE_MASK,
746			  write_dma_map));
747	printf("rt_dma_write_state = %x\n",
748	       rr_tune.rt_dma_write_state);
749	printf("rt_dma_read_state = %x\n", rr_tune.rt_dma_read_state);
750	printf("rt_driver_param = %x\n", rr_tune.rt_driver_param);
751
752}
753
754