Adding eshconfig, used to configure esh (HIPPI network interface)

This commit is contained in:
kml 1998-05-16 18:55:17 +00:00
parent e30b76288b
commit d073a8144e
4 changed files with 877 additions and 2 deletions

View File

@ -1,11 +1,11 @@
# $NetBSD: Makefile,v 1.91 1998/03/15 01:16:32 lukem Exp $
# $NetBSD: Makefile,v 1.92 1998/05/16 18:55:17 kml Exp $
# from: @(#)Makefile 5.20 (Berkeley) 6/12/93
#
# not yet done: catman
SUBDIR= ac accton amd apm apmd arp bad144 bootp \
chown chroot chrtbl config cron dbsym dev_mkdb \
dhcp diskpart dumpfs dumplfs edquota eeprom grfconfig \
dhcp diskpart dumpfs dumplfs edquota eeprom eshconfig grfconfig \
grfinfo gspa hilinfo inetd iostat ipf iteconfig kgmon \
kvm_mkdb lastlogin lpr map-mbone mdconfig mdsetimage \
mopd mountd mrinfo mrouted mtrace mtree named \

View File

@ -0,0 +1,6 @@
# $NetBSD: Makefile,v 1.1 1998/05/16 18:55:17 kml Exp $
PROG= eshconfig
MAN= eshconfig.8
.include <bsd.prog.mk>

View File

@ -0,0 +1,119 @@
.\" $NetBSD: eshconfig.8,v 1.1 1998/05/16 18:55:18 kml Exp $
.\"
.\" Copyright (c) 1997 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Kevin Lahey of the Numerical Aerospace Simulation Facility,
.\" NASA Ames Research Center.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the NetBSD
.\" Foundation, Inc. and its contributors.
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
.\" contributors may be used to endorse or promote products derived
.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd February 3, 1998
.Dt ESHCONFIG 8
.Os NetBSD 1.4
.Sh NAME
.Nm eshconfig
.Nd configure Essential Communications' HIPPI network interface
.Sh SYNOPSIS
.Nm eshconfig
.Op Fl b Ar bytes
.Op Fl c Ar bytes
.Op Fl d Ar filename
.Op Fl e
.Op Fl m Ar bytes
.Op Fl r Ar bytes
.Op Fl s
.Op Fl t
.Op Fl u Ar filename
.Op Fl w Ar bytes
.Op Ar interface
.Sh DESCRIPTION
.Nm
is used to configure device-specific parameters and download new firmware
to the Essential Communications RoadRunner-based HIPPI network interface.
The interface is very sensitive to the DMA performance characteristics
of the host, and so requires careful tuning to achieve reasonable
performance.
In addition, firmware is likely to change frequently, which necessitates
a reasonably easy way to update that firmware.
.Pp
Available operands for
.Nm eshconfig :
.Bl -tag -width Ds
.It Fl b
Adjust the burst size for read (by NIC of host memory) DMA.
.It Fl c
Adjust the burst size for write (by NIC of host memory) DMA.
.It Fl d
Filename for file to download into NIC firmware.
This must be a file in the standard Essential format, with :04 preceding
every line, and a tag line at the end indicating the characteristics
of the firmware file.
.It Fl e
Write data to EEPROM.
Normally, setting tuning parameters will only persist until the
system is rebooted.
Setting this parameter ensures that the changes will be written to
EEPROM.
.It Fl m
Minimum number of bytes to DMA in one direction (read or write)
before allowing a DMA in the other direction. Tuning this prevents
one direction from dominating the flow of bytes, and artificially
throttling the NIC.
.It Fl r
Bytes before DMA starts for read (from host to NIC).
This controls how soon the DMA is triggered; until this many bytes
are requested, the DMA will not begin.
.It Fl s
Show statistics for the HIPPI NIC.
Repeat the option to suppress non-zero statistics.
.It Fl t
Show current tuning parameters on the host.
.It Fl u
Name of file to which the NIC firmware should be uploaded.
Not currently supported.
.It Fl w
Number of bytes required before write (from NIC to host) DMA
is started.
Until this many bytes are ready to be written, the DMA will not start.
.Pp
Only the super-user may modify the configuration of a network interface.
.Sh DIAGNOSTICS
Messages indicating the specified interface does not exist
or the user is not privileged and
tried to alter an interface's configuration.
.Sh SEE ALSO
.Xr ifconfig 8 ,
.Xr esh 4
.Sh HISTORY
The
.Nm
command first appeared in
.Bx NetBSD 1.4.

View File

@ -0,0 +1,750 @@
/* $NetBSD: eshconfig.c,v 1.1 1998/05/16 18:55:18 kml Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code contributed to The NetBSD Foundation by Kevin M. Lahey
* of the Numerical Aerospace Simulation Facility, NASA Ames Research
* Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: eshconfig.c,v 1.1 1998/05/16 18:55:18 kml Exp $");
#endif /* not lint */
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <fcntl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dev/ic/rrunnerreg.h>
#include <dev/ic/rrunnervar.h>
/*
* Create a simple pair of tables to map possible burst DMA values
* to the values required by the RoadRunner.
*/
struct map_dma {
int value;
u_int32_t rr_value;
};
struct map_dma read_dma_map[] = {{0, RR_PS_READ_DISABLE},
{4, RR_PS_READ_4},
{16, RR_PS_READ_16},
{32, RR_PS_READ_32},
{64, RR_PS_READ_64},
{128, RR_PS_READ_128},
{256, RR_PS_READ_256},
{1024, RR_PS_READ_1024},
{-1, 0}};
struct map_dma write_dma_map[] = {{0, RR_PS_WRITE_DISABLE},
{4, RR_PS_WRITE_4},
{16, RR_PS_WRITE_16},
{32, RR_PS_WRITE_32},
{64, RR_PS_WRITE_64},
{128, RR_PS_WRITE_128},
{256, RR_PS_WRITE_256},
{1024, RR_PS_WRITE_1024},
{-1, 0}};
/*
* The RunCode is composed of separate segments, each of which has a
* starting address in SRAM memory (for running) and in EEPROM
* (for storage).
*/
struct rr_seg_descr {
u_int32_t start_addr;
u_int32_t length;
u_int32_t ee_addr;
};
static u_int32_t do_map __P((int, struct map_dma *));
static void eeprom_upload __P((const char *));
static void eeprom_download __P((const char *));
static u_int32_t rr_checksum __P((const u_int32_t *, int));
static void esh_tune __P((void));
static void esh_tune_eeprom __P((void));
static void esh_tuning_stats __P((void));
static void esh_stats __P((int));
static int drvspec_ioctl __P((char *, int, int, int, caddr_t));
static void usage __P((void));
int main __P((int, char *[]));
struct ifreq ifr;
char name[30] = "esh0";
int s;
#define RR_EE_SIZE 8192
u_int32_t eeprom[RR_EE_SIZE];
u_int32_t runcode[RR_EE_SIZE];
struct ifdrv ifd;
/* drvspec_ioctl
*
* We defined a driver-specific socket ioctl to allow us to tweak
* the characteristics of network devices. This routine will
* provide a shortcut to calling this routine, which would otherwise
* require lots of costly and annoying setup.
*/
static int
drvspec_ioctl(char *name, int fd, int cmd, int len, caddr_t data)
{
strcpy(ifd.ifd_name, name);
ifd.ifd_cmd = cmd;
ifd.ifd_len = len;
ifd.ifd_data = data;
return ioctl(fd, SIOCSDRVSPEC, (caddr_t) &ifd);
}
static void
usage()
{
fprintf(stderr, "eshconfig -- configure Essential Communications "
"HIPPI driver\n");
fprintf(stderr, "-b burst size for read\n");
fprintf(stderr, "-c burst size for write:\n");
fprintf(stderr, "\t0 (no limit), 5, 16, 32, 64, 128, 256, 1024\n");
fprintf(stderr, "-d download filename\n");
fprintf(stderr, "-e write data to EEPROM\n");
fprintf(stderr, "-m minimum bytes DMA per direction\n");
fprintf(stderr, "-r bytes before DMA starts for read\n");
fprintf(stderr, "-s show statistics (-ss to display only non-zero)\n");
fprintf(stderr, "-t show tuning parameters\n");
fprintf(stderr, "-u upload filename [not working]\n");
fprintf(stderr, "-w bytes before DMA starts for write\n");
fprintf(stderr, "-i interrupt delay in usecs\n");
exit(1);
}
/* do_map
*
* Map between values for burst DMA sizes and the values expected by
* the RoadRunner chip.
*/
static u_int32_t
do_map(int value, struct map_dma *map)
{
int i;
for (i = 0; map[i].value != -1; i++)
if (value == map[i].value)
return map[i].rr_value;
return -1;
}
/* do_map_dma
*
* Reverse the mapping.
*/
static int
do_map_dma(int value, struct map_dma *map)
{
int i;
for (i = 0; map[i].value != -1; i++)
if (value == map[i].rr_value)
return map[i].value;
return 0;
}
int dma_thresh_read = -1;
int dma_thresh_write = -1;
int dma_min_grab = -1;
int dma_max_read = -1;
int dma_max_write = -1;
int interrupt_delay = -1;
int get_stats = 0;
int get_tuning_stats = 0;
int eeprom_write = 0;
char *eeprom_download_filename = NULL;
char *eeprom_upload_filename = NULL;
struct rr_tuning rr_tune;
struct rr_eeprom rr_eeprom;
struct rr_stats rr_stats;
int
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
int ch;
/* Parse command-line options */
while ((ch = getopt(argc, argv, "b:c:d:ei:m:r:stu:w:")) != -1) {
switch (ch) {
case 'b':
dma_max_read = atoi(optarg);
break;
case 'c':
dma_max_write = atoi(optarg);
break;
case 'd':
eeprom_download_filename = optarg;
break;
case 'e':
eeprom_write++;
break;
case 'i':
interrupt_delay = atoi(optarg);
break;
case 'm':
dma_min_grab = atoi(optarg);
break;
case 'r':
dma_thresh_read = atoi(optarg);
break;
case 's':
get_stats++;
break;
case 't':
get_tuning_stats++;
break;
case 'u':
eeprom_upload_filename = optarg;
break;
case 'w':
dma_thresh_write = atoi(optarg);
break;
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (argc > 1)
usage();
if (argc == 1) {
(void) strncpy(name, argv[0], sizeof(name));
argc--; argv++;
}
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
err(1, "socket");
if (eeprom_upload_filename)
eeprom_upload(eeprom_upload_filename);
if (eeprom_download_filename)
eeprom_download(eeprom_download_filename);
if (get_stats) {
esh_stats(get_stats);
}
if (drvspec_ioctl(name, s, EIOCGTUNE, sizeof(struct rr_tuning),
(caddr_t) &rr_tune) < 0) {
err(1, "ioctl(EIOCGTUNE)");
}
if (get_tuning_stats) {
if (get_stats)
printf("\n");
esh_tuning_stats();
}
if (eeprom_write || dma_thresh_read != -1 ||
dma_thresh_write != -1 ||
dma_min_grab != -1 ||
dma_max_read != -1 ||
dma_max_write != -1 ||
interrupt_delay != -1) {
esh_tune();
}
if (eeprom_write)
esh_tune_eeprom();
exit(0);
}
static void
esh_tune()
{
dma_max_read = do_map(dma_max_read, read_dma_map);
if (dma_max_read != -1) {
rr_tune.rt_pci_state &= ~RR_PS_READ_MASK;
rr_tune.rt_pci_state |= dma_max_read;
}
dma_max_write = do_map(dma_max_write, write_dma_map);
if (dma_max_write != -1) {
rr_tune.rt_pci_state &= ~RR_PS_WRITE_MASK;
rr_tune.rt_pci_state |= dma_max_write;
}
if (dma_min_grab != -1) {
if ((dma_min_grab & (RR_PS_MIN_DMA_MASK >> RR_PS_MIN_DMA_SHIFT))
!= dma_min_grab)
usage();
rr_tune.rt_pci_state &= ~RR_PS_MIN_DMA_MASK;
rr_tune.rt_pci_state |=
(dma_min_grab << RR_PS_MIN_DMA_SHIFT);
}
if (dma_thresh_write != -1) {
if (dma_thresh_write < 1 || dma_thresh_write > RR_DW_THRESHOLD_MAX)
usage();
rr_tune.rt_dma_write_state &= ~RR_DW_THRESHOLD_MASK;
rr_tune.rt_dma_write_state |=
dma_thresh_write << RR_DW_THRESHOLD_SHIFT;
}
if (dma_thresh_read != -1) {
if (dma_thresh_read < 1 || dma_thresh_read > RR_DR_THRESHOLD_MAX)
usage();
rr_tune.rt_dma_read_state &= ~RR_DR_THRESHOLD_MASK;
rr_tune.rt_dma_read_state |=
dma_thresh_read << RR_DR_THRESHOLD_SHIFT;
}
rr_tune.rt_stats_timer = ESH_STATS_TIMER_DEFAULT;
if (interrupt_delay != -1)
rr_tune.rt_interrupt_timer = interrupt_delay;
if (drvspec_ioctl(name, s, EIOCSTUNE, sizeof(struct rr_tuning),
(caddr_t) &rr_tune) < 0)
err(1, "EIOCSTUNE");
}
/* esh_tune_eeprom
*
* Store the current tuning data into the eeprom.
*/
static void
esh_tune_eeprom()
{
#define LAST (RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN)
#define FIRST (RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN)
u_int32_t tuning_data[LAST + 1];
rr_eeprom.ifr_buffer = tuning_data;
rr_eeprom.ifr_length = sizeof(tuning_data);
rr_eeprom.ifr_offset = 0;
if (drvspec_ioctl(name, s, EIOCGEEPROM, sizeof(struct rr_eeprom),
(caddr_t) &rr_eeprom) == -1)
err(6, "ioctl to retrieve tuning information from EEPROM");
tuning_data[RR_EE_PCI_STATE / RR_EE_WORD_LEN] =
rr_tune.rt_pci_state;
tuning_data[RR_EE_DMA_WRITE_STATE / RR_EE_WORD_LEN] =
rr_tune.rt_dma_write_state;
tuning_data[RR_EE_DMA_READ_STATE / RR_EE_WORD_LEN] =
rr_tune.rt_dma_read_state;
tuning_data[RR_EE_INTERRUPT_TIMER / RR_EE_WORD_LEN] = rr_tune.rt_interrupt_timer;
tuning_data[RR_EE_STATS_TIMER / RR_EE_WORD_LEN] =
ESH_STATS_TIMER_DEFAULT;
tuning_data[RR_EE_HEADER_CHECKSUM / RR_EE_WORD_LEN] =
rr_checksum(&tuning_data[FIRST], LAST - FIRST);
rr_eeprom.ifr_buffer = tuning_data;
rr_eeprom.ifr_length = sizeof(tuning_data);
rr_eeprom.ifr_offset = 0;
if (drvspec_ioctl(name, s, EIOCSEEPROM, sizeof(struct rr_eeprom),
(caddr_t) &rr_eeprom) == -1)
err(7, "ioctl to set tuning information from EEPROM");
}
/* eeprom_upload
*
* Upload the EEPROM from the card and store in the data file.
*/
static void
eeprom_upload(const char *filename)
{
int fd;
bzero(eeprom, sizeof(eeprom));
if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) < 0)
err(4, "Couldn't open %s for output", filename);
rr_eeprom.ifr_buffer = eeprom;
rr_eeprom.ifr_length = sizeof(eeprom);
rr_eeprom.ifr_offset = 0;
if (drvspec_ioctl(name, s, EIOCGEEPROM, sizeof(struct rr_eeprom),
(caddr_t) &rr_eeprom) == -1)
err(5, "ioctl to retrieve all of EEPROM");
write(fd, eeprom, sizeof(eeprom));
close(fd);
}
/* eeprom_download
*
* Download into eeprom the contents of a file. The file is made up
* of ASCII text; the first three characters can be ignored, the next
* four hex characters define an address, the next two characters can
* be ignored, and the final eight hex characters are the data.
*/
static void
eeprom_download(const char *filename)
{
FILE *fp;
struct rr_seg_descr *segd = NULL;
char id[BUFSIZ];
char pad[BUFSIZ];
char buffer[BUFSIZ];
u_int32_t address = 0;
u_int32_t last_address = 0;
u_int32_t value;
u_int32_t length = 0;
int segment_start = 0;
int seg_table_start;
int seg_count_offset;
int phase2_start;
int phase2_checksum;
int in_segment = 0;
int segment = 0;
int eof = 0;
int line = 0;
int zero_count = 0;
int i;
/* Clear out eeprom storage space, then read in the value on the card */
bzero(eeprom, sizeof(eeprom));
bzero(runcode, sizeof(runcode));
rr_eeprom.ifr_buffer = eeprom;
rr_eeprom.ifr_length = sizeof(eeprom);
rr_eeprom.ifr_offset = 0;
if (drvspec_ioctl(name, s, EIOCGEEPROM, sizeof(struct rr_eeprom),
(caddr_t) &rr_eeprom) == -1)
err(5, "ioctl to retrieve EEPROM");
/*
* Open the input file and proceed to read the data file, storing
* the data and counting the number of segments.
*/
if ((fp = fopen(filename, "r")) == NULL)
err(2, "fopen");
do {
if (fgets(buffer, sizeof(buffer), fp) == NULL)
errx(3, "premature, unmarked end of file, line %d", line);
line++;
if (!strncmp(buffer + 7, "01", 2)) { /* check for EOF marker... */
eof = 1;
} else {
sscanf(buffer, "%3s%4x%2s%8x%2s",
id, &address, pad, &value, pad);
if (strcmp(id, ":04") != 0)
errx(3, "bad initial id on line %d", line);
}
/*
* Check to see if we terminated a segment; this happens
* when we are at end of file, or we hit a non-sequential
* address value, or we see three or more zeroes in a row.
*/
if ((length == RR_EE_SEG_SIZE || eof || zero_count >= 3 ||
(last_address && last_address != address - 1)) && in_segment) {
length -= zero_count;
segment_start += length;
segd[segment].length = length;
printf("segment %d, %d words\n", segment, length);
last_address = in_segment = zero_count = length = 0;
segment++;
}
if (eof)
break;
/* Skip zero values starting a segment */
if (!in_segment && value == 0)
continue;
last_address = address;
/*
* If we haven't started a segment yet, do so now.
* Store away the address at which this code should be placed
* in memory and the address of the code in the EEPROM.
*/
if (!in_segment) {
in_segment = 1;
segd = realloc(segd, sizeof(struct rr_seg_descr) * (segment + 1));
if (segd == NULL)
err(6, "couldn't realloc segment descriptor space");
segd[segment].start_addr = address * sizeof(u_int32_t);
segd[segment].ee_addr = segment_start;
}
/* Keep track of consecutive zeroes */
if (in_segment && value == 0)
zero_count++;
else
zero_count = 0;
/* Store away the actual data */
runcode[segment_start + length++] = value;
} while (!eof);
fclose(fp);
/* Now that we have a segment count, fill in the EEPROM image. */
seg_count_offset = eeprom[RR_EE_RUNCODE_SEGMENTS / RR_EE_WORD_LEN];
seg_count_offset = (seg_count_offset - RR_EE_OFFSET) / RR_EE_WORD_LEN;
seg_table_start = seg_count_offset + 1;
phase2_checksum = seg_table_start + 3 * segment;
phase2_start = eeprom[RR_EE_PHASE2_EE_START / RR_EE_WORD_LEN];
phase2_start = (phase2_start - RR_EE_OFFSET) / RR_EE_WORD_LEN;
printf("segment table start = %x, segments = %d\n",
seg_table_start, eeprom[seg_count_offset]);
/* We'll fill in anything after the segment count, so clear it */
bzero(eeprom + seg_count_offset,
sizeof(eeprom) - seg_count_offset * sizeof(eeprom[0]));
eeprom[seg_count_offset] = segment;
for (i = 0; i < segment; i++)
segd[i].ee_addr = RR_EE_OFFSET +
(segd[i].ee_addr + phase2_checksum + 1) * RR_EE_WORD_LEN;
bcopy(segd, &eeprom[seg_table_start],
sizeof(struct rr_seg_descr) * segment);
bcopy(runcode, &eeprom[phase2_checksum + 1],
segment_start * sizeof(u_int32_t));
eeprom[phase2_checksum] = rr_checksum(&eeprom[phase2_start],
phase2_checksum - phase2_start);
eeprom[segment_start + phase2_checksum + 1] =
rr_checksum(&eeprom[phase2_checksum + 1], segment_start);
printf("phase2 checksum %x, runcode checksum %x\n",
eeprom[phase2_checksum],
eeprom[segment_start + phase2_checksum + 1]);
rr_eeprom.ifr_buffer = eeprom;
rr_eeprom.ifr_length = sizeof(eeprom);
rr_eeprom.ifr_offset = 0;
if (drvspec_ioctl(name, s, EIOCSEEPROM, sizeof(struct rr_eeprom),
(caddr_t) &rr_eeprom) == -1)
err(5, "ioctl to retrieve EEPROM");
}
/* rr_checksum
*
* Perform checksum on RunCode. Length is in words. Ugh.
*/
static u_int32_t
rr_checksum(const u_int32_t *data, int length)
{
u_int32_t checksum = 0;
while (length--)
checksum += *data++;
checksum = 0 - checksum;
return checksum;
}
struct stats_values {
int offset;
char *name;
};
struct stats_values stats_values[] = {
{0x04, "receive rings created"},
{0x08, "receive rings deleted"},
{0x0c, "interrupts"},
{0x10, "event overflows"},
{0x14, "invalid commands"},
{0x18, "DMA read errors"},
{0x1c, "DMA write errors"},
{0x20, "stats updates per timer"},
{0x24, "stats updates per host"},
{0x28, "watchdog"},
{0x2c, "trace"},
{0x30, "link ready sync established"},
{0x34, "GLink errors"},
{0x38, "alternating flag errors"},
{0x3c, "overhead bit 8 synchronized"},
{0x40, "remote serial parity errors"},
{0x44, "remote parallel parity errors"},
{0x48, "remote loopback requested"},
{0x50, "transmit connections established"},
{0x54, "transmit connections rejected"},
{0x58, "transmit connections retried"},
{0x5c, "transmit connections timed out"},
{0x60, "transmit connections disconnected"},
{0x64, "transmit parity errors"},
{0x68, "packets sent"},
{0x74, "short first burst sent"},
{0x80, "transmit data not moving"},
{0x90, "receive connections accepted"},
{0x94, "receive connections rejected -- bad parity"},
{0x98, "receive connections rejected -- 64-bit width"},
{0x9c, "receive connections rejected -- buffers low"},
{0xa0, "receive connections disconnected"},
{0xa4, "receive connections with no data"},
{0xa8, "packets received"},
{0xb4, "short first burst received"},
{0xc0, "receive parity error"},
{0xc4, "receive LLRC error"},
{0xc8, "receive burst size error"},
{0xcc, "receive state error"},
{0xd0, "receive ready ULP"},
{0xd4, "receive invalid ULP"},
{0xd8, "receive packets flow control due to buffer space"},
{0xdc, "receive packets flow control due to descriptors"},
{0xe0, "receive ring fulls"},
{0xe4, "packet length errors"},
{0xe8, "packets with checksum error"},
{0xec, "packets dropped"},
{0xf0, "ring low on space"},
{0xf4, "data in ring at close"},
{0xf8, "receives to ring not moving data"},
{0xfc, "receiver idles"},
{0, 0},
};
static void
esh_stats(int get_stats)
{
u_int32_t *stats;
long long value;
int offset;
if (drvspec_ioctl(name, s, EIOCGSTATS, sizeof(struct rr_stats),
(caddr_t) &rr_stats) < 0)
err(1, "ioctl(EIOCGTUNE)");
stats = rr_stats.rs_stats;
value = (((long long) stats[0x78 / 4]) << 32) | stats[0x7c / 4];
if (get_stats == 1 || value > 0)
printf("%12qd bytes sent\n", value);
value = ((long long) stats[0xb8 / 4] << 32) | stats[0xbc / 4];
if (get_stats == 1 || value > 0)
printf("%12qd bytes received\n", value);
for (offset = 0; stats_values[offset].offset != 0; offset++) {
if (get_stats == 1 || stats[stats_values[offset].offset / 4] > 0)
printf("%12d %s\n", stats[stats_values[offset].offset / 4],
stats_values[offset].name);
}
}
static void
esh_tuning_stats()
{
printf("rt_mode_and_status = %x\n",
rr_tune.rt_mode_and_status);
printf("rt_conn_retry_count = %x\n",
rr_tune.rt_conn_retry_count);
printf("rt_conn_retry_timer = %x\n",
rr_tune.rt_conn_retry_timer);
printf("rt_conn_timeout = %x\n", rr_tune.rt_conn_timeout);
printf("rt_stats_timer = %x\n", rr_tune.rt_stats_timer);
printf("rt_interrupt_timer = %x\n",
rr_tune.rt_interrupt_timer);
printf("rt_tx_timeout = %x\n", rr_tune.rt_tx_timeout);
printf("rt_rx_timeout = %x\n", rr_tune.rt_rx_timeout);
printf("rt_pci_state = %x"
" min dma %x read max %x write max %x\n",
rr_tune.rt_pci_state,
(rr_tune.rt_pci_state & RR_PS_MIN_DMA_MASK)
>> RR_PS_MIN_DMA_SHIFT,
do_map_dma(rr_tune.rt_pci_state & RR_PS_READ_MASK,
read_dma_map),
do_map_dma(rr_tune.rt_pci_state & RR_PS_WRITE_MASK,
write_dma_map));
printf("rt_dma_write_state = %x\n",
rr_tune.rt_dma_write_state);
printf("rt_dma_read_state = %x\n", rr_tune.rt_dma_read_state);
printf("rt_driver_param = %x\n", rr_tune.rt_driver_param);
}