summaryrefslogtreecommitdiffstats
path: root/sys/dev/hfa
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
committerphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
commitc3dd1fa899d435ea4bf79897f646a93cb80c94ac (patch)
tree98dfbc96e3c6aa7ff1f322855f6484c4e609819d /sys/dev/hfa
parent9ed6892f4808d56de443849229e151f8f7ad43b0 (diff)
downloadFreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.zip
FreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.tar.gz
Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc. This software was developed with the support of the Defense Advanced Research Projects Agency (DARPA).
Diffstat (limited to 'sys/dev/hfa')
-rw-r--r--sys/dev/hfa/fore.h144
-rw-r--r--sys/dev/hfa/fore_aali.h604
-rw-r--r--sys/dev/hfa/fore_buffer.c772
-rw-r--r--sys/dev/hfa/fore_command.c445
-rw-r--r--sys/dev/hfa/fore_globals.c119
-rw-r--r--sys/dev/hfa/fore_if.c205
-rw-r--r--sys/dev/hfa/fore_include.h139
-rw-r--r--sys/dev/hfa/fore_init.c314
-rw-r--r--sys/dev/hfa/fore_intr.c268
-rw-r--r--sys/dev/hfa/fore_load.c1618
-rw-r--r--sys/dev/hfa/fore_output.c415
-rw-r--r--sys/dev/hfa/fore_receive.c582
-rw-r--r--sys/dev/hfa/fore_slave.h191
-rw-r--r--sys/dev/hfa/fore_stats.c164
-rw-r--r--sys/dev/hfa/fore_stats.h83
-rw-r--r--sys/dev/hfa/fore_timer.c97
-rw-r--r--sys/dev/hfa/fore_transmit.c371
-rw-r--r--sys/dev/hfa/fore_var.h269
-rw-r--r--sys/dev/hfa/fore_vcm.c321
19 files changed, 7121 insertions, 0 deletions
diff --git a/sys/dev/hfa/fore.h b/sys/dev/hfa/fore.h
new file mode 100644
index 0000000..42f44f0
--- /dev/null
+++ b/sys/dev/hfa/fore.h
@@ -0,0 +1,144 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore.h,v 1.8 1998/08/26 23:28:57 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Protocol and implementation definitions
+ *
+ */
+
+#ifndef _FORE_H
+#define _FORE_H
+
+#ifndef FORE_DEV_NAME
+#define FORE_DEV_NAME "hfa"
+#endif
+
+#define FORE_MAX_UNITS 8 /* Maximum number of devices we support */
+#define FORE_MIN_UCODE 0x20300 /* Minimum microcode version we support */
+
+#define FORE_IFF_MTU 9188 /* Network interface MTU */
+#define FORE_MAX_VCC 1024 /* Maximum number of open VCCs */
+#define FORE_MAX_VPI 0 /* Maximum VPI value */
+#define FORE_MAX_VCI 1023 /* Maximum VCI value */
+#define FORE_DEF_RATE 0x00000000 /* Default rate control = disabled */
+
+#define XMIT_QUELEN 32 /* Length of transmit queue */
+#define RECV_QUELEN 32 /* Length of receive queue */
+#define CMD_QUELEN 8 /* Length of command queue */
+
+#define FORE_TIME_TICK 5 /* Watchdog timer tick (seconds) */
+#define FORE_WATCHDOG 3 /* Device watchdog timeout (ticks) */
+#define FORE_RECV_RETRY 3 /* Wait for receive queue entry retry count */
+#define FORE_RECV_DELAY 10 /* Wait for receive queue entry delay (usec) */
+
+
+/*
+ * Receive Buffer strategies
+ */
+#define BUF_MIN_VCC 4 /* Minimum for buffer supply calculations */
+
+#ifdef FORE_SBUS
+#if defined(sun4c)
+#define BUF_DATA_ALIGN 32 /* Fore-required data alignment */
+#elif defined(sun4m)
+#define BUF_DATA_ALIGN 64 /* Fore-required data alignment */
+#endif
+#endif
+#ifdef FORE_PCI
+#define BUF_DATA_ALIGN 4 /* Fore-required data alignment */
+#endif
+
+#if defined(BSD)
+/*
+ * Strategy 1 Small - mbuf
+ * Strategy 1 Large - cluster mbuf
+ *
+ * XXX buffer controls - the RECV_MAX_SEGS calculation comes out wrong
+ * using the true buffer size values if the CP really only does full-cell
+ * filling of a particular buffer - we must clarify this...it also appears
+ * the minimum buffer size is 64, even if the CP can only fit in 1 cell.
+ */
+#define SIZEOF_Buf_handle 16 /* XXX sizeof(Buf_handle) */
+
+#if BSD >= 199103
+#undef m_ext
+typedef struct m_ext M_ext;
+#define m_ext M_dat.MH.MH_dat.MH_ext
+#define BUF1_SM_HOFF (sizeof(struct m_hdr)) /* Buffer-to-handle offset */
+#define BUF1_SM_HDR (sizeof(struct m_hdr) + sizeof(struct pkthdr))
+#define BUF1_SM_LEN (MHLEN)
+#define BUF1_LG_HOFF (sizeof(struct m_hdr) + sizeof(struct pkthdr) \
+ + sizeof(M_ext)) /* Buffer-to-handle offset */
+#else
+#define BUF1_SM_HOFF (MMINOFF) /* Buffer-to-handle offset */
+#define BUF1_SM_HDR (MMINOFF)
+#define BUF1_SM_LEN (MLEN)
+#define BUF1_LG_HOFF (MMINOFF + 16) /* Buffer-to-handle offset */
+#endif
+
+/*
+ * BUF1_SM_DOFF - CP data offset into buffer data space
+ * BUF1_SM_SIZE - Buffer size
+ *
+ * These should be defined as follows, but we need compile-time constants:
+ *
+ * #define BUF1_SM_DOFF (roundup(BUF1_SM_HOFF + SIZEOF_Buf_handle,
+ * BUF_DATA_ALIGN) - BUF1_SM_HDR)
+ * #define BUF1_SM_SIZE MAX(BUF1_SM_LEN - BUF1_SM_DOFF, 64)
+ *
+ */
+#if ((BSD >= 199103) && defined(FORE_PCI))
+#define BUF1_SM_DOFF ((BUF1_SM_HOFF + SIZEOF_Buf_handle) - BUF1_SM_HDR)
+#define BUF1_SM_SIZE (BUF1_SM_LEN - BUF1_SM_DOFF)
+#endif
+#if ((BSD < 199103) && defined(FORE_SBUS) && defined(sun4c))
+#define BUF1_SM_DOFF (BUF_DATA_ALIGN - BUF1_SM_HDR)
+#define BUF1_SM_SIZE (BUF1_SM_LEN - BUF1_SM_DOFF)
+#endif
+#if ((BSD < 199103) && defined(FORE_SBUS) && defined(sun4m))
+#define BUF1_SM_DOFF (BUF_DATA_ALIGN - BUF1_SM_HDR)
+#define BUF1_SM_SIZE (64)
+#endif
+
+#define BUF1_SM_QUELEN 16 /* Entries in supply queue */
+#define BUF1_SM_CPPOOL 256 /* Buffers in CP-resident pool */
+#define BUF1_SM_ENTSIZE 8 /* Buffers in each supply queue entry */
+
+#define BUF1_LG_DOFF 0 /* CP data offset into mbuf data space */
+#define BUF1_LG_SIZE MCLBYTES /* Buffer size */
+#define BUF1_LG_QUELEN 16 /* Entries in supply queue */
+#define BUF1_LG_CPPOOL 512 /* Buffers in CP-resident pool */
+#define BUF1_LG_ENTSIZE 8 /* Buffers in each supply queue entry */
+
+#endif /* defined(BSD) */
+
+#endif /* _FORE_H */
diff --git a/sys/dev/hfa/fore_aali.h b/sys/dev/hfa/fore_aali.h
new file mode 100644
index 0000000..d59dcfc
--- /dev/null
+++ b/sys/dev/hfa/fore_aali.h
@@ -0,0 +1,604 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_aali.h,v 1.5 1997/05/09 00:42:25 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * ATM Adaptation Layer Interface (AALI) definitions
+ *
+ */
+
+#ifndef _FORE_AALI_H
+#define _FORE_AALI_H
+
+/*
+ * This file contains the definitions required by the FORE ATM Adaptation
+ * Layer Interface (AALI) specification.
+ */
+
+
+/*
+ * Addressing/Pointer definitions
+ *
+ * The CP memory only supports 32-bit word accesses (read and write) - thus,
+ * all memory must be defined and accessed as 32-bit words. Also, since the
+ * data transfers are word-sized, we must take care of byte-swapping issues
+ * from/to little-endian hosts (the CP is an i960 processor, ie big-endian).
+ *
+ * All pointers to CP memory areas are actually offsets from the start of
+ * the adapter RAM address space.
+ *
+ * All CP-resident data structures are declared volatile.
+ */
+typedef void * H_addr; /* Host-resident address */
+typedef unsigned long H_dma; /* Host-resident DMA address */
+typedef unsigned long CP_word; /* CP-resident word */
+typedef unsigned long CP_addr; /* CP-resident CP memory offset */
+typedef unsigned long CP_dma; /* CP-resident DMA address */
+
+
+/*
+ * Structure defining the CP's shared memory interface to the mon960 program
+ */
+struct mon960 {
+ CP_word mon_xmitmon; /* Uart - host to mon960 (see below) */
+ CP_word mon_xmithost; /* Uart - mon960 to host (see below) */
+ CP_word mon_bstat; /* Boot status word (see below) */
+ CP_addr mon_appl; /* Pointer to application memory area */
+ CP_word mon_ver; /* Mon960 firmware version */
+};
+typedef volatile struct mon960 Mon960;
+
+/*
+ * Pseudo-UART usage
+ */
+#define UART_READY 0x00000000 /* UART is ready for more data */
+#define UART_VALID 0x01000000 /* UART character is valid */
+#define UART_DATAMASK 0x000000ff /* UART character data mask */
+
+/*
+ * Boot Status Word
+ */
+#define BOOT_COLDSTART 0xc01dc01d /* CP is performing cold start */
+#define BOOT_MONREADY 0x02201958 /* Monitor is waiting for commands */
+#define BOOT_FAILTEST 0xadbadbad /* Monitor failed self-test */
+#define BOOT_RUNNING 0xce11feed /* Microcode downloaded and running */
+
+#define BOOT_LOOPS 20 /* Loops to wait for CP to boot */
+#define BOOT_DELAY 100000 /* Delay (us) for each boot loop */
+
+
+/*
+ * Supported AALs
+ */
+enum fore_aal {
+ FORE_AAL_0 = 0, /* Cell Service */
+ FORE_AAL_4 = 4, /* AAL 3/4 */
+ FORE_AAL_5 = 5 /* AAL 5 */
+};
+typedef enum fore_aal Fore_aal;
+
+
+/*
+ * Buffer strategy definition
+ */
+struct buf_strategy {
+ CP_word bfs_quelen; /* Buffer supply queue entries */
+ CP_word bfs_bufsize; /* Buffer size */
+ CP_word bfs_cppool; /* Buffers in CP-resident pool */
+ CP_word bfs_entsize; /* Buffers in each supply queue entry */
+};
+typedef volatile struct buf_strategy Buf_strategy;
+
+/*
+ * Buffer strategy id
+ */
+#define BUF_STRAT_1 0 /* Buffer strategy one */
+#define BUF_STRAT_2 1 /* Buffer strategy two */
+
+
+
+#ifdef ATM_KERNEL
+/*
+ * Common Queue Element
+ *
+ * Used for Transmit, Receive and Buffer Supply Queues
+ */
+struct com_queue {
+ CP_dma cq_descr; /* Pointer to element descriptor */
+ CP_dma cq_status; /* Pointer to element status word */
+};
+typedef volatile struct com_queue Com_queue;
+
+
+/*
+ * Queue element status word
+ */
+typedef volatile unsigned long Q_status;
+
+#define QSTAT_PENDING 0x01 /* Operation is pending */
+#define QSTAT_COMPLETED 0x02 /* Operation successfully completed */
+#define QSTAT_FREE 0x04 /* Queue element is free/unused */
+#define QSTAT_ERROR 0x08 /* Operation encountered an error */
+
+#define QSTAT_ALIGN 4
+
+
+/*
+ * PDU Transmit Queue
+ */
+
+/*
+ * PDU Transmit Queue Element
+ */
+typedef volatile struct com_queue Xmit_queue;
+
+
+/*
+ * PDU Transmit buffer segment descriptor
+ */
+struct xmit_seg_descr {
+ H_dma xsd_buffer; /* Buffer's DMA address */
+ u_int xsd_len; /* Data length in buffer */
+};
+typedef struct xmit_seg_descr Xmit_seg_descr;
+
+#define XMIT_SEG_ALIGN 4
+
+
+/*
+ * PDU Transmit descriptor header
+ */
+struct xmit_descr_hdr {
+ u_long xdh_cell_hdr; /* Cell header (minus HEC) */
+ u_long xdh_spec; /* Transmit specification (see below) */
+ u_long xdh_rate; /* Rate control (data/idle cell ratio)*/
+ u_long xdh_pad; /* Pad to quad-word boundary */
+};
+typedef struct xmit_descr_hdr Xmit_descr_hdr;
+
+
+#define XMIT_BLK_BITS 5 /* Bits to encode block size */
+#define XMIT_MAX_BLK_BITS 4 /* Max bits we can use */
+#define XMIT_BLK_SIZE (1 << XMIT_BLK_BITS)
+#define XMIT_SEGS_TO_BLKS(nseg) \
+ ((((nseg) * sizeof(Xmit_seg_descr)) \
+ + sizeof(Xmit_descr_hdr) + (XMIT_BLK_SIZE - 1)) \
+ >> XMIT_BLK_BITS)
+#define XMIT_MAX_BLKS ((1 << XMIT_MAX_BLK_BITS) - 1)
+#define XMIT_HDR_SEGS ((XMIT_BLK_SIZE - sizeof(Xmit_descr_hdr)) \
+ / sizeof(Xmit_seg_descr))
+#define XMIT_BLK_SEGS (XMIT_BLK_SIZE / sizeof(Xmit_seg_descr))
+#define XMIT_EXTRA_SEGS ((XMIT_MAX_BLKS - 1) * XMIT_BLK_SEGS)
+#define XMIT_MAX_SEGS (XMIT_EXTRA_SEGS + XMIT_HDR_SEGS)
+
+
+/*
+ * PDU Transmit descriptor
+ */
+struct xmit_descr {
+ Xmit_descr_hdr xd_hdr; /* Descriptor header */
+ Xmit_seg_descr xd_seg[XMIT_MAX_SEGS]; /* PDU segments */
+};
+typedef struct xmit_descr Xmit_descr;
+
+#define xd_cell_hdr xd_hdr.xdh_cell_hdr
+#define xd_spec xd_hdr.xdh_spec
+#define xd_rate xd_hdr.xdh_rate
+
+/*
+ * Transmit specification
+ *
+ * Bits 0-15 - Total PDU length
+ * Bits 16-23 - Number of transmit segments
+ * Bits 24-27 - AAL type
+ * Bits 28-31 - Interrupt flag
+ */
+#define XDS_SET_SPEC(i,a,n,l) (((i) << 28) | ((a) << 24) | ((n) << 16) | (l))
+#define XDS_GET_LEN(s) ((s) & 0xffff)
+#define XDS_GET_SEGS(s) (((s) >> 16) & 0xff)
+#define XDS_GET_AAL(s) (((s) >> 24) & 0xf)
+#define XDS_GET_INTR(s) (((s) >> 28) & 0xf)
+
+#define XMIT_MAX_PDULEN 65535
+#define XMIT_DESCR_ALIGN 32
+
+
+
+/*
+ * PDU Receive Queue
+ */
+
+/*
+ * PDU Receive Queue Element
+ */
+typedef volatile struct com_queue Recv_queue;
+
+
+/*
+ * Receive PDU buffer segment description
+ */
+struct recv_seg_descr {
+ H_addr rsd_handle; /* Buffer handle (from supply) */
+ u_int rsd_len; /* Data length in buffer */
+};
+typedef struct recv_seg_descr Recv_seg_descr;
+
+
+/*
+ * PDU Receive descriptor header
+ */
+struct recv_descr_hdr {
+ u_long rdh_cell_hdr; /* Cell header (minus HEC) */
+ u_long rdh_nsegs; /* Number of receive segments */
+};
+typedef struct recv_descr_hdr Recv_descr_hdr;
+
+
+#define RECV_BLK_SIZE 32
+#define RECV_HDR_SEGS ((RECV_BLK_SIZE - sizeof(Recv_descr_hdr)) \
+ / sizeof(Recv_seg_descr))
+#define RECV_BLK_SEGS (RECV_BLK_SIZE / sizeof(Recv_seg_descr))
+#define RECV_MAX_LG_SEGS ((FORE_IFF_MTU - BUF1_SM_SIZE \
+ + (BUF1_LG_SIZE - 1)) / BUF1_LG_SIZE)
+#define RECV_EXTRA_BLKS (((RECV_MAX_LG_SEGS + 1 - RECV_HDR_SEGS) \
+ + (RECV_BLK_SEGS - 1)) / RECV_BLK_SEGS)
+#define RECV_EXTRA_SEGS (RECV_EXTRA_BLKS * RECV_BLK_SEGS)
+#define RECV_MAX_SEGS (RECV_EXTRA_SEGS + RECV_HDR_SEGS)
+
+
+/*
+ * PDU Receive descriptor
+ */
+struct recv_descr {
+ Recv_descr_hdr rd_hdr; /* Descriptor header */
+ Recv_seg_descr rd_seg[RECV_MAX_SEGS]; /* PDU segments */
+};
+typedef struct recv_descr Recv_descr;
+
+#define rd_cell_hdr rd_hdr.rdh_cell_hdr
+#define rd_nsegs rd_hdr.rdh_nsegs
+
+#define RECV_DESCR_ALIGN 32
+
+
+
+/*
+ * Buffer Supply Queue
+ */
+
+/*
+ * Buffer Supply Queue Element
+ */
+typedef volatile struct com_queue Buf_queue;
+
+
+/*
+ * Buffer supply descriptor for supplying receive buffers
+ */
+struct buf_descr {
+ H_addr bsd_handle; /* Host-specific buffer handle */
+ H_dma bsd_buffer; /* Buffer DMA address */
+};
+typedef struct buf_descr Buf_descr;
+
+#define BUF_DESCR_ALIGN 32
+
+
+
+/*
+ * Command Queue
+ */
+
+/*
+ * Command Codes
+ */
+typedef volatile unsigned long Cmd_code;
+
+#define CMD_INIT 0x01 /* Initialize microcode */
+#define CMD_ACT_VCCIN 0x02 /* Activate incoming VCC */
+#define CMD_ACT_VCCOUT 0x03 /* Activate outgoing VCC */
+#define CMD_DACT_VCCIN 0x04 /* Deactivate incoming VCC */
+#define CMD_DACT_VCCOUT 0x05 /* Deactivate outgoing VCC */
+#define CMD_GET_STATS 0x06 /* Get adapter statistics */
+#define CMD_SET_OC3_REG 0x07 /* Set SUNI OC3 registers */
+#define CMD_GET_OC3_REG 0x08 /* Get SUNI OC3 registers */
+#define CMD_GET_PROM 0x09 /* Get PROM data */
+#define CMD_INTR_REQ 0x80 /* Request host interrupt */
+
+#endif /* ATM_KERNEL */
+
+
+/*
+ * Structure defining the parameters for the Initialize command
+ */
+struct init_parms {
+ CP_word init_cmd; /* Command code */
+ CP_word init_status; /* Completion status */
+ CP_word init_indisc; /* Not used */
+ CP_word init_numvcc; /* Number of VCC's supported */
+ CP_word init_cmd_elem; /* # of command queue elements */
+ CP_word init_xmit_elem; /* # of transmit queue elements */
+ CP_word init_recv_elem; /* # of receive queue elements */
+ CP_word init_recv_ext; /* # of extra receive descr SEGMENTS */
+ CP_word init_xmit_ext; /* # of extra transmit descr SEGMENTS */
+ CP_word init_cls_vcc; /* Not used */
+ CP_word init_pad[2]; /* Pad to quad-word boundary */
+ Buf_strategy init_buf1s; /* Buffer strategy - 1 small */
+ Buf_strategy init_buf1l; /* Buffer strategy - 1 large */
+ Buf_strategy init_buf2s; /* Buffer strategy - 2 small */
+ Buf_strategy init_buf2l; /* Buffer strategy - 2 large */
+};
+typedef volatile struct init_parms Init_parms;
+
+
+#ifdef ATM_KERNEL
+/*
+ * Structure defining the parameters for the Activate commands
+ */
+struct activate_parms {
+ CP_word act_spec; /* Command specification (see below) */
+ CP_word act_vccid; /* VCC id (VPI=0,VCI=id) */
+ CP_word act_batch; /* # cells in batch (AAL=NULL) */
+ CP_word act_pad; /* Pad to quad-word boundary */
+};
+typedef volatile struct activate_parms Activate_parms;
+
+/*
+ * Activate command specification
+ *
+ * Bits 0-7 - command code
+ * Bits 8-15 - AAL type
+ * Bits 16-23 - buffer strategy
+ * Bits 24-31 - reserved
+ */
+#define ACT_SET_SPEC(b,a,c) (((b) << 16) | ((a) << 8) | (c))
+#define ACT_GET_CMD(s) ((s) & 0xff)
+#define ACT_GET_AAL(s) (((s) >> 8) & 0xff)
+#define ACT_GET_STRAT(s) (((s) >> 16) & 0xff)
+
+
+/*
+ * Structure defining the parameters for the Deactivate commands
+ */
+struct dactivate_parms {
+ CP_word dact_cmd; /* Command code */
+ CP_word dact_vccid; /* VCC id (VPI=0,VCI=id) */
+ CP_word dact_pad[2]; /* Pad to quad-word boundary */
+};
+typedef volatile struct dactivate_parms Dactivate_parms;
+
+
+/*
+ * Structure defining the parameters for the Get Statistics command
+ */
+struct stats_parms {
+ CP_word stats_cmd; /* Command code */
+ CP_dma stats_buffer; /* DMA address of host stats buffer */
+ CP_word stats_pad[2]; /* Pad to quad-word boundary */
+};
+typedef volatile struct stats_parms Stats_parms;
+
+
+/*
+ * Structure defining the parameters for the SUNI OC3 commands
+ */
+struct suni_parms {
+ CP_word suni_spec; /* Command specification (see below) */
+ CP_dma suni_buffer; /* DMA address of host SUNI buffer */
+ CP_word suni_pad[2]; /* Pad to quad-word boundary */
+};
+typedef volatile struct suni_parms Suni_parms;
+
+/*
+ * SUNI OC3 command specification
+ *
+ * Bits 0-7 - command code
+ * Bits 8-15 - SUNI register number
+ * Bits 16-23 - Value(s) to set in register
+ * Bits 24-31 - Mask selecting value bits
+ */
+#define SUNI_SET_SPEC(m,v,r,c) (((m) << 24) | ((v) << 16) | ((r) << 8) | (c))
+#define SUNI_GET_CMD(s) ((s) & 0xff)
+#define SUNI_GET_REG(s) (((s) >> 8) & 0xff)
+#define SUNI_GET_VALUE(s) (((s) >> 16) & 0xff)
+#define SUNI_GET_MASK(s) (((s) >> 24) & 0xff)
+
+
+/*
+ * Structure defining the parameters for the Get Prom command
+ */
+struct prom_parms {
+ CP_word prom_cmd; /* Command code */
+ CP_dma prom_buffer; /* DMA address of host prom buffer */
+ CP_word prom_pad[2]; /* Pad to quad-word boundary */
+};
+typedef volatile struct prom_parms Prom_parms;
+
+
+/*
+ * Command Queue Element
+ */
+struct cmd_queue {
+ union { /* Command-specific parameters */
+ Activate_parms cmdqu_act;
+ Dactivate_parms cmdqu_dact;
+ Stats_parms cmdqu_stats;
+ Suni_parms cmdqu_suni;
+ Prom_parms cmdqu_prom;
+ } cmdq_u;
+ CP_dma cmdq_status; /* Pointer to element status word */
+ CP_word cmdq_pad[3]; /* Pad to quad-word boundary */
+};
+#define cmdq_act cmdq_u.cmdqu_act
+#define cmdq_dact cmdq_u.cmdqu_dact
+#define cmdq_stats cmdq_u.cmdqu_stats
+#define cmdq_suni cmdq_u.cmdqu_suni
+#define cmdq_prom cmdq_u.cmdqu_prom
+typedef volatile struct cmd_queue Cmd_queue;
+
+#endif /* ATM_KERNEL */
+
+
+
+/*
+ * Structure defining the CP's shared memory interface to the
+ * AALI firmware program (downloaded microcode)
+ */
+struct aali {
+ CP_addr aali_cmd_q; /* Pointer to command queue */
+ CP_addr aali_xmit_q; /* Pointer to transmit queue */
+ CP_addr aali_recv_q; /* Pointer to receive queue */
+ CP_addr aali_buf1s_q; /* Pointer to strategy-1 small queue */
+ CP_addr aali_buf1l_q; /* Pointer to strategy-1 large queue */
+ CP_addr aali_buf2s_q; /* Pointer to strategy-2 small queue */
+ CP_addr aali_buf2l_q; /* Pointer to strategy-2 large queue */
+ CP_word aali_intr_ena; /* Enables interrupts if non-zero */
+ CP_word aali_intr_sent; /* Interrupt issued if non-zero */
+ CP_addr aali_heap; /* Pointer to application heap */
+ CP_word aali_heaplen; /* Length of application heap */
+ CP_word aali_hostlog; /* FORE internal use */
+ CP_word aali_heartbeat; /* Monitor microcode health */
+ CP_word aali_ucode_ver; /* Microcode firmware version */
+ CP_word aali_mon_ver; /* Mon960 version */
+ CP_word aali_xmit_tput; /* FORE internal use */
+
+ /* This must be on a quad-word boundary */
+ Init_parms aali_init; /* Initialize command parameters */
+};
+typedef volatile struct aali Aali;
+
+
+/*
+ * CP maintained statistics - DMA'd to host with CMD_GET_STATS command
+ */
+struct stats_taxi {
+ u_long taxi_bad_crc; /* Bad header CRC errors */
+ u_long taxi_framing; /* Framing errors */
+ u_long taxi_pad[2]; /* Pad to quad-word boundary */
+};
+typedef struct stats_taxi Stats_taxi;
+
+struct stats_oc3 {
+ u_long oc3_sect_bip8; /* Section 8-bit intrlv parity errors */
+ u_long oc3_path_bip8; /* Path 8-bit intrlv parity errors */
+ u_long oc3_line_bip24; /* Line 24-bit intrlv parity errors */
+ u_long oc3_line_febe; /* Line far-end block errors */
+ u_long oc3_path_febe; /* Path far-end block errors */
+ u_long oc3_hec_corr; /* Correctible HEC errors */
+ u_long oc3_hec_uncorr; /* Uncorrectible HEC errors */
+ u_long oc3_pad; /* Pad to quad-word boundary */
+};
+typedef struct stats_oc3 Stats_oc3;
+
+struct stats_atm {
+ u_long atm_xmit; /* Cells transmitted */
+ u_long atm_rcvd; /* Cells received */
+ u_long atm_vpi_range; /* Cell drops - VPI out of range */
+ u_long atm_vpi_noconn; /* Cell drops - no connect for VPI */
+ u_long atm_vci_range; /* Cell drops - VCI out of range */
+ u_long atm_vci_noconn; /* Cell drops - no connect for VCI */
+ u_long atm_pad[2]; /* Pad to quad-word boundary */
+};
+typedef struct stats_atm Stats_atm;
+
+struct stats_aal0 {
+ u_long aal0_xmit; /* Cells transmitted */
+ u_long aal0_rcvd; /* Cells received */
+ u_long aal0_drops; /* Cell drops */
+ u_long aal0_pad; /* Pad to quad-word boundary */
+};
+typedef struct stats_aal0 Stats_aal0;
+
+struct stats_aal4 {
+ u_long aal4_xmit; /* Cells transmitted */
+ u_long aal4_rcvd; /* Cells received */
+ u_long aal4_crc; /* Cells with payload CRC errors */
+ u_long aal4_sar_cs; /* Cells with SAR/CS errors */
+ u_long aal4_drops; /* Cell drops */
+ u_long aal4_pdu_xmit; /* CS PDUs transmitted */
+ u_long aal4_pdu_rcvd; /* CS PDUs received */
+ u_long aal4_pdu_errs; /* CS layer protocol errors */
+ u_long aal4_pdu_drops; /* CS PDUs dropped */
+ u_long aal4_pad[3]; /* Pad to quad-word boundary */
+};
+typedef struct stats_aal4 Stats_aal4;
+
+struct stats_aal5 {
+ u_long aal5_xmit; /* Cells transmitted */
+ u_long aal5_rcvd; /* Cells received */
+ u_long aal5_crc_len; /* Cells with CRC/length errors */
+ u_long aal5_drops; /* Cell drops */
+ u_long aal5_pdu_xmit; /* CS PDUs transmitted */
+ u_long aal5_pdu_rcvd; /* CS PDUs received */
+ u_long aal5_pdu_crc; /* CS PDUs with CRC errors */
+ u_long aal5_pdu_errs; /* CS layer protocol errors */
+ u_long aal5_pdu_drops; /* CS PDUs dropped */
+ u_long aal5_pad[3]; /* Pad to quad-word boundary */
+};
+typedef struct stats_aal5 Stats_aal5;
+
+struct stats_misc {
+ u_long buf1_sm_fail; /* Alloc fail: buffer strat 1 small */
+ u_long buf1_lg_fail; /* Alloc fail: buffer strat 1 large */
+ u_long buf2_sm_fail; /* Alloc fail: buffer strat 2 small */
+ u_long buf2_lg_fail; /* Alloc fail: buffer strat 2 large */
+ u_long rcvd_pdu_fail; /* Received PDU allocation failure */
+ u_long carrier_status; /* Carrier status */
+ u_long misc_pad[2]; /* Pad to quad-word boundary */
+};
+typedef struct stats_misc Stats_misc;
+
+struct fore_cp_stats {
+ Stats_taxi st_cp_taxi; /* TAXI layer statistics */
+ Stats_oc3 st_cp_oc3; /* OC3 layer statistics */
+ Stats_atm st_cp_atm; /* ATM layer statistics */
+ Stats_aal0 st_cp_aal0; /* AAL0 layer statistics */
+ Stats_aal4 st_cp_aal4; /* AAL3/4 layer statistics */
+ Stats_aal5 st_cp_aal5; /* AAL5 layer statistics */
+ Stats_misc st_cp_misc; /* Miscellaneous statistics */
+};
+typedef struct fore_cp_stats Fore_cp_stats;
+
+#define FORE_STATS_ALIGN 32
+
+/*
+ * CP PROM data - DMA'd to host with CMD_GET_PROM command
+ */
+struct fore_prom {
+ u_long pr_hwver; /* Hardware version number */
+ u_long pr_serno; /* Serial number */
+ u_char pr_mac[8]; /* MAC address */
+};
+typedef struct fore_prom Fore_prom;
+
+#define FORE_PROM_ALIGN 32
+
+#endif /* _FORE_AALI_H */
diff --git a/sys/dev/hfa/fore_buffer.c b/sys/dev/hfa/fore_buffer.c
new file mode 100644
index 0000000..d8bdce4
--- /dev/null
+++ b/sys/dev/hfa/fore_buffer.c
@@ -0,0 +1,772 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_buffer.c,v 1.6 1997/05/06 22:09:21 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Buffer Supply queue management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_buffer.c,v 1.6 1997/05/06 22:09:21 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Local functions
+ */
+static void fore_buf_drain __P((Fore_unit *));
+static void fore_buf_supply_1s __P((Fore_unit *));
+static void fore_buf_supply_1l __P((Fore_unit *));
+
+
+/*
+ * Allocate Buffer Supply Queues Data Structures
+ *
+ * Here we are allocating memory for both Strategy 1 Small and Large
+ * structures contiguously.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * 0 allocations successful
+ * else allocation failed
+ */
+int
+fore_buf_allocate(fup)
+ Fore_unit *fup;
+{
+ caddr_t memp;
+
+ /*
+ * Allocate non-cacheable memory for buffer supply status words
+ */
+ memp = atm_dev_alloc(
+ sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN),
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_buf1s_stat = (Q_status *) memp;
+ fup->fu_buf1l_stat = ((Q_status *) memp) + BUF1_SM_QUELEN;
+
+ memp = DMA_GET_ADDR(fup->fu_buf1s_stat,
+ sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN),
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_buf1s_statd = (Q_status *) memp;
+ fup->fu_buf1l_statd = ((Q_status *) memp) + BUF1_SM_QUELEN;
+
+ /*
+ * Allocate memory for buffer supply descriptors
+ */
+ memp = atm_dev_alloc(sizeof(Buf_descr) *
+ ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) +
+ (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)),
+ BUF_DESCR_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_buf1s_desc = (Buf_descr *) memp;
+ fup->fu_buf1l_desc = ((Buf_descr *) memp) +
+ (BUF1_SM_QUELEN * BUF1_SM_ENTSIZE);
+
+ memp = DMA_GET_ADDR(fup->fu_buf1s_desc, sizeof(Buf_descr) *
+ ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) +
+ (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)),
+ BUF_DESCR_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_buf1s_descd = (Buf_descr *) memp;
+ fup->fu_buf1l_descd = ((Buf_descr *) memp) +
+ (BUF1_SM_QUELEN * BUF1_SM_ENTSIZE);
+
+ return (0);
+}
+
+
+/*
+ * Buffer Supply Queues Initialization
+ *
+ * Allocate and initialize the host-resident buffer supply queue structures
+ * and then initialize the CP-resident queue structures.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_buf_initialize(fup)
+ Fore_unit *fup;
+{
+ Aali *aap = fup->fu_aali;
+ Buf_queue *cqp;
+ H_buf_queue *hbp;
+ Buf_descr *bdp;
+ Buf_descr *bdp_dma;
+ Q_status *qsp;
+ Q_status *qsp_dma;
+ int i;
+
+ /*
+ * Initialize Strategy 1 Small Queues
+ */
+
+ /*
+ * Point to CP-resident buffer supply queue
+ */
+ cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1s_q));
+
+ /*
+ * Point to host-resident buffer supply queue structures
+ */
+ hbp = fup->fu_buf1s_q;
+ qsp = fup->fu_buf1s_stat;
+ qsp_dma = fup->fu_buf1s_statd;
+ bdp = fup->fu_buf1s_desc;
+ bdp_dma = fup->fu_buf1s_descd;
+
+ /*
+ * Loop thru all queue entries and do whatever needs doing
+ */
+ for (i = 0; i < BUF1_SM_QUELEN; i++) {
+
+ /*
+ * Set queue status word to free
+ */
+ *qsp = QSTAT_FREE;
+
+ /*
+ * Set up host queue entry and link into ring
+ */
+ hbp->hbq_cpelem = cqp;
+ hbp->hbq_status = qsp;
+ hbp->hbq_descr = bdp;
+ hbp->hbq_descr_dma = bdp_dma;
+ if (i == (BUF1_SM_QUELEN - 1))
+ hbp->hbq_next = fup->fu_buf1s_q;
+ else
+ hbp->hbq_next = hbp + 1;
+
+ /*
+ * Now let the CP into the game
+ */
+ cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
+
+ /*
+ * Bump all queue pointers
+ */
+ hbp++;
+ qsp++;
+ qsp_dma++;
+ bdp += BUF1_SM_ENTSIZE;
+ bdp_dma += BUF1_SM_ENTSIZE;
+ cqp++;
+ }
+
+ /*
+ * Initialize queue pointers
+ */
+ fup->fu_buf1s_head = fup->fu_buf1s_tail = fup->fu_buf1s_q;
+
+
+ /*
+ * Initialize Strategy 1 Large Queues
+ */
+
+ /*
+ * Point to CP-resident buffer supply queue
+ */
+ cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1l_q));
+
+ /*
+ * Point to host-resident buffer supply queue structures
+ */
+ hbp = fup->fu_buf1l_q;
+ qsp = fup->fu_buf1l_stat;
+ qsp_dma = fup->fu_buf1l_statd;
+ bdp = fup->fu_buf1l_desc;
+ bdp_dma = fup->fu_buf1l_descd;
+
+ /*
+ * Loop thru all queue entries and do whatever needs doing
+ */
+ for (i = 0; i < BUF1_LG_QUELEN; i++) {
+
+ /*
+ * Set queue status word to free
+ */
+ *qsp = QSTAT_FREE;
+
+ /*
+ * Set up host queue entry and link into ring
+ */
+ hbp->hbq_cpelem = cqp;
+ hbp->hbq_status = qsp;
+ hbp->hbq_descr = bdp;
+ hbp->hbq_descr_dma = bdp_dma;
+ if (i == (BUF1_LG_QUELEN - 1))
+ hbp->hbq_next = fup->fu_buf1l_q;
+ else
+ hbp->hbq_next = hbp + 1;
+
+ /*
+ * Now let the CP into the game
+ */
+ cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
+
+ /*
+ * Bump all queue pointers
+ */
+ hbp++;
+ qsp++;
+ qsp_dma++;
+ bdp += BUF1_LG_ENTSIZE;
+ bdp_dma += BUF1_LG_ENTSIZE;
+ cqp++;
+ }
+
+ /*
+ * Initialize queue pointers
+ */
+ fup->fu_buf1l_head = fup->fu_buf1l_tail = fup->fu_buf1l_q;
+
+ return;
+}
+
+
+/*
+ * Supply Buffers to CP
+ *
+ * This function will resupply the CP with buffers to be used to
+ * store incoming data.
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_buf_supply(fup)
+ Fore_unit *fup;
+{
+
+ /*
+ * First, clean out the supply queues
+ */
+ fore_buf_drain(fup);
+
+ /*
+ * Then, supply the buffers for each queue
+ */
+ fore_buf_supply_1s(fup);
+ fore_buf_supply_1l(fup);
+
+ return;
+}
+
+
+/*
+ * Supply Strategy 1 Small Buffers to CP
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+static void
+fore_buf_supply_1s(fup)
+ Fore_unit *fup;
+{
+ H_buf_queue *hbp;
+ Buf_queue *cqp;
+ Buf_descr *bdp;
+ Buf_handle *bhp;
+ KBuffer *m;
+ int nvcc, nbuf, i;
+
+ /*
+ * Figure out how many buffers we should be giving to the CP.
+ * We're basing this calculation on the current number of open
+ * VCCs thru this device, with certain minimum and maximum values
+ * enforced. This will then allow us to figure out how many more
+ * buffers we need to supply to the CP. This will be rounded up
+ * to fill a supply queue entry.
+ */
+ nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC);
+ nbuf = nvcc * 4;
+ nbuf = MIN(nbuf, BUF1_SM_CPPOOL);
+ nbuf -= fup->fu_buf1s_cnt;
+ nbuf = roundup(nbuf, BUF1_SM_ENTSIZE);
+
+ /*
+ * OK, now supply the buffers to the CP
+ */
+ while (nbuf > 0) {
+
+ /*
+ * Acquire a supply queue entry
+ */
+ hbp = fup->fu_buf1s_tail;
+ if (!((*hbp->hbq_status) & QSTAT_FREE))
+ break;
+ bdp = hbp->hbq_descr;
+
+ /*
+ * Get a buffer for each descriptor in the queue entry
+ */
+ for (i = 0; i < BUF1_SM_ENTSIZE; i++, bdp++) {
+ caddr_t cp;
+
+ /*
+ * Get a small buffer
+ */
+ KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA);
+ if (m == 0) {
+ break;
+ }
+ KB_HEADSET(m, BUF1_SM_DOFF);
+
+ /*
+ * Point to buffer handle structure
+ */
+ bhp = (Buf_handle *)((caddr_t)m + BUF1_SM_HOFF);
+ bhp->bh_type = BHT_S1_SMALL;
+
+ /*
+ * Setup buffer descriptor
+ */
+ bdp->bsd_handle = bhp;
+ KB_DATASTART(m, cp, caddr_t);
+ bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR(
+ cp, BUF1_SM_SIZE, BUF_DATA_ALIGN, 0);
+ if (bdp->bsd_buffer == NULL) {
+ /*
+ * Unable to assign dma address - free up
+ * this descriptor's buffer
+ */
+ fup->fu_stats->st_drv.drv_bf_segdma++;
+ KB_FREEALL(m);
+ break;
+ }
+
+ /*
+ * All set, so queue buffer (handle)
+ */
+ ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq);
+ }
+
+ /*
+ * If we we're not able to fill all the descriptors for
+ * an entry, free up what's been partially built
+ */
+ if (i != BUF1_SM_ENTSIZE) {
+
+ /*
+ * Clean up each used descriptor
+ */
+ for (bdp = hbp->hbq_descr; i; i--, bdp++) {
+
+ bhp = bdp->bsd_handle;
+
+ DEQUEUE(bhp, Buf_handle, bh_qelem,
+ fup->fu_buf1s_bq);
+
+ m = (KBuffer *)
+ ((caddr_t)bhp - BUF1_SM_HOFF);
+ KB_FREEALL(m);
+ }
+ break;
+ }
+
+ /*
+ * Finally, we've got an entry ready for the CP.
+ * So claim the host queue entry and setup the CP-resident
+ * queue entry. The CP will (potentially) grab the supplied
+ * buffers when the descriptor pointer is set.
+ */
+ fup->fu_buf1s_tail = hbp->hbq_next;
+ (*hbp->hbq_status) = QSTAT_PENDING;
+ cqp = hbp->hbq_cpelem;
+ cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma);
+
+ /*
+ * Update counters, etc for supplied buffers
+ */
+ fup->fu_buf1s_cnt += BUF1_SM_ENTSIZE;
+ nbuf -= BUF1_SM_ENTSIZE;
+ }
+
+ return;
+}
+
+
+/*
+ * Supply Strategy 1 Large Buffers to CP
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+static void
+fore_buf_supply_1l(fup)
+ Fore_unit *fup;
+{
+ H_buf_queue *hbp;
+ Buf_queue *cqp;
+ Buf_descr *bdp;
+ Buf_handle *bhp;
+ KBuffer *m;
+ int nvcc, nbuf, i;
+
+ /*
+ * Figure out how many buffers we should be giving to the CP.
+ * We're basing this calculation on the current number of open
+ * VCCs thru this device, with certain minimum and maximum values
+ * enforced. This will then allow us to figure out how many more
+ * buffers we need to supply to the CP. This will be rounded up
+ * to fill a supply queue entry.
+ */
+ nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC);
+ nbuf = nvcc * 4 * RECV_MAX_SEGS;
+ nbuf = MIN(nbuf, BUF1_LG_CPPOOL);
+ nbuf -= fup->fu_buf1l_cnt;
+ nbuf = roundup(nbuf, BUF1_LG_ENTSIZE);
+
+ /*
+ * OK, now supply the buffers to the CP
+ */
+ while (nbuf > 0) {
+
+ /*
+ * Acquire a supply queue entry
+ */
+ hbp = fup->fu_buf1l_tail;
+ if (!((*hbp->hbq_status) & QSTAT_FREE))
+ break;
+ bdp = hbp->hbq_descr;
+
+ /*
+ * Get a buffer for each descriptor in the queue entry
+ */
+ for (i = 0; i < BUF1_LG_ENTSIZE; i++, bdp++) {
+ caddr_t cp;
+
+ /*
+ * Get a cluster buffer
+ */
+ KB_ALLOCEXT(m, BUF1_LG_SIZE, KB_F_NOWAIT, KB_T_DATA);
+ if (m == 0) {
+ break;
+ }
+ KB_HEADSET(m, BUF1_LG_DOFF);
+
+ /*
+ * Point to buffer handle structure
+ */
+ bhp = (Buf_handle *)((caddr_t)m + BUF1_LG_HOFF);
+ bhp->bh_type = BHT_S1_LARGE;
+
+ /*
+ * Setup buffer descriptor
+ */
+ bdp->bsd_handle = bhp;
+ KB_DATASTART(m, cp, caddr_t);
+ bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR(
+ cp, BUF1_LG_SIZE, BUF_DATA_ALIGN, 0);
+ if (bdp->bsd_buffer == NULL) {
+ /*
+ * Unable to assign dma address - free up
+ * this descriptor's buffer
+ */
+ fup->fu_stats->st_drv.drv_bf_segdma++;
+ KB_FREEALL(m);
+ break;
+ }
+
+ /*
+ * All set, so queue buffer (handle)
+ */
+ ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq);
+ }
+
+ /*
+ * If we we're not able to fill all the descriptors for
+ * an entry, free up what's been partially built
+ */
+ if (i != BUF1_LG_ENTSIZE) {
+
+ /*
+ * Clean up each used descriptor
+ */
+ for (bdp = hbp->hbq_descr; i; i--, bdp++) {
+ bhp = bdp->bsd_handle;
+
+ DEQUEUE(bhp, Buf_handle, bh_qelem,
+ fup->fu_buf1l_bq);
+
+ m = (KBuffer *)
+ ((caddr_t)bhp - BUF1_LG_HOFF);
+ KB_FREEALL(m);
+ }
+ break;
+ }
+
+ /*
+ * Finally, we've got an entry ready for the CP.
+ * So claim the host queue entry and setup the CP-resident
+ * queue entry. The CP will (potentially) grab the supplied
+ * buffers when the descriptor pointer is set.
+ */
+ fup->fu_buf1l_tail = hbp->hbq_next;
+ (*hbp->hbq_status) = QSTAT_PENDING;
+ cqp = hbp->hbq_cpelem;
+ cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma);
+
+ /*
+ * Update counters, etc for supplied buffers
+ */
+ fup->fu_buf1l_cnt += BUF1_LG_ENTSIZE;
+ nbuf -= BUF1_LG_ENTSIZE;
+ }
+
+ return;
+}
+
+
+/*
+ * Drain Buffer Supply Queues
+ *
+ * This function will free all completed entries at the head of each
+ * buffer supply queue. Since we consider the CP to "own" the buffers
+ * once we put them on a supply queue and since a completed supply queue
+ * entry is only telling us that the CP has accepted the buffers that we
+ * gave to it, there's not much to do here.
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+static void
+fore_buf_drain(fup)
+ Fore_unit *fup;
+{
+ H_buf_queue *hbp;
+
+ /*
+ * Drain Strategy 1 Small Queue
+ */
+
+ /*
+ * Process each completed entry
+ */
+ while (*fup->fu_buf1s_head->hbq_status & QSTAT_COMPLETED) {
+
+ hbp = fup->fu_buf1s_head;
+
+ if (*hbp->hbq_status & QSTAT_ERROR) {
+ /*
+ * XXX - what does this mean???
+ */
+ log(LOG_ERR, "fore_buf_drain: buf1s queue error\n");
+ }
+
+ /*
+ * Mark this entry free for use and bump head pointer
+ * to the next entry in the queue
+ */
+ *hbp->hbq_status = QSTAT_FREE;
+ fup->fu_buf1s_head = hbp->hbq_next;
+ }
+
+
+ /*
+ * Drain Strategy 1 Large Queue
+ */
+
+ /*
+ * Process each completed entry
+ */
+ while (*fup->fu_buf1l_head->hbq_status & QSTAT_COMPLETED) {
+
+ hbp = fup->fu_buf1l_head;
+
+ if (*hbp->hbq_status & QSTAT_ERROR) {
+ /*
+ * XXX - what does this mean???
+ */
+ log(LOG_ERR, "fore_buf_drain: buf1l queue error\n");
+ }
+
+ /*
+ * Mark this entry free for use and bump head pointer
+ * to the next entry in the queue
+ */
+ *hbp->hbq_status = QSTAT_FREE;
+ fup->fu_buf1l_head = hbp->hbq_next;
+ }
+
+ return;
+}
+
+
+/*
+ * Free Buffer Supply Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_buf_free(fup)
+ Fore_unit *fup;
+{
+ Buf_handle *bhp;
+ KBuffer *m;
+
+ /*
+ * Free any previously supplied and not returned buffers
+ */
+ if (fup->fu_flags & CUF_INITED) {
+
+ /*
+ * Run through Strategy 1 Small queue
+ */
+ while (bhp = Q_HEAD(fup->fu_buf1s_bq, Buf_handle)) {
+ caddr_t cp;
+
+ /*
+ * Back off to buffer
+ */
+ m = (KBuffer *)((caddr_t)bhp - BUF1_SM_HOFF);
+
+ /*
+ * Dequeue handle and free buffer
+ */
+ DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq);
+
+ KB_DATASTART(m, cp, caddr_t);
+ DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_SM_SIZE, 0);
+
+ KB_FREEALL(m);
+ }
+
+ /*
+ * Run through Strategy 1 Large queue
+ */
+ while (bhp = Q_HEAD(fup->fu_buf1l_bq, Buf_handle)) {
+ caddr_t cp;
+
+ /*
+ * Back off to buffer
+ */
+ m = (KBuffer *)((caddr_t)bhp - BUF1_LG_HOFF);
+
+ /*
+ * Dequeue handle and free buffer
+ */
+ DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq);
+
+ KB_DATASTART(m, cp, caddr_t);
+ DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0);
+
+ KB_FREEALL(m);
+ }
+ }
+
+ /*
+ * Free the status words
+ */
+ if (fup->fu_buf1s_stat) {
+ if (fup->fu_buf1s_statd) {
+ DMA_FREE_ADDR(fup->fu_buf1s_stat, fup->fu_buf1s_statd,
+ sizeof(Q_status) *
+ (BUF1_SM_QUELEN + BUF1_LG_QUELEN),
+ ATM_DEV_NONCACHE);
+ }
+ atm_dev_free((void *)fup->fu_buf1s_stat);
+ fup->fu_buf1s_stat = NULL;
+ fup->fu_buf1s_statd = NULL;
+ fup->fu_buf1l_stat = NULL;
+ fup->fu_buf1l_statd = NULL;
+ }
+
+ /*
+ * Free the transmit descriptors
+ */
+ if (fup->fu_buf1s_desc) {
+ if (fup->fu_buf1s_descd) {
+ DMA_FREE_ADDR(fup->fu_buf1s_desc, fup->fu_buf1s_descd,
+ sizeof(Buf_descr) *
+ ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) +
+ (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)),
+ 0);
+ }
+ atm_dev_free(fup->fu_buf1s_desc);
+ fup->fu_buf1s_desc = NULL;
+ fup->fu_buf1s_descd = NULL;
+ fup->fu_buf1l_desc = NULL;
+ fup->fu_buf1l_descd = NULL;
+ }
+
+ return;
+}
+
diff --git a/sys/dev/hfa/fore_command.c b/sys/dev/hfa/fore_command.c
new file mode 100644
index 0000000..29b99c6
--- /dev/null
+++ b/sys/dev/hfa/fore_command.c
@@ -0,0 +1,445 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_command.c,v 1.10 1998/06/29 21:42:09 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Command queue management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_command.c,v 1.10 1998/06/29 21:42:09 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+/*
+ * Local variables
+ */
+static struct t_atm_cause fore_cause = {
+ T_ATM_ITU_CODING,
+ T_ATM_LOC_USER,
+ T_ATM_CAUSE_TEMPORARY_FAILURE,
+ {0, 0, 0, 0}
+};
+
+
+/*
+ * Allocate Command Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * 0 allocations successful
+ * else allocation failed
+ */
+int
+fore_cmd_allocate(fup)
+ Fore_unit *fup;
+{
+ caddr_t memp;
+
+ /*
+ * Allocate non-cacheable memory for command status words
+ */
+ memp = atm_dev_alloc(sizeof(Q_status) * CMD_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_cmd_stat = (Q_status *) memp;
+
+ memp = DMA_GET_ADDR(fup->fu_cmd_stat, sizeof(Q_status) * CMD_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_cmd_statd = (Q_status *) memp;
+
+ /*
+ * Allocate memory for statistics buffer
+ */
+ memp = atm_dev_alloc(sizeof(Fore_stats), FORE_STATS_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_stats = (Fore_stats *) memp;
+
+#ifdef FORE_PCI
+ /*
+ * Allocate memory for PROM buffer
+ */
+ memp = atm_dev_alloc(sizeof(Fore_prom), FORE_PROM_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_prom = (Fore_prom *) memp;
+#endif
+
+ return (0);
+}
+
+
+/*
+ * Command Queue Initialization
+ *
+ * Allocate and initialize the host-resident command queue structures
+ * and then initialize the CP-resident queue structures.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_cmd_initialize(fup)
+ Fore_unit *fup;
+{
+ Aali *aap = fup->fu_aali;
+ Cmd_queue *cqp;
+ H_cmd_queue *hcp;
+ Q_status *qsp;
+ Q_status *qsp_dma;
+ int i;
+
+ /*
+ * Point to CP-resident command queue
+ */
+ cqp = (Cmd_queue *)(fup->fu_ram + CP_READ(aap->aali_cmd_q));
+
+ /*
+ * Point to host-resident command queue structures
+ */
+ hcp = fup->fu_cmd_q;
+ qsp = fup->fu_cmd_stat;
+ qsp_dma = fup->fu_cmd_statd;
+
+ /*
+ * Loop thru all queue entries and do whatever needs doing
+ */
+ for (i = 0; i < CMD_QUELEN; i++) {
+
+ /*
+ * Set queue status word to free
+ */
+ *qsp = QSTAT_FREE;
+
+ /*
+ * Set up host queue entry and link into ring
+ */
+ hcp->hcq_cpelem = cqp;
+ hcp->hcq_status = qsp;
+ if (i == (CMD_QUELEN - 1))
+ hcp->hcq_next = fup->fu_cmd_q;
+ else
+ hcp->hcq_next = hcp + 1;
+
+ /*
+ * Now let the CP into the game
+ */
+ cqp->cmdq_status = (CP_dma) CP_WRITE(qsp_dma);
+
+ /*
+ * Bump all queue pointers
+ */
+ hcp++;
+ qsp++;
+ qsp_dma++;
+ cqp++;
+ }
+
+ /*
+ * Initialize queue pointers
+ */
+ fup->fu_cmd_head = fup->fu_cmd_tail = fup->fu_cmd_q;
+
+ return;
+}
+
+
+/*
+ * Drain Command Queue
+ *
+ * This function will process and free all completed entries at the head
+ * of the command queue.
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_cmd_drain(fup)
+ Fore_unit *fup;
+{
+ H_cmd_queue *hcp;
+ Fore_vcc *fvp;
+
+ /*
+ * Process each completed entry
+ */
+ while (*fup->fu_cmd_head->hcq_status & QSTAT_COMPLETED) {
+
+ hcp = fup->fu_cmd_head;
+
+ /*
+ * Process command completion
+ */
+ switch (hcp->hcq_code) {
+
+ case CMD_ACT_VCCIN:
+ case CMD_ACT_VCCOUT:
+ fvp = hcp->hcq_arg;
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * VCC activation failed - just abort vcc
+ */
+ if (fvp)
+ atm_cm_abort(fvp->fv_connvc,
+ &fore_cause);
+ fup->fu_pif.pif_cmderrors++;
+ } else {
+ /*
+ * Successful VCC activation
+ */
+ if (fvp) {
+ fvp->fv_state = CVS_ACTIVE;
+ fup->fu_open_vcc++;
+ }
+ }
+ break;
+
+ case CMD_DACT_VCCIN:
+ case CMD_DACT_VCCOUT:
+ fvp = hcp->hcq_arg;
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * VCC dactivation failed - whine
+ */
+ log(LOG_ERR,
+ "fore_cmd_drain: DACT failed, vcc=(%d,%d)\n",
+ fvp->fv_connvc->cvc_vcc->vc_vpi,
+ fvp->fv_connvc->cvc_vcc->vc_vci);
+ fup->fu_pif.pif_cmderrors++;
+ } else {
+ /*
+ * Successful VCC dactivation - so what?
+ */
+ }
+ break;
+
+ case CMD_GET_STATS:
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * Couldn't get stats
+ */
+ fup->fu_pif.pif_cmderrors++;
+ fup->fu_stats_ret = EIO;
+ } else {
+ /*
+ * Stats are now in unit buffer
+ */
+ fup->fu_stats_ret = 0;
+ }
+ DMA_FREE_ADDR(fup->fu_stats, fup->fu_statsd,
+ sizeof(Fore_cp_stats), 0);
+ fup->fu_flags &= ~FUF_STATCMD;
+
+ /*
+ * Flush received stats data
+ */
+#ifdef VAC
+ if (vac)
+ vac_pageflush((addr_t)fup->fu_stats);
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /*
+ * Little endian machines receives the stats in
+ * wrong byte order. Instead of swapping in user
+ * land, swap here so that everything going out
+ * of the kernel is in correct host order.
+ */
+ {
+ u_long *bp = (u_long *)fup->fu_stats;
+ int loop;
+
+ for ( loop = 0; loop < sizeof(Fore_cp_stats)/
+ sizeof(long); loop++, bp++ )
+ *bp = ntohl(*bp);
+ }
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+ /*
+ * Poke whoever is waiting on the stats
+ */
+ wakeup((caddr_t)&fup->fu_stats);
+ break;
+
+#ifdef FORE_PCI
+ case CMD_GET_PROM:
+ if (*hcp->hcq_status & QSTAT_ERROR) {
+ /*
+ * Couldn't get PROM data
+ */
+ fup->fu_pif.pif_cmderrors++;
+ log(LOG_ERR,
+ "fore_cmd_drain: %s%d: GET_PROM failed\n",
+ fup->fu_pif.pif_name,
+ fup->fu_pif.pif_unit);
+ } else {
+ Fore_prom *fp = fup->fu_prom;
+
+ /*
+ * Flush received PROM data
+ */
+#ifdef VAC
+ if (vac)
+ vac_pageflush((addr_t)fp);
+#endif
+ /*
+ * Copy PROM info into config areas
+ */
+ KM_COPY(&fp->pr_mac[2],
+ &fup->fu_pif.pif_macaddr,
+ sizeof(struct mac_addr));
+ fup->fu_config.ac_macaddr =
+ fup->fu_pif.pif_macaddr;
+ sprintf(fup->fu_config.ac_hard_vers, "%d.%d.%d",
+ (fp->pr_hwver >> 16) & 0xff,
+ (fp->pr_hwver >> 8) & 0xff,
+ fp->pr_hwver & 0xff);
+ fup->fu_config.ac_serial = fp->pr_serno;
+ }
+
+ DMA_FREE_ADDR(fup->fu_prom, fup->fu_promd,
+ sizeof(Fore_prom), 0);
+ break;
+#endif /* FORE_PCI */
+
+ default:
+ log(LOG_ERR, "fore_cmd_drain: unknown command %d\n",
+ hcp->hcq_code);
+ }
+
+ /*
+ * Mark this entry free for use and bump head pointer
+ * to the next entry in the queue
+ */
+ *hcp->hcq_status = QSTAT_FREE;
+ fup->fu_cmd_head = hcp->hcq_next;
+ }
+
+ return;
+}
+
+
+/*
+ * Free Command Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_cmd_free(fup)
+ Fore_unit *fup;
+{
+ H_cmd_queue *hcp;
+
+ /*
+ * Deal with any commands left on the queue
+ */
+ if (fup->fu_flags & CUF_INITED) {
+ while (*fup->fu_cmd_head->hcq_status != QSTAT_FREE) {
+ hcp = fup->fu_cmd_head;
+
+ switch (hcp->hcq_code) {
+
+ case CMD_GET_STATS:
+ /*
+ * Just in case someone is sleeping on this
+ */
+ fup->fu_stats_ret = EIO;
+ wakeup((caddr_t)&fup->fu_stats);
+ break;
+ }
+
+ *hcp->hcq_status = QSTAT_FREE;
+ fup->fu_cmd_head = hcp->hcq_next;
+ }
+ }
+
+ /*
+ * Free the statistics buffer
+ */
+ if (fup->fu_stats) {
+ atm_dev_free(fup->fu_stats);
+ fup->fu_stats = NULL;
+ }
+
+#ifdef FORE_PCI
+ /*
+ * Free the PROM buffer
+ */
+ if (fup->fu_prom) {
+ atm_dev_free(fup->fu_prom);
+ fup->fu_prom = NULL;
+ }
+#endif
+
+ /*
+ * Free the status words
+ */
+ if (fup->fu_cmd_stat) {
+ if (fup->fu_cmd_statd) {
+ DMA_FREE_ADDR(fup->fu_cmd_stat, fup->fu_cmd_statd,
+ sizeof(Q_status) * CMD_QUELEN,
+ ATM_DEV_NONCACHE);
+ }
+ atm_dev_free((void *)fup->fu_cmd_stat);
+ fup->fu_cmd_stat = NULL;
+ fup->fu_cmd_statd = NULL;
+ }
+
+ return;
+}
+
diff --git a/sys/dev/hfa/fore_globals.c b/sys/dev/hfa/fore_globals.c
new file mode 100644
index 0000000..4abc5fa
--- /dev/null
+++ b/sys/dev/hfa/fore_globals.c
@@ -0,0 +1,119 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_globals.c,v 1.6 1997/05/06 22:09:31 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Global variable definitions
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_globals.c,v 1.6 1997/05/06 22:09:31 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Supported device models
+ */
+Fore_device fore_devices[] = {
+#ifdef FORE_SBUS
+ {SBA200E_PROM_NAME, DEV_FORE_SBA200E},
+ {SBA200_PROM_NAME, DEV_FORE_SBA200},
+#endif
+ {""}
+};
+
+
+/*
+ * Device unit table
+ */
+Fore_unit *fore_units[FORE_MAX_UNITS] = {NULL};
+int fore_nunits = 0;
+
+
+/*
+ * ATM Interface services
+ */
+static struct stack_defn fore_svaal5 = {
+ NULL,
+ SAP_CPCS_AAL5,
+ SDF_TERM,
+ atm_dev_inst,
+ atm_dev_lower,
+ NULL,
+ 0,
+};
+static struct stack_defn fore_svaal4 = {
+ &fore_svaal5,
+ SAP_CPCS_AAL3_4,
+ SDF_TERM,
+ atm_dev_inst,
+ atm_dev_lower,
+ NULL,
+ 0,
+};
+static struct stack_defn fore_svaal0 = {
+ &fore_svaal4,
+ SAP_ATM,
+ SDF_TERM,
+ atm_dev_inst,
+ atm_dev_lower,
+ NULL,
+ 0,
+};
+struct stack_defn *fore_services = &fore_svaal0;
+
+
+/*
+ * Storage pools
+ */
+struct sp_info fore_nif_pool = {
+ "fore nif pool", /* si_name */
+ sizeof(struct atm_nif), /* si_blksiz */
+ 5, /* si_blkcnt */
+ 20 /* si_maxallow */
+};
+
+struct sp_info fore_vcc_pool = {
+ "fore vcc pool", /* si_name */
+ sizeof(Fore_vcc), /* si_blksiz */
+ 10, /* si_blkcnt */
+ 100 /* si_maxallow */
+};
+
+
+/*
+ * Watchdog timer
+ */
+struct atm_time fore_timer = {0, 0};
+
diff --git a/sys/dev/hfa/fore_if.c b/sys/dev/hfa/fore_if.c
new file mode 100644
index 0000000..7d3b3b6
--- /dev/null
+++ b/sys/dev/hfa/fore_if.c
@@ -0,0 +1,205 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_if.c,v 1.6 1998/08/26 23:28:58 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Network interface layer support
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_if.c,v 1.6 1998/08/26 23:28:58 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Handle netatm core service interface ioctl requests
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * code ioctl function (sub)code
+ * data data to/from ioctl
+ * arg optional code-specific argument
+ *
+ * Returns:
+ * 0 request processed successfully
+ * error request failed - reason code
+ */
+int
+fore_atm_ioctl(code, data, arg)
+ int code;
+ caddr_t data;
+ caddr_t arg;
+{
+ struct atminfreq *aip = (struct atminfreq *)data;
+ struct atm_pif *pip;
+ Fore_unit *fup;
+ caddr_t buf = aip->air_buf_addr;
+ struct air_vinfo_rsp *avr;
+ int count, len, buf_len = aip->air_buf_len;
+ int err = 0;
+ char ifname[2*IFNAMSIZ];
+
+
+ ATM_DEBUG2("fore_atm_ioctl: code=%d, opcode=%d\n",
+ code, aip->air_opcode);
+
+ switch ( aip->air_opcode ) {
+
+ case AIOCS_INF_VST:
+ /*
+ * Get vendor statistics
+ */
+ pip = (struct atm_pif *)arg;
+ fup = (Fore_unit *)pip;
+ if ( pip == NULL )
+ return ( ENXIO );
+ sprintf ( ifname, "%s%d", pip->pif_name, pip->pif_unit );
+
+ /*
+ * Cast response structure onto user's buffer
+ */
+ avr = (struct air_vinfo_rsp *)buf;
+
+ /*
+ * How large is the response structure?
+ */
+ len = sizeof(struct air_vinfo_rsp);
+
+ /*
+ * Sanity check - enough room for response structure?
+ */
+ if ( buf_len < len )
+ return ( ENOSPC );
+
+ /*
+ * Copy interface name into response structure
+ */
+ if ( err = copyout ( ifname, avr->avsp_intf, IFNAMSIZ ) )
+ break;
+
+ /*
+ * Advance the buffer address and decrement the size
+ */
+ buf += len;
+ buf_len -= len;
+
+ /*
+ * Get the vendor stats from the hardware
+ */
+ count = 0;
+ if ( ( err = fore_get_stats ( fup ) ) == 0 )
+ {
+ /*
+ * Stick as much of it as we have room for
+ * into the response
+ */
+ count = min ( sizeof(Fore_stats), buf_len );
+
+ /*
+ * Copy stats into user's buffer. Return value is
+ * amount of data copied.
+ */
+ if (err = copyout((caddr_t)fup->fu_stats, buf, count))
+ break;
+ buf += count;
+ buf_len -= count;
+ if ( count < sizeof(Fore_stats) )
+ err = ENOSPC;
+ }
+
+ /*
+ * Record amount we're returning as vendor info...
+ */
+ if (err = copyout(&count, &avr->avsp_len, sizeof(int)))
+ break;
+
+ /*
+ * Update the reply pointers and lengths
+ */
+ aip->air_buf_addr = buf;
+ aip->air_buf_len = buf_len;
+ break;
+
+ default:
+ err = ENOSYS; /* Operation not supported */
+ break;
+ }
+
+ return (err);
+}
+
+
+/*
+ * Free Fore-specific device resources
+ *
+ * Frees all dynamically acquired resources for a device unit. Before
+ * this function is called, the CP will have been reset and our interrupt
+ * vectors removed.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+fore_interface_free(fup)
+ Fore_unit *fup;
+{
+
+ /*
+ * Free up all of our allocated memory
+ */
+ fore_xmit_free(fup);
+ fore_recv_free(fup);
+ fore_buf_free(fup);
+ fore_cmd_free(fup);
+
+ /*
+ * Clear device initialized
+ */
+ if (fup->fu_flags & CUF_INITED) {
+ fup->fu_flags &= ~CUF_INITED;
+ }
+
+ if (fup->fu_flags & FUF_STATCMD) {
+ DMA_FREE_ADDR(fup->fu_stats, fup->fu_statsd,
+ sizeof(Fore_cp_stats), 0);
+ fup->fu_flags &= ~FUF_STATCMD;
+ }
+ return;
+}
+
diff --git a/sys/dev/hfa/fore_include.h b/sys/dev/hfa/fore_include.h
new file mode 100644
index 0000000..b146a3c
--- /dev/null
+++ b/sys/dev/hfa/fore_include.h
@@ -0,0 +1,139 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_include.h,v 1.8 1998/02/19 20:10:18 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Local driver include files and global declarations
+ *
+ */
+
+#ifndef _FORE_INCLUDE_H
+#define _FORE_INCLUDE_H
+
+#include <netatm/kern_include.h>
+
+/*
+ * If not specified elsewhere, guess which type of bus support we want
+ */
+#if !(defined(FORE_PCI) || defined(FORE_SBUS))
+#if defined(sparc)
+#define FORE_SBUS
+#elif defined(__i386__)
+#define FORE_PCI
+#endif
+#endif
+
+#ifdef FORE_PCI
+#include <pci/pcireg.h>
+#include <pci/pcivar.h>
+#endif
+
+#include <dev/hfa/fore.h>
+#include <dev/hfa/fore_aali.h>
+#include <dev/hfa/fore_slave.h>
+#include <dev/hfa/fore_stats.h>
+#include <dev/hfa/fore_var.h>
+
+/*
+ * Global function declarations
+ */
+ /* fore_buffer.c */
+int fore_buf_allocate __P((Fore_unit *));
+void fore_buf_initialize __P((Fore_unit *));
+void fore_buf_supply __P((Fore_unit *));
+void fore_buf_free __P((Fore_unit *));
+
+ /* fore_command.c */
+int fore_cmd_allocate __P((Fore_unit *));
+void fore_cmd_initialize __P((Fore_unit *));
+void fore_cmd_drain __P((Fore_unit *));
+void fore_cmd_free __P((Fore_unit *));
+
+ /* fore_if.c */
+int fore_atm_ioctl __P((int, caddr_t, caddr_t));
+void fore_interface_free __P((Fore_unit *));
+
+ /* fore_init.c */
+void fore_initialize __P((Fore_unit *));
+void fore_initialize_complete __P((Fore_unit *));
+
+ /* fore_intr.c */
+#if defined(sun)
+int fore_poll __P((void));
+#endif
+#if (defined(BSD) && (BSD <= 199306))
+int fore_intr __P((void *));
+#else
+void fore_intr __P((void *));
+#endif
+void fore_watchdog __P((Fore_unit *));
+
+ /* fore_load.c */
+
+ /* fore_output.c */
+void fore_output __P((Cmn_unit *, Cmn_vcc *, KBuffer *));
+
+ /* fore_receive.c */
+int fore_recv_allocate __P((Fore_unit *));
+void fore_recv_initialize __P((Fore_unit *));
+void fore_recv_drain __P((Fore_unit *));
+void fore_recv_free __P((Fore_unit *));
+
+ /* fore_stats.c */
+int fore_get_stats __P((Fore_unit *));
+
+ /* fore_timer.c */
+void fore_timeout __P((struct atm_time *));
+
+ /* fore_transmit.c */
+int fore_xmit_allocate __P((Fore_unit *));
+void fore_xmit_initialize __P((Fore_unit *));
+void fore_xmit_drain __P((Fore_unit *));
+void fore_xmit_free __P((Fore_unit *));
+
+ /* fore_vcm.c */
+int fore_instvcc __P((Cmn_unit *, Cmn_vcc *));
+int fore_openvcc __P((Cmn_unit *, Cmn_vcc *));
+int fore_closevcc __P((Cmn_unit *, Cmn_vcc *));
+
+
+/*
+ * Global variable declarations
+ */
+extern Fore_device fore_devices[];
+extern Fore_unit *fore_units[];
+extern int fore_nunits;
+extern struct stack_defn *fore_services;
+extern struct sp_info fore_nif_pool;
+extern struct sp_info fore_vcc_pool;
+extern struct atm_time fore_timer;
+
+#endif /* _FORE_INCLUDE_H */
diff --git a/sys/dev/hfa/fore_init.c b/sys/dev/hfa/fore_init.c
new file mode 100644
index 0000000..61f4f01
--- /dev/null
+++ b/sys/dev/hfa/fore_init.c
@@ -0,0 +1,314 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_init.c,v 1.7 1997/05/06 22:09:43 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Cell Processor (CP) initialization routines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_init.c,v 1.7 1997/05/06 22:09:43 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Local functions
+ */
+#ifdef FORE_PCI
+static void fore_get_prom __P((Fore_unit *));
+#endif
+
+
+/*
+ * Begin CP Initialization
+ *
+ * This function will poll for the successful downloading and starting of
+ * the CP microcode program. After the microcode is running, we will allocate
+ * any needed kernel memory (must do it in non-interrupt mode), build the CP
+ * queue configurations and issue an Initialize command to the CP.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_initialize(fup)
+ Fore_unit *fup;
+{
+ Aali *aap;
+ Init_parms *inp;
+ caddr_t errmsg;
+ u_long vers;
+
+ /*
+ * Must wait until firmware has been downloaded and is running
+ */
+ if (CP_READ(fup->fu_mon->mon_bstat) != BOOT_RUNNING) {
+
+ /*
+ * Try again later
+ */
+ fup->fu_thandle =
+ timeout((KTimeout_ret(*) __P((void *)))fore_initialize,
+ (void *)fup, hz);
+ return;
+ } else
+ callout_handle_init(&fup->fu_thandle);
+
+ /*
+ * Allocate queues and whatever else is needed
+ */
+ if (fore_xmit_allocate(fup)) {
+ errmsg = "transmit queue allocation";
+ goto failed;
+ }
+ if (fore_recv_allocate(fup)) {
+ errmsg = "receive queue allocation";
+ goto failed;
+ }
+ if (fore_buf_allocate(fup)) {
+ errmsg = "buffer supply queue allocation";
+ goto failed;
+ }
+ if (fore_cmd_allocate(fup)) {
+ errmsg = "command queue allocation";
+ goto failed;
+ }
+
+ /*
+ * CP microcode is downloaded - locate shared memory interface
+ */
+ aap = (Aali *)(fup->fu_ram + CP_READ(fup->fu_mon->mon_appl));
+ fup->fu_aali = aap;
+
+ /*
+ * Pick out any interesting info from the microcode
+ */
+ vers = CP_READ(aap->aali_ucode_ver);
+ if (vers < FORE_MIN_UCODE) {
+ errmsg = "unsupported microcode version";
+ goto failed;
+ }
+ sprintf(fup->fu_config.ac_firm_vers, "%d.%d.%d",
+ (vers >> 16) & 0xff, (vers >> 8) & 0xff, vers & 0xff);
+
+#ifdef notdef
+ /*
+ * Turn on CP debugging
+ */
+ aap->aali_hostlog = 1;
+#endif
+
+ /*
+ * Build the initialization block
+ */
+ inp = &aap->aali_init;
+ inp->init_numvcc = CP_WRITE(FORE_MAX_VCC);
+ inp->init_cmd_elem = CP_WRITE(CMD_QUELEN);
+ inp->init_xmit_elem = CP_WRITE(XMIT_QUELEN);
+ inp->init_recv_elem = CP_WRITE(RECV_QUELEN);
+ inp->init_recv_ext = CP_WRITE(RECV_EXTRA_SEGS);
+ inp->init_xmit_ext = CP_WRITE(XMIT_EXTRA_SEGS);
+ inp->init_buf1s.bfs_quelen = CP_WRITE(BUF1_SM_QUELEN);
+ inp->init_buf1s.bfs_bufsize = CP_WRITE(BUF1_SM_SIZE);
+ inp->init_buf1s.bfs_cppool = CP_WRITE(BUF1_SM_CPPOOL);
+ inp->init_buf1s.bfs_entsize = CP_WRITE(BUF1_SM_ENTSIZE);
+ inp->init_buf1l.bfs_quelen = CP_WRITE(BUF1_LG_QUELEN);
+ inp->init_buf1l.bfs_bufsize = CP_WRITE(BUF1_LG_SIZE);
+ inp->init_buf1l.bfs_cppool = CP_WRITE(BUF1_LG_CPPOOL);
+ inp->init_buf1l.bfs_entsize = CP_WRITE(BUF1_LG_ENTSIZE);
+ inp->init_buf2s.bfs_quelen = CP_WRITE(0);
+ inp->init_buf2s.bfs_bufsize = CP_WRITE(0);
+ inp->init_buf2s.bfs_cppool = CP_WRITE(0);
+ inp->init_buf2s.bfs_entsize = CP_WRITE(0);
+ inp->init_buf2l.bfs_quelen = CP_WRITE(0);
+ inp->init_buf2l.bfs_bufsize = CP_WRITE(0);
+ inp->init_buf2l.bfs_cppool = CP_WRITE(0);
+ inp->init_buf2l.bfs_entsize = CP_WRITE(0);
+
+ /*
+ * Enable device interrupts
+ */
+ aap->aali_intr_ena = CP_WRITE(1);
+
+ /*
+ * Issue the Initialize command to the CP and wait for
+ * the CP to interrupt to signal completion
+ */
+ inp->init_status = CP_WRITE(QSTAT_PENDING);
+ inp->init_cmd = CP_WRITE(CMD_INIT | CMD_INTR_REQ);
+ return;
+
+failed:
+ /*
+ * Initialization failure
+ */
+ fore_interface_free(fup);
+ log(LOG_ERR, "fore initialization failed: intf=%s%d, err=%s\n",
+ fup->fu_pif.pif_name, fup->fu_pif.pif_unit, errmsg);
+ return;
+}
+
+
+/*
+ * Complete CP Initialization
+ *
+ * Called after the CP has successfully completed processing of the
+ * Initialize command. We will now finish off our part of the
+ * initialization process by setting up all the host-based queue
+ * management structures.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_initialize_complete(fup)
+ Fore_unit *fup;
+{
+ Aali *aap = fup->fu_aali;
+
+ /*
+ * Log an initialization failure
+ */
+ if (CP_READ(aap->aali_init.init_status) & QSTAT_ERROR) {
+
+ log(LOG_ERR,
+ "fore initialization failed: intf=%s%d, hbeat=0x%x\n",
+ fup->fu_pif.pif_name, fup->fu_pif.pif_unit,
+ CP_READ(aap->aali_heartbeat));
+ return;
+ }
+
+ ATM_DEBUG1("heap=0x%x\n", aap->aali_heap);
+ ATM_DEBUG1("heaplen=0x%x\n", aap->aali_heaplen);
+ ATM_DEBUG1("cmd_q=0x%x\n", aap->aali_cmd_q);
+ ATM_DEBUG1("xmit_q=0x%x\n", aap->aali_xmit_q);
+ ATM_DEBUG1("recv_q=0x%x\n", aap->aali_recv_q);
+ ATM_DEBUG1("buf1s_q=0x%x\n", aap->aali_buf1s_q);
+ ATM_DEBUG1("buf1l_q=0x%x\n", aap->aali_buf1l_q);
+ ATM_DEBUG1("buf2s_q=0x%x\n", aap->aali_buf2s_q);
+ ATM_DEBUG1("buf2l_q=0x%x\n", aap->aali_buf2l_q);
+
+ /*
+ * Initialize all of our queues
+ */
+ fore_xmit_initialize(fup);
+ fore_recv_initialize(fup);
+ fore_buf_initialize(fup);
+ fore_cmd_initialize(fup);
+
+ /*
+ * Mark device initialization completed
+ */
+ fup->fu_flags |= CUF_INITED;
+
+#ifdef FORE_PCI
+ fore_get_prom(fup);
+#endif
+ return;
+}
+
+
+#ifdef FORE_PCI
+/*
+ * Get device PROM values from CP
+ *
+ * This function will issue a GET_PROM command to the CP in order to
+ * initiate the DMA transfer of the CP's PROM structure to the host.
+ * This will be called after CP initialization has completed.
+ * There is (currently) no retry if this fails.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+fore_get_prom(fup)
+ Fore_unit *fup;
+{
+ H_cmd_queue *hcp;
+ Cmd_queue *cqp;
+
+ /*
+ * Queue command at end of command queue
+ */
+ hcp = fup->fu_cmd_tail;
+ if ((*hcp->hcq_status) & QSTAT_FREE) {
+
+ /*
+ * Queue entry available, so set our view of things up
+ */
+ hcp->hcq_code = CMD_GET_PROM;
+ hcp->hcq_arg = NULL;
+ fup->fu_cmd_tail = hcp->hcq_next;
+
+ /*
+ * Now set the CP-resident queue entry - the CP will grab
+ * the command when the op-code is set.
+ */
+ cqp = hcp->hcq_cpelem;
+ (*hcp->hcq_status) = QSTAT_PENDING;
+
+ fup->fu_promd = DMA_GET_ADDR(fup->fu_prom, sizeof(Fore_prom),
+ FORE_PROM_ALIGN, 0);
+ if (fup->fu_promd == NULL) {
+ fup->fu_stats->st_drv.drv_cm_nodma++;
+ return;
+ }
+ cqp->cmdq_prom.prom_buffer = (CP_dma) CP_WRITE(fup->fu_promd);
+ cqp->cmdq_prom.prom_cmd = CP_WRITE(CMD_GET_PROM | CMD_INTR_REQ);
+
+ } else {
+ /*
+ * Command queue full
+ */
+ fup->fu_stats->st_drv.drv_cm_full++;
+ }
+
+ return;
+}
+#endif /* FORE_PCI */
+
diff --git a/sys/dev/hfa/fore_intr.c b/sys/dev/hfa/fore_intr.c
new file mode 100644
index 0000000..f295b62
--- /dev/null
+++ b/sys/dev/hfa/fore_intr.c
@@ -0,0 +1,268 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_intr.c,v 1.7 1997/05/06 22:09:48 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Interrupt processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_intr.c,v 1.7 1997/05/06 22:09:48 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+#if defined(sun)
+/*
+ * Polling interrupt routine
+ *
+ * Polling interrupts are handled by calling all interrupt service
+ * routines for a given level until someone claims to have "handled" the
+ * interrupt.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 1 an interrupt has been serviced
+ * 0 no interrupts serviced
+ *
+ */
+int
+fore_poll()
+{
+ int serviced = 0;
+ int unit;
+
+ /*
+ * See if any of our devices are interrupting
+ */
+ for ( unit = 0; unit < fore_nunits; unit++ )
+ {
+ Fore_unit *fup = fore_units[unit];
+
+ if (fup == NULL)
+ continue;
+
+ serviced += fore_intr((void *)fup);
+ }
+
+ /*
+ * Indicate if we handled an interrupt
+ */
+ return (serviced ? 1 : 0);
+}
+#endif /* defined(sun) */
+
+
+/*
+ * Device interrupt routine
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * arg pointer to device unit structure
+ *
+ * Returns:
+ * 1 device interrupt was serviced
+ * 0 no interrupts serviced
+ *
+ */
+#if (defined(BSD) && (BSD <= 199306))
+int
+#else
+void
+#endif
+fore_intr(arg)
+ void *arg;
+{
+ Fore_unit *fup = arg;
+ Aali *aap;
+#if (defined(BSD) && (BSD <= 199306))
+ int serviced = 0;
+#endif
+
+ /*
+ * Try to prevent stuff happening after we've paniced
+ */
+ if (panicstr) {
+ goto done;
+ }
+
+ /*
+ * Get to the microcode shared memory interface
+ */
+ if ((aap = fup->fu_aali) == NULL)
+ goto done;
+
+ /*
+ * Has this card issued an interrupt??
+ */
+#ifdef FORE_PCI
+ if (*fup->fu_psr) {
+#else
+ if (aap->aali_intr_sent) {
+#endif
+
+ /*
+ * Indicate that we've serviced an interrupt.
+ */
+#if (defined(BSD) && (BSD <= 199306))
+ serviced = 1;
+#endif
+
+ /*
+ * Clear the device interrupt
+ */
+ switch (fup->fu_config.ac_device) {
+
+#ifdef FORE_SBUS
+ case DEV_FORE_SBA200E:
+ SBA200E_HCR_SET(*fup->fu_ctlreg, SBA200E_CLR_SBUS_INTR);
+ break;
+
+ case DEV_FORE_SBA200:
+ *fup->fu_ctlreg = SBA200_CLR_SBUS_INTR;
+ break;
+#endif
+#ifdef FORE_PCI
+ case DEV_FORE_PCA200E:
+ PCA200E_HCR_SET(*fup->fu_ctlreg, PCA200E_CLR_HBUS_INT);
+ break;
+#endif
+
+ }
+ aap->aali_intr_sent = CP_WRITE(0);
+
+ /*
+ * Reset the watchdog timer
+ */
+ fup->fu_timer = FORE_WATCHDOG;
+
+ /*
+ * Device initialization handled separately
+ */
+ if ((fup->fu_flags & CUF_INITED) == 0) {
+
+ /*
+ * We're just initializing device now, so see if
+ * the initialization command has completed
+ */
+ if (CP_READ(aap->aali_init.init_status) &
+ QSTAT_COMPLETED)
+ fore_initialize_complete(fup);
+
+ /*
+ * If we're still not inited, none of the host
+ * queues are setup yet
+ */
+ if ((fup->fu_flags & CUF_INITED) == 0)
+ goto done;
+ }
+
+ /*
+ * Drain the queues of completed work
+ */
+ fore_cmd_drain(fup);
+ fore_recv_drain(fup);
+ fore_xmit_drain(fup);
+
+ /*
+ * Supply more buffers to the CP
+ */
+ fore_buf_supply(fup);
+ }
+
+done:
+#if (defined(BSD) && (BSD <= 199306))
+ return(serviced);
+#else
+ return;
+#endif
+}
+
+
+/*
+ * Watchdog timeout routine
+ *
+ * Called when we haven't heard from the card in a while. Just in case
+ * we missed an interrupt, we'll drain the queues and try to resupply the
+ * CP with more receive buffers. If the CP is partially wedged, hopefully
+ * this will be enough to get it going again.
+ *
+ * Called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+fore_watchdog(fup)
+ Fore_unit *fup;
+{
+ /*
+ * Try to prevent stuff happening after we've paniced
+ */
+ if (panicstr) {
+ return;
+ }
+
+ /*
+ * Reset the watchdog timer
+ */
+ fup->fu_timer = FORE_WATCHDOG;
+
+ /*
+ * If the device is initialized, nudge it (wink, wink)
+ */
+ if (fup->fu_flags & CUF_INITED) {
+
+ /*
+ * Drain the queues of completed work
+ */
+ fore_cmd_drain(fup);
+ fore_recv_drain(fup);
+ fore_xmit_drain(fup);
+
+ /*
+ * Supply more buffers to the CP
+ */
+ fore_buf_supply(fup);
+ }
+
+ return;
+}
diff --git a/sys/dev/hfa/fore_load.c b/sys/dev/hfa/fore_load.c
new file mode 100644
index 0000000..4250ddc
--- /dev/null
+++ b/sys/dev/hfa/fore_load.c
@@ -0,0 +1,1618 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_load.c,v 1.12 1998/06/29 21:42:14 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Loadable kernel module and device identification support
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_load.c,v 1.12 1998/06/29 21:42:14 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Local functions
+ */
+static int fore_start __P((void));
+static int fore_stop __P((void));
+static int fore_doload __P((void));
+static int fore_dounload __P((void));
+#ifdef sun
+static int fore_identify __P((char *));
+static int fore_attach __P((struct devinfo *));
+#endif
+#ifdef __FreeBSD__
+static char * fore_pci_probe __P((pcici_t, pcidi_t));
+static void fore_pci_attach __P((pcici_t, int));
+#if BSD < 199506
+static int fore_pci_shutdown __P((struct kern_devconf *, int));
+#else
+static void fore_pci_shutdown __P((int, void *));
+#endif
+#endif
+static void fore_unattach __P((Fore_unit *));
+static void fore_reset __P((Fore_unit *));
+
+
+/*
+ * Local variables
+ */
+static int fore_inited = 0;
+
+/*
+ * Driver entry points
+ */
+#ifdef sun
+static struct dev_ops fore_ops = {
+ 1, /* revision */
+ fore_identify, /* identify */
+ fore_attach, /* attach */
+ NULL, /* open */
+ NULL, /* close */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* strategy */
+ NULL, /* dump */
+ NULL, /* psize */
+ NULL, /* ioctl */
+ NULL, /* reset */
+ NULL /* mmap */
+};
+#endif
+
+#ifdef __FreeBSD__
+static u_long fore_pci_count = 0;
+
+static struct pci_device fore_pci_device = {
+ FORE_DEV_NAME,
+ fore_pci_probe,
+ fore_pci_attach,
+ &fore_pci_count,
+#if BSD < 199506
+ fore_pci_shutdown
+#else
+ NULL
+#endif
+};
+
+DATA_SET(pcidevice_set, fore_pci_device);
+#endif
+
+
+/*
+ * Initialize driver processing
+ *
+ * This will be called during module loading. Not much to do here, as
+ * we must wait for our identify/attach routines to get called before
+ * we know what we're in for.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 startup was successful
+ * errno startup failed - reason indicated
+ *
+ */
+static int
+fore_start()
+{
+
+ /*
+ * Verify software version
+ */
+ if (atm_version != ATM_VERSION) {
+ log(LOG_ERR, "version mismatch: fore=%d.%d kernel=%d.%d\n",
+ ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION),
+ ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version));
+ return (EINVAL);
+ }
+
+ /*
+ * Initialize DMA mapping
+ */
+ DMA_INIT();
+
+ /*
+ * Start up watchdog timer
+ */
+ atm_timeout(&fore_timer, ATM_HZ * FORE_TIME_TICK, fore_timeout);
+
+ fore_inited = 1;
+
+ return (0);
+}
+
+
+/*
+ * Halt driver processing
+ *
+ * This will be called just prior to unloading the module from memory.
+ * Everything we've setup since we've been loaded must be undone here.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 shutdown was successful
+ * errno shutdown failed - reason indicated
+ *
+ */
+static int
+fore_stop()
+{
+ int err = 0;
+ int s = splimp();
+ int i;
+
+ /*
+ * Stop the watchdog timer
+ */
+ (void) atm_untimeout(&fore_timer);
+
+ /*
+ * Clean up each device (if any)
+ */
+ for ( i = 0; i < fore_nunits; i++ ) {
+ Fore_unit *fup = fore_units[i];
+
+ if (fup == NULL)
+ continue;
+
+ /*
+ * Deregister device from kernel services
+ */
+ if (err = atm_physif_deregister((Cmn_unit *)fup)) {
+ (void) splx(s);
+ return (err);
+ }
+
+ /*
+ * Unattach the device from the system
+ */
+ fore_unattach(fup);
+
+ /*
+ * Free any Fore-specific device resources
+ */
+ fore_interface_free(fup);
+
+ /*
+ * Free the unit structure
+ */
+ atm_dev_free(fup);
+ fore_units[i] = NULL;
+ }
+
+ fore_nunits = 0;
+
+ /*
+ * Now free our global resources
+ */
+
+ /*
+ * Release our storage pools
+ */
+ atm_release_pool(&fore_vcc_pool);
+ atm_release_pool(&fore_nif_pool);
+
+ /*
+ * Release all DMA mappings
+ */
+ DMA_RELEASE();
+
+ fore_inited = 0;
+
+ (void) splx(s);
+
+ return (0);
+}
+
+
+#ifdef sun
+/*
+ * Device identify routine
+ *
+ * Determine if this driver will support the named device. If we claim to
+ * support the device, our attach routine will (later) be called for the
+ * device.
+ *
+ * Arguments:
+ * name pointer to identifier string from device
+ *
+ * Returns:
+ * 1 driver claims support for this device
+ * 0 device not claimed by this driver
+ *
+ */
+static int
+fore_identify(name)
+ char *name;
+{
+ int ret = 0;
+ int i = 0;
+
+ /*
+ * Initialize driver stuff
+ */
+ if (fore_inited == 0) {
+ if (fore_start())
+ return (0);
+ }
+
+ while (fore_devices[i].fd_name) {
+ if (strcmp(fore_devices[i].fd_name, name) == 0) {
+
+ /*
+ * We support this device!!
+ */
+ if (fore_nunits < FORE_MAX_UNITS) {
+ fore_nunits++;
+ ret = 1;
+ } else {
+ log(LOG_ERR,
+ "fore_identify: Too many devices\n");
+ }
+ break;
+ }
+ i++;
+ }
+ return (ret);
+}
+
+
+/*
+ * Device attach routine
+ *
+ * Attach a device we've previously claimed to support. Walk through its
+ * register set and map, as required. Determine what level the device will
+ * be interrupting at and then register an interrupt handler for it. If we
+ * succeed, then reset the adapter and read useful info from its PROM.
+ * Last, register the interface with the kernel ATM services.
+ *
+ * Arguments:
+ * devinfo_p pointer to device information structure
+ *
+ * Returns:
+ * 0 attach was successful
+ * -1 attach failed
+ *
+ */
+static int
+fore_attach(devinfo_p)
+ struct dev_info *devinfo_p;
+{
+ struct dev_reg *dev_reg_p;
+ struct dev_intr *dev_intr_p;
+ Fore_unit *fup;
+ Atm_config *fcp;
+ addr_t valp;
+ int val;
+ int i;
+ int err_count = BOOT_LOOPS;
+ static int unit = 0;
+
+ /*
+ * Sanity check
+ */
+ if (devinfo_p == NULL)
+ return (-1);
+
+ /*
+ * Make sure this isn't a duplicate unit
+ */
+ if (fore_units[unit] != NULL)
+ return (-1);
+
+ /*
+ * Allocate a new unit structure
+ */
+ fup = (Fore_unit *) atm_dev_alloc(sizeof(Fore_unit), sizeof(int), 0);
+ if (fup == NULL)
+ return (-1);
+
+ /*
+ * Start initializing it
+ */
+ fup->fu_unit = unit;
+ fup->fu_mtu = FORE_IFF_MTU;
+ fup->fu_devinfo = devinfo_p;
+ fup->fu_vcc_pool = &fore_vcc_pool;
+ fup->fu_nif_pool = &fore_nif_pool;
+ fup->fu_ioctl = fore_atm_ioctl;
+ fup->fu_instvcc = fore_instvcc;
+ fup->fu_openvcc = fore_openvcc;
+ fup->fu_closevcc = fore_closevcc;
+ fup->fu_output = fore_output;
+
+ /*
+ * Consider this unit assigned
+ */
+ fore_units[unit] = fup;
+ unit++;
+
+ ATM_DEBUG1("fore_attach: fup=0x%x\n", (int)fup);
+ ATM_DEBUG2("\tfu_xmit_q=0x%x fu_xmit_head=0x%x\n",
+ (int)fup->fu_xmit_q, (int)&fup->fu_xmit_head);
+ ATM_DEBUG2("\tfu_recv_q=0x%x fu_recv_head=0x%x\n",
+ (int)fup->fu_recv_q, (int)&fup->fu_recv_head);
+ ATM_DEBUG2("\tfu_buf1s_q=0x%x fu_buf1s_head=0x%x\n",
+ (int)fup->fu_buf1s_q, (int)&fup->fu_buf1s_head);
+ ATM_DEBUG2("\tfu_buf1l_q=0x%x fu_buf1l_head=0x%x\n",
+ (int)fup->fu_buf1l_q, (int)&fup->fu_buf1l_head);
+ ATM_DEBUG2("\tfu_cmd_q=0x%x fu_cmd_head=0x%x\n",
+ (int)fup->fu_cmd_q, (int)&fup->fu_cmd_head);
+ ATM_DEBUG1("\tfu_stats=0x%x\n",
+ (int)&fup->fu_stats);
+
+ /*
+ * Tell kernel our unit number
+ */
+ devinfo_p->devi_unit = fup->fu_unit;
+
+ /*
+ * Figure out what type of device we've got. This should always
+ * work since we've already done this at identify time!
+ */
+ i = 0;
+ while (fore_devices[i].fd_name) {
+ if (strcmp(fore_devices[i].fd_name, devinfo_p->devi_name) == 0)
+ break;
+ i++;
+ }
+ if (fore_devices[i].fd_name == NULL)
+ return (-1);
+
+ fup->fu_config.ac_device = fore_devices[i].fd_devtyp;
+
+ /*
+ * Walk through the OPENPROM register information
+ * mapping register banks as they are found.
+ */
+ for ( dev_reg_p = devinfo_p->devi_reg, i = 1;
+ i <= devinfo_p->devi_nreg; i++, ++dev_reg_p )
+ {
+ if ( dev_reg_p == NULL )
+ {
+ /*
+ * Can't happen...
+ */
+ return ( -1 );
+ }
+
+ /*
+ * Each device type has different register sets
+ */
+ switch (fup->fu_config.ac_device) {
+
+#ifdef FORE_SBUS
+ case DEV_FORE_SBA200E:
+
+ switch ( i )
+ {
+ /*
+ * Host Control Register (HCR)
+ */
+ case 1:
+ if ( sizeof(Fore_reg) != dev_reg_p->reg_size )
+ {
+ return ( -1 );
+ }
+ fup->fu_ctlreg = (Fore_reg *)
+ map_regs ( dev_reg_p->reg_addr,
+ sizeof(Fore_reg),
+ dev_reg_p->reg_bustype );
+ if ( fup->fu_ctlreg == NULL )
+ {
+ return ( -1 );
+ }
+ break;
+
+ /*
+ * SBus Burst Transfer Configuration Register
+ */
+ case 2:
+ /*
+ * Not used
+ */
+ break;
+
+ /*
+ * SBus Interrupt Level Select Register
+ */
+ case 3:
+ if ( sizeof (Fore_reg) != dev_reg_p->reg_size )
+ {
+ return ( -1 );
+ }
+ fup->fu_intlvl = (Fore_reg *)
+ map_regs ( dev_reg_p->reg_addr,
+ sizeof(Fore_reg),
+ dev_reg_p->reg_bustype );
+ if ( fup->fu_intlvl == NULL )
+ {
+ return ( -1 );
+ }
+ break;
+
+ /*
+ * i960 RAM
+ */
+ case 4:
+ fup->fu_ram = (Fore_mem *)
+ map_regs ( dev_reg_p->reg_addr,
+ dev_reg_p->reg_size,
+ dev_reg_p->reg_bustype );
+ if ( fup->fu_ram == NULL )
+ {
+ return ( -1 );
+ }
+ fup->fu_ramsize = dev_reg_p->reg_size;
+
+ /*
+ * Various versions of the Sun PROM mess with
+ * the reg_addr value in unpredictable (to me,
+ * at least) ways, so just use the "memoffset"
+ * property, which should give us the RAM
+ * offset directly.
+ */
+ val = getprop(devinfo_p->devi_nodeid,
+ "memoffset", -1);
+ if (val == -1) {
+ return (-1);
+ }
+ fup->fu_config.ac_ram = val;
+ fup->fu_config.ac_ramsize = fup->fu_ramsize;
+
+ /*
+ * Set monitor interface for initializing
+ */
+ fup->fu_mon = (Mon960 *)
+ (fup->fu_ram + MON960_BASE);
+ break;
+
+ default:
+ log(LOG_ERR,
+ "fore_attach: Too many registers\n");
+ return ( -1 );
+ }
+ break;
+
+ case DEV_FORE_SBA200:
+
+ switch ( i )
+ {
+ /*
+ * Board Control Register (BCR)
+ */
+ case 1:
+ if ( sizeof(Fore_reg) != dev_reg_p->reg_size )
+ {
+ return ( -1 );
+ }
+ fup->fu_ctlreg = (Fore_reg *)
+ map_regs ( dev_reg_p->reg_addr,
+ sizeof(Fore_reg),
+ dev_reg_p->reg_bustype );
+ if ( fup->fu_ctlreg == NULL )
+ {
+ return ( -1 );
+ }
+ break;
+
+ /*
+ * i960 RAM
+ */
+ case 2:
+ fup->fu_ram = (Fore_mem *)
+ map_regs ( dev_reg_p->reg_addr,
+ dev_reg_p->reg_size,
+ dev_reg_p->reg_bustype );
+ if ( fup->fu_ram == NULL )
+ {
+ return ( -1 );
+ }
+ fup->fu_ramsize = dev_reg_p->reg_size;
+
+ /*
+ * Various versions of the Sun PROM mess with
+ * the reg_addr value in unpredictable (to me,
+ * at least) ways, so just use the "memoffset"
+ * property, which should give us the RAM
+ * offset directly.
+ */
+ val = getprop(devinfo_p->devi_nodeid,
+ "memoffset", -1);
+ if (val == -1) {
+ return (-1);
+ }
+ fup->fu_config.ac_ram = val;
+ fup->fu_config.ac_ramsize = fup->fu_ramsize;
+
+ /*
+ * Set monitor interface for initializing
+ */
+ fup->fu_mon = (Mon960 *)
+ (fup->fu_ram + MON960_BASE);
+ break;
+
+ default:
+ log(LOG_ERR,
+ "fore_attach: Too many registers\n");
+ return ( -1 );
+ }
+ break;
+#endif /* FORE_SBUS */
+
+ default:
+ log(LOG_ERR,
+ "fore_attach: Unsupported device type %d\n",
+ fup->fu_config.ac_device);
+ return (-1);
+ }
+ }
+
+ /*
+ * Install the device in the interrupt chain.
+ *
+ * dev_intr_p may be null IFF devi_nintr is zero.
+ */
+ dev_intr_p = devinfo_p->devi_intr;
+ for ( i = devinfo_p->devi_nintr; i > 0; --i, ++dev_intr_p )
+ {
+
+ if ( dev_intr_p == NULL )
+ {
+ /*
+ * Can't happen.
+ */
+ return ( -1 );
+ }
+
+ /*
+ * Convert hardware ipl (0-15) into spl level.
+ */
+ if ( ipltospl ( dev_intr_p->int_pri ) > fup->fu_intrpri )
+ {
+ fup->fu_intrpri = ipltospl ( dev_intr_p->int_pri );
+
+ /*
+ * If SBA-200E card, set SBus interrupt level
+ * into board register
+ */
+ if ( fup->fu_intlvl ) {
+#if defined(sun4c)
+ *(fup->fu_intlvl) = dev_intr_p->int_pri;
+#elif defined(sun4m)
+ extern int svimap[];
+
+ *(fup->fu_intlvl) =
+ svimap[dev_intr_p->int_pri & 0xf];
+#else
+ #error PORT ME;
+#endif
+ }
+ }
+
+ DEVICE_LOCK((Cmn_unit *)fup);
+
+ /*
+ * Register our interrupt routine.
+ */
+ (void) addintr ( dev_intr_p->int_pri, fore_poll,
+ devinfo_p->devi_name, devinfo_p->devi_unit );
+
+ /*
+ * If we can do DMA (we can), then DVMA routines need
+ * to know the highest IPL level we will interrupt at.
+ */
+ adddma ( dev_intr_p->int_pri );
+
+ DEVICE_UNLOCK((Cmn_unit *)fup);
+ }
+
+ /*
+ * Poke the hardware...boot the CP and prepare it for downloading
+ */
+ fore_reset(fup);
+
+ switch (fup->fu_config.ac_device) {
+
+#ifdef FORE_SBUS
+ case DEV_FORE_SBA200E:
+ /*
+ * Enable interrupts
+ */
+ SBA200E_HCR_SET(*fup->fu_ctlreg, SBA200E_SBUS_ENA);
+ break;
+#endif /* FORE_SBUS */
+ }
+
+ /*
+ * Wait for monitor to perform self-test
+ */
+ while (CP_READ(fup->fu_mon->mon_bstat) != BOOT_MONREADY) {
+ if (CP_READ(fup->fu_mon->mon_bstat) == BOOT_FAILTEST) {
+ log(LOG_ERR, "fore_attach: Unit %d failed self-test\n",
+ fup->fu_unit);
+ return (-1);
+
+ } else if ( --err_count == 0 ) {
+ log(LOG_ERR, "fore_attach: Unit %d unable to boot\n",
+ fup->fu_unit);
+ return (-1);
+ }
+ DELAY ( BOOT_DELAY );
+ }
+
+ /*
+ * Write a one line message to the console informing
+ * that we've attached the device.
+ */
+ report_dev ( devinfo_p );
+
+ /*
+ * Get the mac address from the card PROM
+ */
+ val = getprop ( devinfo_p->devi_nodeid, "macaddress1", -1 );
+ if ( val != -1 ) {
+ fup->fu_pif.pif_macaddr.ma_data[0] = val & 0xff;
+ val = getprop ( devinfo_p->devi_nodeid, "macaddress2", -1 );
+ fup->fu_pif.pif_macaddr.ma_data[1] = val & 0xff;
+ val = getprop ( devinfo_p->devi_nodeid, "macaddress3", -1 );
+ fup->fu_pif.pif_macaddr.ma_data[2] = val & 0xff;
+ val = getprop ( devinfo_p->devi_nodeid, "macaddress4", -1 );
+ fup->fu_pif.pif_macaddr.ma_data[3] = val & 0xff;
+ val = getprop ( devinfo_p->devi_nodeid, "macaddress5", -1 );
+ fup->fu_pif.pif_macaddr.ma_data[4] = val & 0xff;
+ val = getprop ( devinfo_p->devi_nodeid, "macaddress6", -1 );
+ fup->fu_pif.pif_macaddr.ma_data[5] = val & 0xff;
+ } else {
+ /*
+ * Newer PROM - mac addresses have been combined. Also,
+ * macaddrlo2 reflects the board serial number.
+ */
+ val = htonl(getprop(devinfo_p->devi_nodeid, "macaddrlo2", -1));
+ KM_COPY ( (caddr_t)&val,
+ (caddr_t)&fup->fu_pif.pif_macaddr.ma_data[2],
+ sizeof(val) );
+ val = htonl(getprop(devinfo_p->devi_nodeid, "macaddrhi4", -1));
+ KM_COPY ( (caddr_t)&val,
+ (caddr_t)fup->fu_pif.pif_macaddr.ma_data,
+ sizeof(val) );
+ }
+
+ /*
+ * Setup the adapter config info
+ */
+ fcp = &fup->fu_config;
+ fcp->ac_vendor = VENDOR_FORE;
+ fcp->ac_vendapi = VENDAPI_FORE_1;
+ fcp->ac_macaddr = fup->fu_pif.pif_macaddr;
+ val = getprop ( devinfo_p->devi_nodeid, "promversion", -1 );
+ if ( val == -1 ) {
+ val = getprop ( devinfo_p->devi_nodeid, "hw-version", -1 );
+ }
+ if (val != -1) {
+ sprintf(fcp->ac_hard_vers, "%d.%d.%d",
+ (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
+ } else
+ sprintf(fcp->ac_hard_vers, "Unknown");
+
+ val = getprop ( devinfo_p->devi_nodeid, "serialnumber", -1 );
+ if ( val != -1 )
+ fcp->ac_serial = val;
+
+ valp = (addr_t)getlongprop ( devinfo_p->devi_nodeid, "model" );
+ if ( valp )
+ {
+ /*
+ * Media Type
+ */
+ switch (fcp->ac_device) {
+
+#ifdef FORE_SBUS
+ case DEV_FORE_SBA200E:
+ fcp->ac_media = MEDIA_OC3C;
+ fup->fu_pif.pif_pcr = ATM_PCR_OC3C;
+ break;
+
+ case DEV_FORE_SBA200:
+ /*
+ * Look at the /SSS trailer to determine 4B5B speed
+ * TAXI-100 = 125; TAXI-140 = 175
+ * Assume that OC3 has no /SSS speed identifier.
+ */
+ while (*valp && *valp != '/')
+ valp++;
+ if (*valp == NULL) {
+ fcp->ac_media = MEDIA_OC3C;
+ fup->fu_pif.pif_pcr = ATM_PCR_OC3C;
+ } else if (strcmp(valp, "/125") == 0) {
+ fcp->ac_media = MEDIA_TAXI_100;
+ fup->fu_pif.pif_pcr = ATM_PCR_TAXI100;
+ } else {
+ fcp->ac_media = MEDIA_TAXI_140;
+ fup->fu_pif.pif_pcr = ATM_PCR_TAXI140;
+ }
+ break;
+#endif /* FORE_SBUS */
+ }
+
+ /*
+ * Free property space
+ */
+ KM_FREE(valp, getproplen(devinfo_p->devi_nodeid, "model"), 0);
+ }
+
+ /*
+ * Bus information
+ */
+ fcp->ac_busslot =
+#ifdef SBUS_SIZE
+ (long)(devinfo_p->devi_reg->reg_addr - SBUS_BASE) / SBUS_SIZE;
+#else
+ sbusslot((u_long)devinfo_p->devi_reg->reg_addr);
+#endif
+
+ val = getprop(devinfo_p->devi_parent->devi_nodeid, "burst-sizes", 0);
+ if (val & SBUS_BURST32)
+ fcp->ac_bustype = BUS_SBUS_B32;
+ else
+ fcp->ac_bustype = BUS_SBUS_B16;
+
+ /*
+ * Set device capabilities
+ */
+ fup->fu_pif.pif_maxvpi = FORE_MAX_VPI;
+ fup->fu_pif.pif_maxvci = FORE_MAX_VCI;
+
+ /*
+ * Register this interface with ATM core services
+ */
+ if ( atm_physif_register
+ ((Cmn_unit *)fup, FORE_DEV_NAME, fore_services) != 0 )
+ {
+ /*
+ * Registration failed - back everything out
+ */
+ /*
+ * Modload calls UNLOAD if it get's a failure - don't
+ * call fore_unload() here.
+ */
+ return ( -1 );
+ }
+
+ /*
+ * Initialize the CP microcode program.
+ */
+ fore_initialize(fup);
+
+ return (0);
+}
+#endif /* sun */
+
+
+#ifdef __FreeBSD__
+/*
+ * Device probe routine
+ *
+ * Determine if this driver will support the identified device. If we claim
+ * to support the device, our attach routine will (later) be called for the
+ * device.
+ *
+ * Arguments:
+ * config_id device's PCI configuration ID
+ * device_id device's PCI Vendor/Device ID
+ *
+ * Returns:
+ * name device identification string
+ * NULL device not claimed by this driver
+ *
+ */
+static char *
+fore_pci_probe(config_id, device_id)
+ pcici_t config_id;
+ pcidi_t device_id;
+{
+
+ /*
+ * Initialize driver stuff
+ */
+ if (fore_inited == 0) {
+ if (fore_start())
+ return (NULL);
+ }
+
+ if ((device_id & 0xffff) != FORE_VENDOR_ID)
+ return (NULL);
+
+ if (((device_id >> 16) & 0xffff) == FORE_PCA200E_ID)
+ return ("FORE Systems PCA-200E ATM");
+
+ return (NULL);
+}
+
+
+/*
+ * Device attach routine
+ *
+ * Attach a device we've previously claimed to support. Walk through its
+ * register set and map, as required. Determine what level the device will
+ * be interrupting at and then register an interrupt handler for it. If we
+ * succeed, then reset the adapter and initialize the microcode.
+ * Last, register the interface with the kernel ATM services.
+ *
+ * Arguments:
+ * config_id device's PCI configuration ID
+ * unit device unit number
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+fore_pci_attach(config_id, unit)
+ pcici_t config_id;
+ int unit;
+{
+ Fore_unit *fup;
+ vm_offset_t va;
+ vm_offset_t pa;
+ pcidi_t device_id;
+ long val;
+ int err_count = BOOT_LOOPS;
+
+ /*
+ * Just checking...
+ */
+ if (unit >= FORE_MAX_UNITS) {
+ log(LOG_ERR, "%s%d: too many devices\n",
+ FORE_DEV_NAME, unit);
+ return;
+ }
+
+ /*
+ * Make sure this isn't a duplicate unit
+ */
+ if (fore_units[unit] != NULL)
+ return;
+
+ /*
+ * Allocate a new unit structure
+ */
+ fup = (Fore_unit *) atm_dev_alloc(sizeof(Fore_unit), sizeof(int), 0);
+ if (fup == NULL)
+ return;
+
+ /*
+ * Start initializing it
+ */
+ fup->fu_unit = unit;
+ fup->fu_mtu = FORE_IFF_MTU;
+ fup->fu_pcitag = config_id;
+ fup->fu_vcc_pool = &fore_vcc_pool;
+ fup->fu_nif_pool = &fore_nif_pool;
+ fup->fu_ioctl = fore_atm_ioctl;
+ fup->fu_instvcc = fore_instvcc;
+ fup->fu_openvcc = fore_openvcc;
+ fup->fu_closevcc = fore_closevcc;
+ fup->fu_output = fore_output;
+ callout_handle_init(&fup->fu_thandle);
+
+ /*
+ * Get our device type
+ */
+ device_id = pci_conf_read ( config_id, PCI_ID_REG );
+ switch ((device_id >> 16) & 0xffff) {
+
+ case FORE_PCA200E_ID:
+ fup->fu_config.ac_device = DEV_FORE_PCA200E;
+ break;
+
+ default:
+ fup->fu_config.ac_device = DEV_UNKNOWN;
+ }
+
+ /*
+ * Map RAM
+ */
+ if ((pci_map_mem(config_id, PCA200E_PCI_MEMBASE, &va, &pa)) == 0) {
+ log(LOG_ERR, "%s%d: unable to map memory\n",
+ FORE_DEV_NAME, unit);
+ goto failed;
+ }
+ fup->fu_ram = (Fore_mem *)va;
+ fup->fu_ramsize = PCA200E_RAM_SIZE;
+ fup->fu_mon = (Mon960 *)(fup->fu_ram + MON960_BASE);
+ fup->fu_ctlreg = (Fore_reg *)(va + PCA200E_HCR_OFFSET);
+ fup->fu_imask = (Fore_reg *)(va + PCA200E_IMASK_OFFSET);
+ fup->fu_psr = (Fore_reg *)(va + PCA200E_PSR_OFFSET);
+
+ /*
+ * Convert Endianess of Slave RAM accesses
+ */
+ val = pci_conf_read(config_id, PCA200E_PCI_MCTL);
+ val |= PCA200E_MCTL_SWAP;
+ pci_conf_write(config_id, PCA200E_PCI_MCTL, val);
+
+ /*
+ * Map interrupt in
+ */
+ if ( !pci_map_int( config_id, fore_intr, fup, &net_imask ) ) {
+ log(LOG_ERR, "%s%d: unable to map interrupt\n",
+ FORE_DEV_NAME, unit);
+ goto failed;
+ }
+
+ /*
+ * Poke the hardware - boot the CP and prepare it for downloading
+ */
+ fore_reset(fup);
+
+ /*
+ * Wait for the monitor to perform self-test
+ */
+ while (CP_READ(fup->fu_mon->mon_bstat) != BOOT_MONREADY) {
+ if (CP_READ(fup->fu_mon->mon_bstat) == BOOT_FAILTEST) {
+ log(LOG_ERR, "%s%d: failed self-test\n",
+ FORE_DEV_NAME, unit);
+ goto failed;
+ } else if ( --err_count == 0 ) {
+ log(LOG_ERR, "%s%d: unable to boot - status=0x%x\n",
+ FORE_DEV_NAME, unit,
+ CP_READ(fup->fu_mon->mon_bstat));
+ goto failed;
+ }
+ DELAY ( BOOT_DELAY );
+ }
+
+ /*
+ * Setup the adapter config info - at least as much as we can
+ */
+ fup->fu_config.ac_vendor = VENDOR_FORE;
+ fup->fu_config.ac_vendapi = VENDAPI_FORE_1;
+ fup->fu_config.ac_media = MEDIA_OC3C;
+ fup->fu_pif.pif_pcr = ATM_PCR_OC3C;
+ fup->fu_config.ac_bustype = BUS_PCI;
+ fup->fu_config.ac_busslot = config_id->bus << 8 | config_id->slot;
+
+ /*
+ * Save device ram info for user-level programs
+ */
+ fup->fu_config.ac_ram = (long)fup->fu_ram;
+ fup->fu_config.ac_ramsize = fup->fu_ramsize;
+
+ /*
+ * Set device capabilities
+ */
+ fup->fu_pif.pif_maxvpi = FORE_MAX_VPI;
+ fup->fu_pif.pif_maxvci = FORE_MAX_VCI;
+
+ /*
+ * Register this interface with ATM core services
+ */
+ if ( atm_physif_register
+ ((Cmn_unit *)fup, FORE_DEV_NAME, fore_services) != 0 )
+ {
+ /*
+ * Registration failed - back everything out
+ */
+ goto failed;
+ }
+
+ fore_units[unit] = fup;
+ fore_nunits++;
+
+#if BSD >= 199506
+ /*
+ * Add hook to our shutdown function
+ */
+ at_shutdown(fore_pci_shutdown, fup, SHUTDOWN_POST_SYNC);
+#endif
+
+ /*
+ * Initialize the CP microcode program.
+ */
+ fore_initialize(fup);
+
+ return;
+
+failed:
+ /*
+ * Unattach the device from the system
+ */
+ fore_unattach(fup);
+
+ /*
+ * Free any Fore-specific device resources
+ */
+ fore_interface_free(fup);
+
+ atm_dev_free(fup);
+
+ return;
+}
+
+
+#if BSD < 199506
+/*
+ * Device shutdown routine
+ *
+ * Arguments:
+ * kdc pointer to device's configuration table
+ * force forced shutdown flag
+ *
+ * Returns:
+ * none
+ *
+ */
+static int
+fore_pci_shutdown(kdc, force)
+ struct kern_devconf *kdc;
+ int force;
+{
+ Fore_unit *fup;
+
+ if (kdc->kdc_unit < fore_nunits) {
+
+ fup = fore_units[kdc->kdc_unit];
+ if (fup != NULL) {
+ fore_reset(fup);
+ }
+ }
+
+ (void) dev_detach(kdc);
+ return (0);
+}
+#else
+/*
+ * Device shutdown routine
+ *
+ * Arguments:
+ * howto type of shutdown
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ *
+ */
+static void
+fore_pci_shutdown(howto, fup)
+ int howto;
+ void *fup;
+{
+
+ fore_reset((Fore_unit *) fup);
+
+ return;
+}
+#endif /* BSD < 199506 */
+#endif /* __FreeBSD__ */
+
+
+/*
+ * Device unattach routine
+ *
+ * Reset the physical device, remove any pending timeouts,
+ * unmap any register sets, and unregister any interrupts.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+static void
+fore_unattach(fup)
+ Fore_unit *fup;
+{
+#ifdef sun
+ struct dev_info *devinfo_p = fup->fu_devinfo;
+ struct dev_reg *dev_reg_p;
+ struct dev_intr *dev_intr_p;
+#endif
+ int i;
+
+
+ /*
+ * Reset the board and return it to cold_start state.
+ * Hopefully, this will prevent use of resources as
+ * we're trying to free things up.
+ */
+ fore_reset(fup);
+
+ /*
+ * Lock out all device interrupts
+ */
+ DEVICE_LOCK((Cmn_unit *)fup);
+
+ /*
+ * Remove any pending timeout()'s
+ */
+ (void)untimeout((KTimeout_ret(*) __P((void *)))fore_initialize,
+ (void *)fup, fup->fu_thandle);
+
+#ifdef sun
+ /*
+ * Remove any mappings of the device
+ */
+ for ( dev_reg_p = devinfo_p->devi_reg, i = 1;
+ i <= devinfo_p->devi_nreg; i++, ++dev_reg_p )
+ {
+ if ( dev_reg_p == NULL )
+ {
+ /*
+ * Can't happen...
+ */
+ break;
+ }
+
+ /*
+ * Each device type has different register sets
+ */
+ switch (fup->fu_config.ac_device) {
+
+#ifdef FORE_SBUS
+ case DEV_FORE_SBA200E:
+
+ switch ( i )
+ {
+ /*
+ * Host Control Register (HCR)
+ */
+ case 1:
+ unmap_regs((addr_t)fup->fu_ctlreg,
+ sizeof(Fore_reg));
+ break;
+
+ /*
+ * SBus Burst Transfer Configuration Register
+ */
+ case 2:
+ /*
+ * Not used
+ */
+ break;
+
+ /*
+ * SBus Interrupt Level Select Register
+ */
+ case 3:
+ unmap_regs((addr_t)fup->fu_intlvl,
+ sizeof(Fore_reg));
+ break;
+
+ /*
+ * i960 RAM
+ */
+ case 4:
+ unmap_regs((addr_t)fup->fu_ram,
+ fup->fu_ramsize);
+ break;
+ }
+ break;
+
+ case DEV_FORE_SBA200:
+
+ switch ( i )
+ {
+ /*
+ * Board Control Register (BCR)
+ */
+ case 1:
+ unmap_regs((addr_t)fup->fu_ctlreg,
+ sizeof(Fore_reg));
+ break;
+
+ /*
+ * i960 RAM
+ */
+ case 2:
+ unmap_regs((addr_t)fup->fu_ram,
+ fup->fu_ramsize);
+ break;
+ }
+ break;
+#endif /* FORE_SBUS */
+ }
+ }
+
+ /*
+ * Remove the interrupt vector(s)
+ */
+ dev_intr_p = devinfo_p->devi_intr;
+ for ( i = devinfo_p->devi_nintr; i > 0; --i, ++dev_intr_p )
+ {
+ if ( dev_intr_p == NULL )
+ {
+ /*
+ * Can't happen...
+ */
+ break;
+ }
+ (void) remintr ( dev_intr_p->int_pri, fore_poll );
+ }
+#endif /* sun */
+
+#ifdef __FreeBSD__
+ /*
+ * Unmap the device interrupt
+ */
+ (void) pci_unmap_int(fup->fu_pcitag);
+
+ /*
+ * Unmap memory
+ */
+#ifdef notdef
+ (void) pci_unmap_mem(fup->fu_pcitag, PCA200E_PCI_MEMBASE);
+#endif
+#endif /* __FreeBSD__ */
+
+ DEVICE_UNLOCK((Cmn_unit *)fup);
+}
+
+
+/*
+ * Device reset routine
+ *
+ * Reset the physical device
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+static void
+fore_reset(fup)
+ Fore_unit *fup;
+{
+ int s = splimp();
+
+ /*
+ * Reset the board and return it to cold_start state
+ */
+ if (fup->fu_mon)
+ fup->fu_mon->mon_bstat = CP_WRITE(BOOT_COLDSTART);
+
+ if (fup->fu_ctlreg) {
+
+ switch (fup->fu_config.ac_device) {
+
+#ifdef FORE_SBUS
+ case DEV_FORE_SBA200E:
+ /*
+ * Reset i960 by setting and clearing RESET
+ */
+ SBA200E_HCR_INIT(*fup->fu_ctlreg, SBA200E_RESET);
+ SBA200E_HCR_CLR(*fup->fu_ctlreg, SBA200E_RESET);
+ break;
+
+ case DEV_FORE_SBA200:
+ /*
+ * Reset i960 by setting and clearing RESET
+ *
+ * SBA200 will NOT reset if bit is OR'd in!
+ */
+ *fup->fu_ctlreg = SBA200_RESET;
+ *fup->fu_ctlreg = SBA200_RESET_CLR;
+ break;
+#endif /* FORE_SBUS */
+#ifdef FORE_PCI
+ case DEV_FORE_PCA200E:
+ /*
+ * Reset i960 by setting and clearing RESET
+ */
+ PCA200E_HCR_INIT(*fup->fu_ctlreg, PCA200E_RESET);
+ DELAY(10000);
+ PCA200E_HCR_CLR(*fup->fu_ctlreg, PCA200E_RESET);
+ break;
+
+#endif
+ }
+ }
+
+ (void) splx(s);
+ return;
+}
+
+
+#ifndef ATM_LINKED
+/*
+ *******************************************************************
+ *
+ * Loadable Module Support
+ *
+ *******************************************************************
+ */
+
+/*
+ * Generic module load processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being loaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 load was successful
+ * errno load failed - reason indicated
+ *
+ */
+static int
+fore_doload()
+{
+ int err = 0;
+
+ /*
+ * Start us up
+ */
+ err = fore_start();
+ if (err)
+ /* Problems, clean up */
+ (void)fore_stop();
+
+ return (err);
+}
+
+
+/*
+ * Generic module unload processing
+ *
+ * This function is called by an OS-specific function when this
+ * module is being unloaded.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * 0 unload was successful
+ * errno unload failed - reason indicated
+ *
+ */
+static int
+fore_dounload()
+{
+ int err = 0;
+
+ /*
+ * OK, try to clean up our mess
+ */
+ err = fore_stop();
+
+ return (err);
+}
+
+
+#ifdef sun
+/*
+ * Loadable driver description
+ */
+static struct vdldrv fore_drv = {
+ VDMAGIC_DRV, /* Device Driver */
+ "fore_mod", /* name */
+ &fore_ops, /* dev_ops */
+ NULL, /* bdevsw */
+ NULL, /* cdevsw */
+ 0, /* blockmajor */
+ 0 /* charmajor */
+};
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the vd driver for all loadable module
+ * functions for this pseudo driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * cmd vd command code
+ * vdp pointer to vd driver's structure
+ * vdi pointer to command-specific vdioctl_* structure
+ * vds pointer to status structure (VDSTAT only)
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+fore_mod(cmd, vdp, vdi, vds)
+ int cmd;
+ struct vddrv *vdp;
+ caddr_t vdi;
+ struct vdstat *vds;
+{
+ int err = 0;
+
+ switch (cmd) {
+
+ case VDLOAD:
+ /*
+ * Module Load
+ *
+ * We dont support any user configuration
+ */
+ err = fore_doload();
+ if (err == 0)
+ /* Let vd driver know about us */
+ vdp->vdd_vdtab = (struct vdlinkage *)&fore_drv;
+ break;
+
+ case VDUNLOAD:
+ /*
+ * Module Unload
+ */
+ err = fore_dounload();
+ break;
+
+ case VDSTAT:
+ /*
+ * Module Status
+ */
+
+ /* Not much to say at the moment */
+
+ break;
+
+ default:
+ log(LOG_ERR, "fore_mod: Unknown vd command 0x%x\n", cmd);
+ err = EINVAL;
+ }
+
+ return (err);
+}
+#endif /* sun */
+
+#ifdef __FreeBSD__
+#ifdef notdef
+
+/*
+ * Driver entry points
+ */
+static struct cdevsw fore_cdev = {
+ (d_open_t *)enodev, /* open */
+ (d_close_t *)enodev, /* close */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* ioctl */
+ NULL, /* stop */
+ NULL, /* reset */
+ NULL, /* devtotty */
+ NULL, /* select */
+ NULL, /* mmap */
+ NULL /* strategy */
+};
+
+
+/*
+ * Loadable device driver module description
+ */
+#if BSD < 199506
+MOD_DEV("fore_mod", LM_DT_CHAR, -1, (void *)&fore_cdev);
+#else
+MOD_DEV(fore, LM_DT_CHAR, -1, (void *)&fore_cdev);
+#endif
+
+
+/*
+ * Loadable module support "load" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+fore_load(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(fore_doload());
+}
+
+
+/*
+ * Loadable module support "unload" entry point
+ *
+ * This is the routine called by the lkm driver whenever the
+ * modunload(1) command is issued for this module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+static int
+fore_unload(lkmtp, cmd)
+ struct lkm_table *lkmtp;
+ int cmd;
+{
+ return(fore_dounload());
+}
+
+
+/*
+ * Loadable module support entry point
+ *
+ * This is the routine called by the lkm driver for all loadable module
+ * functions for this driver. This routine name must be specified
+ * on the modload(1) command. This routine will be called whenever the
+ * modload(1), modunload(1) or modstat(1) commands are issued for this
+ * module.
+ *
+ * Arguments:
+ * lkmtp pointer to lkm drivers's structure
+ * cmd lkm command code
+ * ver lkm version
+ *
+ * Returns:
+ * 0 command was successful
+ * errno command failed - reason indicated
+ *
+ */
+int
+fore_mod(lkmtp, cmd, ver)
+ struct lkm_table *lkmtp;
+ int cmd;
+ int ver;
+{
+#if BSD < 199506
+ DISPATCH(lkmtp, cmd, ver, fore_load, fore_unload, nosys);
+#else
+ DISPATCH(lkmtp, cmd, ver, fore_load, fore_unload, lkm_nullcmd);
+#endif
+}
+#endif /* notdef */
+#endif /* __FreeBSD__ */
+
+#endif /* ATM_LINKED */
+
diff --git a/sys/dev/hfa/fore_output.c b/sys/dev/hfa/fore_output.c
new file mode 100644
index 0000000..59c82c9
--- /dev/null
+++ b/sys/dev/hfa/fore_output.c
@@ -0,0 +1,415 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_output.c,v 1.7 1998/02/19 20:10:34 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * PDU output processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_output.c,v 1.7 1998/02/19 20:10:34 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Local functions
+ */
+static KBuffer * fore_xmit_segment __P((Fore_unit *, KBuffer *,
+ H_xmit_queue *, u_int *, u_int *));
+
+
+/*
+ * Output a PDU
+ *
+ * This function is called via the common driver code after receiving a
+ * stack *_DATA* command. The common code has already validated most of
+ * the request so we just need to check a few more Fore-specific details.
+ * Then we just build a transmit descriptor request for the PDU and issue
+ * the command to the CP.
+ *
+ * Arguments:
+ * cup pointer to device common unit
+ * cvp pointer to common VCC entry
+ * m pointer to output PDU buffer chain head
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+fore_output(cup, cvp, m)
+ Cmn_unit *cup;
+ Cmn_vcc *cvp;
+ KBuffer *m;
+{
+ Fore_unit *fup = (Fore_unit *)cup;
+ Fore_vcc *fvp = (Fore_vcc *)cvp;
+ struct vccb *vcp;
+ H_xmit_queue *hxp;
+ Xmit_queue *cqp;
+ Xmit_descr *xdp;
+ u_int retry, nsegs, pdulen;
+ int s;
+
+#ifdef DIAGNOSTIC
+ if (atm_dev_print)
+ atm_dev_pdu_print(cup, cvp, m, "fore_output");
+#endif
+
+ vcp = fvp->fv_connvc->cvc_vcc;
+
+ /*
+ * If we're still waiting for activation to finish, delay for
+ * a little while before we toss the PDU
+ */
+ if (fvp->fv_state == CVS_INITED) {
+ retry = 3;
+ while (retry-- && (fvp->fv_state == CVS_INITED))
+ DELAY(1000);
+ if (fvp->fv_state != CVS_ACTIVE) {
+ /*
+ * Activation still hasn't finished, oh well....
+ */
+ fup->fu_stats->st_drv.drv_xm_notact++;
+ vcp->vc_oerrors++;
+ if (vcp->vc_nif)
+ vcp->vc_nif->nif_if.if_oerrors++;
+ KB_FREEALL(m);
+ return;
+ }
+ }
+
+ /*
+ * Queue PDU at end of transmit queue
+ *
+ * If queue is full we'll delay a bit before tossing the PDU
+ */
+ s = splnet();
+ hxp = fup->fu_xmit_tail;
+ if (!((*hxp->hxq_status) & QSTAT_FREE)) {
+
+ fup->fu_stats->st_drv.drv_xm_full++;
+ retry = 3;
+ do {
+ DELAY(1000);
+
+ DEVICE_LOCK((Cmn_unit *)fup);
+ fore_xmit_drain(fup);
+ DEVICE_UNLOCK((Cmn_unit *)fup);
+
+ } while (--retry && (!((*hxp->hxq_status) & QSTAT_FREE)));
+
+ if (!((*hxp->hxq_status) & QSTAT_FREE)) {
+ /*
+ * Queue is still full, bye-bye PDU
+ */
+ fup->fu_pif.pif_oerrors++;
+ vcp->vc_oerrors++;
+ if (vcp->vc_nif)
+ vcp->vc_nif->nif_if.if_oerrors++;
+ KB_FREEALL(m);
+ (void) splx(s);
+ return;
+ }
+ }
+
+ /*
+ * We've got a free transmit queue entry
+ */
+
+ /*
+ * Now build the transmit segment descriptors for this PDU
+ */
+ m = fore_xmit_segment(fup, m, hxp, &nsegs, &pdulen);
+ if (m == NULL) {
+ /*
+ * The build failed, buffer chain has been freed
+ */
+ vcp->vc_oerrors++;
+ if (vcp->vc_nif)
+ vcp->vc_nif->nif_if.if_oerrors++;
+ (void) splx(s);
+ return;
+ }
+
+ /*
+ * Set up the descriptor header
+ */
+ xdp = hxp->hxq_descr;
+ xdp->xd_cell_hdr = ATM_HDR_SET(vcp->vc_vpi, vcp->vc_vci, 0, 0);
+ xdp->xd_spec = XDS_SET_SPEC(0, fvp->fv_aal, nsegs, pdulen);
+ xdp->xd_rate = FORE_DEF_RATE;
+
+ /*
+ * Everything is ready to go, so officially claim the host queue
+ * entry and setup the CP-resident queue entry. The CP will grab
+ * the PDU when the descriptor pointer is set.
+ */
+ fup->fu_xmit_tail = hxp->hxq_next;
+ hxp->hxq_buf = m;
+ hxp->hxq_vcc = fvp;
+ (*hxp->hxq_status) = QSTAT_PENDING;
+ cqp = hxp->hxq_cpelem;
+ cqp->cq_descr = (CP_dma)
+ CP_WRITE((u_long)hxp->hxq_descr_dma | XMIT_SEGS_TO_BLKS(nsegs));
+
+ (void) splx(s);
+
+ /*
+ * See if there are any completed queue entries
+ */
+ DEVICE_LOCK((Cmn_unit *)fup);
+ fore_xmit_drain(fup);
+ DEVICE_UNLOCK((Cmn_unit *)fup);
+
+ return;
+}
+
+
+/*
+ * Build Transmit Segment Descriptors
+ *
+ * This function will take a supplied buffer chain of data to be transmitted
+ * and build the transmit segment descriptors for the data. This will include
+ * the dreaded operation of ensuring that the data for each transmit segment
+ * is full-word aligned and (except for the last segment) is an integral number
+ * of words in length. If the data isn't already aligned and sized as
+ * required, then the data must be shifted (copied) into place - a sure
+ * performance killer. Note that we rely on the fact that all buffer data
+ * areas are allocated with (at least) full-word alignments/lengths.
+ *
+ * If any errors are encountered, the buffer chain will be freed.
+ *
+ * Arguments:
+ * fup pointer to device unit
+ * m pointer to output PDU buffer chain head
+ * hxp pointer to host transmit queue entry
+ * segp pointer to return the number of transmit segments
+ * lenp pointer to return the pdu length
+ *
+ * Returns:
+ * m build successful, pointer to (possibly new) head of
+ * output PDU buffer chain
+ * NULL build failed, buffer chain freed
+ *
+ */
+static KBuffer *
+fore_xmit_segment(fup, m, hxp, segp, lenp)
+ Fore_unit *fup;
+ KBuffer *m;
+ H_xmit_queue *hxp;
+ u_int *segp;
+ u_int *lenp;
+{
+ Xmit_descr *xdp = hxp->hxq_descr;
+ Xmit_seg_descr *xsp;
+ H_dma *sdmap;
+ KBuffer *m0, *m1, *mprev;
+ caddr_t cp, bfr;
+ void *dma;
+ u_int pdulen, nsegs, len, align;
+ int compressed = 0;
+
+ m0 = m;
+
+retry:
+ xsp = xdp->xd_seg;
+ sdmap = hxp->hxq_dma;
+ mprev = NULL;
+ pdulen = 0;
+ nsegs = 0;
+
+ /*
+ * Loop thru each buffer in the chain, performing the necessary
+ * data positioning and then building a segment descriptor for
+ * that data.
+ */
+ while (m) {
+ /*
+ * Get rid of any zero-length buffers
+ */
+ if (KB_LEN(m) == 0) {
+ if (mprev) {
+ KB_UNLINK(m, mprev, m1);
+ } else {
+ KB_UNLINKHEAD(m, m1);
+ m0 = m1;
+ }
+ m = m1;
+ continue;
+ }
+
+ /*
+ * Make sure we don't try to use too many segments
+ */
+ if (nsegs >= XMIT_MAX_SEGS) {
+ /*
+ * Try to compress buffer chain (but only once)
+ */
+ if (compressed) {
+ KB_FREEALL(m0);
+ return (NULL);
+ }
+
+ fup->fu_stats->st_drv.drv_xm_maxpdu++;
+
+ m = atm_dev_compress(m0);
+ if (m == NULL) {
+ return (NULL);
+ }
+
+ /*
+ * Build segment descriptors for compressed chain
+ */
+ m0 = m;
+ compressed = 1;
+ goto retry;
+ }
+
+ /*
+ * Get start of data onto full-word alignment
+ */
+ KB_DATASTART(m, cp, caddr_t);
+ if (align = ((u_int)cp) & (XMIT_SEG_ALIGN - 1)) {
+ /*
+ * Gotta slide the data up
+ */
+ fup->fu_stats->st_drv.drv_xm_segnoal++;
+ bfr = cp - align;
+ KM_COPY(cp, bfr, KB_LEN(m));
+ KB_HEADMOVE(m, -align);
+ } else {
+ /*
+ * Data already aligned
+ */
+ bfr = cp;
+ }
+
+ /*
+ * Now work on getting the data length correct
+ */
+ len = KB_LEN(m);
+ while ((align = (len & (XMIT_SEG_ALIGN - 1))) &&
+ (m1 = KB_NEXT(m))) {
+
+ /*
+ * Have to move some data from following buffer(s)
+ * to word-fill this buffer
+ */
+ u_int ncopy = MIN(XMIT_SEG_ALIGN - align, KB_LEN(m1));
+
+ if (ncopy) {
+ /*
+ * Move data to current buffer
+ */
+ caddr_t dest;
+
+ fup->fu_stats->st_drv.drv_xm_seglen++;
+ KB_DATASTART(m1, cp, caddr_t);
+ dest = bfr + len;
+ KB_HEADADJ(m1, -ncopy);
+ KB_TAILADJ(m, ncopy);
+ len += ncopy;
+ while (ncopy--) {
+ *dest++ = *cp++;
+ }
+ }
+
+ /*
+ * If we've drained the buffer, free it
+ */
+ if (KB_LEN(m1) == 0) {
+ KBuffer *m2;
+
+ KB_UNLINK(m1, m, m2);
+ }
+ }
+
+ /*
+ * Finally, build the segment descriptor
+ */
+
+ /*
+ * Round last segment to fullword length (if needed)
+ */
+ if (len & (XMIT_SEG_ALIGN - 1))
+ xsp->xsd_len = KB_LEN(m) =
+ (len + XMIT_SEG_ALIGN) & ~(XMIT_SEG_ALIGN - 1);
+ else
+ xsp->xsd_len = KB_LEN(m) = len;
+
+ /*
+ * Get a DMA address for the data
+ */
+ dma = DMA_GET_ADDR(bfr, xsp->xsd_len, XMIT_SEG_ALIGN, 0);
+ if (dma == NULL) {
+
+ fup->fu_stats->st_drv.drv_xm_segdma++;
+ KB_FREEALL(m0);
+ return (NULL);
+ }
+
+ /*
+ * Now we're really ready to call it a segment
+ */
+ *sdmap++ = xsp->xsd_buffer = (H_dma) dma;
+
+ /*
+ * Bump counters and get ready for next buffer
+ */
+ pdulen += len;
+ nsegs++;
+ xsp++;
+ mprev = m;
+ m = KB_NEXT(m);
+ }
+
+ /*
+ * Validate PDU length
+ */
+ if (pdulen > XMIT_MAX_PDULEN) {
+ fup->fu_stats->st_drv.drv_xm_maxpdu++;
+ KB_FREEALL(m0);
+ return (NULL);
+ }
+
+ /*
+ * Return the good news to the caller
+ */
+ *segp = nsegs;
+ *lenp = pdulen;
+
+ return (m0);
+}
+
diff --git a/sys/dev/hfa/fore_receive.c b/sys/dev/hfa/fore_receive.c
new file mode 100644
index 0000000..f9a9d19
--- /dev/null
+++ b/sys/dev/hfa/fore_receive.c
@@ -0,0 +1,582 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_receive.c,v 1.10 1998/07/17 20:19:35 root Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Receive queue management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_receive.c,v 1.10 1998/07/17 20:19:35 root Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Local functions
+ */
+static void fore_recv_stack __P((void *, KBuffer *));
+
+
+/*
+ * Allocate Receive Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * 0 allocations successful
+ * else allocation failed
+ */
+int
+fore_recv_allocate(fup)
+ Fore_unit *fup;
+{
+ caddr_t memp;
+
+ /*
+ * Allocate non-cacheable memory for receive status words
+ */
+ memp = atm_dev_alloc(sizeof(Q_status) * RECV_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_recv_stat = (Q_status *) memp;
+
+ memp = DMA_GET_ADDR(fup->fu_recv_stat, sizeof(Q_status) * RECV_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_recv_statd = (Q_status *) memp;
+
+ /*
+ * Allocate memory for receive descriptors
+ */
+ memp = atm_dev_alloc(sizeof(Recv_descr) * RECV_QUELEN,
+ RECV_DESCR_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_recv_desc = (Recv_descr *) memp;
+
+ memp = DMA_GET_ADDR(fup->fu_recv_desc,
+ sizeof(Recv_descr) * RECV_QUELEN, RECV_DESCR_ALIGN, 0);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_recv_descd = (Recv_descr *) memp;
+
+ return (0);
+}
+
+
+/*
+ * Receive Queue Initialization
+ *
+ * Allocate and initialize the host-resident receive queue structures
+ * and then initialize the CP-resident queue structures.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_recv_initialize(fup)
+ Fore_unit *fup;
+{
+ Aali *aap = fup->fu_aali;
+ Recv_queue *cqp;
+ H_recv_queue *hrp;
+ Recv_descr *rdp;
+ Recv_descr *rdp_dma;
+ Q_status *qsp;
+ Q_status *qsp_dma;
+ int i;
+
+ /*
+ * Point to CP-resident receive queue
+ */
+ cqp = (Recv_queue *)(fup->fu_ram + CP_READ(aap->aali_recv_q));
+
+ /*
+ * Point to host-resident receive queue structures
+ */
+ hrp = fup->fu_recv_q;
+ qsp = fup->fu_recv_stat;
+ qsp_dma = fup->fu_recv_statd;
+ rdp = fup->fu_recv_desc;
+ rdp_dma = fup->fu_recv_descd;
+
+ /*
+ * Loop thru all queue entries and do whatever needs doing
+ */
+ for (i = 0; i < RECV_QUELEN; i++) {
+
+ /*
+ * Set queue status word to free
+ */
+ *qsp = QSTAT_FREE;
+
+ /*
+ * Set up host queue entry and link into ring
+ */
+ hrp->hrq_cpelem = cqp;
+ hrp->hrq_status = qsp;
+ hrp->hrq_descr = rdp;
+ hrp->hrq_descr_dma = rdp_dma;
+ if (i == (RECV_QUELEN - 1))
+ hrp->hrq_next = fup->fu_recv_q;
+ else
+ hrp->hrq_next = hrp + 1;
+
+ /*
+ * Now let the CP into the game
+ */
+ cqp->cq_descr = (CP_dma) CP_WRITE(rdp_dma);
+ cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
+
+ /*
+ * Bump all queue pointers
+ */
+ hrp++;
+ qsp++;
+ qsp_dma++;
+ rdp++;
+ rdp_dma++;
+ cqp++;
+ }
+
+ /*
+ * Initialize queue pointers
+ */
+ fup->fu_recv_head = fup->fu_recv_q;
+
+ return;
+}
+
+
+/*
+ * Drain Receive Queue
+ *
+ * This function will process all completed entries at the head of the
+ * receive queue. The received segments will be linked into a received
+ * PDU buffer chain and it will then be passed up the PDU's VCC stack for
+ * processing by the next higher protocol layer.
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_recv_drain(fup)
+ Fore_unit *fup;
+{
+ H_recv_queue *hrp = NULL;
+ Recv_descr *rdp;
+ Recv_seg_descr *rsp;
+ Buf_handle *bhp;
+ Fore_vcc *fvp;
+ struct vccb *vcp;
+ KBuffer *m, *mhead, *mtail;
+ caddr_t cp;
+ u_long hdr, nsegs;
+ u_int seglen, type0;
+ int i, pdulen, retries = 0, error;
+
+ /* Silence the compiler */
+ mtail = NULL;
+ type0 = 0;
+
+ /*
+ * Process each completed entry
+ */
+retry:
+ while (*fup->fu_recv_head->hrq_status & QSTAT_COMPLETED) {
+
+ /*
+ * Get completed entry's receive descriptor
+ */
+ hrp = fup->fu_recv_head;
+ rdp = hrp->hrq_descr;
+
+#ifdef VAC
+ /*
+ * Cache flush receive descriptor
+ */
+ if (vac) {
+ vac_flush((addr_t)rdp, sizeof(Recv_descr));
+ }
+#endif
+
+ hdr = rdp->rd_cell_hdr;
+ nsegs = rdp->rd_nsegs;
+
+ pdulen = 0;
+ error = 0;
+ mhead = NULL;
+
+ /*
+ * Locate incoming VCC for this PDU
+ */
+ fvp = (Fore_vcc *) atm_dev_vcc_find((Cmn_unit *)fup,
+ ATM_HDR_GET_VPI(hdr), ATM_HDR_GET_VCI(hdr), VCC_IN);
+
+ /*
+ * Check for a receive error
+ *
+ * Apparently the receive descriptor itself contains valid
+ * information, but the received pdu data is probably bogus.
+ * We'll arrange for the receive buffer segments to be tossed.
+ */
+ if (*hrp->hrq_status & QSTAT_ERROR) {
+
+ fup->fu_pif.pif_ierrors++;
+ if (fvp) {
+ vcp = fvp->fv_connvc->cvc_vcc;
+ vcp->vc_ierrors++;
+ if (vcp->vc_nif)
+ vcp->vc_nif->nif_if.if_ierrors++;
+ }
+ ATM_DEBUG1("fore receive error: hdr=0x%x\n", hdr);
+ error = 1;
+ }
+
+ /*
+ * Build PDU buffer chain from receive segments
+ */
+ for (i = 0, rsp = rdp->rd_seg; i < nsegs; i++, rsp++) {
+
+ bhp = rsp->rsd_handle;
+ seglen = rsp->rsd_len;
+
+ /*
+ * Remove buffer from our supplied queue and get
+ * to the underlying buffer
+ */
+ switch (bhp->bh_type) {
+
+ case BHT_S1_SMALL:
+ DEQUEUE(bhp, Buf_handle, bh_qelem,
+ fup->fu_buf1s_bq);
+ fup->fu_buf1s_cnt--;
+ m = (KBuffer *) ((caddr_t)bhp - BUF1_SM_HOFF);
+ KB_DATASTART(m, cp, caddr_t);
+ DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_SM_SIZE, 0);
+ break;
+
+ case BHT_S1_LARGE:
+ DEQUEUE(bhp, Buf_handle, bh_qelem,
+ fup->fu_buf1l_bq);
+ fup->fu_buf1l_cnt--;
+ m = (KBuffer *) ((caddr_t)bhp - BUF1_LG_HOFF);
+ KB_DATASTART(m, cp, caddr_t);
+ DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0);
+ break;
+
+ default:
+ log(LOG_ERR,
+ "fore_recv_drain: bhp=0x%x type=0x%x\n",
+ (int)bhp, bhp->bh_type);
+ panic("fore_recv_drain: bad buffer type");
+ }
+
+ /*
+ * Toss any zero-length or receive error buffers
+ */
+ if ((seglen == 0) || error) {
+ KB_FREEALL(m);
+ continue;
+ }
+
+ /*
+ * Link buffer into chain
+ */
+ if (mhead == NULL) {
+ type0 = bhp->bh_type;
+ KB_LINKHEAD(m, mhead);
+ mhead = m;
+ } else {
+ KB_LINK(m, mtail);
+ }
+ KB_LEN(m) = seglen;
+ pdulen += seglen;
+ mtail = m;
+
+ /*
+ * Flush received buffer data
+ */
+#ifdef VAC
+ if (vac) {
+ addr_t dp;
+
+ KB_DATASTART(m, dp, addr_t);
+ vac_pageflush(dp);
+ }
+#endif
+ }
+
+ /*
+ * Make sure we've got a non-null PDU
+ */
+ if (mhead == NULL) {
+ goto free_ent;
+ }
+
+ /*
+ * We only support user data PDUs (for now)
+ */
+ if (hdr & ATM_HDR_SET_PT(ATM_PT_NONUSER)) {
+ KB_FREEALL(mhead);
+ goto free_ent;
+ }
+
+ /*
+ * Toss the data if there's no VCC
+ */
+ if (fvp == NULL) {
+ fup->fu_stats->st_drv.drv_rv_novcc++;
+ KB_FREEALL(mhead);
+ goto free_ent;
+ }
+
+#ifdef DIAGNOSTIC
+ if (atm_dev_print)
+ atm_dev_pdu_print((Cmn_unit *)fup, (Cmn_vcc *)fvp,
+ mhead, "fore_recv");
+#endif
+
+ /*
+ * Make sure we have our queueing headroom at the front
+ * of the buffer chain
+ */
+ if (type0 != BHT_S1_SMALL) {
+
+ /*
+ * Small buffers already have headroom built-in, but
+ * if CP had to use a large buffer for the first
+ * buffer, then we have to allocate a buffer here to
+ * contain the headroom.
+ */
+ fup->fu_stats->st_drv.drv_rv_nosbf++;
+
+ KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA);
+ if (m == NULL) {
+ fup->fu_stats->st_drv.drv_rv_nomb++;
+ KB_FREEALL(mhead);
+ goto free_ent;
+ }
+
+ /*
+ * Put new buffer at head of PDU chain
+ */
+ KB_LINKHEAD(m, mhead);
+ KB_LEN(m) = 0;
+ KB_HEADSET(m, BUF1_SM_DOFF);
+ mhead = m;
+ }
+
+ /*
+ * It looks like we've got a valid PDU - count it quick!!
+ */
+ KB_PLENSET(mhead, pdulen);
+ fup->fu_pif.pif_ipdus++;
+ fup->fu_pif.pif_ibytes += pdulen;
+ vcp = fvp->fv_connvc->cvc_vcc;
+ vcp->vc_ipdus++;
+ vcp->vc_ibytes += pdulen;
+ if (vcp->vc_nif) {
+ vcp->vc_nif->nif_ibytes += pdulen;
+ vcp->vc_nif->nif_if.if_ipackets++;
+#if (defined(BSD) && (BSD >= 199103))
+ vcp->vc_nif->nif_if.if_ibytes += pdulen;
+#endif
+ }
+
+ /*
+ * The STACK_CALL needs to happen at splnet() in order
+ * for the stack sequence processing to work. Schedule an
+ * interrupt queue callback at splnet() since we are
+ * currently at device level.
+ */
+
+ /*
+ * Prepend callback function pointer and token value to buffer.
+ * We have already guaranteed that the space is available
+ * in the first buffer.
+ */
+ KB_HEADADJ(mhead, sizeof(atm_intr_func_t) + sizeof(int));
+ KB_DATASTART(mhead, cp, caddr_t);
+ *((atm_intr_func_t *)cp) = fore_recv_stack;
+ cp += sizeof(atm_intr_func_t);
+ *((void **)cp) = (void *)fvp;
+
+ /*
+ * Schedule callback
+ */
+ if (!IF_QFULL(&atm_intrq)) {
+ IF_ENQUEUE(&atm_intrq, mhead);
+ SCHED_ATM;
+ } else {
+ fup->fu_stats->st_drv.drv_rv_ifull++;
+ KB_FREEALL(mhead);
+ goto free_ent;
+ }
+
+free_ent:
+ /*
+ * Mark this entry free for use and bump head pointer
+ * to the next entry in the queue
+ */
+ *hrp->hrq_status = QSTAT_FREE;
+ hrp->hrq_cpelem->cq_descr =
+ (CP_dma) CP_WRITE((u_long)hrp->hrq_descr_dma);
+ fup->fu_recv_head = hrp->hrq_next;
+ }
+
+ /*
+ * Nearly all of the interrupts generated by the CP will be due
+ * to PDU reception. However, we may receive an interrupt before
+ * the CP has completed the status word DMA to host memory. Thus,
+ * if we haven't processed any PDUs during this interrupt, we will
+ * wait a bit for completed work on the receive queue, rather than
+ * having to field an extra interrupt very soon.
+ */
+ if (hrp == NULL) {
+ if (++retries <= FORE_RECV_RETRY) {
+ DELAY(FORE_RECV_DELAY);
+ goto retry;
+ }
+ }
+
+ return;
+}
+
+
+/*
+ * Pass Incoming PDU up Stack
+ *
+ * This function is called via the core ATM interrupt queue callback
+ * set in fore_recv_drain(). It will pass the supplied incoming
+ * PDU up the incoming VCC's stack.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tok token to identify stack instantiation
+ * m pointer to incoming PDU buffer chain
+ *
+ * Returns:
+ * none
+ */
+static void
+fore_recv_stack(tok, m)
+ void *tok;
+ KBuffer *m;
+{
+ Fore_vcc *fvp = (Fore_vcc *)tok;
+ int err;
+
+ /*
+ * Send the data up the stack
+ */
+ STACK_CALL(CPCS_UNITDATA_SIG, fvp->fv_upper,
+ fvp->fv_toku, fvp->fv_connvc, (int)m, 0, err);
+ if (err)
+ KB_FREEALL(m);
+
+ return;
+}
+
+
+/*
+ * Free Receive Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_recv_free(fup)
+ Fore_unit *fup;
+{
+ /*
+ * We'll just let fore_buf_free() take care of freeing any
+ * buffers sitting on the receive queue (which are also still
+ * on the fu_*_bq queue).
+ */
+ if (fup->fu_flags & CUF_INITED) {
+ }
+
+ /*
+ * Free the status words
+ */
+ if (fup->fu_recv_stat) {
+ if (fup->fu_recv_statd) {
+ DMA_FREE_ADDR(fup->fu_recv_stat, fup->fu_recv_statd,
+ sizeof(Q_status) * RECV_QUELEN,
+ ATM_DEV_NONCACHE);
+ }
+ atm_dev_free((void *)fup->fu_recv_stat);
+ fup->fu_recv_stat = NULL;
+ fup->fu_recv_statd = NULL;
+ }
+
+ /*
+ * Free the receive descriptors
+ */
+ if (fup->fu_recv_desc) {
+ if (fup->fu_recv_descd) {
+ DMA_FREE_ADDR(fup->fu_recv_desc, fup->fu_recv_descd,
+ sizeof(Recv_descr) * RECV_QUELEN, 0);
+ }
+ atm_dev_free(fup->fu_recv_desc);
+ fup->fu_recv_desc = NULL;
+ fup->fu_recv_descd = NULL;
+ }
+
+ return;
+}
+
diff --git a/sys/dev/hfa/fore_slave.h b/sys/dev/hfa/fore_slave.h
new file mode 100644
index 0000000..05e7b5b
--- /dev/null
+++ b/sys/dev/hfa/fore_slave.h
@@ -0,0 +1,191 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_slave.h,v 1.5 1997/08/22 19:45:50 jpt Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Slave Interface definitions
+ *
+ */
+
+#ifndef _FORE_SLAVE_H
+#define _FORE_SLAVE_H
+
+/*
+ * This file contains the (mostly hardware) definitions for each of the
+ * supported 200-series slave interfaces.
+ */
+
+
+/*
+ * Structure defining the supported FORE 200-series interfaces
+ */
+struct fore_device {
+ char *fd_name; /* Device name (from PROM) */
+ Atm_device fd_devtyp; /* Device type */
+};
+typedef struct fore_device Fore_device;
+
+
+
+/*
+ * Common definitions
+ * ------------------
+ */
+#define MON960_BASE 0x400 /* Address offset of Mon960 */
+#define AALI_BASE 0x4d40 /* Address offset of Aali */
+
+typedef volatile unsigned int Fore_reg; /* Slave control register */
+typedef volatile unsigned char Fore_mem; /* Slave memory */
+
+
+/*
+ * SBA-200E SBus Slave Interface
+ * -----------------------------
+ */
+
+#define SBA200E_PROM_NAME "FORE,sba-200e"
+
+/*
+ * SBA-200E Host Control Register (HCR)
+ */
+#define SBA200E_READ_BITS 0x1ff /* Valid read data bits */
+#define SBA200E_WRITE_BITS 0x01f /* Valid write data bits */
+#define SBA200E_STICKY_BITS 0x013 /* Sticky data bits */
+
+/* Read access */
+#define SBA200E_SBUS_INTR_RD 0x100 /* State of SBus interrupt */
+#define SBA200E_TEST_MODE 0x080 /* Device is in test-mode */
+#define SBA200E_IFIFO_FULL 0x040 /* Input FIFO almost full (when 0) */
+#define SBA200E_ESP_HOLD_RD 0x020 /* State of ESP bus hold */
+#define SBA200E_SBUS_ENA_RD 0x010 /* State of SBus interrupt enable */
+#define SBA200E_OFIFO_FULL 0x008 /* Output FIFO almost full */
+#define SBA200E_SELFTEST_FAIL 0x004 /* i960 self-test failed (when 0) */
+#define SBA200E_HOLD_LOCK_RD 0x002 /* State of i960 hold lock signal */
+#define SBA200E_RESET_RD 0x001 /* State of board reset signal */
+
+/* Write access - bit set (clear) */
+#define SBA200E_SBUS_ENA 0x010 /* Enable (disable) SBus interrupts */
+#define SBA200E_CLR_SBUS_INTR 0x008 /* Clear SBus interrupt */
+#define SBA200E_I960_INTR 0x004 /* Issue interrupt to i960 */
+#define SBA200E_HOLD_LOCK 0x002 /* Set (clear) i960 hold lock signal */
+#define SBA200E_RESET 0x001 /* Set (clear) board reset signal */
+
+#define SBA200E_HCR_INIT(hcr,bits) \
+ ((hcr) = (SBA200E_WRITE_BITS & (bits)))
+#define SBA200E_HCR_SET(hcr,bits) \
+ ((hcr) = (((hcr) & SBA200E_STICKY_BITS) | (bits)))
+#define SBA200E_HCR_CLR(hcr,bits) \
+ ((hcr) = ((hcr) & (SBA200E_STICKY_BITS ^ (bits))))
+
+
+
+/*
+ * SBA-200 SBus Slave Interface
+ * ----------------------------
+ */
+
+#define SBA200_PROM_NAME "FORE,sba-200"
+
+/*
+ * SBA-200 Board Control Register (BCR)
+ */
+/* Write access - bit set */
+#define SBA200_CLR_SBUS_INTR 0x04 /* Clear SBus interrupt */
+#define SBA200_RESET 0x01 /* Assert board reset signal */
+
+/* Write access - bit clear */
+#define SBA200_RESET_CLR 0x00 /* Clear board reset signal */
+
+
+
+/*
+ * PCA-200E PCI Bus Slave Interface
+ * --------------------------------
+ */
+
+/*
+ * PCI Identifiers
+ */
+#define FORE_VENDOR_ID 0x1127
+#define FORE_PCA200E_ID 0x0300
+
+/*
+ * PCA-200E PCI Configuration Space
+ */
+#define PCA200E_PCI_MEMBASE 0x10 /* Memory base address */
+#define PCA200E_PCI_MCTL 0x40 /* Master control */
+
+/*
+ * PCA-200E Address Space
+ */
+#define PCA200E_RAM_SIZE 0x100000
+#define PCA200E_HCR_OFFSET 0x100000
+#define PCA200E_IMASK_OFFSET 0x100004
+#define PCA200E_PSR_OFFSET 0x100008
+#define PCA200E_MMAP_SIZE 0x10000c
+
+/*
+ * PCA-200E Master Control
+ */
+#define PCA200E_MCTL_SWAP 0x4000 /* Convert Slave endianess */
+
+/*
+ * PCA-200E Host Control Register (HCR)
+ */
+#define PCA200E_READ_BITS 0x0ff /* Valid read data bits */
+#define PCA200E_WRITE_BITS 0x01f /* Valid write data bits */
+#define PCA200E_STICKY_BITS 0x000 /* Sticky data bits */
+
+/* Read access */
+#define PCA200E_TEST_MODE 0x080 /* Device is in test-mode */
+#define PCA200E_IFIFO_FULL 0x040 /* Input FIFO almost full */
+#define PCA200E_ESP_HOLD_RD 0x020 /* State of ESP hold bus */
+#define PCA200E_OFIFO_FULL 0x010 /* Output FIFO almost full */
+#define PCA200E_HOLD_ACK 0x008 /* State of Hold Ack */
+#define PCA200E_SELFTEST_FAIL 0x004 /* i960 self-test failed */
+#define PCA200E_HOLD_LOCK_RD 0x002 /* State of i960 hold lock signal */
+#define PCA200E_RESET_BD 0x001 /* State of board reset signal */
+
+/* Write access */
+#define PCA200E_CLR_HBUS_INT 0x010 /* Clear host bus interrupt */
+#define PCA200E_I960_INTRA 0x008 /* Set slave interrupt A */
+#define PCA200E_I960_INTRB 0x004 /* Set slave interrupt B */
+#define PCA200E_HOLD_LOCK 0x002 /* Set (clear) i960 hold lock signal */
+#define PCA200E_RESET 0x001 /* Set (clear) board reset signal */
+
+#define PCA200E_HCR_INIT(hcr,bits) \
+ ((hcr) = (PCA200E_WRITE_BITS & (bits)))
+#define PCA200E_HCR_SET(hcr,bits) \
+ ((hcr) = (bits))
+#define PCA200E_HCR_CLR(hcr,bits) \
+ ((hcr) = 0)
+
+#endif /* _FORE_SLAVE_H */
diff --git a/sys/dev/hfa/fore_stats.c b/sys/dev/hfa/fore_stats.c
new file mode 100644
index 0000000..a8271a2
--- /dev/null
+++ b/sys/dev/hfa/fore_stats.c
@@ -0,0 +1,164 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_stats.c,v 1.5 1997/08/22 18:41:21 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Device statistics routines
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_stats.c,v 1.5 1997/08/22 18:41:21 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Get device statistics from CP
+ *
+ * This function will issue a GET_STATS command to the CP in order to
+ * initiate the DMA transfer of the CP's statistics structure to the host.
+ * We will then sleep pending command completion. This must only be called
+ * from the ioctl system call handler.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * 0 stats retrieval successful
+ * errno stats retrieval failed - reason indicated
+ *
+ */
+int
+fore_get_stats(fup)
+ Fore_unit *fup;
+{
+ H_cmd_queue *hcp;
+ Cmd_queue *cqp;
+ int s, sst;
+
+ ATM_DEBUG1("fore_get_stats: fup=0x%x\n", (int)fup);
+
+ /*
+ * Make sure device has been initialized
+ */
+ if ((fup->fu_flags & CUF_INITED) == 0) {
+ return (EIO);
+ }
+
+ /*
+ * If someone has already initiated a stats request, we'll
+ * just wait for that one to complete
+ */
+ s = splimp();
+ if (fup->fu_flags & FUF_STATCMD) {
+
+#if (defined(BSD) && (BSD >= 199103))
+ sst = tsleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH, "fore", 0);
+#else
+ sst = sleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH);
+ if (sst != 0)
+ sst = EINTR;
+#endif
+ (void) splx(s);
+ return (sst ? sst : fup->fu_stats_ret);
+ }
+
+ /*
+ * Limit stats gathering to once a second or so
+ */
+ if (time_second == fup->fu_stats_time) {
+ (void) splx(s);
+ return (0);
+ } else
+ fup->fu_stats_time = time_second;
+
+ /*
+ * Queue command at end of command queue
+ */
+ hcp = fup->fu_cmd_tail;
+ if ((*hcp->hcq_status) & QSTAT_FREE) {
+ void *dma;
+
+ /*
+ * Queue entry available, so set our view of things up
+ */
+ hcp->hcq_code = CMD_GET_STATS;
+ hcp->hcq_arg = NULL;
+ fup->fu_cmd_tail = hcp->hcq_next;
+
+ /*
+ * Now set the CP-resident queue entry - the CP will grab
+ * the command when the op-code is set.
+ */
+ cqp = hcp->hcq_cpelem;
+ (*hcp->hcq_status) = QSTAT_PENDING;
+
+ dma = DMA_GET_ADDR(fup->fu_stats, sizeof(Fore_cp_stats),
+ FORE_STATS_ALIGN, 0);
+ if (dma == NULL) {
+ fup->fu_stats->st_drv.drv_cm_nodma++;
+ (void) splx(s);
+ return (EIO);
+ }
+ fup->fu_statsd = dma;
+ cqp->cmdq_stats.stats_buffer = (CP_dma) CP_WRITE(dma);
+
+ fup->fu_flags |= FUF_STATCMD;
+ cqp->cmdq_stats.stats_cmd =
+ CP_WRITE(CMD_GET_STATS | CMD_INTR_REQ);
+
+ /*
+ * Now wait for command to finish
+ */
+#if (defined(BSD) && (BSD >= 199103))
+ sst = tsleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH, "fore", 0);
+#else
+ sst = sleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH);
+ if (sst != 0)
+ sst = EINTR;
+#endif
+ (void) splx(s);
+ return (sst ? sst : fup->fu_stats_ret);
+
+ } else {
+ /*
+ * Command queue full
+ */
+ fup->fu_stats->st_drv.drv_cm_full++;
+ (void) splx(s);
+ return (EIO);
+ }
+}
+
diff --git a/sys/dev/hfa/fore_stats.h b/sys/dev/hfa/fore_stats.h
new file mode 100644
index 0000000..3803ddd
--- /dev/null
+++ b/sys/dev/hfa/fore_stats.h
@@ -0,0 +1,83 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_stats.h,v 1.3 1997/05/06 22:10:21 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Driver statistics definitions
+ *
+ */
+
+#ifndef _FORE_STATS_H
+#define _FORE_STATS_H
+
+
+/*
+ * Fore Driver Statistics
+ */
+struct Stats_driver {
+ u_long drv_xm_notact; /* PDU drops out - VCC not active */
+ u_long drv_xm_full; /* Xmit queue full */
+ u_long drv_xm_maxpdu; /* PDU drops out - max segment/size */
+ u_long drv_xm_segnoal; /* Non-aligned segments */
+ u_long drv_xm_seglen; /* Padded length segments */
+ u_long drv_xm_segdma; /* PDU drops out - no dma address */
+ u_long drv_rv_novcc; /* PDU drops in - no VCC */
+ u_long drv_rv_nosbf; /* No small buffers */
+ u_long drv_rv_nomb; /* PDU drops in - no buffer */
+ u_long drv_rv_ifull; /* PDU drops in - intr queue full */
+ u_long drv_bf_segdma; /* Buffer supply - no dma address */
+ u_long drv_cm_full; /* Command queue full */
+ u_long drv_cm_nodma; /* Command failed - no dma address */
+};
+typedef struct Stats_driver Stats_driver;
+
+
+/*
+ * Fore Device Statistics
+ *
+ * This structure is used by pass all statistics (including CP maintained
+ * and driver maintained) data to user space (atm command).
+ */
+struct fore_stats {
+ Fore_cp_stats st_cpstat; /* CP stats */
+ Stats_driver st_drv; /* Driver maintained stats */
+};
+typedef struct fore_stats Fore_stats;
+
+#define st_taxi st_cpstat.st_cp_taxi
+#define st_oc3 st_cpstat.st_cp_oc3
+#define st_atm st_cpstat.st_cp_atm
+#define st_aal0 st_cpstat.st_cp_aal0
+#define st_aal4 st_cpstat.st_cp_aal4
+#define st_aal5 st_cpstat.st_cp_aal5
+#define st_misc st_cpstat.st_cp_misc
+
+#endif /* _FORE_STATS_H */
diff --git a/sys/dev/hfa/fore_timer.c b/sys/dev/hfa/fore_timer.c
new file mode 100644
index 0000000..e0d0c0e
--- /dev/null
+++ b/sys/dev/hfa/fore_timer.c
@@ -0,0 +1,97 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_timer.c,v 1.5 1997/05/06 22:10:24 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Timer processing
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_timer.c,v 1.5 1997/05/06 22:10:24 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Process a Fore timer tick
+ *
+ * This function is called every FORE_TIME_TICK seconds in order to update
+ * all of the unit watchdog timers.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * tip pointer to fore timer control block
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+fore_timeout(tip)
+ struct atm_time *tip;
+{
+ Fore_unit *fup;
+ int i;
+
+
+ /*
+ * Schedule next timeout
+ */
+ atm_timeout(&fore_timer, ATM_HZ * FORE_TIME_TICK, fore_timeout);
+
+ /*
+ * Run through all units, updating each active timer.
+ * If an expired timer is found, notify that unit.
+ */
+ for (i = 0; i < fore_nunits; i++) {
+
+ if ((fup = fore_units[i]) == NULL)
+ continue;
+
+ /*
+ * Decrement timer, if it's active
+ */
+ if (fup->fu_timer && (--fup->fu_timer == 0)) {
+
+ /*
+ * Timeout occurred - go check out the queues
+ */
+ ATM_DEBUG0("fore_timeout\n");
+ DEVICE_LOCK((Cmn_unit *)fup);
+ fore_watchdog(fup);
+ DEVICE_UNLOCK((Cmn_unit *)fup);
+ }
+ }
+}
+
diff --git a/sys/dev/hfa/fore_transmit.c b/sys/dev/hfa/fore_transmit.c
new file mode 100644
index 0000000..744e775
--- /dev/null
+++ b/sys/dev/hfa/fore_transmit.c
@@ -0,0 +1,371 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_transmit.c,v 1.8 1998/07/17 20:19:37 root Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Transmit queue management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_transmit.c,v 1.8 1998/07/17 20:19:37 root Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * Allocate Transmit Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * 0 allocations successful
+ * else allocation failed
+ */
+int
+fore_xmit_allocate(fup)
+ Fore_unit *fup;
+{
+ void *memp;
+ H_xmit_queue *hxp;
+ int i;
+
+ /*
+ * Allocate non-cacheable memory for transmit status words
+ */
+ memp = atm_dev_alloc(sizeof(Q_status) * XMIT_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_xmit_stat = (Q_status *) memp;
+
+ memp = DMA_GET_ADDR(fup->fu_xmit_stat, sizeof(Q_status) * XMIT_QUELEN,
+ QSTAT_ALIGN, ATM_DEV_NONCACHE);
+ if (memp == NULL) {
+ return (1);
+ }
+ fup->fu_xmit_statd = (Q_status *) memp;
+
+ /*
+ * Allocate memory for transmit descriptors
+ *
+ * We will allocate the transmit descriptors individually rather than
+ * as a single memory block, which will often be larger than a memory
+ * page. On some systems (eg. FreeBSD) the physical addresses of
+ * adjacent virtual memory pages are not contiguous.
+ */
+ hxp = fup->fu_xmit_q;
+ for (i = 0; i < XMIT_QUELEN; i++, hxp++) {
+
+ /*
+ * Allocate a transmit descriptor for this queue entry
+ */
+ hxp->hxq_descr = atm_dev_alloc(sizeof(Xmit_descr),
+ XMIT_DESCR_ALIGN, 0);
+ if (hxp->hxq_descr == NULL) {
+ return (1);
+ }
+
+ hxp->hxq_descr_dma = DMA_GET_ADDR(hxp->hxq_descr,
+ sizeof(Xmit_descr), XMIT_DESCR_ALIGN, 0);
+ if (hxp->hxq_descr_dma == NULL) {
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Transmit Queue Initialization
+ *
+ * Allocate and initialize the host-resident transmit queue structures
+ * and then initialize the CP-resident queue structures.
+ *
+ * Called at interrupt level.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_xmit_initialize(fup)
+ Fore_unit *fup;
+{
+ Aali *aap = fup->fu_aali;
+ Xmit_queue *cqp;
+ H_xmit_queue *hxp;
+ Q_status *qsp;
+ Q_status *qsp_dma;
+ int i;
+
+ /*
+ * Point to CP-resident transmit queue
+ */
+ cqp = (Xmit_queue *)(fup->fu_ram + CP_READ(aap->aali_xmit_q));
+
+ /*
+ * Point to host-resident transmit queue structures
+ */
+ hxp = fup->fu_xmit_q;
+ qsp = fup->fu_xmit_stat;
+ qsp_dma = fup->fu_xmit_statd;
+
+ /*
+ * Loop thru all queue entries and do whatever needs doing
+ */
+ for (i = 0; i < XMIT_QUELEN; i++) {
+
+ /*
+ * Set queue status word to free
+ */
+ *qsp = QSTAT_FREE;
+
+ /*
+ * Set up host queue entry and link into ring
+ */
+ hxp->hxq_cpelem = cqp;
+ hxp->hxq_status = qsp;
+ if (i == (XMIT_QUELEN - 1))
+ hxp->hxq_next = fup->fu_xmit_q;
+ else
+ hxp->hxq_next = hxp + 1;
+
+ /*
+ * Now let the CP into the game
+ */
+ cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
+
+ /*
+ * Bump all queue pointers
+ */
+ hxp++;
+ qsp++;
+ qsp_dma++;
+ cqp++;
+ }
+
+ /*
+ * Initialize queue pointers
+ */
+ fup->fu_xmit_head = fup->fu_xmit_tail = fup->fu_xmit_q;
+
+ return;
+}
+
+
+/*
+ * Drain Transmit Queue
+ *
+ * This function will free all completed entries at the head of the
+ * transmit queue. Freeing the entry includes releasing the transmit
+ * buffers (buffer chain) back to the kernel.
+ *
+ * May be called in interrupt state.
+ * Must be called with interrupts locked out.
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_xmit_drain(fup)
+ Fore_unit *fup;
+{
+ H_xmit_queue *hxp;
+ H_dma *sdmap;
+ Fore_vcc *fvp;
+ struct vccb *vcp;
+ KBuffer *m;
+
+ /*
+ * Process each completed entry
+ */
+ while (*fup->fu_xmit_head->hxq_status & QSTAT_COMPLETED) {
+
+ hxp = fup->fu_xmit_head;
+
+ /*
+ * Release the entry's DMA addresses and buffer chain
+ */
+ for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m;
+ m = KB_NEXT(m), sdmap++) {
+ caddr_t cp;
+
+ KB_DATASTART(m, cp, caddr_t);
+ DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0);
+ }
+ KB_FREEALL(hxp->hxq_buf);
+
+ /*
+ * Get VCC over which data was sent (may be null if
+ * VCC has been closed in the meantime)
+ */
+ fvp = hxp->hxq_vcc;
+
+ /*
+ * Now collect some statistics
+ */
+ if (*hxp->hxq_status & QSTAT_ERROR) {
+ /*
+ * CP ran into problems, not much we can do
+ * other than record the event
+ */
+ fup->fu_pif.pif_oerrors++;
+ if (fvp) {
+ vcp = fvp->fv_connvc->cvc_vcc;
+ vcp->vc_oerrors++;
+ if (vcp->vc_nif)
+ vcp->vc_nif->nif_if.if_oerrors++;
+ }
+ } else {
+ /*
+ * Good transmission
+ */
+ int len = XDS_GET_LEN(hxp->hxq_descr->xd_spec);
+
+ fup->fu_pif.pif_opdus++;
+ fup->fu_pif.pif_obytes += len;
+ if (fvp) {
+ vcp = fvp->fv_connvc->cvc_vcc;
+ vcp->vc_opdus++;
+ vcp->vc_obytes += len;
+ if (vcp->vc_nif) {
+ vcp->vc_nif->nif_obytes += len;
+ vcp->vc_nif->nif_if.if_opackets++;
+#if (defined(BSD) && (BSD >= 199103))
+ vcp->vc_nif->nif_if.if_obytes += len;
+#endif
+ }
+ }
+ }
+
+ /*
+ * Mark this entry free for use and bump head pointer
+ * to the next entry in the queue
+ */
+ *hxp->hxq_status = QSTAT_FREE;
+ fup->fu_xmit_head = hxp->hxq_next;
+ }
+
+ return;
+}
+
+
+/*
+ * Free Transmit Queue Data Structures
+ *
+ * Arguments:
+ * fup pointer to device unit structure
+ *
+ * Returns:
+ * none
+ */
+void
+fore_xmit_free(fup)
+ Fore_unit *fup;
+{
+ H_xmit_queue *hxp;
+ H_dma *sdmap;
+ KBuffer *m;
+ int i;
+
+ /*
+ * Free any transmit buffers left on the queue
+ */
+ if (fup->fu_flags & CUF_INITED) {
+ while (*fup->fu_xmit_head->hxq_status != QSTAT_FREE) {
+
+ hxp = fup->fu_xmit_head;
+
+ /*
+ * Release the entry's DMA addresses and buffer chain
+ */
+ for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m;
+ m = KB_NEXT(m), sdmap++) {
+ caddr_t cp;
+
+ KB_DATASTART(m, cp, caddr_t);
+ DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0);
+ }
+ KB_FREEALL(hxp->hxq_buf);
+
+ *hxp->hxq_status = QSTAT_FREE;
+ fup->fu_xmit_head = hxp->hxq_next;
+ }
+ }
+
+ /*
+ * Free the status words
+ */
+ if (fup->fu_xmit_stat) {
+ if (fup->fu_xmit_statd) {
+ DMA_FREE_ADDR(fup->fu_xmit_stat, fup->fu_xmit_statd,
+ sizeof(Q_status) * XMIT_QUELEN,
+ ATM_DEV_NONCACHE);
+ }
+ atm_dev_free((void *)fup->fu_xmit_stat);
+ fup->fu_xmit_stat = NULL;
+ fup->fu_xmit_statd = NULL;
+ }
+
+ /*
+ * Free the transmit descriptors
+ */
+ hxp = fup->fu_xmit_q;
+ for (i = 0; i < XMIT_QUELEN; i++, hxp++) {
+
+ /*
+ * Free the transmit descriptor for this queue entry
+ */
+ if (hxp->hxq_descr_dma) {
+ DMA_FREE_ADDR(hxp->hxq_descr, hxp->hxq_descr_dma,
+ sizeof(Xmit_descr), 0);
+ hxp->hxq_descr_dma = NULL;
+ }
+
+ if (hxp->hxq_descr) {
+ atm_dev_free(hxp->hxq_descr);
+ hxp->hxq_descr = NULL;
+ }
+ }
+
+ return;
+}
+
diff --git a/sys/dev/hfa/fore_var.h b/sys/dev/hfa/fore_var.h
new file mode 100644
index 0000000..25d2131
--- /dev/null
+++ b/sys/dev/hfa/fore_var.h
@@ -0,0 +1,269 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_var.h,v 1.8 1998/02/19 20:10:53 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Host protocol control blocks
+ *
+ */
+
+#ifndef _FORE_VAR_H
+#define _FORE_VAR_H
+
+/*
+ * Device VCC Entry
+ *
+ * Contains the common and Fore-specific information for each VCC
+ * which is opened through a Fore device.
+ */
+struct fore_vcc {
+ struct cmn_vcc fv_cmn; /* Common VCC stuff */
+ Fore_aal fv_aal; /* CP version of AAL */
+};
+typedef struct fore_vcc Fore_vcc;
+
+#define fv_next fv_cmn.cv_next
+#define fv_toku fv_cmn.cv_toku
+#define fv_upper fv_cmn.cv_upper
+#define fv_connvc fv_cmn.cv_connvc
+#define fv_state fv_cmn.cv_state
+#define fv_flags fv_cmn.cv_flags
+
+/*
+ * VCC Flags
+ */
+#define FVF_ACTCMD 0x01 /* Activate command issued */
+
+
+/*
+ * Host Transmit Queue Element
+ *
+ * Defines the host's view of the CP PDU Transmit Queue
+ */
+struct h_xmit_queue {
+ struct h_xmit_queue *hxq_next; /* Next element in queue */
+ Xmit_queue *hxq_cpelem; /* CP queue element */
+ Q_status *hxq_status; /* Element status word */
+ Xmit_descr *hxq_descr; /* Element's transmit descriptor */
+ Xmit_descr *hxq_descr_dma; /* Element's transmit descriptor */
+ Fore_vcc *hxq_vcc; /* Data's VCC */
+ KBuffer *hxq_buf; /* Data's buffer chain head */
+ H_dma hxq_dma[XMIT_MAX_SEGS]; /* DMA addresses for segments */
+};
+typedef struct h_xmit_queue H_xmit_queue;
+
+
+
+/*
+ * Host Receive Queue Element
+ *
+ * Defines the host's view of the CP PDU Receive Queue
+ */
+struct h_recv_queue {
+ struct h_recv_queue *hrq_next; /* Next element in queue */
+ Recv_queue *hrq_cpelem; /* CP queue element */
+ Q_status *hrq_status; /* Element status word */
+ Recv_descr *hrq_descr; /* Element's receive descriptor */
+ Recv_descr *hrq_descr_dma; /* Element's receive descriptor */
+};
+typedef struct h_recv_queue H_recv_queue;
+
+
+
+/*
+ * Host Buffer Supply Queue Element
+ *
+ * Defines the host's view of the CP Buffer Supply Queue
+ */
+struct h_buf_queue {
+ struct h_buf_queue *hbq_next; /* Next element in queue */
+ Buf_queue *hbq_cpelem; /* CP queue element */
+ Q_status *hbq_status; /* Element status word */
+ Buf_descr *hbq_descr; /* Element's buffer descriptor array */
+ Buf_descr *hbq_descr_dma; /* Element's buffer descriptor array */
+};
+typedef struct h_buf_queue H_buf_queue;
+
+
+
+/*
+ * Host Command Queue Element
+ *
+ * Defines the host's view of the CP Command Queue
+ */
+struct h_cmd_queue {
+ struct h_cmd_queue *hcq_next; /* Next element in queue */
+ Cmd_queue *hcq_cpelem; /* CP queue element */
+ Q_status *hcq_status; /* Element status word */
+ Cmd_code hcq_code; /* Command code */
+ void *hcq_arg; /* Command-specific argument */
+};
+typedef struct h_cmd_queue H_cmd_queue;
+
+
+
+/*
+ * Host Buffer Handle
+ *
+ * For each buffer supplied to the CP, there will be one of these structures
+ * embedded into the non-data portion of the buffer. This will allow us to
+ * track which buffers are currently "controlled" by the CP. The address of
+ * this structure will supplied to/returned from the CP as the buffer handle.
+ */
+struct buf_handle {
+ Qelem_t bh_qelem; /* Queuing element */
+ u_int bh_type; /* Buffer type (see below) */
+ H_dma bh_dma; /* Buffer DMA address */
+};
+typedef struct buf_handle Buf_handle;
+#define SIZEOF_Buf_handle 16
+
+/*
+ * Buffer Types
+ */
+#define BHT_S1_SMALL 1 /* Buffer strategy 1, small */
+#define BHT_S1_LARGE 2 /* Buffer strategy 1, large */
+#define BHT_S2_SMALL 3 /* Buffer strategy 2, small */
+#define BHT_S2_LARGE 4 /* Buffer strategy 2, large */
+
+
+
+/*
+ * Device Unit Structure
+ *
+ * Contains all the information for a single device (adapter).
+ */
+struct fore_unit {
+ Cmn_unit fu_cmn; /* Common unit stuff */
+#ifdef sun
+ struct dev_info *fu_devinfo; /* Device node for this unit */
+#endif
+ Fore_reg *fu_ctlreg; /* Device control register */
+#ifdef FORE_SBUS
+ Fore_reg *fu_intlvl; /* Interrupt level register */
+#endif
+#ifdef FORE_PCI
+ Fore_reg *fu_imask; /* Interrupt mask register */
+ Fore_reg *fu_psr; /* PCI specific register */
+ pcici_t fu_pcitag; /* PCI tag */
+#endif
+ Fore_mem *fu_ram; /* Device RAM */
+ u_int fu_ramsize; /* Size of device RAM */
+ Mon960 *fu_mon; /* Monitor program interface */
+ Aali *fu_aali; /* Microcode program interface */
+ u_int fu_timer; /* Watchdog timer value */
+
+ /* Transmit Queue */
+ H_xmit_queue fu_xmit_q[XMIT_QUELEN]; /* Host queue */
+ H_xmit_queue *fu_xmit_head; /* Queue head */
+ H_xmit_queue *fu_xmit_tail; /* Queue tail */
+ Q_status *fu_xmit_stat; /* Status array (host) */
+ Q_status *fu_xmit_statd; /* Status array (DMA) */
+
+ /* Receive Queue */
+ H_recv_queue fu_recv_q[RECV_QUELEN]; /* Host queue */
+ H_recv_queue *fu_recv_head; /* Queue head */
+ Q_status *fu_recv_stat; /* Status array (host) */
+ Q_status *fu_recv_statd; /* Status array (DMA) */
+ Recv_descr *fu_recv_desc; /* Descriptor array (host) */
+ Recv_descr *fu_recv_descd; /* Descriptor array (DMA) */
+
+ /* Buffer Supply Queue - Strategy 1 Small */
+ H_buf_queue fu_buf1s_q[BUF1_SM_QUELEN]; /* Host queue */
+ H_buf_queue *fu_buf1s_head; /* Queue head */
+ H_buf_queue *fu_buf1s_tail; /* Queue tail */
+ Q_status *fu_buf1s_stat; /* Status array (host) */
+ Q_status *fu_buf1s_statd;/* Status array (DMA) */
+ Buf_descr *fu_buf1s_desc; /* Descriptor array (host) */
+ Buf_descr *fu_buf1s_descd;/* Descriptor array (DMA) */
+ Queue_t fu_buf1s_bq; /* Queue of supplied buffers */
+ u_int fu_buf1s_cnt; /* Count of supplied buffers */
+
+ /* Buffer Supply Queue - Strategy 1 Large */
+ H_buf_queue fu_buf1l_q[BUF1_LG_QUELEN]; /* Host queue */
+ H_buf_queue *fu_buf1l_head; /* Queue head */
+ H_buf_queue *fu_buf1l_tail; /* Queue tail */
+ Q_status *fu_buf1l_stat; /* Status array (host) */
+ Q_status *fu_buf1l_statd;/* Status array (DMA) */
+ Buf_descr *fu_buf1l_desc; /* Descriptor array (host) */
+ Buf_descr *fu_buf1l_descd;/* Descriptor array (DMA) */
+ Queue_t fu_buf1l_bq; /* Queue of supplied buffers */
+ u_int fu_buf1l_cnt; /* Count of supplied buffers */
+
+ /* Command Queue */
+ H_cmd_queue fu_cmd_q[CMD_QUELEN]; /* Host queue */
+ H_cmd_queue *fu_cmd_head; /* Queue head */
+ H_cmd_queue *fu_cmd_tail; /* Queue tail */
+ Q_status *fu_cmd_stat; /* Status array (host) */
+ Q_status *fu_cmd_statd; /* Status array (DMA) */
+
+ Fore_stats *fu_stats; /* Device statistics buffer */
+ Fore_stats *fu_statsd; /* Device statistics buffer (DMA) */
+ time_t fu_stats_time; /* Last stats request timestamp */
+ int fu_stats_ret; /* Stats request return code */
+#ifdef FORE_PCI
+ Fore_prom *fu_prom; /* Device PROM buffer */
+ Fore_prom *fu_promd; /* Device PROM buffer (DMA) */
+#endif
+ struct callout_handle fu_thandle; /* Timer handle */
+};
+typedef struct fore_unit Fore_unit;
+
+#define fu_pif fu_cmn.cu_pif
+#define fu_unit fu_cmn.cu_unit
+#define fu_flags fu_cmn.cu_flags
+#define fu_mtu fu_cmn.cu_mtu
+#define fu_open_vcc fu_cmn.cu_open_vcc
+#define fu_vcc fu_cmn.cu_vcc
+#define fu_intrpri fu_cmn.cu_intrpri
+#define fu_savepri fu_cmn.cu_savepri
+#define fu_vcc_pool fu_cmn.cu_vcc_pool
+#define fu_nif_pool fu_cmn.cu_nif_pool
+#define fu_ioctl fu_cmn.cu_ioctl
+#define fu_instvcc fu_cmn.cu_instvcc
+#define fu_openvcc fu_cmn.cu_openvcc
+#define fu_closevcc fu_cmn.cu_closevcc
+#define fu_output fu_cmn.cu_output
+#define fu_config fu_cmn.cu_config
+
+/*
+ * Device flags (in addition to CUF_* flags)
+ */
+#define FUF_STATCMD 0x80 /* Statistics request in progress */
+
+
+/*
+ * Macros to access CP memory
+ */
+#define CP_READ(x) ntohl((u_long)(x))
+#define CP_WRITE(x) htonl((u_long)(x))
+
+#endif /* _FORE_VAR_H */
diff --git a/sys/dev/hfa/fore_vcm.c b/sys/dev/hfa/fore_vcm.c
new file mode 100644
index 0000000..3efea6a
--- /dev/null
+++ b/sys/dev/hfa/fore_vcm.c
@@ -0,0 +1,321 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: fore_vcm.c,v 1.7 1998/06/29 21:42:20 mks Exp $
+ *
+ */
+
+/*
+ * FORE Systems 200-Series Adapter Support
+ * ---------------------------------------
+ *
+ * Virtual Channel Management
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: fore_vcm.c,v 1.7 1998/06/29 21:42:20 mks Exp $";
+#endif
+
+#include <dev/hfa/fore_include.h>
+
+
+/*
+ * VCC Stack Instantiation
+ *
+ * This function is called via the common driver code during a device VCC
+ * stack instantiation. The common code has already validated some of
+ * the request so we just need to check a few more Fore-specific details.
+ *
+ * Called at splnet.
+ *
+ * Arguments:
+ * cup pointer to device common unit
+ * cvp pointer to common VCC entry
+ *
+ * Returns:
+ * 0 instantiation successful
+ * err instantiation failed - reason indicated
+ *
+ */
+int
+fore_instvcc(cup, cvp)
+ Cmn_unit *cup;
+ Cmn_vcc *cvp;
+{
+ Fore_vcc *fvp = (Fore_vcc *)cvp;
+ Atm_attributes *ap = &fvp->fv_connvc->cvc_attr;
+
+ /*
+ * Validate requested AAL
+ */
+ switch (ap->aal.type) {
+
+ case ATM_AAL0:
+ fvp->fv_aal = FORE_AAL_0;
+ break;
+
+ case ATM_AAL3_4:
+ fvp->fv_aal = FORE_AAL_4;
+ if ((ap->aal.v.aal4.forward_max_SDU_size > FORE_IFF_MTU) ||
+ (ap->aal.v.aal4.backward_max_SDU_size > FORE_IFF_MTU))
+ return (EINVAL);
+ break;
+
+ case ATM_AAL5:
+ fvp->fv_aal = FORE_AAL_5;
+ if ((ap->aal.v.aal5.forward_max_SDU_size > FORE_IFF_MTU) ||
+ (ap->aal.v.aal5.backward_max_SDU_size > FORE_IFF_MTU))
+ return (EINVAL);
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Open a VCC
+ *
+ * This function is called via the common driver code after receiving a
+ * stack *_INIT command. The common code has already validated most of
+ * the request so we just need to check a few more Fore-specific details.
+ * Then we just issue the command to the CP. Note that we can't wait around
+ * for the CP to process the command, so we return success for now and abort
+ * the connection if the command later fails.
+ *
+ * Called at splimp.
+ *
+ * Arguments:
+ * cup pointer to device common unit
+ * cvp pointer to common VCC entry
+ *
+ * Returns:
+ * 0 open successful
+ * else open failed
+ *
+ */
+int
+fore_openvcc(cup, cvp)
+ Cmn_unit *cup;
+ Cmn_vcc *cvp;
+{
+ Fore_unit *fup = (Fore_unit *)cup;
+ Fore_vcc *fvp = (Fore_vcc *)cvp;
+ H_cmd_queue *hcp;
+ Cmd_queue *cqp;
+ struct vccb *vcp;
+
+ vcp = fvp->fv_connvc->cvc_vcc;
+
+ ATM_DEBUG4("fore_openvcc: fup=0x%x, fvp=0x%x, vcc=(%d,%d)\n",
+ (int)fup, (int)fvp, vcp->vc_vpi, vcp->vc_vci);
+
+ /*
+ * Validate the VPI and VCI values
+ */
+ if ((vcp->vc_vpi > fup->fu_pif.pif_maxvpi) ||
+ (vcp->vc_vci > fup->fu_pif.pif_maxvci)) {
+ return (1);
+ }
+
+ /*
+ * Only need to tell the CP about incoming VCCs
+ */
+ if ((vcp->vc_type & VCC_IN) == 0) {
+ DEVICE_LOCK((Cmn_unit *)fup);
+ fup->fu_open_vcc++;
+ fvp->fv_state = CVS_ACTIVE;
+ DEVICE_UNLOCK((Cmn_unit *)fup);
+ return (0);
+ }
+
+ /*
+ * Queue command at end of command queue
+ */
+ hcp = fup->fu_cmd_tail;
+ if ((*hcp->hcq_status) & QSTAT_FREE) {
+
+ /*
+ * Queue entry available, so set our view of things up
+ */
+ hcp->hcq_code = CMD_ACT_VCCIN;
+ hcp->hcq_arg = fvp;
+ fup->fu_cmd_tail = hcp->hcq_next;
+ fvp->fv_flags |= FVF_ACTCMD;
+
+ /*
+ * Now set the CP-resident queue entry - the CP will grab
+ * the command when the op-code is set.
+ */
+ cqp = hcp->hcq_cpelem;
+ (*hcp->hcq_status) = QSTAT_PENDING;
+ cqp->cmdq_act.act_vccid = CP_WRITE(vcp->vc_vci);
+ if (fvp->fv_aal == FORE_AAL_0)
+ cqp->cmdq_act.act_batch = CP_WRITE(1);
+ cqp->cmdq_act.act_spec = CP_WRITE(
+ ACT_SET_SPEC(BUF_STRAT_1, fvp->fv_aal,
+ CMD_ACT_VCCIN | CMD_INTR_REQ));
+ } else {
+ /*
+ * Command queue full
+ */
+ fup->fu_stats->st_drv.drv_cm_full++;
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Close a VCC
+ *
+ * This function is called via the common driver code after receiving a
+ * stack *_TERM command. The common code has already validated most of
+ * the request so we just need to check a few more Fore-specific details.
+ * Then we just issue the command to the CP. Note that we can't wait around
+ * for the CP to process the command, so we return success for now and whine
+ * if the command later fails.
+ *
+ * Called at splimp.
+ *
+ * Arguments:
+ * cup pointer to device common unit
+ * cvp pointer to common VCC entry
+ *
+ * Returns:
+ * 0 close successful
+ * else close failed
+ *
+ */
+int
+fore_closevcc(cup, cvp)
+ Cmn_unit *cup;
+ Cmn_vcc *cvp;
+{
+ Fore_unit *fup = (Fore_unit *)cup;
+ Fore_vcc *fvp = (Fore_vcc *)cvp;
+ H_xmit_queue *hxp;
+ H_cmd_queue *hcp;
+ Cmd_queue *cqp;
+ struct vccb *vcp;
+ int i, err = 0;
+
+ vcp = fvp->fv_connvc->cvc_vcc;
+
+ ATM_DEBUG4("fore_closevcc: fup=0x%x, fvp=0x%x, vcc=(%d,%d)\n",
+ (int)fup, (int)fvp, vcp->vc_vpi, vcp->vc_vci);
+
+ DEVICE_LOCK((Cmn_unit *)fup);
+
+ /*
+ * Clear any references to this VCC in our transmit queue
+ */
+ for (hxp = fup->fu_xmit_head, i = 0;
+ (*hxp->hxq_status != QSTAT_FREE) && (i < XMIT_QUELEN);
+ hxp = hxp->hxq_next, i++) {
+ if (hxp->hxq_vcc == fvp) {
+ hxp->hxq_vcc = NULL;
+ }
+ }
+
+ /*
+ * Clear any references to this VCC in our command queue
+ */
+ for (hcp = fup->fu_cmd_head, i = 0;
+ (*hcp->hcq_status != QSTAT_FREE) && (i < CMD_QUELEN);
+ hcp = hcp->hcq_next, i++) {
+ switch (hcp->hcq_code) {
+
+ case CMD_ACT_VCCIN:
+ case CMD_ACT_VCCOUT:
+ if (hcp->hcq_arg == fvp) {
+ hcp->hcq_arg = NULL;
+ }
+ break;
+ }
+ }
+
+ /*
+ * If this VCC has been previously activated, then we need to tell
+ * the CP to deactivate it.
+ */
+ if (fvp->fv_flags & FVF_ACTCMD) {
+
+ /*
+ * Queue command at end of command queue
+ */
+ hcp = fup->fu_cmd_tail;
+ if ((*hcp->hcq_status) & QSTAT_FREE) {
+
+ /*
+ * Queue entry available, so set our view of things up
+ */
+ hcp->hcq_code = CMD_DACT_VCCIN;
+ hcp->hcq_arg = fvp;
+ fup->fu_cmd_tail = hcp->hcq_next;
+
+ /*
+ * Now set the CP-resident queue entry - the CP will
+ * grab the command when the op-code is set.
+ */
+ cqp = hcp->hcq_cpelem;
+ (*hcp->hcq_status) = QSTAT_PENDING;
+ cqp->cmdq_dact.dact_vccid = CP_WRITE(vcp->vc_vci);
+ cqp->cmdq_dact.dact_cmd =
+ CP_WRITE(CMD_DACT_VCCIN|CMD_INTR_REQ);
+ } else {
+ /*
+ * Command queue full
+ *
+ * If we get here, we'll be getting out-of-sync with
+ * the CP because we can't (for now at least) do
+ * anything about close errors in the common code.
+ * This won't be too bad, since we'll just toss any
+ * PDUs received from the VCC and the sigmgr's will
+ * always get open failures when trying to use this
+ * (vpi,vci)...oh, well...always gotta have that one
+ * last bug to fix! XXX
+ */
+ fup->fu_stats->st_drv.drv_cm_full++;
+ err = 1;
+ }
+ }
+
+ /*
+ * Finish up...
+ */
+ if (fvp->fv_state == CVS_ACTIVE)
+ fup->fu_open_vcc--;
+
+ DEVICE_UNLOCK((Cmn_unit *)fup);
+
+ return (err);
+}
+
OpenPOWER on IntegriCloud