diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/dev/ic |
initial import of NetBSD tree
Diffstat (limited to 'sys/dev/ic')
29 files changed, 11816 insertions, 0 deletions
diff --git a/sys/dev/ic/ad1848reg.h b/sys/dev/ic/ad1848reg.h new file mode 100644 index 00000000000..fd8de8f3a1c --- /dev/null +++ b/sys/dev/ic/ad1848reg.h @@ -0,0 +1,198 @@ +/* $NetBSD: ad1848reg.h,v 1.1 1995/07/07 02:11:45 brezak Exp $ */ + +/* + * Copyright (c) 1994 John Brezak + * Copyright (c) 1991-1993 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* + * Copyright (c) 1993 Analog Devices Inc. All rights reserved + */ + +/* parent driver is primarily responsible for checking this */ +#define AD1848_BASE_VALID(base) (((base) & 0x003) == 0) + +/* AD1848 direct registers */ +#define AD1848_IADDR 0x04 +#define AD1848_IDATA 0x05 +#define AD1848_STATUS 0x06 +#define AD1848_PIO 0x07 + +/* Gain constants */ +#define GAIN_0 0x00 +#define GAIN_1_5 0x01 +#define GAIN_3 0x02 +#define GAIN_4_5 0x03 +#define GAIN_6 0x04 +#define GAIN_7_5 0x05 +#define GAIN_9 0x06 +#define GAIN_10_5 0x07 +#define GAIN_12 0x08 +#define GAIN_13_5 0x09 +#define GAIN_15 0x0a +#define GAIN_16_5 0x0b +#define GAIN_18 0x0c +#define GAIN_19_5 0x0d +#define GAIN_21 0x0e +#define GAIN_22_5 0x0f + +/* Attenuation constants */ + +#define ATTEN_0 0x00 +#define ATTEN_1_5 0x01 +#define ATTEN_3 0x02 +#define ATTEN_4_5 0x03 +#define ATTEN_6 0x04 +#define ATTEN_7_5 0x05 +#define ATTEN_9 0x06 +#define ATTEN_10_5 0x07 +#define ATTEN_12 0x08 +#define ATTEN_13_5 0x09 +#define ATTEN_15 0x0a +#define ATTEN_16_5 0x0b +#define ATTEN_18 0x0c +#define ATTEN_19_5 0x0d +#define ATTEN_21 0x0e +#define ATTEN_22_5 0x0f + +/* AD1848 Sound Port bit defines */ +#define SP_IN_INIT 0x80 +#define MODE_CHANGE_ENABLE 0x40 +#define MODE_CHANGE_MASK 0xbf +#define TRANSFER_DISABLE 0x20 +#define TRANSFER_DISABLE_MASK 0xdf +#define ADDRESS_MASK 0xe0 + +/* Status bits */ +#define INTERRUPT_STATUS 0x01 +#define PLAYBACK_READY 0x02 +#define PLAYBACK_LEFT 0x04 +/* pbright is not left */ +#define PLAYBACK_UPPER 0x08 +/* bplower is not upper */ + +#define SAMPLE_ERROR 0x10 +#define CAPTURE_READY 0x20 +#define CAPTURE_LEFT 0x40 +/* cpright is not left */ +#define CAPTURE_UPPER 0x08 +/* cplower is not upper */ + +/* Input & Output regs bits */ +#define LINE_INPUT 0x00 +#define AUX_INPUT 0x40 +#define MIC_INPUT 0x80 +#define MIXED_DAC_INPUT 0xC0 +#define INPUT_GAIN_MASK 0xf0 +#define INPUT_MIC_GAIN_ENABLE 0x20 +#define INPUT_MIC_GAIN_MASK 0xdf +#define INPUT_SOURCE_MASK 0x3f +#define AUX_INPUT_ATTEN_BITS 0x1f +#define AUX_INPUT_ATTEN_MASK 0xe0 +#define AUX_INPUT_MUTE 0x80 +#define AUX_INPUT_MUTE_MASK 0x7f +#define OUTPUT_MUTE 0x80 +#define OUTPUT_MUTE_MASK 0x7f +#define OUTPUT_ATTEN_BITS 0x3f +#define OUTPUT_ATTEN_MASK 0xc0 + +/* Clock and Data format reg bits (some also Capture Data format) */ +#define CLOCK_SELECT_MASK 0xfe +#define CLOCK_XTAL2 0x01 +#define CLOCK_XTAL1 0x00 +#define CLOCK_FREQ_MASK 0xf1 +#define STEREO_MONO_MASK 0xef +#define FMT_STEREO 0x10 +#define FMT_MONO 0x00 +#define FORMAT_MASK 0x1f +#define FMT_PCM8 0x00 /* 8-bit unsigned */ +#define FMT_ULAW 0x20 /* 8-bit mu-law */ +#define FMT_TWOS_COMP 0x40 /* 16-bit signed */ +#define FMT_ALAW 0x60 /* 8-bit alaw */ +#define FMT_TWOS_COMP_BE 0xC0 /* 16-bit signed, big endian */ + +/* Interface Configuration reg bits */ +#define PLAYBACK_ENABLE 0x01 +#define PLAYBACK_ENABLE_MASK 0xfe +#define CAPTURE_ENABLE 0x02 +#define CAPTURE_ENABLE_MASK 0xfd +#define SINGLE_DMA 0x04 +#define SINGLE_DMA_MASK 0xfb +#define DUAL_DMA 0x00 +#define AUTO_CAL_ENABLE 0x08 +#define AUTO_CAL_DISABLE_MASK 0xf7 +#define PLAYBACK_PIO_ENABLE 0x40 +#define PLAYBACK_DMA_MASK 0xbf +#define CAPTURE_PIO_ENABLE 0x80 +#define CAPTURE_DMA_MASK 0x7f + +/* Pin control bits */ +#define INTERRUPT_ENABLE 0x02 +#define INTERRUPT_MASK 0xfd +#define XCTL0_ENABLE 0x40 +#define XCTL1_ENABLE 0x80 + +/* Test and init reg bits */ +#define OVERRANGE_LEFT_MASK 0xfc +#define OVERRANGE_RIGHT_MASK 0xf3 +#define DATA_REQUEST_STATUS 0x10 +#define AUTO_CAL_IN_PROG 0x20 +#define PLAYBACK_UNDERRUN 0x40 +#define CAPTURE_OVERRUN 0x80 + +/* Miscellaneous Control reg bits */ +#define ID_MASK 0x70 +#define MODE2 0x40 + +/* Digital Mix Control reg bits */ +#define DIGITAL_MIX1_MUTE_MASK 0xfe +#define DIGITAL_MIX1_ENABLE 0x01 +#define MIX_ATTEN_MASK 0xfc + +/* AD1848 Sound Port reg defines */ +#define SP_LEFT_INPUT_CONTROL 0x00 +#define SP_RIGHT_INPUT_CONTROL 0x01 +#define SP_LEFT_AUX1_CONTROL 0x02 +#define SP_RIGHT_AUX1_CONTROL 0x03 +#define SP_LEFT_AUX2_CONTROL 0x04 +#define SP_RIGHT_AUX2_CONTROL 0x05 +#define SP_LEFT_OUTPUT_CONTROL 0x06 +#define SP_RIGHT_OUTPUT_CONTROL 0x07 +#define SP_CLOCK_DATA_FORMAT 0x08 +#define SP_INTERFACE_CONFIG 0x09 +#define SP_PIN_CONTROL 0x0A +#define SP_TEST_AND_INIT 0x0B +#define SP_MISC_INFO 0x0C +#define SP_DIGITAL_MIX 0x0D +#define SP_UPPER_BASE_COUNT 0x0E +#define SP_LOWER_BASE_COUNT 0x0F + diff --git a/sys/dev/ic/aic7xxx.c b/sys/dev/ic/aic7xxx.c new file mode 100644 index 00000000000..dd2ddf0a9fc --- /dev/null +++ b/sys/dev/ic/aic7xxx.c @@ -0,0 +1,2227 @@ +/* $NetBSD: aic7xxx.c,v 1.1 1995/10/09 09:49:30 mycroft Exp $ */ + +/* + * Generic driver for the aic7xxx based adaptec SCSI controllers + * Copyright (c) 1994, 1995 Justin T. Gibbs. + * All rights reserved. + * + * Product specific probe and attach routines can be found in: + * i386/isa/aic7770.c 27/284X and aic7770 motherboard controllers + * /pci/aic7870.c 294x and aic7870 motherboard controllers + * + * Portions of this driver are based on the FreeBSD 1742 Driver: + * + * Written by Julian Elischer (julian@tfs.com) + * for TRW Financial Systems for use under the MACH(2.5) operating system. + * + * TRW Financial Systems, in accordance with their agreement with Carnegie + * Mellon University, makes this software available to CMU to distribute + * or use in any manner that they see fit as long as this message is kept with + * the software. For this reason TFS also grants any other persons or + * organisations permission to use or modify this software. + * + * TFS supplies this software to be publicly redistributed + * on the understanding that TFS is not responsible for the correct + * functioning of this software in any circumstances. + * + * commenced: Sun Sep 27 18:14:01 PDT 1992 + */ +/* + * TODO: + * Add target reset capabilities + * Implement Target Mode + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/user.h> + +#include <machine/pio.h> + +#include <dev/isa/isareg.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsi_debug.h> +#include <scsi/scsiconf.h> + +#include <dev/ic/aic7xxxvar.h> + +int ahc_init __P((struct ahc_softc *)); +void ahc_loadseq __P((int)); +int ahc_scsi_cmd __P((struct scsi_xfer *)); +void ahc_timeout __P((void *)); +void ahc_done __P((struct ahc_softc *, struct ahc_scb *)); +struct ahc_scb *ahc_get_scb __P((struct ahc_softc *, int)); +void ahc_free_scb __P((struct ahc_softc *, struct ahc_scb *, int)); +void ahc_abort_scb __P((struct ahc_softc *, struct ahc_scb *)); +void ahcminphys __P((struct buf *)); +int ahc_poll __P((struct ahc_softc *, struct scsi_xfer *, int)); + +/* Different debugging levels */ +#define AHC_SHOWMISC 0x0001 +#define AHC_SHOWCMDS 0x0002 +#define AHC_SHOWSCBS 0x0004 +/*#define AHC_DEBUG /**/ +int ahc_debug = AHC_SHOWMISC; + +/*#define AHC_MORE_DEBUG /**/ + +#ifdef AHC_MORE_DEBUG +#define DEBUGLEVEL -1 +#define DEBUGTARGET 0x0 +#endif + +/**** bit definitions for SCSIDEF ****/ +#define HSCSIID 0x07 /* our SCSI ID */ +#define HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ + +struct scsi_adapter ahc_switch = { + ahc_scsi_cmd, + ahcminphys, + 0, + 0, +}; + + +/* the below structure is so we have a default dev struct for our link struct */ +struct scsi_device ahc_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ +}; + + +/* + * All of these should be in a separate header file shared by the sequencer + * code and the kernel level driver. The only catch is that we would need to + * add an additional 0xc00 offset when using them in the kernel driver. The + * aic7770 assembler must be modified to allow include files as well. All + * page numbers refer to the Adaptec AIC-7770 Data Book available from + * Adaptec's Technical Documents Department 1-800-934-2766 + */ + +/* -------------------- AIC-7770 offset definitions ----------------------- */ + +/* + * SCSI Sequence Control (p. 3-11). + * Each bit, when set starts a specific SCSI sequence on the bus + */ +#define SCSISEQ 0xc00ul +#define TEMODEO 0x80 +#define ENSELO 0x40 +#define ENSELI 0x20 +#define ENRSELI 0x10 +#define ENAUTOATNO 0x08 +#define ENAUTOATNI 0x04 +#define ENAUTOATNP 0x02 +#define SCSIRSTO 0x01 + +/* + * SCSI Transfer Control 1 Register (pp. 3-14,15). + * Controls the SCSI module data path. + */ +#define SXFRCTL1 0xc02ul +#define BITBUCKET 0x80 +#define SWRAPEN 0x40 +#define ENSPCHK 0x20 +#define STIMESEL 0x18 +#define ENSTIMER 0x04 +#define ACTNEGEN 0x02 +#define STPWEN 0x01 /* Powered Termination */ + +/* + * SCSI Interrrupt Mode 1 (pp. 3-28,29). + * Set bits in this register enable the corresponding + * interrupt source. + */ +#define SIMODE1 0xc11ul +#define ENSELTIMO 0x80 +#define ENATNTARG 0x40 +#define ENSCSIRST 0x20 +#define ENPHASEMIS 0x10 +#define ENBUSFREE 0x08 +#define ENSCSIPERR 0x04 +#define ENPHASECHG 0x02 +#define ENREQINIT 0x01 + +/* + * SCSI Control Signal Read Register (p. 3-15). + * Reads the actual state of the SCSI bus pins + */ +#define SCSISIGI 0xc03ul +#define CDI 0x80 +#define IOI 0x40 +#define MSGI 0x20 +#define ATNI 0x10 +#define SELI 0x08 +#define BSYI 0x04 +#define REQI 0x02 +#define ACKI 0x01 + +/* + * SCSI Contol Signal Write Register (p. 3-16). + * Writing to this register modifies the control signals on the bus. Only + * those signals that are allowed in the current mode (Initiator/Target) are + * asserted. + */ +#define SCSISIGO 0xc03ul +#define CDO 0x80 +#define IOO 0x40 +#define MSGO 0x20 +#define ATNO 0x10 +#define SELO 0x08 +#define BSYO 0x04 +#define REQO 0x02 +#define ACKO 0x01 + +/* XXX document this thing */ +#define SCSIRATE 0xc04ul + +/* + * SCSI ID (p. 3-18). + * Contains the ID of the board and the current target on the + * selected channel + */ +#define SCSIID 0xc05ul +#define TID 0xf0 /* Target ID mask */ +#define OID 0x0f /* Our ID mask */ + +/* + * SCSI Status 0 (p. 3-21) + * Contains one set of SCSI Interrupt codes + * These are most likely of interest to the sequencer + */ +#define SSTAT0 0xc0bul +#define TARGET 0x80 /* Board is a target */ +#define SELDO 0x40 /* Selection Done */ +#define SELDI 0x20 /* Board has been selected */ +#define SELINGO 0x10 /* Selection In Progress */ +#define SWRAP 0x08 /* 24bit counter wrap */ +#define SDONE 0x04 /* STCNT = 0x000000 */ +#define SPIORDY 0x02 /* SCSI PIO Ready */ +#define DMADONE 0x01 /* DMA transfer completed */ + +/* + * Clear SCSI Interrupt 1 (p. 3-23) + * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. + */ +#define CLRSINT1 0xc0cul +#define CLRSELTIMEO 0x80 +#define CLRATNO 0x40 +#define CLRSCSIRSTI 0x20 +/* UNUSED 0x10 */ +#define CLRBUSFREE 0x08 +#define CLRSCSIPERR 0x04 +#define CLRPHASECHG 0x02 +#define CLRREQINIT 0x01 + +/* + * SCSI Status 1 (p. 3-24) + * These interrupt bits are of interest to the kernel driver + */ +#define SSTAT1 0xc0cul +#define SELTO 0x80 +#define ATNTARG 0x40 +#define SCSIRSTI 0x20 +#define PHASEMIS 0x10 +#define BUSFREE 0x08 +#define SCSIPERR 0x04 +#define PHASECHG 0x02 +#define REQINIT 0x01 + +/* + * Selection/Reselection ID (p. 3-31) + * Upper four bits are the device id. The ONEBIT is set when the re/selecting + * device did not set its own ID. + */ +#define SELID 0xc19ul +#define SELID_MASK 0xf0 +#define ONEBIT 0x08 +/* UNUSED 0x07 */ + +/* + * SCSI Block Control (p. 3-32) + * Controls Bus type and channel selection. In a twin channel configuration + * addresses 0x00-0x1e are gated to the appropriate channel based on this + * register. SELWIDE allows for the coexistence of 8bit and 16bit devices + * on a wide bus. + */ +#define SBLKCTL 0xc1ful +/* UNUSED 0xc0 */ +#define AUTOFLUSHDIS 0x20 +/* UNUSED 0x10 */ +#define SELBUSB 0x08 +/* UNUSED 0x04 */ +#define SELWIDE 0x02 +/* UNUSED 0x01 */ + +/* + * Sequencer Control (p. 3-33) + * Error detection mode and speed configuration + */ +#define SEQCTL 0xc60ul +#define PERRORDIS 0x80 +#define PAUSEDIS 0x40 +#define FAILDIS 0x20 +#define FASTMODE 0x10 +#define BRKADRINTEN 0x08 +#define STEP 0x04 +#define SEQRESET 0x02 +#define LOADRAM 0x01 + +/* + * Sequencer RAM Data (p. 3-34) + * Single byte window into the Scratch Ram area starting at the address + * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write + * four bytes in sucessesion. The SEQADDRs will increment after the most + * significant byte is written + */ +#define SEQRAM 0xc61ul + +/* + * Sequencer Address Registers (p. 3-35) + * Only the first bit of SEQADDR1 holds addressing information + */ +#define SEQADDR0 0xc62ul +#define SEQADDR1 0xc63ul +#define SEQADDR1_MASK 0x01 + +/* + * Accumulator + * We cheat by passing arguments in the Accumulator up to the kernel driver + */ +#define ACCUM 0xc64ul + +#define SINDEX 0xc65ul + +/* + * Board Control (p. 3-43) + */ +#define BCTL 0xc84ul +/* RSVD 0xf0 */ +#define ACE 0x08 /* Support for external processors */ +/* RSVD 0x06 */ +#define ENABLE 0x01 + +/* + * Host Control (p. 3-47) R/W + * Overal host control of the device. + */ +#define HCNTRL 0xc87ul +/* UNUSED 0x80 */ +#define POWRDN 0x40 +/* UNUSED 0x20 */ +#define SWINT 0x10 +#define IRQMS 0x08 +#define PAUSE 0x04 +#define INTEN 0x02 +#define CHIPRST 0x01 + +/* + * SCB Pointer (p. 3-49) + * Gate one of the four SCBs into the SCBARRAY window. + */ +#define SCBPTR 0xc90ul + +/* + * Interrupt Status (p. 3-50) + * Status for system interrupts + */ +#define INTSTAT 0xc91ul +#define SEQINT_MASK 0xf0 /* SEQINT Status Codes */ +#define BAD_PHASE 0x00 +#define SEND_REJECT 0x10 +#define NO_IDENT 0x20 +#define NO_MATCH 0x30 +#define MSG_SDTR 0x40 +#define MSG_WDTR 0x50 +#define MSG_REJECT 0x60 +#define BAD_STATUS 0x70 +#define RESIDUAL 0x80 +#define ABORT_TAG 0x90 +#define BRKADRINT 0x08 +#define SCSIINT 0x04 +#define CMDCMPLT 0x02 +#define SEQINT 0x01 +#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT) + +/* + * Hard Error (p. 3-53) + * Reporting of catastrophic errors. You usually cannot recover from + * these without a full board reset. + */ +#define ERROR 0xc92ul +/* UNUSED 0xf0 */ +#define PARERR 0x08 +#define ILLOPCODE 0x04 +#define ILLSADDR 0x02 +#define ILLHADDR 0x01 + +/* + * Clear Interrupt Status (p. 3-52) + */ +#define CLRINT 0xc92ul +#define CLRBRKADRINT 0x08 +#define CLRSCSIINT 0x04 +#define CLRCMDINT 0x02 +#define CLRSEQINT 0x01 + +/* + * SCB Auto Increment (p. 3-59) + * Byte offset into the SCB Array and an optional bit to allow auto + * incrementing of the address during download and upload operations + */ +#define SCBCNT 0xc9aul +#define SCBAUTO 0x80 +#define SCBCNT_MASK 0x1f + +/* + * Queue In FIFO (p. 3-60) + * Input queue for queued SCBs (commands that the seqencer has yet to start) + */ +#define QINFIFO 0xc9bul + +/* + * Queue In Count (p. 3-60) + * Number of queued SCBs + */ +#define QINCNT 0xc9cul + +/* + * Queue Out FIFO (p. 3-61) + * Queue of SCBs that have completed and await the host + */ +#define QOUTFIFO 0xc9dul + +/* + * Queue Out Count (p. 3-61) + * Number of queued SCBs in the Out FIFO + */ +#define QOUTCNT 0xc9eul + +#define SCBARRAY 0xca0ul + +/* ---------------- END AIC-7770 Register Definitions ----------------- */ + +/* --------------------- AIC-7870-only definitions -------------------- */ + +#define DSPCISTATUS 0xc86ul + +/* ---------------------- Scratch RAM Offsets ------------------------- */ +/* These offsets are either to values that are initialized by the board's + * BIOS or are specified by the Linux sequencer code. If I can figure out + * how to read the EISA configuration info at probe time, the cards could + * be run without BIOS support installed + */ + +/* + * 1 byte per target starting at this address for configuration values + */ +#define HA_TARG_SCRATCH 0xc20ul + +/* + * The sequencer will stick the frist byte of any rejected message here so + * we can see what is getting thrown away. + */ +#define HA_REJBYTE 0xc31ul + +/* + * Length of pending message + */ +#define HA_MSG_LEN 0xc34ul + +/* + * message body + */ +#define HA_MSG_START 0xc35ul /* outgoing message body */ + +/* + * These are offsets into the card's scratch ram. Some of the values are + * specified in the AHA2742 technical reference manual and are initialized + * by the BIOS at boot time. + */ +#define HA_ARG_1 0xc4aul +#define HA_RETURN_1 0xc4aul +#define SEND_SENSE 0x80 +#define SEND_WDTR 0x80 +#define SEND_SDTR 0x80 +#define SEND_REJ 0x40 + +#define HA_SIGSTATE 0xc4bul + +#define HA_SCBCOUNT 0xc52ul +#define HA_FLAGS 0xc53ul +#define SINGLE_BUS 0x00 +#define TWIN_BUS 0x01 +#define WIDE_BUS 0x02 +#define ACTIVE_MSG 0x20 +#define IDENTIFY_SEEN 0x40 +#define RESELECTING 0x80 + +#define HA_ACTIVE0 0xc54ul +#define HA_ACTIVE1 0xc55ul +#define SAVED_TCL 0xc56ul +#define WAITING_SCBH 0xc57ul +#define WAITING_SCBT 0xc58ul + +#define HA_SCSICONF 0xc5aul +#define INTDEF 0xc5cul +#define HA_HOSTCONF 0xc5dul + +#define MSG_ABORT 0x06 +#define BUS_8_BIT 0x00 +#define BUS_16_BIT 0x01 +#define BUS_32_BIT 0x02 + +/* + * Since the sequencer can disable pausing in a critical section, we + * must loop until it actually stops. + * XXX Should add a timeout in here?? + */ +#define PAUSE_SEQUENCER(ahc) \ + do { \ + outb(HCNTRL + ahc->sc_iobase, ahc->pause); \ + while ((inb(HCNTRL + ahc->sc_iobase) & PAUSE) == 0) \ + ; \ + } while (0) + +#define UNPAUSE_SEQUENCER(ahc) \ + do { \ + outb(HCNTRL + ahc->sc_iobase, ahc->unpause); \ + } while (0) + +/* + * Restart the sequencer program from address zero + * XXX Should add a timeout in here?? + */ +#define RESET_SEQUENCER(ahc) \ + do { \ + do { \ + outb(SEQCTL + ahc->sc_iobase, SEQRESET|FASTMODE); \ + } while (inb(SEQADDR0 + ahc->sc_iobase) != 0 && \ + inb(SEQADDR1 + ahc->sc_iobase) != 0); \ + } while (0) + +#define RESTART_SEQUENCER(ahc) \ + do { \ + RESET_SEQUENCER(ahc); \ + UNPAUSE_SEQUENCER(ahc); \ + } while (0) + +#ifdef AHC_DEBUG +void +ahc_print_scb(scb) + struct ahc_scb *scb; +{ + + printf("scb:0x%x control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%x\n", + scb, + scb->control, + scb->target_channel_lun, + scb->cmdlen, + scb->cmdpointer); + printf("\tdatlen:%d data:0x%x res:0x%x segs:0x%x segp:0x%x\n", + scb->datalen[2] << 16 | scb->datalen[1] << 8 | scb->datalen[0], + scb->data, + scb->RESERVED[1] << 8 | scb->RESERVED[0], + scb->SG_segment_count, + scb->SG_list_pointer); + printf("\tsg_addr:%x sg_len:%d\n", + scb->ahc_dma[0].addr, + scb->ahc_dma[0].len); + printf(" size:%d\n", + (int)&scb->next - (int)scb); +} + +void +ahc_print_active_scb(ahc) + struct ahc_softc *ahc; +{ + int iobase = ahc->sc_iobase; + int scb_index; + + PAUSE_SEQUENCER(ahc); + scb_index = inb(SCBPTR + iobase); + UNPAUSE_SEQUENCER(ahc); + + ahc_print_scb(ahc->scbarray[scb_index]); +} +#endif + +#define PARERR 0x08 +#define ILLOPCODE 0x04 +#define ILLSADDR 0x02 +#define ILLHADDR 0x01 + +static struct { + u_char errno; + char *errmesg; +} hard_error[] = { + { ILLHADDR, "Illegal Host Access" }, + { ILLSADDR, "Illegal Sequencer Address referrenced" }, + { ILLOPCODE, "Illegal Opcode in sequencer program" }, + { PARERR, "Sequencer Ram Parity Error" } +}; + + +/* + * Valid SCSIRATE values. (p. 3-17) + * Provides a mapping of tranfer periods in ns to the proper value to + * stick in the scsiscfr reg to use that transfer rate. + */ +static struct { + u_char sxfr; + int period; /* in ns */ + char *rate; +} ahc_syncrates[] = { + { 0x00, 100, "10.0" }, + { 0x10, 125, "8.0" }, + { 0x20, 150, "6.67" }, + { 0x30, 175, "5.7" }, + { 0x40, 200, "5.0" }, + { 0x50, 225, "4.4" }, + { 0x60, 250, "4.0" }, + { 0x70, 275, "3.6" } +}; + +static int ahc_num_syncrates = + sizeof(ahc_syncrates) / sizeof(ahc_syncrates[0]); + +/* + * Check if the device can be found at the port given + * and if so, determine configuration and set it up for further work. + */ + +int +ahcprobe(ahc, iobase) + struct ahc_softc *ahc; + int iobase; +{ + + ahc->sc_iobase = iobase; + + /* + * Try to initialize a unit at this location + * reset the AIC-7770, read its registers, + * and fill in the dev structure accordingly + */ + + if (ahc_init(ahc) != 0) + return (0); + + return (1); +} + + +/* + * Look up the valid period to SCSIRATE conversion in our table. + */ +static u_char +ahc_scsirate(offset, period, ahc, target) + u_char offset; + int period; + struct ahc_softc *ahc; + int target; +{ + u_char scsirate; + int i; + + for (i = 0; i < ahc_num_syncrates; i++) { + if ((ahc_syncrates[i].period - period) >= 0) { + printf("%s: target %d synchronous at %sMB/s, " + "offset = %d\n", + ahc->sc_dev.dv_xname, target, + ahc_syncrates[i].rate, offset); +#ifdef AHC_DEBUG +#endif /* AHC_DEBUG */ + return ((ahc_syncrates[i].sxfr) | (offset & 0x0f)); + } + } + + /* Default to asyncronous transfers. Also reject this SDTR request. */ + printf("%s: target %d using asyncronous transfers\n", + ahc->sc_dev.dv_xname, target); + return (0); +#ifdef AHC_DEBUG +#endif /* AHC_DEBUG */ +} + +ahcprint() +{ + +} + +/* + * Attach all the sub-devices we can find + */ +int +ahcattach(ahc) + struct ahc_softc *ahc; +{ + + TAILQ_INIT(&ahc->free_scb); + + /* + * fill in the prototype scsi_link. + */ + ahc->sc_link.adapter_softc = ahc; + ahc->sc_link.adapter_target = ahc->ahc_scsi_dev; + ahc->sc_link.adapter = &ahc_switch; + ahc->sc_link.device = &ahc_dev; + ahc->sc_link.openings = 1; + ahc->sc_link.flags = DEBUGLEVEL; + ahc->sc_link.quirks = 0; + + /* + * ask the adapter what subunits are present + */ + printf("%s: Probing channel A\n", ahc->sc_dev.dv_xname); + config_found((void *)ahc, &ahc->sc_link, ahcprint); + if (ahc->type & AHC_TWIN) { + /* Configure the second scsi bus */ + ahc->sc_link_b = ahc->sc_link; + /* XXXX Didn't do this before. */ + ahc->sc_link_b.adapter_target = ahc->ahc_scsi_dev_b; + ahc->sc_link_b.quirks = 0x0008; /**/ + printf("%s: Probing channel B\n", ahc->sc_dev.dv_xname); + config_found((void *)ahc, &ahc->sc_link_b, ahcprint); + } + + return 1; +} + +void +ahc_send_scb(ahc, scb) + struct ahc_softc *ahc; + struct ahc_scb *scb; +{ + int iobase = ahc->sc_iobase; + + PAUSE_SEQUENCER(ahc); + outb(QINFIFO + iobase, scb->position); + UNPAUSE_SEQUENCER(ahc); +} + +static void +ahc_getscb(iobase, scb) + int iobase; + struct ahc_scb *scb; +{ + + outb(SCBCNT + iobase, SCBAUTO); + insb(SCBARRAY + iobase, scb, SCB_UP_SIZE); + outb(SCBCNT + iobase, 0); +} + +/* + * Catch an interrupt from the adaptor + */ +int +ahcintr(ahc) + struct ahc_softc *ahc; +{ + int iobase = ahc->sc_iobase; + u_char intstat = inb(INTSTAT + iobase); + u_char status; + struct ahc_scb *scb = NULL; + struct scsi_xfer *xs = NULL; + + /* + * Is this interrupt for me? or for + * someone who is sharing my interrupt + */ + if ((intstat & INT_PEND) == 0) + return 0; + + if (intstat & BRKADRINT) { + /* We upset the sequencer :-( */ + + /* Lookup the error message */ + int i, error = inb(ERROR + iobase); + int num_errors = sizeof(hard_error)/sizeof(hard_error[0]); + for (i = 0; error != 1 && i < num_errors; i++) + error >>= 1; + panic("%s: brkadrint, %s at seqaddr = 0x%x\n", + ahc->sc_dev.dv_xname, hard_error[i].errmesg, + (inb(SEQADDR1 + iobase) << 8) | + (inb(SEQADDR0 + iobase) << 0)); + } + + if (intstat & SEQINT) { + switch (intstat & SEQINT_MASK) { + case BAD_PHASE: + panic("%s: unknown scsi bus phase. " + "Attempting to continue\n", + ahc->sc_dev.dv_xname); + break; + case SEND_REJECT: + printf("%s: Warning - " + "message reject, message type: 0x%x\n", + ahc->sc_dev.dv_xname, + inb(HA_REJBYTE + iobase)); + break; + case NO_IDENT: + panic("%s: No IDENTIFY message from reconnecting " + "target %d at seqaddr = 0x%lx " + "SAVED_TCL == 0x%x\n", + ahc->sc_dev.dv_xname, + (inb(SELID + iobase) >> 4) & 0xf, + (inb(SEQADDR1 + iobase) << 8) | + (inb(SEQADDR0 + iobase) << 0), + inb(SAVED_TCL + iobase)); + break; + case NO_MATCH: { + u_char active; + int active_port = HA_ACTIVE0 + iobase; + int tcl = inb(SCBARRAY+1 + iobase); + int target = (tcl >> 4) & 0x0f; + printf("%s: no active SCB for reconnecting " + "target %d, channel %c - issuing ABORT\n", + ahc->sc_dev.dv_xname, + target, tcl & 0x08 ? 'B' : 'A'); + printf("SAVED_TCL == 0x%x\n", inb(SAVED_TCL + iobase)); + if (tcl & 0x88) { + /* Second channel stores its info + * in byte two of HA_ACTIVE + */ + active_port++; + } + active = inb(active_port); + active &= ~(0x01 << (target & 0x07)); + outb(SCBARRAY + iobase, SCB_NEEDDMA); + outb(active_port, active); + outb(CLRSINT1 + iobase, CLRSELTIMEO); + RESTART_SEQUENCER(ahc); + break; + } + case MSG_SDTR: { + u_char scsi_id = + (inb(SCSIID + iobase) >> 0x4) | + (inb(SBLKCTL + iobase) & 0x08); + u_char scratch, offset; + int period; + + /* + * Help the sequencer to translate the + * negotiated transfer rate. Transfer is + * 1/4 the period in ns as is returned by + * the sync negotiation message. So, we must + * multiply by four + */ + period = inb(HA_ARG_1 + iobase) << 2; + /* The bottom half of SCSIXFER */ + offset = inb(ACCUM + iobase); + + printf("%s: SDTR, target %d period %d offset %d\n", + ahc->sc_dev.dv_xname, scsi_id, period, offset); + scratch = inb(HA_TARG_SCRATCH + iobase + scsi_id); + scratch &= 0x80; + scratch |= ahc_scsirate(offset, period, ahc, scsi_id); + + if ((scratch & 0x7f) == 0) { + /* + * The requested rate was so low + * that asyncronous transfers are + * faster (not to mention the + * controller won't support them), + * so we issue a message reject to + * ensure we go to asyncronous + * transfers. + */ + outb(HA_RETURN_1 + iobase, SEND_REJ); + } else if (ahc->sdtrpending & (0x01 << scsi_id)) { + /* + * Don't send an SDTR back to the + * target, since we asked first. + */ + outb(HA_RETURN_1 + iobase, 0); + } else { + /* + * Send our own SDTR in reply + */ +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWMISC) + printf("Sending SDTR!!\n"); +#endif + outb(HA_RETURN_1 + iobase, SEND_SDTR); + } + /* + * Negate the flags + */ + ahc->needsdtr &= ~(0x01 << scsi_id); + ahc->sdtrpending &= ~(0x01 << scsi_id); + + outb(HA_TARG_SCRATCH + iobase + scsi_id, scratch); + outb(SCSIRATE + iobase, scratch); + break; + } + case MSG_WDTR: { + u_char scsi_id = + (inb(SCSIID + iobase) >> 0x4) | + (inb(SBLKCTL + iobase) & 0x08); + u_char scratch, width; + + width = inb(ACCUM + iobase); + + scratch = inb(HA_TARG_SCRATCH + iobase + scsi_id); + + if (ahc->wdtrpending & (0x01 << scsi_id)) { + /* + * Don't send a WDTR back to the + * target, since we asked first. + */ + outb(HA_RETURN_1 + iobase, 0); + switch (width) { + case BUS_8_BIT: + scratch &= 0x7f; + break; + case BUS_16_BIT: + printf("%s: target %d using 16Bit " + "transfers\n", + ahc->sc_dev.dv_xname, scsi_id); + scratch &= 0xf8; + scratch |= 0x88; + break; + case BUS_32_BIT: + /* XXXX */ + } + } else { + /* + * Send our own WDTR in reply + */ + switch (width) { + case BUS_8_BIT: + scratch &= 0x7f; + break; + case BUS_32_BIT: + /* Negotiate 16_BITS */ + width = BUS_16_BIT; + case BUS_16_BIT: + printf("%s: target %d using 16Bit " + "transfers\n", + ahc->sc_dev.dv_xname, scsi_id); + scratch &= 0xf8; + scratch |= 0x88; + break; + } + outb(HA_RETURN_1 + iobase, + width | SEND_WDTR); + } + ahc->needwdtr &= ~(0x01 << scsi_id); + ahc->wdtrpending &= ~(0x01 << scsi_id); + + outb(HA_TARG_SCRATCH + iobase + scsi_id, scratch); + outb(SCSIRATE + iobase, scratch); + break; + } + case MSG_REJECT: { + /* + * What we care about here is if we had an + * outstanding SDTR or WDTR message for this + * target. If we did, this is a signal that + * the target is refusing negotiation. + */ + + u_char scsi_id = + (inb(SCSIID + iobase) >> 0x4) | + (inb(SBLKCTL + iobase) & 0x08); + u_char scratch; + u_short mask; + + scratch = inb(HA_TARG_SCRATCH + iobase + scsi_id); + + mask = (0x01 << scsi_id); + if (ahc->wdtrpending & mask) { + /* note 8bit xfers and clear flag */ + scratch &= 0x7f; + ahc->needwdtr &= ~mask; + ahc->wdtrpending &= ~mask; + printf("%s: target %d refusing " + "WIDE negotiation. Using " + "8bit transfers\n", + ahc->sc_dev.dv_xname, scsi_id); + } else if (ahc->sdtrpending & mask) { + /* note asynch xfers and clear flag */ + scratch &= 0xf0; + ahc->needsdtr &= ~mask; + ahc->sdtrpending &= ~mask; + printf("%s: target %d refusing " + "syncronous negotiation; using " + "asyncronous transfers\n", + ahc->sc_dev.dv_xname, scsi_id); + } else { + /* + * Otherwise, we ignore it. + */ +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWMISC) + printf("Message reject -- ignored\n"); +#endif + break; + } + + outb(HA_TARG_SCRATCH + iobase + scsi_id, scratch); + outb(SCSIRATE + iobase, scratch); + break; + } + case BAD_STATUS: { + int scb_index = inb(SCBPTR + iobase); + scb = ahc->scbarray[scb_index]; + + /* + * The sequencer will notify us when a command + * has an error that would be of interest to + * the kernel. This allows us to leave the sequencer + * running in the common case of command completes + * without error. + */ + + /* + * Set the default return value to 0 (don't + * send sense). The sense code with change + * this if needed and this reduces code + * duplication. + */ + outb(HA_RETURN_1 + iobase, 0); + if (!scb || scb->flags == SCB_FREE) { + printf("%s: ahcintr: referenced scb not " + "valid during seqint 0x%x scb(%d)\n", + ahc->sc_dev.dv_xname, intstat, scb_index); + goto clear; + } + + xs = scb->xs; + + ahc_getscb(iobase, scb); + +#ifdef AHC_DEBUG + if (xs->sc_link->target == DEBUGTARGET) + ahc_print_scb(scb); +#endif + xs->status = scb->target_status; + switch (scb->target_status) { + case SCSI_OK: + printf("%s: Interrupted for status of 0???\n", + ahc->sc_dev.dv_xname); + break; + case SCSI_CHECK: +#ifdef AHC_DEBUG + sc_print_addr(xs->sc_link); + printf("requests Check Status\n"); +#endif + + if (xs->error == XS_NOERROR && + scb->flags != SCB_CHKSENSE) { + u_char flags; + u_char head; + u_char tail; + struct ahc_dma_seg *sg = scb->ahc_dma; + struct scsi_sense *sc = &(scb->sense_cmd); + u_char control = scb->control; + u_char tcl = scb->target_channel_lun; +#ifdef AHC_DEBUG + sc_print_addr(xs->sc_link); + printf("Sending Sense\n"); +#endif + bzero(scb, SCB_DOWN_SIZE); + scb->flags = SCB_CHKSENSE; + scb->control = (control & SCB_TE); + sc->opcode = REQUEST_SENSE; + sc->byte2 = xs->sc_link->lun << 5; + sc->length = sizeof(struct scsi_sense_data); + sc->control = 0; + + sg->seg_addr = vtophys(&xs->sense); + sg->seg_len = sizeof(struct scsi_sense_data); + + scb->target_channel_lun = tcl; + scb->SG_segment_count = 1; + scb->SG_list_pointer = vtophys(sg); + scb->cmdpointer = vtophys(sc); + scb->cmdlen = sizeof(*sc); + + outb(SCBCNT + iobase, SCBAUTO); + outsb(SCBARRAY + iobase, scb, + SCB_DOWN_SIZE); + outb(SCBCNT + iobase, 0); + outb(SCBARRAY + iobase + 30, + SCB_LIST_NULL); + + /* + * Add this SCB to the "waiting for + * selection" list. + */ + head = inb(WAITING_SCBH + iobase); + tail = inb(WAITING_SCBT + iobase); + if (head & SCB_LIST_NULL) { + /* List was empty */ + head = scb->position; + tail = SCB_LIST_NULL; + } else if (tail & SCB_LIST_NULL) { + /* List had one element */ + tail = scb->position; + outb(SCBPTR + iobase, head); + outb(SCBARRAY + iobase + 30, + tail); + } else { + outb(SCBPTR + iobase, tail); + tail = scb->position; + outb(SCBARRAY + iobase + 30, + tail); + } + outb(WAITING_SCBH + iobase, head); + outb(WAITING_SCBT + iobase, tail); + outb(HA_RETURN_1 + iobase, SEND_SENSE); + break; + } + /* + * Have the sequencer do a normal command + * complete with either a "DRIVER_STUFFUP" + * error or whatever other error condition + * we already had. + */ + if (xs->error == XS_NOERROR) + xs->error = XS_DRIVER_STUFFUP; + break; + case SCSI_BUSY: + sc_print_addr(xs->sc_link); + printf("Target Busy\n"); + xs->error = XS_BUSY; + break; +#if 0 + case SCSI_QUEUE_FULL: + /* + * The upper level SCSI code will eventually + * handle this properly. + */ + sc_print_addr(xs->sc_link); + printf("Queue Full\n"); + xs->error = XS_BUSY; + break; +#endif + default: + sc_print_addr(xs->sc_link); + printf("unexpected targ_status: %x\n", + scb->target_status); + xs->error = XS_DRIVER_STUFFUP; + break; + } + break; + } + case RESIDUAL: { + int scb_index = inb(SCBPTR + iobase); + scb = ahc->scbarray[scb_index]; + + /* + * Don't clobber valid resid info with + * a resid coming from a check sense + * operation. + */ + if (scb->flags != SCB_CHKSENSE) + scb->xs->resid = + (inb(iobase + SCBARRAY + 17) << 16) | + (inb(iobase + SCBARRAY + 16) << 8) | + (inb(iobase + SCBARRAY + 15) << 0); +#ifdef AHC_MORE_DEBUG + printf("ahc: Handled Residual\n"); +#endif + break; + } + case ABORT_TAG: { + int scb_index = inb(SCBPTR + iobase); + scb = ahc->scbarray[scb_index]; + + /* + * We didn't recieve a valid tag back from + * the target on a reconnect. + */ + sc_print_addr(xs->sc_link); + printf("invalid tag recieved on channel %c " + "-- sending ABORT_TAG\n", + (xs->sc_link->quirks & 0x08) ? 'B' : 'A'); + scb->xs->error = XS_DRIVER_STUFFUP; + untimeout(ahc_timeout, scb); + ahc_done(ahc, scb); + break; + } + default: + printf("%s: seqint, intstat == 0x%x, scsisigi = 0x%x\n", + ahc->sc_dev.dv_xname, + intstat, inb(SCSISIGI + iobase)); + break; + } + + clear: + /* + * Clear the upper byte that holds SEQINT status + * codes and clear the SEQINT bit. + */ + outb(CLRINT + iobase, CLRSEQINT); + + /* + * The sequencer is paused immediately on + * a SEQINT, so we should restart it when + * we leave this section. + */ + UNPAUSE_SEQUENCER(ahc); + } + + if (intstat & SCSIINT) { + int scb_index = inb(SCBPTR + iobase); + scb = ahc->scbarray[scb_index]; + + status = inb(SSTAT1 + iobase); + + if (!scb || scb->flags == SCB_FREE) { + printf("%s: ahcintr - referenced scb not " + "valid during scsiint 0x%x scb(%d)\n", + ahc->sc_dev.dv_xname, status, scb_index); + outb(CLRSINT1 + iobase, status); + UNPAUSE_SEQUENCER(ahc); + outb(CLRINT + iobase, CLRSCSIINT); + scb = NULL; + goto cmdcomplete; + } + xs = scb->xs; + +#ifdef AHC_MORE_DEBUG + if ((xs->sc_link->target & 0xf) == DEBUGTARGET) + printf("Intr status %x\n", status); +#endif + + if (status & SELTO) { + u_char active; + u_char waiting; + u_char flags; + int active_port = HA_ACTIVE0 + iobase; + + outb(SCSISEQ + iobase, ENRSELI); + xs->error = XS_SELTIMEOUT; + /* + * Clear any pending messages for the timed out + * target, and mark the target as free + */ + flags = inb(HA_FLAGS + iobase); + outb(HA_FLAGS + iobase, flags & ~ACTIVE_MSG); + + if (scb->target_channel_lun & 0x88) + active_port++; + + active = inb(active_port) & + ~(0x01 << (xs->sc_link->target & 0x07)); + outb(active_port, active); + + outb(SCBARRAY + iobase, SCB_NEEDDMA); + + outb(CLRSINT1 + iobase, CLRSELTIMEO); + + outb(CLRINT + iobase, CLRSCSIINT); + + /* Shift the waiting for selection queue forward */ + waiting = inb(WAITING_SCBH + iobase); + outb(SCBPTR + iobase, waiting); + waiting = inb(SCBARRAY + iobase + 30); + outb(WAITING_SCBH + iobase, waiting); + + RESTART_SEQUENCER(ahc); + } + + if (status & SCSIPERR) { + sc_print_addr(xs->sc_link); + printf("parity error on channel %c\n", + (xs->sc_link->quirks & 0x08) ? 'B' : 'A'); + xs->error = XS_DRIVER_STUFFUP; + + outb(CLRSINT1 + iobase, CLRSCSIPERR); + UNPAUSE_SEQUENCER(ahc); + + outb(CLRINT + iobase, CLRSCSIINT); + scb = NULL; + } + if (status & BUSFREE) { +#if 0 + /* + * Has seen busfree since selection, i.e. + * a "spurious" selection. Shouldn't happen. + */ + printf("ahc: unexpected busfree\n"); +#if 0 + xs->error = XS_DRIVER_STUFFUP; + outb(CLRSINT1 + iobase, BUSFREE); /* CLRBUSFREE */ +#endif +#endif + } else { + printf("%s: Unknown SCSIINT. Status = 0x%x\n", + ahc->sc_dev.dv_xname, status); + outb(CLRSINT1 + iobase, status); + UNPAUSE_SEQUENCER(ahc); + outb(CLRINT + iobase, CLRSCSIINT); + scb = NULL; + } + if (scb != NULL) { + /* We want to process the command */ + untimeout(ahc_timeout, scb); + ahc_done(ahc, scb); + } + } + +cmdcomplete: + if (intstat & CMDCMPLT) { + int scb_index; + + do { + scb_index = inb(QOUTFIFO + iobase); + scb = ahc->scbarray[scb_index]; + + if (!scb || scb->flags == SCB_FREE) { + printf("%s: WARNING " + "no command for scb %d (cmdcmplt)\n" + "QOUTCNT == %d\n", + ahc->sc_dev.dv_xname, + scb_index, inb(QOUTCNT + iobase)); + outb(CLRINT + iobase, CLRCMDINT); + continue; + } + + /* XXXX Should do this before reading FIFO? */ + outb(CLRINT + iobase, CLRCMDINT); + untimeout(ahc_timeout, scb); + ahc_done(ahc, scb); + } while (inb(QOUTCNT + iobase)); + } + + return 1; +} + +/* + * We have a scb which has been processed by the + * adaptor, now we look to see how the operation + * went. + */ +void +ahc_done(ahc, scb) + struct ahc_softc *ahc; + struct ahc_scb *scb; +{ + struct scsi_xfer *xs = scb->xs; + +#ifdef AHC_MORE_DEBUG + if ((xs->sc_link->target & 0xf) == DEBUGTARGET) { + xs->sc_link->flags |= 0xf0; + SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n")); + printf("%x %x %x %x\n", + scb->flags, + scb->target_status, + xs->flags, + xs->error); + } +#endif + + /* + * Put the results of the operation + * into the xfer and call whoever started it + */ + if (xs->error == XS_NOERROR) { + if (scb->flags == SCB_ABORTED) + xs->error = XS_DRIVER_STUFFUP; + else if (scb->flags == SCB_CHKSENSE) + xs->error = XS_SENSE; + } + + xs->flags |= ITSDONE; + +#ifdef AHC_TAGENABLE + if (xs->cmd->opcode == 0x12 && xs->error == XS_NOERROR) { + struct scsi_inquiry_data *inq_data; + u_short mask = 0x01 << (xs->sc_link->target | + (scb->target_channel_lun & 0x08)); + /* + * Sneak a look at the results of the SCSI Inquiry + * command and see if we can do Tagged queing. XXX This + * should really be done by the higher level drivers. + */ + inq_data = (struct scsi_inquiry_data *)xs->data; + if (((inq_data->device & SID_TYPE) == 0) + && (inq_data->flags & SID_CmdQue) + && !(ahc->tagenable & mask)) { + /* + * Disk type device and can tag + */ + sc_print_addr(xs->sc_link); + printf("Tagged Queuing Device\n"); + ahc->tagenable |= mask; +#ifdef QUEUE_FULL_SUPPORTED + xs->sc_link->openings += 2; */ +#endif + } + } +#endif + + ahc_free_scb(ahc, scb, xs->flags); + scsi_done(xs); +} + +/* + * Start the board, ready for normal operation + */ +/* XXXX clean */ +int +ahc_init(ahc) + struct ahc_softc *ahc; +{ + int iobase = ahc->sc_iobase; + u_char scsi_conf, sblkctl, i; + int intdef, max_targ = 16, wait; + + /* + * Assume we have a board at this stage + * Find out the configured interupt and the card type. + */ + +#ifdef AHC_DEBUG + printf("%s: scb %d bytes; SCB_SIZE %d bytes, ahc_dma %d bytes\n", + ahc->sc_dev.dv_xname, sizeof(struct ahc_scb), SCB_DOWN_SIZE, + sizeof(struct ahc_dma_seg)); +#endif /* AHC_DEBUG */ + /*printf("%s: reading board settings\n", ahc->sc_dev.dv_xname);/**/ + + /* Save the IRQ type before we do a chip reset */ + + ahc->unpause = (inb(HCNTRL + iobase) & IRQMS) | INTEN; + ahc->pause = ahc->unpause | PAUSE; + outb(HCNTRL + iobase, CHIPRST | ahc->pause); + + /* + * Ensure that the reset has finished + */ + wait = 1000; + while (wait--) { + delay(1000); + if (!(inb(HCNTRL + iobase) & CHIPRST)) + break; + } + if (wait == 0) { + printf("\n%s: WARNING - Failed chip reset! " + "Trying to initialize anyway.\n", ahc->sc_dev.dv_xname); + /* Forcibly clear CHIPRST */ + outb(HCNTRL + iobase, ahc->pause); + } + + switch (ahc->type) { + case AHC_274: + printf(": 274x ", ahc->sc_dev.dv_xname); + ahc->maxscbs = 0x4; + break; + case AHC_284: + printf(": 284x ", ahc->sc_dev.dv_xname); + ahc->maxscbs = 0x4; + break; + case AHC_AIC7870: + case AHC_294: + if (ahc->type == AHC_AIC7870) + printf(": aic7870 ", ahc->sc_dev.dv_xname); + else + printf(": 294x ", ahc->sc_dev.dv_xname); + ahc->maxscbs = 0x10; + #define DFTHRESH 3 + outb(DSPCISTATUS + iobase, DFTHRESH << 6); + /* + * XXX Hard coded SCSI ID until we can read it from the + * SEEPROM or NVRAM. + */ + outb(HA_SCSICONF + iobase, 0x07 | (DFTHRESH << 6)); + /* In case we are a wide card */ + outb(HA_SCSICONF + 1 + iobase, 0x07); + break; + } + + /* Determine channel configuration and who we are on the scsi bus. */ + switch ((sblkctl = inb(SBLKCTL + iobase) & 0x0f)) { + case 0: + ahc->ahc_scsi_dev = (inb(HA_SCSICONF + iobase) & HSCSIID); + printf("Single Channel, SCSI Id=%d, ", ahc->ahc_scsi_dev); + outb(HA_FLAGS + iobase, SINGLE_BUS); + break; + case 2: + ahc->ahc_scsi_dev = (inb(HA_SCSICONF + 1 + iobase) & HWSCSIID); + printf("Wide Channel, SCSI Id=%d, ", ahc->ahc_scsi_dev); + ahc->type |= AHC_WIDE; + outb(HA_FLAGS + iobase, WIDE_BUS); + break; + case 8: + ahc->ahc_scsi_dev = (inb(HA_SCSICONF + iobase) & HSCSIID); + ahc->ahc_scsi_dev_b = (inb(HA_SCSICONF + 1 + iobase) & HSCSIID); + printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ", + ahc->ahc_scsi_dev, ahc->ahc_scsi_dev_b); + ahc->type |= AHC_TWIN; + outb(HA_FLAGS + iobase, TWIN_BUS); + break; + default: + printf(" Unsupported adapter type. %x Ignoring\n",sblkctl); + return(-1); + } + + /* + * Take the bus led out of diagnostic mode + */ + outb(SBLKCTL + iobase, sblkctl); + + /* + * Number of SCBs that will be used. Rev E aic7770s and + * aic7870s have 16. The rest have 4. + */ + if (!(ahc->type & AHC_AIC7870)) { + /* + * See if we have a Rev E or higher + * aic7770. Anything below a Rev E will + * have a R/O autoflush disable configuration + * bit. + */ + u_char sblkctl_orig; + sblkctl_orig = inb(SBLKCTL + iobase); + sblkctl = sblkctl_orig ^ AUTOFLUSHDIS; + outb(SBLKCTL + iobase, sblkctl); + sblkctl = inb(SBLKCTL + iobase); + if (sblkctl != sblkctl_orig) { + printf("aic7770 >= Rev E, "); + /* + * Ensure autoflush is enabled + */ + sblkctl &= ~AUTOFLUSHDIS; + outb(SBLKCTL + iobase, sblkctl); + } else + printf("aic7770 <= Rev C, "); + } else + printf("aic7870, "); + printf("%d SCBs\n", ahc->maxscbs); + + if (ahc->pause & IRQMS) + printf("%s: Using Level Sensitive Interrupts\n", + ahc->sc_dev.dv_xname); + else + printf("%s: Using Edge Triggered Interrupts\n", + ahc->sc_dev.dv_xname); + + if (!(ahc->type & AHC_AIC7870)) { + /* + * The 294x cards are PCI, so we get their interrupt from the + * PCI BIOS. + */ + + intdef = inb(INTDEF + iobase); + switch (intdef & 0xf) { + case 9: + ahc->sc_irq = 9; + break; + case 10: + ahc->sc_irq = 10; + break; + case 11: + ahc->sc_irq = 11; + break; + case 12: + ahc->sc_irq = 12; + break; + case 14: + ahc->sc_irq = 14; + break; + case 15: + ahc->sc_irq = 15; + break; + default: + printf("illegal irq setting\n"); + return (EIO); + } + } + + /* Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels */ + if (ahc->type & AHC_TWIN) { + /* + * The device is gated to channel B after a chip reset, + * so set those values first + */ + outb(SCSIID + iobase, ahc->ahc_scsi_dev_b); + scsi_conf = inb(HA_SCSICONF + 1 + iobase) & (ENSPCHK|STIMESEL); + outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN); + outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIPERR); + /* Select Channel A */ + outb(SBLKCTL + iobase, 0); + } + outb(SCSIID + iobase, ahc->ahc_scsi_dev); + scsi_conf = inb(HA_SCSICONF + iobase) & (ENSPCHK|STIMESEL); + outb(SXFRCTL1 + iobase, scsi_conf|ENSTIMER|ACTNEGEN|STPWEN); + outb(SIMODE1 + iobase, ENSELTIMO|ENSCSIPERR); + + /* + * Look at the information that board initialization or + * the board bios has left us. In the lower four bits of each + * target's scratch space any value other than 0 indicates + * that we should initiate syncronous transfers. If it's zero, + * the user or the BIOS has decided to disable syncronous + * negotiation to that target so we don't activate the needsdr + * flag. + */ + ahc->needsdtr_orig = 0; + ahc->needwdtr_orig = 0; + if (!(ahc->type & AHC_WIDE)) + max_targ = 8; + + for (i = 0; i < max_targ; i++) { + u_char target_settings = inb(HA_TARG_SCRATCH + i + iobase); +#if 0 /* XXXX */ + target_settings |= 0x8f; +#endif + if (target_settings & 0x0f) { + ahc->needsdtr_orig |= (0x01 << i); + /* Default to a asyncronous transfers (0 offset) */ + target_settings &= 0xf0; + } + if (target_settings & 0x80) { + ahc->needwdtr_orig |= (0x01 << i); + /* + * We'll set the Wide flag when we + * are successful with Wide negotiation, + * so turn it off for now so we aren't + * confused. + */ + target_settings &= 0x7f; + } + outb(HA_TARG_SCRATCH + i + iobase, target_settings); + } + /* + * If we are not a WIDE device, forget WDTR. This + * makes the driver work on some cards that don't + * leave these fields cleared when the BIOS is not + * installed. + */ + if (!(ahc->type & AHC_WIDE)) + ahc->needwdtr_orig = 0; + ahc->needsdtr = ahc->needsdtr_orig; + ahc->needwdtr = ahc->needwdtr_orig; + ahc->sdtrpending = 0; + ahc->wdtrpending = 0; + ahc->tagenable = 0; + + /* + * Clear the control byte for every SCB so that the sequencer + * doesn't get confused and think that one of them is valid + */ + for (i = 0; i < ahc->maxscbs; i++) { + outb(SCBPTR + iobase, i); + outb(SCBARRAY + iobase, 0); + } + +#ifdef AHC_DEBUG + printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n", ahc->needsdtr, + ahc->needwdtr); +#endif + + /* + * Set the number of availible SCBs + */ + outb(HA_SCBCOUNT + iobase, ahc->maxscbs); + + /* We don't have any busy targets right now */ + outb(HA_ACTIVE0 + iobase, 0); + outb(HA_ACTIVE1 + iobase, 0); + + /* We don't have any waiting selections */ + outb(WAITING_SCBH + iobase, SCB_LIST_NULL); + outb(WAITING_SCBT + iobase, SCB_LIST_NULL); + /* + * Load the Sequencer program and Enable the adapter. + * Place the aic7770 in fastmode which makes a big + * difference when doing many small block transfers. + */ + + printf("%s: Downloading Sequencer Program...", ahc->sc_dev.dv_xname); + ahc_loadseq(iobase); + printf("Done\n"); + + if (!(ahc->type & AHC_AIC7870)) + outb(BCTL + iobase, ENABLE); + + /* Reset the bus */ + outb(SCSISEQ + iobase, SCSIRSTO); + delay(1000); + outb(SCSISEQ + iobase, 0); + + RESTART_SEQUENCER(ahc); + + return (0); +} + +void +ahcminphys(bp) + struct buf *bp; +{ + + if (bp->b_bcount > ((AHC_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((AHC_NSEG - 1) << PGSHIFT); + minphys(bp); +} + +/* + * start a scsi operation given the command and + * the data address, target, and lun all of which + * are stored in the scsi_xfer struct + */ +int +ahc_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *sc_link = xs->sc_link; + struct ahc_softc *ahc = sc_link->adapter_softc; + struct ahc_scb *scb; + struct ahc_dma_seg *sg; + int seg; /* scatter gather seg being worked on */ + u_long thiskv, thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + int s; + u_short mask = (0x01 << (sc_link->target | (sc_link->quirks & 0x08))); + +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + printf("ahc ahc_scsi_cmd for %x\n", sc_link->target); + sc_link->flags = 0xf0; + SC_DEBUG(sc_link, SDEV_DB2, ("ahc_scsi_cmd\n")); + } +#endif + + /* + * get a scb to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ + flags = xs->flags; + if ((flags & (ITSDONE|INUSE)) != INUSE) { + printf("%s: done or not in use?\n", ahc->sc_dev.dv_xname); + xs->flags &= ~ITSDONE; + xs->flags |= INUSE; + } + if ((scb = ahc_get_scb(ahc, flags)) == NULL) { + xs->error = XS_DRIVER_STUFFUP; + return (TRY_AGAIN_LATER); + } + scb->xs = xs; + +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + sc_link->flags = 0xf0; + SC_DEBUG(sc_link, SDEV_DB3, ("start scb(%x)\n", scb)); + } +#endif + + if (flags & SCSI_RESET) { + /* XXX: Needs Implementation */ + printf("ahc: SCSI_RESET called.\n"); + } + + /* + * Put all the arguments for the xfer in the scb + */ + scb->control = 0; + if (ahc->tagenable & mask) + scb->control |= SCB_TE; + if ((ahc->needwdtr & mask) && !(ahc->wdtrpending & mask)) { + scb->control |= SCB_NEEDWDTR; + ahc->wdtrpending |= mask; + } + if ((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask)) { + scb->control |= SCB_NEEDSDTR; + ahc->sdtrpending |= mask; + } + scb->target_channel_lun = ((sc_link->target << 4) & 0xF0) | + (sc_link->quirks & 0x08) | (sc_link->lun & 0x07); + scb->cmdlen = xs->cmdlen; + scb->cmdpointer = vtophys(xs->cmd); + + xs->resid = 0; + if (xs->datalen) { + scb->SG_list_pointer = vtophys(scb->ahc_dma); + sg = scb->ahc_dma; + seg = 0; + { + /* + * Set up the scatter gather block + */ +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + sc_link->flags = 0xf0; + SC_DEBUG(sc_link, SDEV_DB4, + ("%ld @%x:- ", xs->datalen, xs->data)); + } +#endif + datalen = xs->datalen; + thiskv = (long) xs->data; + thisphys = vtophys(thiskv); + + while (datalen && seg < AHC_NSEG) { + bytes_this_seg = 0; + + /* put in the base address */ + sg->seg_addr = thisphys; + +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + sc_link->flags = 0xf0; + SC_DEBUGN(sc_link, SDEV_DB4, ("0x%lx", + thisphys)); + } +#endif + + /* do it at least once */ + nextphys = thisphys; + while (datalen && thisphys == nextphys) { + /* + * This page is contiguous (physically) + * with the the last, just extend the + * length + */ + /* how far to the end of the page */ + nextphys = (thisphys & ~PGOFSET) + NBPG; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page, + datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + + /* get more ready for the next page */ + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) + thisphys = vtophys(thiskv); + } + /* + * next page isn't contiguous, finish the seg + */ +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + sc_link->flags = 0xf0; + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x)", + bytes_this_seg)); + } +#endif + sg->seg_len = bytes_this_seg; + sg++; + seg++; + } + } + /*end of iov/kv decision */ + scb->SG_segment_count = seg; +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + sc_link->flags = 0xf0; + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + } +#endif + if (datalen) { + /* + * there's still data, must have run out of segs! + */ + printf("%s: ahc_scsi_cmd: more than %d dma segs\n", + ahc->sc_dev.dv_xname, AHC_NSEG); + xs->error = XS_DRIVER_STUFFUP; + ahc_free_scb(ahc, scb, flags); + return (COMPLETE); + } + } else { + scb->SG_list_pointer = (physaddr)0; + scb->SG_segment_count = 0; + } + +#ifdef AHC_DEBUG + if (sc_link->target == DEBUGTARGET) + ahc_print_scb(scb); +#endif + + s = splbio(); + + ahc_send_scb(ahc, scb); + + /* + * Usually return SUCCESSFULLY QUEUED + */ + if ((flags & SCSI_POLL) == 0) { + timeout(ahc_timeout, scb, (xs->timeout * hz) / 1000); + splx(s); +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + sc_link->flags = 0xf0; + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); + } +#endif + return (SUCCESSFULLY_QUEUED); + } + + splx(s); + + /* + * If we can't use interrupts, poll on completion + */ +#ifdef AHC_MORE_DEBUG + if ((sc_link->target & 0xf) == DEBUGTARGET) { + sc_link->flags = 0xf0; + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_wait\n")); + } +#endif + if (ahc_poll(ahc, xs, xs->timeout)) { + ahc_timeout(scb); + if (ahc_poll(ahc, xs, 2000)) + ahc_timeout(scb); + } + return (COMPLETE); +} + + +/* + * A scb (and hence an scb entry on the board is put onto the + * free list. + */ +void +ahc_free_scb(ahc, scb, flags) + struct ahc_softc *ahc; + struct ahc_scb *scb; + int flags; +{ + int s; + + s = splbio(); + + scb->flags = SCB_FREE; + TAILQ_INSERT_TAIL(&ahc->free_scb, scb, chain); +#ifdef AHC_DEBUG + ahc->activescbs--; +#endif + + /* + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. + */ + if (scb->chain.tqe_next == 0) + wakeup(&ahc->free_scb); + + splx(s); +} + +/* XXXX check */ +static inline void +ahc_init_scb(ahc, scb) + struct ahc_softc *ahc; + struct ahc_scb *scb; +{ + int iobase = ahc->sc_iobase; + u_char scb_index; + + bzero(scb, sizeof(struct ahc_scb)); + scb->position = ahc->numscbs; + /* + * Place in the scbarray + * Never is removed. Position + * in ahc->scbarray is the scbarray + * position on the board we will + * load it into. + */ + ahc->scbarray[scb->position] = scb; + + /* + * Initialize the host memory location + * of this SCB down on the board and + * flag that it should be DMA's before + * reference. Also set its psuedo + * next pointer (for use in the psuedo + * list of SCBs waiting for selection) + * to SCB_LIST_NULL. + */ + scb->control = SCB_NEEDDMA; + scb->host_scb = vtophys(scb); + scb->next_waiting = SCB_LIST_NULL; + PAUSE_SEQUENCER(ahc); + scb_index = inb(SCBPTR + iobase); + outb(SCBPTR + iobase, scb->position); + outb(SCBCNT + iobase, SCBAUTO); + outsb(SCBARRAY + iobase, scb, 31); + outb(SCBCNT + iobase, 0); + outb(SCBPTR + iobase, scb_index); + UNPAUSE_SEQUENCER(ahc); + scb->control = 0; +} + +static inline void +ahc_reset_scb(ahc, scb) + struct ahc_softc *ahc; + struct ahc_scb *scb; +{ + + bzero(scb, SCB_BZERO_SIZE); +} + +/* + * Get a free scb + * + * If there are none, see if we can allocate a new one. + */ +struct ahc_scb * +ahc_get_scb(ahc, flags) + struct ahc_softc *ahc; + int flags; +{ + struct ahc_scb *scb; + int s; + + s = splbio(); + + /* + * If we can and have to, sleep waiting for one to come free + * but only if we can't allocate a new one. + */ + for (;;) { + scb = ahc->free_scb.tqh_first; + if (scb) { + TAILQ_REMOVE(&ahc->free_scb, scb, chain); + break; + } + if (ahc->numscbs < ahc->maxscbs) { + if (scb = (struct ahc_scb *) malloc(sizeof(struct ahc_scb), + M_TEMP, M_NOWAIT)) { + ahc_init_scb(ahc, scb); + ahc->numscbs++; + } else { + printf("%s: can't malloc scb\n", + ahc->sc_dev.dv_xname); + goto out; + } + break; + } + if ((flags & SCSI_NOSLEEP) != 0) + goto out; + tsleep(&ahc->free_scb, PRIBIO, "ahcscb", 0); + } + + ahc_reset_scb(ahc, scb); + scb->flags = SCB_ACTIVE; +#ifdef AHC_DEBUG + ahc->activescbs++; + if (ahc->activescbs == ahc->maxscbs) + printf("%s: Max SCBs active\n", ahc->sc_dev.dv_xname); +#endif + +out: + splx(s); + return (scb); +} + +/* XXXX check */ +void +ahc_loadseq(iobase) + int iobase; +{ + static u_char seqprog[] = { +# include "aic7xxx_seq.h" + }; + + outb(SEQCTL + iobase, PERRORDIS|SEQRESET|LOADRAM); + outsb(SEQRAM + iobase, seqprog, sizeof(seqprog)); + outb(SEQCTL + iobase, FASTMODE|SEQRESET); +} + +/* + * Function to poll for command completion when in poll mode + */ +int +ahc_poll(ahc, xs, count) + struct ahc_softc *ahc; + struct scsi_xfer *xs; + int count; +{ /* in msec */ + int iobase = ahc->sc_iobase; + int stport = INTSTAT + iobase; + + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + if (inb(stport) & INT_PEND) + ahcintr(ahc); + if (xs->flags & ITSDONE) + return 0; + delay(1000); + count--; + } + return 1; +} + +/* XXXX check */ +void +ahc_abort_scb(ahc, scb) + struct ahc_softc *ahc; + struct ahc_scb *scb; +{ + int iobase = ahc->sc_iobase; + int found = 0; + int scb_index; + u_char flags; + u_char scb_control; + + PAUSE_SEQUENCER(ahc); + /* + * Case 1: In the QINFIFO + */ + { + int saved_queue[AHC_SCB_MAX]; + int i; + int queued = inb(QINCNT + iobase); + + for (i = 0; i < (queued - found); i++) { + saved_queue[i] = inb(QINFIFO + iobase); + if (saved_queue[i] == scb->position) { + i--; + found = 1; + } + } + /* Re-insert entries back into the queue */ + for (queued = 0; queued < i; queued++) + outb(QINFIFO + iobase, saved_queue[queued]); + + if (found) + goto done; + } + + scb_index = inb(SCBPTR + iobase); + /* + * Case 2: Not the active command + */ + if (scb_index != scb->position) { + /* + * Select the SCB we want to abort + * and turn off the disconnected bit. + * the driver will then abort the command + * and notify us of the abort. + */ + outb(SCBPTR + iobase, scb->position); + scb_control = inb(SCBARRAY + iobase); + scb_control &= ~SCB_DIS; + outb(SCBARRAY + iobase, scb_control); + outb(SCBPTR + iobase, scb_index); + goto done; + } + scb_control = inb(SCBARRAY + iobase); + if (scb_control & SCB_DIS) { + scb_control &= ~SCB_DIS; + outb(SCBARRAY + iobase, scb_control); + goto done; + } + /* + * Case 3: Currently active command + */ + if ((flags = inb(HA_FLAGS + iobase)) & ACTIVE_MSG) { + /* + * If there's a message in progress, + * reset the bus and have all devices renegotiate. + */ + if (scb->target_channel_lun & 0x08) { + ahc->needsdtr |= (ahc->needsdtr_orig & 0xff00); + ahc->sdtrpending &= 0x00ff; + outb(HA_ACTIVE1, 0); + } else if (ahc->type & AHC_WIDE) { + ahc->needsdtr = ahc->needsdtr_orig; + ahc->needwdtr = ahc->needwdtr_orig; + ahc->sdtrpending = 0; + ahc->wdtrpending = 0; + outb(HA_ACTIVE0, 0); + outb(HA_ACTIVE1, 0); + } else { + ahc->needsdtr |= (ahc->needsdtr_orig & 0x00ff); + ahc->sdtrpending &= 0xff00; + outb(HA_ACTIVE0, 0); + } + + /* Reset the bus */ + outb(SCSISEQ + iobase, SCSIRSTO); + delay(1000); + outb(SCSISEQ + iobase, 0); + goto done; + } + + /* + * Otherwise, set up an abort message and have the sequencer + * clean up + */ + outb(HA_FLAGS + iobase, flags | ACTIVE_MSG); + outb(HA_MSG_LEN + iobase, 1); + outb(HA_MSG_START + iobase, MSG_ABORT); + + outb(SCSISIGO + iobase, inb(HA_SIGSTATE + iobase) | 0x10); + +done: + scb->flags = SCB_ABORTED; + UNPAUSE_SEQUENCER(ahc); + ahc_done(ahc, scb); + return; +} + +void +ahc_timeout(arg) + void *arg; +{ + struct ahc_scb *scb = arg; + struct scsi_xfer *xs = scb->xs; + struct scsi_link *sc_link = xs->sc_link; + struct ahc_softc *ahc = sc_link->adapter_softc; + int s; + + sc_print_addr(sc_link); + printf("timed out"); + + s = splbio(); + +#ifdef SCSIDEBUG + show_scsi_cmd(scb->xs); +#endif +#ifdef AHC_DEBUG + if (ahc_debug & AHC_SHOWSCBS) + ahc_print_active_scb(ahc); +#endif /*AHC_DEBUG */ + + if (scb->flags & SCB_IMMED) { + printf("\n"); + scb->xs->retries = 0; /* I MEAN IT ! */ + scb->flags |= SCB_IMMED_FAIL; + ahc_done(ahc, scb); + splx(s); + return; + } + + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (scb->flags == SCB_ABORTED) { + /* abort timed out */ + printf(" AGAIN\n"); + scb->xs->retries = 0; /* I MEAN IT ! */ + ahc_done(ahc, scb); + } else { + /* abort the operation that has timed out */ + printf("\n"); + scb->xs->error = XS_TIMEOUT; + scb->flags = SCB_ABORTED; + ahc_abort_scb(ahc, scb); + /* 2 secs for the abort */ + if ((xs->flags & SCSI_POLL) == 0) + timeout(ahc_timeout, scb, 2 * hz); + } + + splx(s); +} diff --git a/sys/dev/ic/aic7xxxvar.h b/sys/dev/ic/aic7xxxvar.h new file mode 100644 index 00000000000..1ba2546a0a6 --- /dev/null +++ b/sys/dev/ic/aic7xxxvar.h @@ -0,0 +1,168 @@ +/* + * Interface to the generic driver for the aic7xxx based adaptec + * SCSI controllers. This is used to implement product specific + * probe and attach routines. + * + * Copyright (c) 1994, 1995 Justin T. Gibbs. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Absolutely no warranty of function or purpose is made by the author + * Justin T. Gibbs. + * 4. Modifications may be freely made to this file if the above conditions + * are met. + * + * $Id: aic7xxxvar.h,v 1.1 1995/10/18 08:52:30 deraadt Exp $ + */ + +#ifndef _AIC7XXX_H_ +#define _AIC7XXX_H_ + +/*#include "ahc.h" /* for NAHC from config */ + +#define AHC_NSEG 256 /* number of dma segments supported */ + +#define AHC_SCB_MAX 16 /* + * Up to 16 SCBs on some types of aic7xxx based + * boards. The aic7770 family only have 4 + */ + +/* #define AHCDEBUG */ + +typedef u_long physaddr; +typedef u_long physlen; + +struct ahc_dma_seg { + physaddr seg_addr; + physlen seg_len; +}; + +typedef u_char ahc_type; +#define AHC_NONE 0x00 +#define AHC_WIDE 0x02 /* Wide Channel */ +#define AHC_TWIN 0x08 /* Twin Channel */ +#define AHC_274 0x10 /* EISA Based Controller */ +#define AHC_284 0x20 /* VL/ISA Based Controller */ +#define AHC_AIC7870 0x40 /* PCI Based Controller */ +#define AHC_294 0xc0 /* PCI Based Controller */ + +/* + * The driver keeps up to MAX_SCB scb structures per card in memory. Only the + * first 26 bytes of the structure are valid for the hardware, the rest used + * for driver level bookeeping. The "__attribute ((packed))" tags ensure that + * gcc does not attempt to pad the long ints in the structure to word + * boundaries since the first 26 bytes of this structure must have the correct + * offsets for the hardware to find them. The driver is further optimized + * so that we only have to download the first 19 bytes since as long + * as we always use S/G, the last fields should be zero anyway. + */ +#if __GNUC__ >= 2 +#if __GNUC_MINOR__ <5 +#pragma pack(1) +#endif +#endif + +struct ahc_scb { +/* ------------ Begin hardware supported fields ---------------- */ +/*1*/ u_char control; +#define SCB_NEEDWDTR 0x80 /* Initiate Wide Negotiation */ +#define SCB_NEEDSDTR 0x40 /* Initiate Sync Negotiation */ +#define SCB_TE 0x20 /* Tag enable */ +#define SCB_NEEDDMA 0x08 /* Refresh SCB from host ram */ +#define SCB_DIS 0x04 +#define SCB_TAG_TYPE 0x3 +#define SIMPLE_QUEUE 0x0 +#define HEAD_QUEUE 0x1 +#define OR_QUEUE 0x2 +/*2*/ u_char target_channel_lun; /* 4/1/3 bits */ +/*3*/ u_char SG_segment_count; +/*7*/ physaddr SG_list_pointer __attribute__ ((packed)); +/*11*/ physaddr cmdpointer __attribute__ ((packed)); +/*12*/ u_char cmdlen; +/*14*/ u_char RESERVED[2]; /* must be zero */ +/*15*/ u_char target_status; +/*18*/ u_char residual_data_count[3]; +/*19*/ u_char residual_SG_segment_count; +#define SCB_DOWN_SIZE 19 /* amount to actually download */ +#define SCB_BZERO_SIZE 19 /* + * amount we need to clear between + * commands + */ +/*23*/ physaddr data __attribute__ ((packed)); +/*26*/ u_char datalen[3]; +#define SCB_UP_SIZE 26 /* + * amount we need to upload to perform + * a request sense. + */ +/*30*/ physaddr host_scb __attribute__ ((packed)); +/*31*/ u_char next_waiting; /* Used to thread SCBs awaiting + * selection + */ +#define SCB_LIST_NULL 0x10 /* SCB list equivelent to NULL */ +#if 0 + /* + * No real point in transferring this to the + * SCB registers. + */ + unsigned char RESERVED[1]; +#endif + /*-----------------end of hardware supported fields----------------*/ + TAILQ_ENTRY(ahc_scb) chain; + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; +#define SCB_FREE 0 +#define SCB_ACTIVE 1 +#define SCB_ABORTED 2 +#define SCB_CHKSENSE 3 +#define SCB_IMMED 4 +#define SCB_IMMED_FAIL 8 + int position; /* Position in scbarray */ + struct ahc_dma_seg ahc_dma[AHC_NSEG] __attribute__ ((packed)); + struct scsi_sense sense_cmd; /* SCSI command block */ +}; + +#if __GNUC__ >= 2 +#if __GNUC_MINOR__ <5 +#pragma pack(4) +#endif +#endif + +struct ahc_softc { + struct device sc_dev; + void *sc_ih; + + int sc_iobase; + int sc_irq; + + ahc_type type; + + struct ahc_scb *scbarray[AHC_SCB_MAX]; /* Mirror boards scbarray */ + TAILQ_HEAD(, ahc_scb) free_scb; + int ahc_scsi_dev; /* our scsi id */ + int ahc_scsi_dev_b; /* B channel scsi id */ + struct ahc_scb *immed_ecb; /* an outstanding immediete command */ + struct scsi_link sc_link; + struct scsi_link sc_link_b; /* Second bus for Twin channel cards */ + u_short needsdtr_orig; /* Targets we initiate sync neg with */ + u_short needwdtr_orig; /* Targets we initiate wide neg with */ + u_short needsdtr; /* Current list of negotiated targets */ + u_short needwdtr; /* Current list of negotiated targets */ + u_short sdtrpending; /* Pending SDTR to these targets */ + u_short wdtrpending; /* Pending WDTR to these targets */ + u_short tagenable; /* Targets that can handle tagqueing */ + int numscbs; + int activescbs; + u_char maxscbs; + u_char unpause; + u_char pause; +}; + +#endif /* _AIC7XXX_H_ */ diff --git a/sys/dev/ic/am7930reg.h b/sys/dev/ic/am7930reg.h new file mode 100644 index 00000000000..192dffe0c6d --- /dev/null +++ b/sys/dev/ic/am7930reg.h @@ -0,0 +1,153 @@ +/* $NetBSD: am7930reg.h,v 1.1 1995/04/24 19:17:17 pk Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bsd_audioreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Bit encodings for chip commands from "Microprocessor Access Guide for + * Indirect Registers", p.19 Am79C30A/32A Advanced Micro Devices spec + * sheet (preliminary). + * + * Indirect register numbers (the value written into cr to select a given + * chip registers) have the form AMDR_*. Register fields look like AMD_*. + */ + +struct amd7930 { + u_char cr; /* command register (wo) */ +#define ir cr /* interrupt register (ro) */ + u_char dr; /* data register (rw) */ + u_char dsr1; /* D-channel status register 1 (ro) */ + u_char der; /* D-channel error register (ro) */ + u_char dctb; /* D-channel transmit register (wo) */ +#define dcrb dctb /* D-channel receive register (ro) */ + u_char bbtb; /* Bb-channel transmit register (wo) */ +#define bbrb bbtb /* Bb-channel receive register (ro) */ + u_char bctb; /* Bc-channel transmit register (wo) */ +#define bcrb bctb /* Bc-channel receive register (ro) */ + u_char dsr2; /* D-channel status register 2 (ro) */ +}; + +#define AMDR_INIT 0x21 +#define AMD_INIT_PMS_IDLE 0x00 +#define AMD_INIT_PMS_ACTIVE 0x01 +#define AMD_INIT_PMS_ACTIVE_DATA 0x02 +#define AMD_INIT_INT_DISABLE (0x01 << 2) +#define AMD_INIT_CDS_DIV2 (0x00 << 3) +#define AMD_INIT_CDS_DIV1 (0x01 << 3) +#define AMD_INIT_CDS_DIV4 (0x02 << 3) +#define AMD_INIT_AS_RX (0x01 << 6) +#define AMD_INIT_AS_TX (0x01 << 7) + +#define AMDR_LIU_LSR 0xa1 +#define AMDR_LIU_LPR 0xa2 +#define AMDR_LIU_LMR1 0xa3 +#define AMDR_LIU_LMR2 0xa4 +#define AMDR_LIU_2_4 0xa5 +#define AMDR_LIU_MF 0xa6 +#define AMDR_LIU_MFSB 0xa7 +#define AMDR_LIU_MFQB 0xa8 + +#define AMDR_MUX_MCR1 0x41 +#define AMDR_MUX_MCR2 0x42 +#define AMDR_MUX_MCR3 0x43 +#define AMD_MCRCHAN_NC 0x00 +#define AMD_MCRCHAN_B1 0x01 +#define AMD_MCRCHAN_B2 0x02 +#define AMD_MCRCHAN_BA 0x03 +#define AMD_MCRCHAN_BB 0x04 +#define AMD_MCRCHAN_BC 0x05 +#define AMD_MCRCHAN_BD 0x06 +#define AMD_MCRCHAN_BE 0x07 +#define AMD_MCRCHAN_BF 0x08 +#define AMDR_MUX_MCR4 0x44 +#define AMD_MCR4_INT_ENABLE (1 << 3) +#define AMD_MCR4_SWAPBB (1 << 4) +#define AMD_MCR4_SWAPBC (1 << 5) + +#define AMDR_MUX_1_4 0x45 + +#define AMDR_MAP_X 0x61 +#define AMDR_MAP_R 0x62 +#define AMDR_MAP_GX 0x63 +#define AMDR_MAP_GR 0x64 +#define AMDR_MAP_GER 0x65 +#define AMDR_MAP_STG 0x66 +#define AMDR_MAP_FTGR 0x67 +#define AMDR_MAP_ATGR 0x68 +#define AMDR_MAP_MMR1 0x69 +#define AMD_MMR1_ALAW 0x01 +#define AMD_MMR1_GX 0x02 +#define AMD_MMR1_GR 0x04 +#define AMD_MMR1_GER 0x08 +#define AMD_MMR1_X 0x10 +#define AMD_MMR1_R 0x20 +#define AMD_MMR1_STG 0x40 +#define AMD_MMR1_LOOP 0x80 +#define AMDR_MAP_MMR2 0x6a +#define AMD_MMR2_AINB 0x01 +#define AMD_MMR2_LS 0x02 +#define AMD_MMR2_DTMF 0x04 +#define AMD_MMR2_GEN 0x08 +#define AMD_MMR2_RNG 0x10 +#define AMD_MMR2_DIS_HPF 0x20 +#define AMD_MMR2_DIS_AZ 0x40 +#define AMDR_MAP_1_10 0x6b + +#define AMDR_DLC_FRAR123 0x81 +#define AMDR_DLC_SRAR123 0x82 +#define AMDR_DLC_TAR 0x83 +#define AMDR_DLC_DRLR 0x84 +#define AMDR_DLC_DTCR 0x85 +#define AMDR_DLC_DMR1 0x86 +#define AMDR_DLC_DMR2 0x87 +#define AMDR_DLC_1_7 0x88 +#define AMDR_DLC_DRCR 0x89 +#define AMDR_DLC_RNGR1 0x8a +#define AMDR_DLC_RNGR2 0x8b +#define AMDR_DLC_FRAR4 0x8c +#define AMDR_DLC_SRAR4 0x8d +#define AMDR_DLC_DMR3 0x8e +#define AMDR_DLC_DMR4 0x8f +#define AMDR_DLC_12_15 0x90 +#define AMDR_DLC_ASR 0x91 diff --git a/sys/dev/ic/am7990.c b/sys/dev/ic/am7990.c new file mode 100644 index 00000000000..d1a8ef3d68d --- /dev/null +++ b/sys/dev/ic/am7990.c @@ -0,0 +1,1218 @@ +/* $NetBSD: am7990.c,v 1.3 1995/07/24 04:34:51 mycroft Exp $ */ + +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_le.c 8.2 (Berkeley) 11/16/93 + */ + +#include <sys/ioctl.h> +#include <sys/errno.h> + +#ifdef INET +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#ifdef NS +#include <netns/ns.h> +#include <netns/ns_if.h> +#endif + +#if defined(CCITT) && defined(LLC) +#include <sys/socketvar.h> +#include <netccitt/x25.h> +extern llc_ctlinput(), cons_rtrequest(); +#endif + +#if NBPFILTER > 0 +#include <net/bpf.h> +#include <net/bpfdesc.h> +#endif + +#ifdef LEDEBUG +void recv_print __P((struct le_softc *, int)); +void xmit_print __P((struct le_softc *, int)); +#endif + +void +leconfig(sc) + struct le_softc *sc; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + int mem; + + /* Make sure the chip is stopped. */ + lestop(sc); + + /* Initialize ifnet structure. */ + ifp->if_unit = sc->sc_dev.dv_unit; + ifp->if_start = lestart; + ifp->if_ioctl = leioctl; + ifp->if_watchdog = lewatchdog; + ifp->if_flags = + IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; + + /* Attach the interface. */ + if_attach(ifp); + ether_ifattach(ifp); + +#if NBPFILTER > 0 + bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); +#endif + + switch (sc->sc_memsize) { + case 8192: + sc->sc_nrbuf = 4; + sc->sc_ntbuf = 1; + break; + case 16384: + sc->sc_nrbuf = 8; + sc->sc_ntbuf = 2; + break; + case 32768: + sc->sc_nrbuf = 16; + sc->sc_ntbuf = 4; + break; + case 65536: + sc->sc_nrbuf = 32; + sc->sc_ntbuf = 8; + break; + default: + panic("leconfig: weird memory size"); + } + + printf(": address %s, %d receive buffers, %d transmit buffers\n", + ether_sprintf(sc->sc_arpcom.ac_enaddr), + sc->sc_nrbuf, sc->sc_ntbuf); + + mem = 0; + sc->sc_initaddr = mem; + mem += sizeof(struct leinit); + sc->sc_rmdaddr = mem; + mem += sizeof(struct lermd) * sc->sc_nrbuf; + sc->sc_tmdaddr = mem; + mem += sizeof(struct letmd) * sc->sc_ntbuf; + sc->sc_rbufaddr = mem; + mem += LEBLEN * sc->sc_nrbuf; + sc->sc_tbufaddr = mem; + mem += LEBLEN * sc->sc_ntbuf; +#ifdef notyet + if (mem > ...) + panic(...); +#endif +} + +void +lereset(sc) + struct le_softc *sc; +{ + int s; + + s = splimp(); + leinit(sc); + splx(s); +} + +void +lewatchdog(unit) + short unit; +{ + struct le_softc *sc = LE_SOFTC(unit); + + log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); + ++sc->sc_arpcom.ac_if.if_oerrors; + + lereset(sc); +} + +/* + * Set up the initialization block and the descriptor rings. + */ +void +lememinit(sc) + register struct le_softc *sc; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + u_long a; + int bix; + struct leinit init; + struct lermd rmd; + struct letmd tmd; + +#if NBPFILTER > 0 + if (ifp->if_flags & IFF_PROMISC) + init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM; + else +#endif + init.init_mode = LE_MODE_NORMAL; + init.init_padr[0] = + (sc->sc_arpcom.ac_enaddr[1] << 8) | sc->sc_arpcom.ac_enaddr[0]; + init.init_padr[1] = + (sc->sc_arpcom.ac_enaddr[3] << 8) | sc->sc_arpcom.ac_enaddr[2]; + init.init_padr[2] = + (sc->sc_arpcom.ac_enaddr[5] << 8) | sc->sc_arpcom.ac_enaddr[4]; + lesetladrf(&sc->sc_arpcom, init.init_ladrf); + + sc->sc_last_rd = 0; + sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0; + + a = sc->sc_addr + LE_RMDADDR(sc, 0); + init.init_rdra = a; + init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13); + + a = sc->sc_addr + LE_TMDADDR(sc, 0); + init.init_tdra = a; + init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13); + + (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init)); + + /* + * Set up receive ring descriptors. + */ + for (bix = 0; bix < sc->sc_nrbuf; bix++) { + a = sc->sc_addr + LE_RBUFADDR(sc, bix); + rmd.rmd0 = a; + rmd.rmd1_hadr = a >> 16; + rmd.rmd1_bits = LE_R1_OWN; + rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; + rmd.rmd3 = 0; + (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix), + sizeof(rmd)); + } + + /* + * Set up transmit ring descriptors. + */ + for (bix = 0; bix < sc->sc_ntbuf; bix++) { + a = sc->sc_addr + LE_TBUFADDR(sc, bix); + tmd.tmd0 = a; + tmd.tmd1_hadr = a >> 16; + tmd.tmd1_bits = 0; + tmd.tmd2 = 0 | LE_XMD2_ONES; + tmd.tmd3 = 0; + (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix), + sizeof(tmd)); + } +} + +void +lestop(sc) + struct le_softc *sc; +{ + + lewrcsr(sc, LE_CSR0, LE_C0_STOP); +} + +/* + * Initialization of interface; set up initialization block + * and transmit/receive descriptor rings. + */ +void +leinit(sc) + register struct le_softc *sc; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + register int timo; + u_long a; + + lewrcsr(sc, LE_CSR0, LE_C0_STOP); + LE_DELAY(100); + + /* Set the correct byte swapping mode, etc. */ + lewrcsr(sc, LE_CSR3, sc->sc_conf3); + + /* Set up LANCE init block. */ + lememinit(sc); + + /* Give LANCE the physical address of its init block. */ + a = sc->sc_addr + LE_INITADDR(sc); + lewrcsr(sc, LE_CSR1, a); + lewrcsr(sc, LE_CSR2, a >> 16); + + /* Try to initialize the LANCE. */ + LE_DELAY(100); + lewrcsr(sc, LE_CSR0, LE_C0_INIT); + + /* Wait for initialization to finish. */ + for (timo = 100000; timo; timo--) + if (lerdcsr(sc, LE_CSR0) & LE_C0_IDON) + break; + + if (lerdcsr(sc, LE_CSR0) & LE_C0_IDON) { + /* Start the LANCE. */ + lewrcsr(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT | LE_C0_IDON); + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + ifp->if_timer = 0; + lestart(ifp); + } else + printf("%s: card failed to initialize\n", sc->sc_dev.dv_xname); +} + +/* + * Routine to copy from mbuf chain to transmit buffer in + * network buffer memory. + */ +integrate int +leput(sc, boff, m) + struct le_softc *sc; + int boff; + register struct mbuf *m; +{ + register struct mbuf *n; + register int len, tlen = 0; + + for (; m; m = n) { + len = m->m_len; + if (len == 0) { + MFREE(m, n); + continue; + } + (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len); + boff += len; + tlen += len; + MFREE(m, n); + } + if (tlen < LEMINSIZE) { + (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen); + tlen = LEMINSIZE; + } + return (tlen); +} + +/* + * Pull data off an interface. + * Len is length of data, with local net header stripped. + * We copy the data into mbufs. When full cluster sized units are present + * we copy into clusters. + */ +integrate struct mbuf * +leget(sc, boff, totlen) + struct le_softc *sc; + int boff, totlen; +{ + register struct mbuf *m; + struct mbuf *top, **mp; + int len, pad; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return (0); + m->m_pkthdr.rcvif = &sc->sc_arpcom.ac_if; + m->m_pkthdr.len = totlen; + pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); + m->m_data += pad; + len = MHLEN - pad; + top = 0; + mp = ⊤ + + while (totlen > 0) { + if (top) { + MGET(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m_freem(top); + return 0; + } + len = MLEN; + } + if (top && totlen >= MINCLSIZE) { + MCLGET(m, M_DONTWAIT); + if (m->m_flags & M_EXT) + len = MCLBYTES; + } + m->m_len = len = min(totlen, len); + (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len); + boff += len; + totlen -= len; + *mp = m; + mp = &m->m_next; + } + + return (top); +} + +/* + * Pass a packet to the higher levels. + */ +integrate void +leread(sc, boff, len) + register struct le_softc *sc; + int boff, len; +{ + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + struct mbuf *m; + struct ether_header *eh; + + if (len <= sizeof(struct ether_header) || + len > ETHERMTU + sizeof(struct ether_header)) { + printf("%s: invalid packet size %d; dropping\n", + sc->sc_dev.dv_xname, len); + ifp->if_ierrors++; + return; + } + + /* Pull packet off interface. */ + m = leget(sc, boff, len); + if (m == 0) { + ifp->if_ierrors++; + return; + } + + ifp->if_ipackets++; + + /* We assume that the header fit entirely in one mbuf. */ + eh = mtod(m, struct ether_header *); + +#if NBPFILTER > 0 + /* + * Check if there's a BPF listener on this interface. + * If so, hand off the raw packet to BPF. + */ + if (ifp->if_bpf) { + bpf_mtap(ifp->if_bpf, m); + + /* + * Note that the interface cannot be in promiscuous mode if + * there are no BPF listeners. And if we are in promiscuous + * mode, we have to check if this packet is really ours. + */ + if ((ifp->if_flags & IFF_PROMISC) != 0 && + (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */ + bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0) { + m_freem(m); + return; + } + } +#endif + + /* Pass the packet up, with the ether header sort-of removed. */ + m_adj(m, sizeof(struct ether_header)); + ether_input(ifp, eh, m); +} + +integrate void +lerint(sc) + struct le_softc *sc; +{ + register int bix; + int rp; + struct lermd rmd; + + bix = sc->sc_last_rd; + + /* Process all buffers with valid data. */ + for (;;) { + rp = LE_RMDADDR(sc, bix); + (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd)); + + if (rmd.rmd1_bits & LE_R1_OWN) + break; + + if (rmd.rmd1_bits & LE_R1_ERR) { + if (rmd.rmd1_bits & LE_R1_ENP) { + if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) { + if (rmd.rmd1_bits & LE_R1_FRAM) + printf("%s: framing error\n", + sc->sc_dev.dv_xname); + if (rmd.rmd1_bits & LE_R1_CRC) + printf("%s: crc mismatch\n", + sc->sc_dev.dv_xname); + } + } else { + if (rmd.rmd1_bits & LE_R1_OFLO) + printf("%s: overflow\n", + sc->sc_dev.dv_xname); + } + if (rmd.rmd1_bits & LE_R1_BUFF) + printf("%s: receive buffer error\n", + sc->sc_dev.dv_xname); + } else if (rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP) != + (LE_R1_STP | LE_R1_ENP)) { + printf("%s: dropping chained buffer\n", + sc->sc_dev.dv_xname); + } else { +#ifdef LEDEBUG + if (sc->sc_debug) + recv_print(sc, sc->sc_last_rd); +#endif + leread(sc, LE_RBUFADDR(sc, bix), (int)rmd.rmd3 - 4); + } + + rmd.rmd1_bits = LE_R1_OWN; + rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; + rmd.rmd3 = 0; + (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd)); + +#ifdef LEDEBUG + if (sc->sc_debug) + printf("sc->sc_last_rd = %x, rmd = %x\n", + sc->sc_last_rd, rmd); +#endif + + if (++bix == sc->sc_nrbuf) + bix = 0; + } + + sc->sc_last_rd = bix; +} + +integrate void +letint(sc) + register struct le_softc *sc; +{ + register struct ifnet *ifp = &sc->sc_arpcom.ac_if; + register int bix; + struct letmd tmd; + + bix = sc->sc_first_td; + + for (;;) { + if (sc->sc_no_td <= 0) + break; + +#ifdef LEDEBUG + if (sc->sc_debug) + printf("trans tmd = %x\n", tmd); +#endif + + (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), + sizeof(tmd)); + + if (tmd.tmd1_bits & LE_T1_OWN) + break; + + ifp->if_flags &= ~IFF_OACTIVE; + + if (tmd.tmd1_bits & LE_T1_ERR) { + if (tmd.tmd3 & LE_T3_BUFF) + printf("%s: transmit buffer error\n", sc->sc_dev.dv_xname); + else if (tmd.tmd3 & LE_T3_UFLO) + printf("%s: underflow\n", sc->sc_dev.dv_xname); + if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) { + lereset(sc); + return; + } + if (tmd.tmd3 & LE_T3_LCAR) + printf("%s: lost carrier\n", sc->sc_dev.dv_xname); + if (tmd.tmd3 & LE_T3_LCOL) + ifp->if_collisions++; + if (tmd.tmd3 & LE_T3_RTRY) { + printf("%s: excessive collisions, tdr %d\n", + sc->sc_dev.dv_xname, tmd.tmd3 & LE_T3_TDR_MASK); + ifp->if_collisions += 16; + } + ifp->if_oerrors++; + } else { + if (tmd.tmd1_bits & LE_T1_ONE) + ifp->if_collisions++; + else if (tmd.tmd1_bits & LE_T1_MORE) + /* Real number is unknown. */ + ifp->if_collisions += 2; + ifp->if_opackets++; + } + + if (++bix == sc->sc_ntbuf) + bix = 0; + + --sc->sc_no_td; + } + + sc->sc_first_td = bix; + + lestart(ifp); + + if (sc->sc_no_td == 0) + ifp->if_timer = 0; +} + +/* + * Controller interrupt. + */ +#ifdef LEINTR_UNIT +int +leintr(unit) + int unit; +{ + register struct le_softc *sc = LE_SOFTC(unit); +#else +int +leintr(arg) + register void *arg; +{ + register struct le_softc *sc = arg; +#endif + register u_int16_t isr; + + isr = lerdcsr(sc, LE_CSR0); +#ifdef LEDEBUG + if (sc->sc_debug) + printf("%s: leintr entering with isr=%04x\n", + sc->sc_dev.dv_xname, isr); +#endif + if ((isr & LE_C0_INTR) == 0) + return (0); + + lewrcsr(sc, LE_CSR0, + isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR | + LE_C0_RINT | LE_C0_TINT | LE_C0_IDON)); + if (isr & LE_C0_ERR) { + if (isr & LE_C0_BABL) { + printf("%s: babble\n", sc->sc_dev.dv_xname); + sc->sc_arpcom.ac_if.if_oerrors++; + } +#if 0 + if (isr & LE_C0_CERR) { + printf("%s: collision error\n", sc->sc_dev.dv_xname); + sc->sc_arpcom.ac_if.if_collisions++; + } +#endif + if (isr & LE_C0_MISS) + sc->sc_arpcom.ac_if.if_ierrors++; + if (isr & LE_C0_MERR) { + printf("%s: memory error\n", sc->sc_dev.dv_xname); + lereset(sc); + return (1); + } + } + + if ((isr & LE_C0_RXON) == 0) { + printf("%s: receiver disabled\n", sc->sc_dev.dv_xname); + sc->sc_arpcom.ac_if.if_ierrors++; + lereset(sc); + return (1); + } + if ((isr & LE_C0_TXON) == 0) { + printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname); + sc->sc_arpcom.ac_if.if_oerrors++; + lereset(sc); + return (1); + } + + if (isr & LE_C0_RINT) + lerint(sc); + if (isr & LE_C0_TINT) + letint(sc); + + return (1); +} + +/* + * Setup output on interface. + * Get another datagram to send off of the interface queue, and map it to the + * interface before starting the output. + * Called only at splimp or interrupt level. + */ +void +lestart(ifp) + register struct ifnet *ifp; +{ + register struct le_softc *sc = LE_SOFTC(ifp->if_unit); + register int bix; + register struct mbuf *m; + struct letmd tmd; + int rp; + int len; + + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + + bix = sc->sc_last_td; + + for (;;) { + rp = LE_TMDADDR(sc, bix); + (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd)); + + if (tmd.tmd1_bits & LE_T1_OWN) { + ifp->if_flags |= IFF_OACTIVE; + printf("missing buffer, no_td = %d, last_td = %d\n", + sc->sc_no_td, sc->sc_last_td); + } + + IF_DEQUEUE(&ifp->if_snd, m); + if (m == 0) + break; + +#if NBPFILTER > 0 + /* + * If BPF is listening on this interface, let it see the packet + * before we commit it to the wire. + */ + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m); +#endif + + /* + * Copy the mbuf chain into the transmit buffer. + */ + len = leput(sc, LE_TBUFADDR(sc, bix), m); + +#ifdef LEDEBUG + if (len > ETHERMTU + sizeof(struct ether_header)) + printf("packet length %d\n", len); +#endif + + ifp->if_timer = 5; + + /* + * Init transmit registers, and set transmit start flag. + */ + tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP; + tmd.tmd2 = -len | LE_XMD2_ONES; + tmd.tmd3 = 0; + + (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd)); + +#ifdef LEDEBUG + if (sc->sc_debug) + xmit_print(sc, sc->sc_last_td); +#endif + + lewrcsr(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); + + if (++bix == sc->sc_ntbuf) + bix = 0; + + if (++sc->sc_no_td == sc->sc_ntbuf) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + + } + + sc->sc_last_td = bix; +} + +/* + * Process an ioctl request. + */ +int +leioctl(ifp, cmd, data) + register struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct le_softc *sc = LE_SOFTC(ifp->if_unit); + struct ifaddr *ifa = (struct ifaddr *)data; + struct ifreq *ifr = (struct ifreq *)data; + int s, error = 0; + + s = splimp(); + + switch (cmd) { + + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + + switch (ifa->ifa_addr->sa_family) { +#ifdef INET + case AF_INET: + leinit(sc); + arp_ifinit(&sc->sc_arpcom, ifa); + break; +#endif +#ifdef NS + case AF_NS: + { + register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; + + if (ns_nullhost(*ina)) + ina->x_host = + *(union ns_host *)(sc->sc_arpcom.ac_enaddr); + else + bcopy(ina->x_host.c_host, + sc->sc_arpcom.ac_enaddr, + sizeof(sc->sc_arpcom.ac_enaddr)); + /* Set new address. */ + leinit(sc); + break; + } +#endif + default: + leinit(sc); + break; + } + break; + +#if defined(CCITT) && defined(LLC) + case SIOCSIFCONF_X25: + ifp->if_flags |= IFF_UP; + ifa->ifa_rtrequest = (void (*)())cons_rtrequest; /* XXX */ + error = x25_llcglue(PRC_IFUP, ifa->ifa_addr); + if (error == 0) + leinit(sc); + break; +#endif /* CCITT && LLC */ + + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && + (ifp->if_flags & IFF_RUNNING) != 0) { + /* + * If interface is marked down and it is running, then + * stop it. + */ + lestop(sc); + ifp->if_flags &= ~IFF_RUNNING; + } else if ((ifp->if_flags & IFF_UP) != 0 && + (ifp->if_flags & IFF_RUNNING) == 0) { + /* + * If interface is marked up and it is stopped, then + * start it. + */ + leinit(sc); + } else { + /* + * Reset the interface to pick up changes in any other + * flags that affect hardware registers. + */ + /*lestop(sc);*/ + leinit(sc); + } +#ifdef LEDEBUG + if (ifp->if_flags & IFF_DEBUG) + sc->sc_debug = 1; + else + sc->sc_debug = 0; +#endif + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + error = (cmd == SIOCADDMULTI) ? + ether_addmulti(ifr, &sc->sc_arpcom) : + ether_delmulti(ifr, &sc->sc_arpcom); + + if (error == ENETRESET) { + /* + * Multicast list has changed; set the hardware filter + * accordingly. + */ + lereset(sc); + error = 0; + } + break; + + default: + error = EINVAL; + break; + } + + splx(s); + return (error); +} + +#ifdef LEDEBUG +void +recv_print(sc, no) + struct le_softc *sc; + int no; +{ + struct lermd rmd; + u_int16_t len; + struct ether_header eh; + + (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd)); + len = rmd.rmd3; + printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no, + len); + printf("%s: status %04x\n", sc->sc_dev.dv_xname, lerdcsr(sc, LE_CSR0)); + printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", + sc->sc_dev.dv_xname, + rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3); + if (len >= sizeof(eh)) { + (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh)); + printf("%s: dst %s", ether_sprintf(eh.ether_dhost)); + printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), + ntohs(eh.ether_type)); + } +} + +void +xmit_print(sc, no) + struct le_softc *sc; + int no; +{ + struct letmd tmd; + u_int16_t len; + struct ether_header eh; + + (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd)); + len = -tmd.tmd2; + printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no, + len); + printf("%s: status %04x\n", sc->sc_dev.dv_xname, lerdcsr(sc, LE_CSR0)); + printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", + sc->sc_dev.dv_xname, + tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3); + if (len >= sizeof(eh)) { + (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh)); + printf("%s: dst %s", ether_sprintf(eh.ether_dhost)); + printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), + ntohs(eh.ether_type)); + } +} +#endif /* LEDEBUG */ + +/* + * Set up the logical address filter. + */ +void +lesetladrf(ac, af) + struct arpcom *ac; + u_int16_t *af; +{ + struct ifnet *ifp = &ac->ac_if; + struct ether_multi *enm; + register u_char *cp, c; + register u_int32_t crc; + register int i, len; + struct ether_multistep step; + + /* + * Set up multicast address filter by passing all multicast addresses + * through a crc generator, and then using the high order 6 bits as an + * index into the 64 bit logical address filter. The high order bit + * selects the word, while the rest of the bits select the bit within + * the word. + */ + + if (ifp->if_flags & IFF_PROMISC) + goto allmulti; + + af[0] = af[1] = af[2] = af[3] = 0x0000; + ETHER_FIRST_MULTI(step, ac, enm); + while (enm != NULL) { + if (bcmp(enm->enm_addrlo, enm->enm_addrhi, + sizeof(enm->enm_addrlo)) != 0) { + /* + * We must listen to a range of multicast addresses. + * For now, just accept all multicasts, rather than + * trying to set only those filter bits needed to match + * the range. (At this time, the only use of address + * ranges is for IP multicast routing, for which the + * range is big enough to require all bits set.) + */ + goto allmulti; + } + + cp = enm->enm_addrlo; + crc = 0xffffffff; + for (len = sizeof(enm->enm_addrlo); --len >= 0;) { + c = *cp++; + for (i = 8; --i >= 0;) { + if ((crc & 0x01) ^ (c & 0x01)) { + crc >>= 1; + crc ^= 0xedb88320; + } else + crc >>= 1; + c >>= 1; + } + } + /* Just want the 6 most significant bits. */ + crc >>= 26; + + /* Set the corresponding bit in the filter. */ + af[crc >> 4] |= 1 << (crc & 0xf); + + ETHER_NEXT_MULTI(step, enm); + } + ifp->if_flags &= ~IFF_ALLMULTI; + return; + +allmulti: + ifp->if_flags |= IFF_ALLMULTI; + af[0] = af[1] = af[2] = af[3] = 0xffff; +} + + +#if 0 /* USE OF THE FOLLOWING IS MACHINE-SPECIFIC */ +/* + * Routines for accessing the transmit and receive buffers. Unfortunately, + * CPU addressing of these buffers is done in one of 3 ways: + * - contiguous (for the 3max and turbochannel option card) + * - gap2, which means shorts (2 bytes) interspersed with short (2 byte) + * spaces (for the pmax) + * - gap16, which means 16bytes interspersed with 16byte spaces + * for buffers which must begin on a 32byte boundary (for 3min and maxine) + * The buffer offset is the logical byte offset, assuming contiguous storage. + */ +void +copytodesc_contig(sc, from, boff, len) + struct le_softc *sc; + caddr_t from; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + + /* + * Just call bcopy() to do the work. + */ + bcopy(from, buf + boff, len); +} + +void +copyfromdesc_contig(sc, to, boff, len) + struct le_softc *sc; + caddr_t to; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + + /* + * Just call bcopy() to do the work. + */ + bcopy(buf + boff, to, len); +} + +void +copytobuf_contig(sc, from, boff, len) + struct le_softc *sc; + caddr_t from; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + + /* + * Just call bcopy() to do the work. + */ + bcopy(from, buf + boff, len); +} + +void +copyfrombuf_contig(sc, to, boff, len) + struct le_softc *sc; + caddr_t to; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + + /* + * Just call bcopy() to do the work. + */ + bcopy(buf + boff, to, len); +} + +void +zerobuf_contig(sc, boff, len) + struct le_softc *sc; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + + /* + * Just let bzero() do the work + */ + bzero(buf + boff, len); +} + +/* + * For the pmax the buffer consists of shorts (2 bytes) interspersed with + * short (2 byte) spaces and must be accessed with halfword load/stores. + * (don't worry about doing an extra byte) + */ +void +copytobuf_gap2(sc, from, boff, len) + struct le_softc *sc; + register caddr_t from; + int boff; + register int len; +{ + volatile caddr_t buf = sc->sc_mem; + register volatile u_short *bptr; + register int xfer; + + if (boff & 0x1) { + /* handle unaligned first byte */ + bptr = ((volatile u_short *)buf) + (boff - 1); + *bptr = (*from++ << 8) | (*bptr & 0xff); + bptr += 2; + len--; + } else + bptr = ((volatile u_short *)buf) + boff; + if ((unsigned)from & 0x1) { + while (len > 1) { + *bptr = (from[1] << 8) | (from[0] & 0xff); + bptr += 2; + from += 2; + len -= 2; + } + } else { + /* optimize for aligned transfers */ + xfer = (int)((unsigned)len & ~0x1); + CopyToBuffer((u_short *)from, bptr, xfer); + bptr += xfer; + from += xfer; + len -= xfer; + } + if (len == 1) + *bptr = (u_short)*from; +} + +void +copyfrombuf_gap2(sc, to, boff, len) + struct le_softc *sc; + register caddr_t to; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + register volatile u_short *bptr; + register u_short tmp; + register int xfer; + + if (boff & 0x1) { + /* handle unaligned first byte */ + bptr = ((volatile u_short *)buf) + (boff - 1); + *to++ = (*bptr >> 8) & 0xff; + bptr += 2; + len--; + } else + bptr = ((volatile u_short *)buf) + boff; + if ((unsigned)to & 0x1) { + while (len > 1) { + tmp = *bptr; + *to++ = tmp & 0xff; + *to++ = (tmp >> 8) & 0xff; + bptr += 2; + len -= 2; + } + } else { + /* optimize for aligned transfers */ + xfer = (int)((unsigned)len & ~0x1); + CopyFromBuffer(bptr, to, xfer); + bptr += xfer; + to += xfer; + len -= xfer; + } + if (len == 1) + *to = *bptr & 0xff; +} + +void +zerobuf_gap2(sc, boff, len) + struct le_softc *sc; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + register volatile u_short *bptr; + + if ((unsigned)boff & 0x1) { + bptr = ((volatile u_short *)buf) + (boff - 1); + *bptr &= 0xff; + bptr += 2; + len--; + } else + bptr = ((volatile u_short *)buf) + boff; + while (len > 0) { + *bptr = 0; + bptr += 2; + len -= 2; + } +} + +/* + * For the 3min and maxine, the buffers are in main memory filled in with + * 16byte blocks interspersed with 16byte spaces. + */ +void +copytobuf_gap16(sc, from, boff, len) + struct le_softc *sc; + register caddr_t from; + int boff; + register int len; +{ + volatile caddr_t buf = sc->sc_mem; + register caddr_t bptr; + register int xfer; + + bptr = buf + ((boff << 1) & ~0x1f); + boff &= 0xf; + xfer = min(len, 16 - boff); + while (len > 0) { + bcopy(from, bptr + boff, xfer); + from += xfer; + bptr += 32; + boff = 0; + len -= xfer; + xfer = min(len, 16); + } +} + +void +copyfrombuf_gap16(sc, to, boff, len) + struct le_softc *sc; + register caddr_t to; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + register caddr_t bptr; + register int xfer; + + bptr = buf + ((boff << 1) & ~0x1f); + boff &= 0xf; + xfer = min(len, 16 - boff); + while (len > 0) { + bcopy(bptr + boff, to, xfer); + to += xfer; + bptr += 32; + boff = 0; + len -= xfer; + xfer = min(len, 16); + } +} + +void +zerobuf_gap16(sc, boff, len) + struct le_softc *sc; + int boff, len; +{ + volatile caddr_t buf = sc->sc_mem; + register caddr_t bptr; + register int xfer; + + bptr = buf + ((boff << 1) & ~0x1f); + boff &= 0xf; + xfer = min(len, 16 - boff); + while (len > 0) { + bzero(bptr + boff, xfer); + bptr += 32; + boff = 0; + len -= xfer; + xfer = min(len, 16); + } +} +#endif diff --git a/sys/dev/ic/am7990reg.h b/sys/dev/ic/am7990reg.h new file mode 100644 index 00000000000..2e563efc20c --- /dev/null +++ b/sys/dev/ic/am7990reg.h @@ -0,0 +1,178 @@ +/* $NetBSD: am7990reg.h,v 1.1 1995/04/11 04:17:50 mycroft Exp $ */ + +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_lereg.h 8.1 (Berkeley) 6/10/93 + */ + +#define LEBLEN 1536 /* ETHERMTU + header + CRC */ +#define LEMINSIZE 60 /* should be 64 if mode DTCR is set */ + +/* + * Receive message descriptor + */ +struct lermd { + u_int16_t rmd0; +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t rmd1_bits; + u_int8_t rmd1_hadr; +#else + u_int8_t rmd1_hadr; + u_int8_t rmd1_bits; +#endif + int16_t rmd2; + u_int16_t rmd3; +}; + +/* + * Transmit message descriptor + */ +struct letmd { + u_int16_t tmd0; +#if BYTE_ORDER == BIG_ENDIAN + u_int8_t tmd1_bits; + u_int8_t tmd1_hadr; +#else + u_int8_t tmd1_hadr; + u_int8_t tmd1_bits; +#endif + int16_t tmd2; + u_int16_t tmd3; +}; + +/* + * Initialization block + */ +struct leinit { + u_int16_t init_mode; /* +0x0000 */ + u_int16_t init_padr[3]; /* +0x0002 */ + u_int16_t init_ladrf[4]; /* +0x0008 */ + u_int16_t init_rdra; /* +0x0010 */ + u_int16_t init_rlen; /* +0x0012 */ + u_int16_t init_tdra; /* +0x0014 */ + u_int16_t init_tlen; /* +0x0016 */ + int16_t pad0[4]; /* Pad to 16 shorts */ +}; + +#define LE_INITADDR(sc) (sc->sc_initaddr) +#define LE_RMDADDR(sc, bix) (sc->sc_rmdaddr + sizeof(struct lermd) * (bix)) +#define LE_TMDADDR(sc, bix) (sc->sc_tmdaddr + sizeof(struct letmd) * (bix)) +#define LE_RBUFADDR(sc, bix) (sc->sc_rbufaddr + LEBLEN * (bix)) +#define LE_TBUFADDR(sc, bix) (sc->sc_tbufaddr + LEBLEN * (bix)) + +/* register addresses */ +#define LE_CSR0 0x0000 /* Control and status register */ +#define LE_CSR1 0x0001 /* low address of init block */ +#define LE_CSR2 0x0002 /* high address of init block */ +#define LE_CSR3 0x0003 /* Bus master and control */ + +/* Control and status register 0 (csr0) */ +#define LE_C0_ERR 0x8000 /* error summary */ +#define LE_C0_BABL 0x4000 /* transmitter timeout error */ +#define LE_C0_CERR 0x2000 /* collision */ +#define LE_C0_MISS 0x1000 /* missed a packet */ +#define LE_C0_MERR 0x0800 /* memory error */ +#define LE_C0_RINT 0x0400 /* receiver interrupt */ +#define LE_C0_TINT 0x0200 /* transmitter interrupt */ +#define LE_C0_IDON 0x0100 /* initalization done */ +#define LE_C0_INTR 0x0080 /* interrupt condition */ +#define LE_C0_INEA 0x0040 /* interrupt enable */ +#define LE_C0_RXON 0x0020 /* receiver on */ +#define LE_C0_TXON 0x0010 /* transmitter on */ +#define LE_C0_TDMD 0x0008 /* transmit demand */ +#define LE_C0_STOP 0x0004 /* disable all external activity */ +#define LE_C0_STRT 0x0002 /* enable external activity */ +#define LE_C0_INIT 0x0001 /* begin initalization */ + +#define LE_C0_BITS \ + "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\ +\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT" + +/* Control and status register 3 (csr3) */ +#define LE_C3_BSWP 0x0004 /* byte swap */ +#define LE_C3_ACON 0x0002 /* ALE control, eh? */ +#define LE_C3_BCON 0x0001 /* byte control */ + +/* Initialzation block (mode) */ +#define LE_MODE_PROM 0x8000 /* promiscuous mode */ +/* 0x7f80 reserved, must be zero */ +#define LE_MODE_INTL 0x0040 /* internal loopback */ +#define LE_MODE_DRTY 0x0020 /* disable retry */ +#define LE_MODE_COLL 0x0010 /* force a collision */ +#define LE_MODE_DTCR 0x0008 /* disable transmit CRC */ +#define LE_MODE_LOOP 0x0004 /* loopback mode */ +#define LE_MODE_DTX 0x0002 /* disable transmitter */ +#define LE_MODE_DRX 0x0001 /* disable receiver */ +#define LE_MODE_NORMAL 0 /* none of the above */ + +/* Receive message descriptor 1 (rmd1_bits) */ +#define LE_R1_OWN 0x80 /* LANCE owns the packet */ +#define LE_R1_ERR 0x40 /* error summary */ +#define LE_R1_FRAM 0x20 /* framing error */ +#define LE_R1_OFLO 0x10 /* overflow error */ +#define LE_R1_CRC 0x08 /* CRC error */ +#define LE_R1_BUFF 0x04 /* buffer error */ +#define LE_R1_STP 0x02 /* start of packet */ +#define LE_R1_ENP 0x01 /* end of packet */ + +#define LE_R1_BITS \ + "\20\10OWN\7ERR\6FRAM\5OFLO\4CRC\3BUFF\2STP\1ENP" + +/* Transmit message descriptor 1 (tmd1_bits) */ +#define LE_T1_OWN 0x80 /* LANCE owns the packet */ +#define LE_T1_ERR 0x40 /* error summary */ +#define LE_T1_MORE 0x10 /* multiple collisions */ +#define LE_T1_ONE 0x08 /* single collision */ +#define LE_T1_DEF 0x04 /* defferred transmit */ +#define LE_T1_STP 0x02 /* start of packet */ +#define LE_T1_ENP 0x01 /* end of packet */ + +#define LE_T1_BITS \ + "\20\10OWN\7ERR\6RES\5MORE\4ONE\3DEF\2STP\1ENP" + +/* Transmit message descriptor 3 (tmd3) */ +#define LE_T3_BUFF 0x8000 /* buffer error */ +#define LE_T3_UFLO 0x4000 /* underflow error */ +#define LE_T3_LCOL 0x1000 /* late collision */ +#define LE_T3_LCAR 0x0800 /* loss of carrier */ +#define LE_T3_RTRY 0x0400 /* retry error */ +#define LE_T3_TDR_MASK 0x03ff /* time domain reflectometry counter */ + +#define LE_XMD2_ONES 0xf000 + +#define LE_T3_BITS \ + "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY" diff --git a/sys/dev/ic/am7990var.h b/sys/dev/ic/am7990var.h new file mode 100644 index 00000000000..b1f86584a42 --- /dev/null +++ b/sys/dev/ic/am7990var.h @@ -0,0 +1,63 @@ +/* $NetBSD: am7990var.h,v 1.1 1995/06/28 02:24:56 cgd Exp $ */ + +/* + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef DDB +#define integrate +#else +#define integrate static inline +#endif + +void leconfig __P((struct le_softc *)); +void leinit __P((struct le_softc *)); +int leioctl __P((struct ifnet *, u_long, caddr_t)); +void lememinit __P((struct le_softc *)); +void lereset __P((struct le_softc *)); +void lesetladrf __P((struct arpcom *, u_int16_t *)); +void lestart __P((struct ifnet *)); +void lestop __P((struct le_softc *)); +void lewatchdog __P((/* short */)); + +integrate u_int16_t lerdcsr __P((/* struct le_softc *, u_int16_t */)); +integrate void lewrcsr __P((/* struct le_softc *, u_int16_t, u_int16_t */)); + +integrate void lerint __P((struct le_softc *)); +integrate void letint __P((struct le_softc *)); + +integrate int leput __P((struct le_softc *, int, struct mbuf *)); +integrate struct mbuf *leget __P((struct le_softc *, int, int)); +integrate void leread __P((struct le_softc *, int, int)); + +void copytodesc_contig(), copyfromdesc_contig(); +void copytobuf_contig(), copyfrombuf_contig(), zerobuf_contig(); +#ifdef 0 +void copytobuf_gap2(), copyfrombuf_gap2(), zerobuf_gap2(); +void copytobuf_gap16(), copyfrombuf_gap16(), zerobuf_gap16(); +#endif diff --git a/sys/dev/ic/cd1400reg.h b/sys/dev/ic/cd1400reg.h new file mode 100644 index 00000000000..9481f71f004 --- /dev/null +++ b/sys/dev/ic/cd1400reg.h @@ -0,0 +1,123 @@ +/* $NetBSD: cd1400reg.h,v 1.2 1994/10/27 04:18:37 cgd Exp $ */ + +/* + * cyclades cyclom-y serial driver + * Andrew Herbert <andrew@werple.apana.org.au>, 17 August 1993 + * + * Copyright (c) 1993 Andrew Herbert. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name Andrew Herbert may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define CD1400_NO_OF_CHANNELS 4 /* four serial channels per chip */ +#define CD1400_FIFOSIZE 12 /* 12 chars */ + +/* register definitions */ + +#define CD1400_CCR 2*0x05 /* channel control */ +#define CD1400_CMD_RESET 0x81 /* full reset */ + +#define CD1400_SRER 2*0x06 /* service request enable */ + +#define CD1400_GFRCR 2*0x40 /* global firmware revision code */ + +#define CD1400_LIVR 2*0x18 /* local intr vector */ +#define CD1400_MIVR 2*0x41 /* modem intr vector */ +#define CD1400_TIVR 2*0x42 /* transmit intr vector */ +#define CD1400_RIVR 2*0x43 /* receive intr vector */ +#define CD1400_RIVR_EXCEPTION (1<<2) /* receive exception bit */ + +#define CD1400_RICR 2*0x44 /* receive intr channel */ +#define CD1400_TICR 2*0x45 /* transmit intr channel */ +#define CD1400_MICR 2*0x46 /* modem intr channel */ + +#define CD1400_RDCR 2*0x0e /* rx data count */ + +#define CD1400_EOSRR 2*0x60 /* end of service request */ +#define CD1400_RDSR 2*0x62 /* rx data/status */ +#define CD1400_RDSR_OVERRUN (1<<0) /* rx overrun error */ +#define CD1400_RDSR_FRAMING (1<<1) /* rx framing error */ +#define CD1400_RDSR_PARITY (1<<2) /* rx parity error */ +#define CD1400_RDSR_BREAK (1<<3) /* rx break */ +#define CD1400_RDSR_SPECIAL (7<<4) /* rx special char */ +#define CD1400_RDSR_SPECIAL_SHIFT 4 /* rx special char shift */ +#define CD1400_RDSR_TIMEOUT (1<<7) /* rx timeout */ + +#define CD1400_TDR 2*0x63 /* tx data */ + +#define CD1400_MISR 2*0x4c /* modem intr status */ +#define CD1400_MISR_DSRd (1<<7) /* DSR delta */ +#define CD1400_MISR_CTSd (1<<6) /* CTS delta */ +#define CD1400_MISR_RId (1<<5) /* RI delta */ +#define CD1400_MISR_CDd (1<<4) /* CD delta */ + +#define CD1400_MSVR 2*0x6d /* modem signals */ +#define CD1400_MSVR_DSR (1<<7) /* !DSR line */ +#define CD1400_MSVR_CTS (1<<6) /* !CTS line */ +#define CD1400_MSVR_RI (1<<5) /* !RI line */ +#define CD1400_MSVR_CD (1<<4) /* !CD line */ +#define CD1400_MSVR_DTR (1<<1) /* DTR line */ + +#define CD1400_DTR 2*0x6d /* dtr control */ +#define CD1400_DTR_CLEAR 0 +#define CD1400_DTR_SET (1<<1) + +#define CD1400_PPR 2*0x7e +#define CD1400_CLOCK_25_1MS 0x31 + +#define CD1400_CAR 2*0x68 /* channel access */ + +#define CD1400_RIR 2*0x6B /* receive interrupt status */ +#define CD1400_TIR 2*0x6A /* transmit interrupt status */ +#define CD1400_MIR 2*0x69 /* modem interrupt status */ + +#define CD1400_RBPR 2*0x78 /* receive baud rate period */ +#define CD1400_RCOR 2*0x7C /* receive clock option */ +#define CD1400_TBPR 2*0x72 /* transmit baud rate period */ +#define CD1400_TCOR 2*0x76 /* transmit clock option */ + +#define CD1400_COR1 2*0x08 /* channel option 1 */ +#define CD1400_COR2 2*0x09 /* channel option 2 */ +#define CD1400_COR3 2*0x0A /* channel option 3 */ +#define CD1400_COR4 2*0x1E /* channel option 4 */ +#define CD1400_COR5 2*0x1F /* channel option 5 */ + +#define CD1400_SCHR1 2*0x1A /* special character 1 */ +#define CD1400_SCHR2 2*0x1B /* special character 2 */ +#define CD1400_SCHR3 2*0x1C /* special character 3 */ +#define CD1400_SCHR4 2*0x1D /* special character 4 */ + +#define CD1400_MCOR1 2*0x15 /* modem change 1 */ +#define CD1400_MCOR2 2*0x16 /* modem change 2 */ +#define CD1400_RTPR 2*0x21 /* receive timeout period */ + +#define CD1400_SVRR 2*0x67 /* service request */ +#define CD1400_SVRR_RX (1<<0) +#define CD1400_SVRR_TX (1<<1) +#define CD1400_SVRR_MDM (1<<2) + +/* hardware SVCACK addresses, for use in interrupt handlers */ +#define CD1400_SVCACKR 0x100 +#define CD1400_SVCACKT 0x200 +#define CD1400_SVCACKM 0x300 diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c new file mode 100644 index 00000000000..8c5c5480544 --- /dev/null +++ b/sys/dev/ic/com.c @@ -0,0 +1,996 @@ +/* $NetBSD: com.c,v 1.61 1995/07/04 06:47:18 mycroft Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)com.c 7.5 (Berkeley) 5/16/91 + */ + +/* + * COM driver, based on HP dca driver + * uses National Semiconductor NS16450/NS16550AF UART + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/types.h> +#include <sys/device.h> + +#include <machine/cpu.h> +#include <machine/pio.h> + +#include <dev/isa/isavar.h> +#include <dev/isa/comreg.h> +#include <dev/ic/ns16550reg.h> + +#define COM_IBUFSIZE (2 * 256) +#define COM_IHIGHWATER ((3 * COM_IBUFSIZE) / 4) + +struct com_softc { + struct device sc_dev; + void *sc_ih; + struct tty *sc_tty; + + int sc_overflows; + int sc_floods; + int sc_errors; + + int sc_iobase; + u_char sc_hwflags; +#define COM_HW_NOIEN 0x01 +#define COM_HW_FIFO 0x02 +#define COM_HW_CONSOLE 0x40 + u_char sc_swflags; +#define COM_SW_SOFTCAR 0x01 +#define COM_SW_CLOCAL 0x02 +#define COM_SW_CRTSCTS 0x04 +#define COM_SW_MDMBUF 0x08 + u_char sc_msr, sc_mcr; + u_char sc_dtr; + + u_char *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend; + u_char sc_ibufs[2][COM_IBUFSIZE]; +}; + +int comprobe __P((struct device *, void *, void *)); +void comattach __P((struct device *, struct device *, void *)); +int comopen __P((dev_t, int, int, struct proc *)); +int comclose __P((dev_t, int, int, struct proc *)); +void comdiag __P((void *)); +int comintr __P((void *)); +void compoll __P((void *)); +int comparam __P((struct tty *, struct termios *)); +void comstart __P((struct tty *)); + +struct cfdriver comcd = { + NULL, "com", comprobe, comattach, DV_TTY, sizeof(struct com_softc) +}; + +int comdefaultrate = TTYDEF_SPEED; +#ifdef COMCONSOLE +int comconsole = COMCONSOLE; +#else +int comconsole = -1; +#endif +int comconsinit; +int commajor; +int comsopen = 0; +int comevents = 0; + +#ifdef KGDB +#include <machine/remote-sl.h> +extern int kgdb_dev; +extern int kgdb_rate; +extern int kgdb_debug_init; +#endif + +#define COMUNIT(x) (minor(x)) + +#define bis(c, b) do { const register int com_ad = (c); \ + outb(com_ad, inb(com_ad) | (b)); } while(0) +#define bic(c, b) do { const register int com_ad = (c); \ + outb(com_ad, inb(com_ad) & ~(b)); } while(0) + +int +comspeed(speed) + long speed; +{ +#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ + + int x, err; + + if (speed == 0) + return 0; + if (speed < 0) + return -1; + x = divrnd((COM_FREQ / 16), speed); + if (x <= 0) + return -1; + err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000; + if (err < 0) + err = -err; + if (err > COM_TOLERANCE) + return -1; + return x; + +#undef divrnd(n, q) +} + +int +comprobe1(iobase) + int iobase; +{ + + /* force access to id reg */ + outb(iobase + com_cfcr, 0); + outb(iobase + com_iir, 0); + if (inb(iobase + com_iir) & 0x38) + return 0; + + return 1; +} + +int +comprobe(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct isa_attach_args *ia = aux; + int iobase = ia->ia_iobase; + + if (!comprobe1(iobase)) + return 0; + + ia->ia_iosize = COM_NPORTS; + ia->ia_msize = 0; + return 1; +} + +void +comattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct com_softc *sc = (void *)self; + struct isa_attach_args *ia = aux; + struct cfdata *cf = sc->sc_dev.dv_cfdata; + int iobase = ia->ia_iobase; + struct tty *tp; + + sc->sc_iobase = iobase; + sc->sc_hwflags = cf->cf_flags & COM_HW_NOIEN; + sc->sc_swflags = 0; + + if (sc->sc_dev.dv_unit == comconsole) + delay(1000); + + /* look for a NS 16550AF UART with FIFOs */ + outb(iobase + com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); + delay(100); + if ((inb(iobase + com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) + if ((inb(iobase + com_fifo) & FIFO_TRIGGER_14) == FIFO_TRIGGER_14) { + sc->sc_hwflags |= COM_HW_FIFO; + printf(": ns16550a, working fifo\n"); + } else + printf(": ns16550, broken fifo\n"); + else + printf(": ns8250 or ns16450, no fifo\n"); + outb(iobase + com_fifo, 0); + + /* disable interrupts */ + outb(iobase + com_ier, 0); + outb(iobase + com_mcr, 0); + + if (ia->ia_irq != IRQUNK) + sc->sc_ih = isa_intr_establish(ia->ia_irq, ISA_IST_EDGE, + ISA_IPL_TTY, comintr, sc); + +#ifdef KGDB + if (kgdb_dev == makedev(commajor, unit)) { + if (comconsole == unit) + kgdb_dev = -1; /* can't debug over console port */ + else { + (void) cominit(unit, kgdb_rate); + if (kgdb_debug_init) { + /* + * Print prefix of device name, + * let kgdb_connect print the rest. + */ + printf("%s: ", sc->sc_dev.dv_xname); + kgdb_connect(1); + } else + printf("%s: kgdb enabled\n", + sc->sc_dev.dv_xname); + } + } +#endif + + if (sc->sc_dev.dv_unit == comconsole) { + /* + * Need to reset baud rate, etc. of next print so reset + * comconsinit. Also make sure console is always "hardwired". + */ + comconsinit = 0; + sc->sc_hwflags |= COM_HW_CONSOLE; + sc->sc_swflags |= COM_SW_SOFTCAR; + } +} + +int +comopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = COMUNIT(dev); + struct com_softc *sc; + int iobase; + struct tty *tp; + int s; + int error = 0; + + if (unit >= comcd.cd_ndevs) + return ENXIO; + sc = comcd.cd_devs[unit]; + if (!sc) + return ENXIO; + + if (!sc->sc_tty) + tp = sc->sc_tty = ttymalloc(); + else + tp = sc->sc_tty; + + tp->t_oproc = comstart; + tp->t_param = comparam; + tp->t_dev = dev; + if ((tp->t_state & TS_ISOPEN) == 0) { + tp->t_state |= TS_WOPEN; + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + if (sc->sc_swflags & COM_SW_CLOCAL) + tp->t_cflag |= CLOCAL; + if (sc->sc_swflags & COM_SW_CRTSCTS) + tp->t_cflag |= CRTSCTS; + if (sc->sc_swflags & COM_SW_MDMBUF) + tp->t_cflag |= MDMBUF; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = comdefaultrate; + + s = spltty(); + + comparam(tp, &tp->t_termios); + ttsetwater(tp); + + if (comsopen++ == 0) + timeout(compoll, NULL, 1); + + sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; + sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER; + sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE; + + iobase = sc->sc_iobase; + /* Set the FIFO threshold based on the receive speed. */ + if (sc->sc_hwflags & COM_HW_FIFO) + outb(iobase + com_fifo, + FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | + (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); + /* flush any pending I/O */ + while (inb(iobase + com_lsr) & LSR_RXRDY) + (void) inb(iobase + com_data); + /* you turn me on, baby */ + sc->sc_mcr = MCR_DTR | MCR_RTS; + if ((sc->sc_hwflags & COM_HW_NOIEN) == 0) + sc->sc_mcr |= MCR_IENABLE; + outb(iobase + com_mcr, sc->sc_mcr); + outb(iobase + com_ier, + IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); + + sc->sc_msr = inb(iobase + com_msr); + if (sc->sc_swflags & COM_SW_SOFTCAR || sc->sc_msr & MSR_DCD || + tp->t_cflag & MDMBUF) + tp->t_state |= TS_CARR_ON; + else + tp->t_state &= ~TS_CARR_ON; + } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) { + return EBUSY; + } else + s = spltty(); + + /* wait for carrier if necessary */ + if ((flag & O_NONBLOCK) == 0) + while ((tp->t_cflag & CLOCAL) == 0 && + (tp->t_state & TS_CARR_ON) == 0) { + tp->t_state |= TS_WOPEN; + error = ttysleep(tp, (caddr_t)&tp->t_rawq, + TTIPRI | PCATCH, ttopen, 0); + if (error) { + /* XXX should turn off chip if we're the + only waiter */ + splx(s); + return error; + } + } + splx(s); + + return (*linesw[tp->t_line].l_open)(dev, tp); +} + +int +comclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + int unit = COMUNIT(dev); + struct com_softc *sc = comcd.cd_devs[unit]; + struct tty *tp = sc->sc_tty; + int iobase = sc->sc_iobase; + int s; + + /* XXX This is for cons.c. */ + if ((tp->t_state & TS_ISOPEN) == 0) + return 0; + + (*linesw[tp->t_line].l_close)(tp, flag); + s = spltty(); + bic(iobase + com_cfcr, CFCR_SBREAK); + outb(iobase + com_ier, 0); + if (tp->t_cflag & HUPCL && + (sc->sc_swflags & COM_SW_SOFTCAR) == 0) { + /* XXX perhaps only clear DTR */ + outb(iobase + com_mcr, 0); + } + tp->t_state &= ~(TS_BUSY | TS_FLUSH); + if (--comsopen == 0) + untimeout(compoll, NULL); + splx(s); + ttyclose(tp); +#ifdef notyet /* XXXX */ + if (unit != comconsole) { + ttyfree(tp); + sc->sc_tty = 0; + } +#endif + return 0; +} + +int +comread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +comwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +struct tty * +comtty(dev) + dev_t dev; +{ + struct com_softc *sc = comcd.cd_devs[COMUNIT(dev)]; + struct tty *tp = sc->sc_tty; + + return (tp); +} + +static u_char +tiocm_xxx2mcr(data) + int data; +{ + u_char m = 0; + + if (data & TIOCM_DTR) + m |= MCR_DTR; + if (data & TIOCM_RTS) + m |= MCR_RTS; + return m; +} + +int +comioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + int unit = COMUNIT(dev); + struct com_softc *sc = comcd.cd_devs[unit]; + struct tty *tp = sc->sc_tty; + int iobase = sc->sc_iobase; + int error; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return error; + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return error; + + switch (cmd) { + case TIOCSBRK: + bis(iobase + com_cfcr, CFCR_SBREAK); + break; + case TIOCCBRK: + bic(iobase + com_cfcr, CFCR_SBREAK); + break; + case TIOCSDTR: + outb(iobase + com_mcr, sc->sc_mcr |= sc->sc_dtr); + break; + case TIOCCDTR: + outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr); + break; + case TIOCMSET: + sc->sc_mcr &= ~(MCR_DTR | MCR_RTS); + case TIOCMBIS: + outb(iobase + com_mcr, + sc->sc_mcr |= tiocm_xxx2mcr(*(int *)data)); + break; + case TIOCMBIC: + outb(iobase + com_mcr, + sc->sc_mcr &= ~tiocm_xxx2mcr(*(int *)data)); + break; + case TIOCMGET: { + u_char m; + int bits = 0; + + m = sc->sc_mcr; + if (m & MCR_DTR) + bits |= TIOCM_DTR; + if (m & MCR_RTS) + bits |= TIOCM_RTS; + m = sc->sc_msr; + if (m & MSR_DCD) + bits |= TIOCM_CD; + if (m & MSR_CTS) + bits |= TIOCM_CTS; + if (m & MSR_DSR) + bits |= TIOCM_DSR; + if (m & (MSR_RI | MSR_TERI)) + bits |= TIOCM_RI; + if (inb(iobase + com_ier)) + bits |= TIOCM_LE; + *(int *)data = bits; + break; + } + case TIOCGFLAGS: { + int bits = 0; + + if (sc->sc_swflags & COM_SW_SOFTCAR) + bits |= TIOCFLAG_SOFTCAR; + if (sc->sc_swflags & COM_SW_CLOCAL) + bits |= TIOCFLAG_CLOCAL; + if (sc->sc_swflags & COM_SW_CRTSCTS) + bits |= TIOCFLAG_CRTSCTS; + if (sc->sc_swflags & COM_SW_MDMBUF) + bits |= TIOCFLAG_MDMBUF; + + *(int *)data = bits; + break; + } + case TIOCSFLAGS: { + int userbits, driverbits = 0; + + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + return(EPERM); + + userbits = *(int *)data; + if ((userbits & TIOCFLAG_SOFTCAR) || + (sc->sc_hwflags & COM_HW_CONSOLE)) + driverbits |= COM_SW_SOFTCAR; + if (userbits & TIOCFLAG_CLOCAL) + driverbits |= COM_SW_CLOCAL; + if (userbits & TIOCFLAG_CRTSCTS) + driverbits |= COM_SW_CRTSCTS; + if (userbits & TIOCFLAG_MDMBUF) + driverbits |= COM_SW_MDMBUF; + + sc->sc_swflags = driverbits; + break; + } + default: + return ENOTTY; + } + + return 0; +} + +int +comparam(tp, t) + struct tty *tp; + struct termios *t; +{ + struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; + int iobase = sc->sc_iobase; + int ospeed = comspeed(t->c_ospeed); + u_char cfcr; + tcflag_t oldcflag; + int s; + + /* check requested parameters */ + if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) + return EINVAL; + + switch (t->c_cflag & CSIZE) { + case CS5: + cfcr = CFCR_5BITS; + break; + case CS6: + cfcr = CFCR_6BITS; + break; + case CS7: + cfcr = CFCR_7BITS; + break; + case CS8: + cfcr = CFCR_8BITS; + break; + } + if (t->c_cflag & PARENB) { + cfcr |= CFCR_PENAB; + if ((t->c_cflag & PARODD) == 0) + cfcr |= CFCR_PEVEN; + } + if (t->c_cflag & CSTOPB) + cfcr |= CFCR_STOPB; + + s = spltty(); + + if (ospeed == 0) + outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_DTR); + + /* + * Set the FIFO threshold based on the receive speed, if we are + * changing it. + */ + if (tp->t_ispeed != t->c_ispeed) { + if (sc->sc_hwflags & COM_HW_FIFO) + outb(iobase + com_fifo, + FIFO_ENABLE | + (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); + } + + if (ospeed != 0) { + outb(iobase + com_cfcr, cfcr | CFCR_DLAB); + outb(iobase + com_dlbl, ospeed); + outb(iobase + com_dlbh, ospeed >> 8); + outb(iobase + com_cfcr, cfcr); + outb(iobase + com_mcr, sc->sc_mcr |= MCR_DTR); + } else + outb(iobase + com_cfcr, cfcr); + + /* When not using CRTSCTS, RTS follows DTR. */ + if ((t->c_cflag & CRTSCTS) == 0) { + if (sc->sc_mcr & MCR_DTR) { + if ((sc->sc_mcr & MCR_RTS) == 0) + outb(iobase + com_mcr, sc->sc_mcr |= MCR_RTS); + } else { + if (sc->sc_mcr & MCR_RTS) + outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_RTS); + } + sc->sc_dtr = MCR_DTR | MCR_RTS; + } else + sc->sc_dtr = MCR_DTR; + + /* and copy to tty */ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + oldcflag = tp->t_cflag; + tp->t_cflag = t->c_cflag; + + /* + * If DCD is off and MDMBUF is changed, ask the tty layer if we should + * stop the device. + */ + if ((sc->sc_msr & MSR_DCD) == 0 && + (sc->sc_swflags & COM_SW_SOFTCAR) == 0 && + (oldcflag & MDMBUF) != (tp->t_cflag & MDMBUF) && + (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { + outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr); + } + + splx(s); + return 0; +} + +void +comstart(tp) + struct tty *tp; +{ + struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; + int iobase = sc->sc_iobase; + int s; + + s = spltty(); + if (tp->t_state & (TS_TTSTOP | TS_BUSY)) + goto out; + if ((tp->t_cflag & CRTSCTS) != 0 && + (sc->sc_msr & MSR_CTS) == 0) + goto out; + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_outq); + } + if (tp->t_outq.c_cc == 0) + goto out; + selwakeup(&tp->t_wsel); + } + tp->t_state |= TS_BUSY; + if (sc->sc_hwflags & COM_HW_FIFO) { + u_char buffer[16], *cp = buffer; + int n = q_to_b(&tp->t_outq, cp, sizeof buffer); + do { + outb(iobase + com_data, *cp++); + } while (--n); + } else + outb(iobase + com_data, getc(&tp->t_outq)); +out: + splx(s); +} + +/* + * Stop output on a line. + */ +void +comstop(tp, flag) + struct tty *tp; +{ + int s; + + s = spltty(); + if (tp->t_state & TS_BUSY) + if ((tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; + splx(s); +} + +void +comdiag(arg) + void *arg; +{ + struct com_softc *sc = arg; + int overflows, floods; + int s; + + s = spltty(); + sc->sc_errors = 0; + overflows = sc->sc_overflows; + sc->sc_overflows = 0; + floods = sc->sc_floods; + sc->sc_floods = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", + sc->sc_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +void +compoll(arg) + void *arg; +{ + int unit; + struct com_softc *sc; + struct tty *tp; + register u_char *ibufp; + u_char *ibufend; + register int c; + int s; + static int lsrmap[8] = { + 0, TTY_PE, + TTY_FE, TTY_PE|TTY_FE, + TTY_FE, TTY_PE|TTY_FE, + TTY_FE, TTY_PE|TTY_FE + }; + + s = spltty(); + if (comevents == 0) { + splx(s); + goto out; + } + comevents = 0; + splx(s); + + for (unit = 0; unit < comcd.cd_ndevs; unit++) { + sc = comcd.cd_devs[unit]; + if (sc == 0 || sc->sc_ibufp == sc->sc_ibuf) + continue; + + tp = sc->sc_tty; + + s = spltty(); + + ibufp = sc->sc_ibuf; + ibufend = sc->sc_ibufp; + + if (ibufp == ibufend) { + splx(s); + continue; + } + + sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? + sc->sc_ibufs[1] : sc->sc_ibufs[0]; + sc->sc_ibufhigh = sc->sc_ibuf + COM_IHIGHWATER; + sc->sc_ibufend = sc->sc_ibuf + COM_IBUFSIZE; + + if (tp == 0 || (tp->t_state & TS_ISOPEN) == 0) { + splx(s); + continue; + } + + if ((tp->t_cflag & CRTSCTS) != 0 && + (sc->sc_mcr & MCR_RTS) == 0) + outb(sc->sc_iobase + com_mcr, sc->sc_mcr |= MCR_RTS); + + splx(s); + + while (ibufp < ibufend) { + c = *ibufp++; + if (*ibufp & LSR_OE) { + sc->sc_overflows++; + if (sc->sc_errors++ == 0) + timeout(comdiag, sc, 60 * hz); + } + /* This is ugly, but fast. */ + c |= lsrmap[(*ibufp++ & (LSR_BI|LSR_FE|LSR_PE)) >> 2]; + (*linesw[tp->t_line].l_rint)(c, tp); + } + } + +out: + timeout(compoll, NULL, 1); +} + +int +comintr(arg) + void *arg; +{ + struct com_softc *sc = arg; + int iobase = sc->sc_iobase; + struct tty *tp; + u_char lsr, data, msr, delta; + + if (inb(iobase + com_iir) & IIR_NOPEND) + return (0); + + tp = sc->sc_tty; + + for (;;) { + lsr = inb(iobase + com_lsr); + + if (lsr & LSR_RCV_MASK) { + register u_char *p = sc->sc_ibufp; + + comevents = 1; + do { + if ((lsr & LSR_BI) != 0) { +#ifdef DDB + if (sc->sc_dev.dv_unit == comconsole) { + Debugger(); + goto next; + } +#endif + data = '\0'; + } else + data = inb(iobase + com_data); + if (p >= sc->sc_ibufend) { + sc->sc_floods++; + if (sc->sc_errors++ == 0) + timeout(comdiag, sc, 60 * hz); + } else { + *p++ = data; + *p++ = lsr; + if (p == sc->sc_ibufhigh && + (tp->t_cflag & CRTSCTS) != 0) + outb(iobase + com_mcr, + sc->sc_mcr &= ~MCR_RTS); + } + next: + lsr = inb(iobase + com_lsr); + } while (lsr & LSR_RCV_MASK); + + sc->sc_ibufp = p; + } + + if (lsr & LSR_TXRDY && (tp->t_state & TS_BUSY) != 0) { + tp->t_state &= ~TS_BUSY; + if (tp->t_state & TS_FLUSH) + tp->t_state &= ~TS_FLUSH; + else + (*linesw[tp->t_line].l_start)(tp); + } + + msr = inb(iobase + com_msr); + + if (msr != sc->sc_msr) { + delta = msr ^ sc->sc_msr; + sc->sc_msr = msr; + if ((delta & MSR_DCD) != 0 && + (sc->sc_swflags & COM_SW_SOFTCAR) == 0 && + (*linesw[tp->t_line].l_modem)(tp, (msr & MSR_DCD) != 0) == 0) { + outb(iobase + com_mcr, sc->sc_mcr &= ~sc->sc_dtr); + } + if ((delta & msr & MSR_CTS) != 0 && + (tp->t_cflag & CRTSCTS) != 0) { + /* the line is up and we want to do rts/cts flow control */ + (*linesw[tp->t_line].l_start)(tp); + } + } + + if (inb(iobase + com_iir) & IIR_NOPEND) + return (1); + } +} + +/* + * Following are all routines needed for COM to act as console + */ +#include <dev/cons.h> + +void +comcnprobe(cp) + struct consdev *cp; +{ + + if (!comprobe1(CONADDR)) { + cp->cn_pri = CN_DEAD; + return; + } + + /* locate the major number */ + for (commajor = 0; commajor < nchrdev; commajor++) + if (cdevsw[commajor].d_open == comopen) + break; + + /* initialize required fields */ + cp->cn_dev = makedev(commajor, CONUNIT); +#ifdef COMCONSOLE + cp->cn_pri = CN_REMOTE; /* Force a serial port console */ +#else + cp->cn_pri = CN_NORMAL; +#endif +} + +void +comcninit(cp) + struct consdev *cp; +{ + + cominit(CONUNIT, comdefaultrate); + comconsole = CONUNIT; + comconsinit = 0; +} + +cominit(unit, rate) + int unit, rate; +{ + int s = splhigh(); + int iobase = CONADDR; + u_char stat; + + outb(iobase + com_cfcr, CFCR_DLAB); + rate = comspeed(comdefaultrate); + outb(iobase + com_dlbl, rate); + outb(iobase + com_dlbh, rate >> 8); + outb(iobase + com_cfcr, CFCR_8BITS); + outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY); + outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4); + stat = inb(iobase + com_iir); + splx(s); +} + +comcngetc(dev) + dev_t dev; +{ + int s = splhigh(); + int iobase = CONADDR; + u_char stat, c; + + while (((stat = inb(iobase + com_lsr)) & LSR_RXRDY) == 0) + ; + c = inb(iobase + com_data); + stat = inb(iobase + com_iir); + splx(s); + return c; +} + +/* + * Console kernel output character routine. + */ +void +comcnputc(dev, c) + dev_t dev; + int c; +{ + int s = splhigh(); + int iobase = CONADDR; + u_char stat; + register int timo; + +#ifdef KGDB + if (dev != kgdb_dev) +#endif + if (comconsinit == 0) { + (void) cominit(COMUNIT(dev), comdefaultrate); + comconsinit = 1; + } + /* wait for any pending transmission to finish */ + timo = 50000; + while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo) + ; + outb(iobase + com_data, c); + /* wait for this transmission to complete */ + timo = 1500000; + while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo) + ; + /* clear any interrupts generated by this transmission */ + stat = inb(iobase + com_iir); + splx(s); +} + +void +comcnpollc(dev, on) + dev_t dev; + int on; +{ + +} diff --git a/sys/dev/ic/comreg.h b/sys/dev/ic/comreg.h new file mode 100644 index 00000000000..4a4f0e90c25 --- /dev/null +++ b/sys/dev/ic/comreg.h @@ -0,0 +1,118 @@ +/* $NetBSD: comreg.h,v 1.6 1995/06/28 04:31:30 cgd Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)comreg.h 7.2 (Berkeley) 5/9/91 + */ + +#include <dev/ic/ns16550reg.h> + +#define COM_FREQ 1843200 /* 16-bit baud rate divisor */ +#define COM_TOLERANCE 30 /* baud rate tolerance, in 0.1% units */ + +/* interrupt enable register */ +#define IER_ERXRDY 0x1 +#define IER_ETXRDY 0x2 +#define IER_ERLS 0x4 +#define IER_EMSC 0x8 + +/* interrupt identification register */ +#define IIR_IMASK 0xf +#define IIR_RXTOUT 0xc +#define IIR_RLS 0x6 +#define IIR_RXRDY 0x4 +#define IIR_TXRDY 0x2 +#define IIR_NOPEND 0x1 +#define IIR_MLSC 0x0 +#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */ + +/* fifo control register */ +#define FIFO_ENABLE 0x01 +#define FIFO_RCV_RST 0x02 +#define FIFO_XMT_RST 0x04 +#define FIFO_DMA_MODE 0x08 +#define FIFO_TRIGGER_1 0x00 +#define FIFO_TRIGGER_4 0x40 +#define FIFO_TRIGGER_8 0x80 +#define FIFO_TRIGGER_14 0xc0 + +/* character format control register */ +#define CFCR_DLAB 0x80 +#define CFCR_SBREAK 0x40 +#define CFCR_PZERO 0x30 +#define CFCR_PONE 0x20 +#define CFCR_PEVEN 0x10 +#define CFCR_PODD 0x00 +#define CFCR_PENAB 0x08 +#define CFCR_STOPB 0x04 +#define CFCR_8BITS 0x03 +#define CFCR_7BITS 0x02 +#define CFCR_6BITS 0x01 +#define CFCR_5BITS 0x00 + +/* modem control register */ +#define MCR_LOOPBACK 0x10 +#define MCR_IENABLE 0x08 +#define MCR_DRS 0x04 +#define MCR_RTS 0x02 +#define MCR_DTR 0x01 + +/* line status register */ +#define LSR_RCV_FIFO 0x80 +#define LSR_TSRE 0x40 +#define LSR_TXRDY 0x20 +#define LSR_BI 0x10 +#define LSR_FE 0x08 +#define LSR_PE 0x04 +#define LSR_OE 0x02 +#define LSR_RXRDY 0x01 +#define LSR_RCV_MASK 0x1f + +/* modem status register */ +#define MSR_DCD 0x80 +#define MSR_RI 0x40 +#define MSR_DSR 0x20 +#define MSR_CTS 0x10 +#define MSR_DDCD 0x08 +#define MSR_TERI 0x04 +#define MSR_DDSR 0x02 +#define MSR_DCTS 0x01 + +#define COM_NPORTS 8 + +/* + * WARNING: Serial console is assumed to be at COM1 address + * and CONUNIT must be 0. + */ +#define CONADDR (0x3f8) +#define CONUNIT (0) diff --git a/sys/dev/ic/cs4231reg.h b/sys/dev/ic/cs4231reg.h new file mode 100644 index 00000000000..7ad90f03999 --- /dev/null +++ b/sys/dev/ic/cs4231reg.h @@ -0,0 +1,103 @@ +/* $NetBSD: cs4231reg.h,v 1.1 1995/07/07 02:11:46 brezak Exp $ */ +/* + * Copyright (c) 1995 John T. Kohl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Register defs for Crystal Semiconductor CS4231 Audio Codec/mixer + * chip, used on Gravis UltraSound MAX cards. + * + * Block diagram: + * +----------------------------------------------------+ + * | | + * | +----------------------------------------------+ | + * | |mixed in +-+ | | + * | +------------>--| | | | + * | mic in | | | | + * Mic --+-->| --------- GAIN ->-| | | | + * | | AUX 1 in |M| | | + * GF1 --)-->| -------------+-->-|U| | | + * | | Line in | |X|---- GAIN ----------+ | | + * Line --)-->| ---------+---)-->-| | | | | + * | | | | | | | | | + * | | | | +-+ ADC | | + * | | | | | | | + * | | | | | | | + * | | | +--- L/M --\ | | | AMP--> + * | | | \ | | | | + * | | | \ | | | | + * | | +---- L/M -------O-->--+--------)-------+-|--+-> line + * | | mono in /| | | | + * +---|-->------------ L/M -----/ | | | | + * | AUX 2 in | | | | + * CD --------|-->------------ L/M -------+ L/M | | + * | | v | + * | | | | + * | DAC | | + * | | | | + * +----------------------------------------------------+ + * | | + * | | + * v v + * Pc BUS (DISK) ??? + * + */ + + +/* + * The CS4231 mixer is write-only--it cannot be queried for current + * settings. Drivers must keep track of current values themselves. + */ + +/* CS4231/AD1845 mode2 registers; added to AD1848 registers */ +#define CS_ALT_FEATURE1 0x10 +#define CS_ALT_FEATURE2 0x11 +#define CS_LEFT_LINE_CONTROL 0x12 +#define CS_RIGHT_LINE_CONTROL 0x13 +#define CS_TIMER_LOW 0x14 +#define CS_TIMER_HIGH 0x15 +#define CS_UPPER_FREQUENCY_SEL 0x16 +#define CS_LOWER_FREQUENCY_SEL 0x17 +#define CS_IRQ_STATUS 0x18 +#define CS_VERSION_ID 0x19 +#define CS_MONO_IO_CONTROL 0x1A +#define CS_POWERDOWN_CONTROL 0x1B +#define CS_REC_FORMAT 0x1C +#define CS_XTAL_SELECT 0x1D +#define CS_UPPER_REC_CNT 0x1E +#define CS_LOWER_REC_CNT 0x1F + +#define MONO_INPUT_ATTEN_BITS 0x0f +#define MONO_INPUT_ATTEN_MASK 0xf0 +#define MONO_INPUT_MUTE 0x80 +#define MONO_INPUT_MUTE_MASK 0x7f + +#define LINE_INPUT_ATTEN_BITS 0x1f +#define LINE_INPUT_ATTEN_MASK 0xe0 +#define LINE_INPUT_MUTE 0x80 +#define LINE_INPUT_MUTE_MASK 0x7f diff --git a/sys/dev/ic/dc21040reg.h b/sys/dev/ic/dc21040reg.h new file mode 100644 index 00000000000..a330c09d4f9 --- /dev/null +++ b/sys/dev/ic/dc21040reg.h @@ -0,0 +1,332 @@ +/* $NetBSD: dc21040reg.h,v 1.6 1995/08/19 04:15:29 cgd Exp $ */ + +/*- + * Copyright (c) 1994, 1995 Matt Thomas (thomas@lkg.dec.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(_DC21040_H) +#define _DC21040_H + +typedef u_int16_t tulip_uint16_t; +typedef u_int32_t tulip_uint32_t; + +#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN +#define TULIP_BITFIELD2(a, b) b, a +#define TULIP_BITFIELD3(a, b, c) c, b, a +#define TULIP_BITFIELD4(a, b, c, d) d, c, b, a +#else +#define TULIP_BITFIELD2(a, b) a, b +#define TULIP_BITFIELD3(a, b, c) a, b, c +#define TULIP_BITFIELD4(a, b, c, d) a, b, c, d +#endif + +typedef struct { + tulip_uint32_t d_status; + tulip_uint32_t TULIP_BITFIELD3(d_length1 : 11, + d_length2 : 11, + d_flag : 10); + tulip_uint32_t d_addr1; + tulip_uint32_t d_addr2; +} tulip_desc_t; + +#define TULIP_DSTS_OWNER 0x80000000 /* Owner (1 = DC21040) */ +#define TULIP_DSTS_ERRSUM 0x00008000 /* Error Summary */ +/* + * Transmit Status + */ +#define TULIP_DSTS_TxBABBLE 0x00004000 /* Transmitter Babbled */ +#define TULIP_DSTS_TxCARRLOSS 0x00000800 /* Carrier Loss */ +#define TULIP_DSTS_TxNOCARR 0x00000400 /* No Carrier */ +#define TULIP_DSTS_TxLATECOLL 0x00000200 /* Late Collision */ +#define TULIP_DSTS_TxEXCCOLL 0x00000100 /* Excessive Collisions */ +#define TULIP_DSTS_TxNOHRTBT 0x00000080 /* No Heartbeat */ +#define TULIP_DSTS_TxCOLLMASK 0x00000078 /* Collision Count (mask) */ +#define TULIP_DSTS_V_TxCOLLCNT 0x00000003 /* Collision Count (bit) */ +#define TULIP_DSTS_TxLINKFAIL 0x00000004 /* Link Failure */ +#define TULIP_DSTS_TxUNDERFLOW 0x00000002 /* Underflow Error */ +#define TULIP_DSTS_TxDEFERRED 0x00000001 /* Initially Deferred */ +/* + * Receive Status + */ +#define TULIP_DSTS_RxBADLENGTH 0x00004000 /* Length Error */ +#define TULIP_DSTS_RxDATATYPE 0x00003000 /* Data Type */ +#define TULIP_DSTS_RxRUNT 0x00000800 /* Runt Frame */ +#define TULIP_DSTS_RxMULTICAST 0x00000400 /* Multicast Frame */ +#define TULIP_DSTS_RxFIRSTDESC 0x00000200 /* First Descriptor */ +#define TULIP_DSTS_RxLASTDESC 0x00000100 /* Last Descriptor */ +#define TULIP_DSTS_RxTOOLONG 0x00000080 /* Frame Too Long */ +#define TULIP_DSTS_RxCOLLSEEN 0x00000040 /* Collision Seen */ +#define TULIP_DSTS_RxFRAMETYPE 0x00000020 /* Frame Type */ +#define TULIP_DSTS_RxWATCHDOG 0x00000010 /* Receive Watchdog */ +#define TULIP_DSTS_RxDRBBLBIT 0x00000004 /* Dribble Bit */ +#define TULIP_DSTS_RxBADCRC 0x00000002 /* CRC Error */ +#define TULIP_DSTS_RxOVERFLOW 0x00000001 /* Overflow */ + + +#define TULIP_DFLAG_ENDRING 0x0008 /* End of Transmit Ring */ +#define TULIP_DFLAG_CHAIN 0x0004 /* Chain using d_addr2 */ + +#define TULIP_DFLAG_TxWANTINTR 0x0200 /* Signal Interrupt on Completion */ +#define TULIP_DFLAG_TxLASTSEG 0x0100 /* Last Segment */ +#define TULIP_DFLAG_TxFIRSTSEG 0x0080 /* First Segment */ +#define TULIP_DFLAG_TxINVRSFILT 0x0040 /* Inverse Filtering */ +#define TULIP_DFLAG_TxSETUPPKT 0x0020 /* Setup Packet */ +#define TULIP_DFLAG_TxHASCRC 0x0010 /* Don't Append the CRC */ +#define TULIP_DFLAG_TxNOPADDING 0x0002 /* Don't AutoPad */ +#define TULIP_DFLAG_TxHASHFILT 0x0001 /* Hash/Perfect Filtering */ + +/* + * The DC21040 Registers (IO Space Addresses) + */ +#define TULIP_REG_BUSMODE 0x00 /* CSR0 -- Bus Mode */ +#define TULIP_REG_TXPOLL 0x08 /* CSR1 -- Transmit Poll Demand */ +#define TULIP_REG_RXPOLL 0x10 /* CSR2 -- Receive Poll Demand */ +#define TULIP_REG_RXLIST 0x18 /* CSR3 -- Receive List Base Addr */ +#define TULIP_REG_TXLIST 0x20 /* CSR4 -- Transmit List Base Addr */ +#define TULIP_REG_STATUS 0x28 /* CSR5 -- Status */ +#define TULIP_REG_CMD 0x30 /* CSR6 -- Command */ +#define TULIP_REG_INTR 0x38 /* CSR7 -- Interrupt Control */ +#define TULIP_REG_MISSES 0x40 /* CSR8 -- Missed Frame Counter */ +#define TULIP_REG_ADDRROM 0x48 /* CSR9 -- ENET ROM Register */ +#define TULIP_REG_RSRVD 0x50 /* CSR10 -- Reserved */ +#define TULIP_REG_FULL_DUPLEX 0x58 /* CSR11 -- Full Duplex */ +#define TULIP_REG_SIA_STATUS 0x60 /* CSR12 -- SIA Status */ +#define TULIP_REG_SIA_CONN 0x68 /* CSR13 -- SIA Connectivity */ +#define TULIP_REG_SIA_TXRX 0x70 /* CSR14 -- SIA Tx Rx */ +#define TULIP_REG_SIA_GEN 0x78 /* CSR15 -- SIA General */ + +/* + * CSR5 -- Status Register + * CSR7 -- Interrupt Control + */ +#define TULIP_STS_ERRORMASK 0x03800000L /* ( R) Error Bits (Valid when SYSERROR is set) */ +#define TULIP_STS_ERR_PARITY 0x00000000L /* 000 - Parity Error (Perform Reset) */ +#define TULIP_STS_ERR_MASTER 0x00800000L /* 001 - Master Abort */ +#define TULIP_STS_ERR_TARGET 0x01000000L /* 010 - Target Abort */ +#define TULIP_STS_TXSTATEMASK 0x00700000L /* ( R) Transmission Process State */ +#define TULIP_STS_TXS_RESET 0x00000000L /* 000 - Rset or transmit jabber expired */ +#define TULIP_STS_TXS_FETCH 0x00100000L /* 001 - Fetching transmit descriptor */ +#define TULIP_STS_TXS_WAITEND 0x00200000L /* 010 - Wait for end of transmission */ +#define TULIP_STS_TXS_READING 0x00300000L /* 011 - Read buffer and enqueue data */ +#define TULIP_STS_TXS_RSRVD 0x00400000L /* 100 - Reserved */ +#define TULIP_STS_TXS_SETUP 0x00500000L /* 101 - Setup Packet */ +#define TULIP_STS_TXS_SUSPEND 0x00600000L /* 110 - Transmit FIFO underflow or an + unavailable transmit descriptor */ +#define TULIP_STS_TXS_CLOSE 0x00700000L /* 111 - Close transmit descriptor */ +#define TULIP_STS_RXSTATEMASK 0x000E0000L /* ( R) Receive Process State*/ +#define TULIP_STS_RXS_STOPPED 0x00000000L /* 000 - Stopped */ +#define TULIP_STS_RXS_FETCH 0x00020000L /* 001 - Running -- Fetch receive descriptor */ +#define TULIP_STS_RXS_ENDCHECK 0x00040000L /* 010 - Running -- Check for end of receive + packet before prefetch of next descriptor */ +#define TULIP_STS_RXS_WAIT 0x00060000L /* 011 - Running -- Wait for receive packet */ +#define TULIP_STS_RXS_SUSPEND 0x00080000L /* 100 - Suspended -- As a result of + unavailable receive buffers */ +#define TULIP_STS_RXS_CLOSE 0x000A0000L /* 101 - Running -- Close receive descriptor */ +#define TULIP_STS_RXS_FLUSH 0x000C0000L /* 110 - Running -- Flush the current frame + from the receive FIFO as a result of + an unavailable receive buffer */ +#define TULIP_STS_RXS_DEQUEUE 0x000E0000L /* 111 - Running -- Dequeue the receive frame + from the receive FIFO into the receive + buffer. */ +#define TULIP_STS_NORMALINTR 0x00010000L /* (RW) Normal Interrupt */ +#define TULIP_STS_ABNRMLINTR 0x00008000L /* (RW) Abnormal Interrupt */ +#define TULIP_STS_SYSERROR 0x00002000L /* (RW) System Error */ +#define TULIP_STS_LINKFAIL 0x00001000L /* (RW) Link Failure (DC21040) */ +#define TULIP_STS_FULDPLXSHRT 0x00000800L /* (RW) Full Duplex Short Fram Rcvd (DC21040) */ +#define TULIP_STS_GPTIMEOUT 0x00000800L /* (RW) General Purpose Timeout (DC21140) */ +#define TULIP_STS_AUI 0x00000400L /* (RW) AUI/TP Switch (DC21040) */ +#define TULIP_STS_RXTIMEOUT 0x00000200L /* (RW) Receive Watchbog Timeout */ +#define TULIP_STS_RXSTOPPED 0x00000100L /* (RW) Receive Process Stopped */ +#define TULIP_STS_RXNOBUF 0x00000080L /* (RW) Receive Buffer Unavailable */ +#define TULIP_STS_RXINTR 0x00000040L /* (RW) Receive Interrupt */ +#define TULIP_STS_TXUNDERFLOW 0x00000020L /* (RW) Transmit Underflow */ +#define TULIP_STS_LINKPASS 0x00000010L /* (RW) LinkPass (DC21041) */ +#define TULIP_STS_TXBABBLE 0x00000008L /* (RW) Transmit Jabber Timeout */ +#define TULIP_STS_TXNOBUF 0x00000004L /* (RW) Transmit Buffer Unavailable */ +#define TULIP_STS_TXSTOPPED 0x00000002L /* (RW) Transmit Process Stopped */ +#define TULIP_STS_TXINTR 0x00000001L /* (RW) Transmit Interrupt */ + +/* + * CSR6 -- Command (Operation Mode) Register + */ +#define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (DC21140) */ +#define TULIP_CMD_SCRAMBLER 0x01000000L /* (RW) Scrambler Mode (DC21140) */ +#define TULIP_CMD_PCSFUNCTION 0x00800000L /* (RW) PCS Function (DC21140) */ +#define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (DC21140) */ +#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (DC21140) */ +#define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (DC21140) */ +#define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (DC21140) */ +#define TULIP_CMD_ENHCAPTEFFCT 0x00040000L /* (RW) Enhanced Capture Effecty (DC21041) */ +#define TULIP_CMD_CAPTREFFCT 0x00020000L /* (RW) Capture Effect (!802.3) */ +#define TULIP_CMD_BACKPRESSURE 0x00010000L /* (RW) Back Pressure (!802.3) (DC21040) */ +#define TULIP_CMD_THRESHOLDCTL 0x0000C000L /* (RW) Threshold Control */ +#define TULIP_CMD_THRSHLD72 0x00000000L /* 00 - 72 Bytes */ +#define TULIP_CMD_THRSHLD96 0x00004000L /* 01 - 96 Bytes */ +#define TULIP_CMD_THRSHLD128 0x00008000L /* 10 - 128 bytes */ +#define TULIP_CMD_THRSHLD160 0x0000C000L /* 11 - 160 Bytes */ +#define TULIP_CMD_TXRUN 0x00002000L /* (RW) Start/Stop Transmitter */ +#define TULIP_CMD_FORCECOLL 0x00001000L /* (RW) Force Collisions */ +#define TULIP_CMD_OPERMODE 0x00000C00L /* (RW) Operating Mode */ +#define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */ +#define TULIP_CMD_FLAKYOSCDIS 0x00000100L /* (RW) Flakey Oscillator Disable */ +#define TULIP_CMD_ALLMULTI 0x00000080L /* (RW) Pass All Multicasts */ +#define TULIP_CMD_PROMISCUOUS 0x00000040L /* (RW) Promiscuous Mode */ +#define TULIP_CMD_BACKOFFCTR 0x00000020L /* (RW) Start/Stop Backoff Counter (!802.3) */ +#define TULIP_CMD_INVFILTER 0x00000010L /* (R ) Inverse Filtering */ +#define TULIP_CMD_PASSBADPKT 0x00000008L /* (RW) Pass Bad Frames */ +#define TULIP_CMD_HASHONLYFLTR 0x00000004L /* (R ) Hash Only Filtering */ +#define TULIP_CMD_RXRUN 0x00000002L /* (RW) Start/Stop Receive Filtering */ +#define TULIP_CMD_HASHPRFCTFLTR 0x00000001L /* (R ) Hash/Perfect Receive Filtering */ + + +#define TULIP_SIASTS_OTHERRXACTIVITY 0x00000200L +#define TULIP_SIASTS_RXACTIVITY 0x00000100L +#define TULIP_SIASTS_LINKFAIL 0x00000004L +#define TULIP_SIACONN_RESET 0x00000000L + +#define TULIP_SIACONN_AUI 0x0000000DL +#define TULIP_SIACONN_10BASET 0x00000005L + +#define TULIP_DC21041_SIACONN_10BASET 0x0000EF01L +#define TULIP_DC21041_SIATXRX_10BASET 0x0000FF3FL +#define TULIP_DC21041_SIAGEN_10BASET 0x00000000L + +#define TULIP_DC21041_SIACONN_AUI 0x0000EF09L +#define TULIP_DC21041_SIATXRX_AUI 0x0000F73DL +#define TULIP_DC21041_SIAGEN_AUI 0x0000000EL + +#define TULIP_DC21041_SIACONN_BNC 0x0000EF09L +#define TULIP_DC21041_SIATXRX_BNC 0x0000F73DL +#define TULIP_DC21041_SIAGEN_BNC 0x00000006L + +#define TULIP_BUSMODE_SWRESET 0x00000001L +#define TULIP_BUSMODE_DESCSKIPLEN_MASK 0x0000007CL +#define TULIP_BUSMODE_BIGENDIAN 0x00000080L +#define TULIP_BUSMODE_BURSTLEN_MASK 0x00003F00L +#define TULIP_BUSMODE_BURSTLEN_DEFAULT 0x00000000L +#define TULIP_BUSMODE_BURSTLEN_1LW 0x00000100L +#define TULIP_BUSMODE_BURSTLEN_2LW 0x00000200L +#define TULIP_BUSMODE_BURSTLEN_4LW 0x00000400L +#define TULIP_BUSMODE_BURSTLEN_8LW 0x00000800L +#define TULIP_BUSMODE_BURSTLEN_16LW 0x00001000L +#define TULIP_BUSMODE_BURSTLEN_32LW 0x00002000L +#define TULIP_BUSMODE_CACHE_NOALIGN 0x00000000L +#define TULIP_BUSMODE_CACHE_ALIGN8 0x00004000L +#define TULIP_BUSMODE_CACHE_ALIGN16 0x00008000L +#define TULIP_BUSMODE_CACHE_ALIGN32 0x0000C000L +#define TULIP_BUSMODE_TXPOLL_NEVER 0x00000000L +#define TULIP_BUSMODE_TXPOLL_200000ns 0x00020000L +#define TULIP_BUSMODE_TXPOLL_800000ns 0x00040000L +#define TULIP_BUSMODE_TXPOLL_1600000ns 0x00060000L +#define TULIP_BUSMODE_TXPOLL_12800ns 0x00080000L /* DC21041 only */ +#define TULIP_BUSMODE_TXPOLL_25600ns 0x000A0000L /* DC21041 only */ +#define TULIP_BUSMODE_TXPOLL_51200ns 0x000C0000L /* DC21041 only */ +#define TULIP_BUSMODE_TXPOLL_102400ns 0x000E0000L /* DC21041 only */ +#define TULIP_BUSMODE_DESC_BIGENDIAN 0x00100000L /* DC21041 only */ + +/* + * These are the defintitions used for the DEC DC21140 + * evaluation board. + */ +#define TULIP_GP_EB_PINS 0x0000011F /* General Purpose Pin directions */ +#define TULIP_GP_EB_OK10 0x00000080 /* 10 Mb/sec Signal Detect gep<7> */ +#define TULIP_GP_EB_OK100 0x00000040 /* 100 Mb/sec Signal Detect gep<6> */ +#define TULIP_GP_EB_INIT 0x0000000B /* No loopback --- point-to-point */ + +/* + * There are the definitions used for the DEC DE500-XA + * 10/100 board + */ +#define TULIP_GP_DE500_PINS 0x0000010FL +#define TULIP_GP_DE500_NOTOK_10 0x00000080L +#define TULIP_GP_DE500_NOTOK_100 0x00000040L +#define TULIP_GP_DE500_HALFDUPLEX 0x00000008L +#define TULIP_GP_DE500_FORCE_100 0x00000001L + +/* + * These are the defintitions used for the Cogent EM100 + * DC21140 board. + */ +#define TULIP_GP_EM100_PINS 0x0000013F /* General Purpose Pin directions */ +#define TULIP_GP_EM100_INIT 0x00000009 /* No loopback --- point-to-point */ +#define TULIP_OUI_COGENT_0 0x00 +#define TULIP_OUI_COGENT_1 0x00 +#define TULIP_OUI_COGENT_2 0x94 +#define TULIP_COGENT_EM100_ID 0x12 + + +/* + * These are the defintitions used for the Znyx ZX342 + * 10/100 board + */ +#define TULIP_GP_ZX34X_PINS 0x0000011F /* General Purpose Pin directions */ +#define TULIP_GP_ZX34X_OK10 0x00000080 /* 10 Mb/sec Signal Detect gep<7> */ +#define TULIP_GP_ZX34X_OK100 0x00000040 /* 100 Mb/sec Signal Detect gep<6> */ +#define TULIP_GP_ZX34X_INIT 0x00000009 +#define TULIP_OUI_ZNYX_0 0x00 +#define TULIP_OUI_ZNYX_1 0xC0 +#define TULIP_OUI_ZNYX_2 0x95 + + +/* + * SROM definitions for the DC21140 and DC21041. + */ +#define SROMSEL 0x0800 +#define SROMRD 0x4000 +#define SROMWR 0x2000 +#define SROMDIN 0x0008 +#define SROMDOUT 0x0004 +#define SROMDOUTON 0x0004 +#define SROMDOUTOFF 0x0004 +#define SROMCLKON 0x0002 +#define SROMCLKOFF 0x0002 +#define SROMCSON 0x0001 +#define SROMCSOFF 0x0001 +#define SROMCS 0x0001 + +#define SROMCMD_MODE 4 +#define SROMCMD_WR 5 +#define SROMCMD_RD 6 + +#define SROM_BITWIDTH 6 + +/* + * Definitions for the DE425. + */ +#define DE425_CFID 0x08 /* Configuration Id */ +#define DE425_CFCS 0x0C /* Configuration Command-Status */ +#define DE425_CFRV 0x18 /* Configuration Revision */ +#define DE425_CFLT 0x1C /* Configuration Latency Timer */ +#define DE425_CBIO 0x28 /* Configuration Base IO Address */ +#define DE425_CFDA 0x2C /* Configuration Driver Area */ +#define DE425_ENETROM_OFFSET 0xC90 /* Offset in I/O space for ENETROM */ +#define DE425_CFG0 0xC88 /* IRQ register */ + +#define DEC_VENDORID 0x1011 +#define DC21040_CHIPID 0x0002 +#define DC21140_CHIPID 0x0009 +#define DC21041_CHIPID 0x0014 +#define PCI_VENDORID(x) ((x) & 0xFFFF) +#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF) + +#endif /* !defined(_DC21040_H) */ diff --git a/sys/dev/ic/dp8390reg.h b/sys/dev/ic/dp8390reg.h new file mode 100644 index 00000000000..ba7aad30bda --- /dev/null +++ b/sys/dev/ic/dp8390reg.h @@ -0,0 +1,550 @@ +/* $NetBSD: dp8390reg.h,v 1.2 1995/04/12 16:12:42 mycroft Exp $ */ + +/* + * National Semiconductor DS8390 NIC register definitions. + * + * Copyright (C) 1993, David Greenman. This software may be used, modified, + * copied, distributed, and sold, in both source and binary form provided that + * the above copyright and these terms are retained. Under no circumstances is + * the author responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its use. + */ + +/* + * Page 0 register offsets + */ +#define ED_P0_CR 0x00 /* Command Register */ + +#define ED_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */ +#define ED_P0_PSTART 0x01 /* Page Start register (write) */ + +#define ED_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */ +#define ED_P0_PSTOP 0x02 /* Page Stop register (write) */ + +#define ED_P0_BNRY 0x03 /* Boundary Pointer */ + +#define ED_P0_TSR 0x04 /* Transmit Status Register (read) */ +#define ED_P0_TPSR 0x04 /* Transmit Page Start (write) */ + +#define ED_P0_NCR 0x05 /* Number of Collisions Reg (read) */ +#define ED_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */ + +#define ED_P0_FIFO 0x06 /* FIFO register (read) */ +#define ED_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */ + +#define ED_P0_ISR 0x07 /* Interrupt Status Register */ + +#define ED_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */ +#define ED_P0_RSAR0 0x08 /* Remote Start Address low (write) */ + +#define ED_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */ +#define ED_P0_RSAR1 0x09 /* Remote Start Address high (write) */ + +#define ED_P0_RBCR0 0x0a /* Remote Byte Count low (write) */ + +#define ED_P0_RBCR1 0x0b /* Remote Byte Count high (write) */ + +#define ED_P0_RSR 0x0c /* Receive Status (read) */ +#define ED_P0_RCR 0x0c /* Receive Configuration Reg (write) */ + +#define ED_P0_CNTR0 0x0d /* frame alignment error counter (read) */ +#define ED_P0_TCR 0x0d /* Transmit Configuration Reg (write) */ + +#define ED_P0_CNTR1 0x0e /* CRC error counter (read) */ +#define ED_P0_DCR 0x0e /* Data Configuration Reg (write) */ + +#define ED_P0_CNTR2 0x0f /* missed packet counter (read) */ +#define ED_P0_IMR 0x0f /* Interrupt Mask Register (write) */ + +/* + * Page 1 register offsets + */ +#define ED_P1_CR 0x00 /* Command Register */ +#define ED_P1_PAR0 0x01 /* Physical Address Register 0 */ +#define ED_P1_PAR1 0x02 /* Physical Address Register 1 */ +#define ED_P1_PAR2 0x03 /* Physical Address Register 2 */ +#define ED_P1_PAR3 0x04 /* Physical Address Register 3 */ +#define ED_P1_PAR4 0x05 /* Physical Address Register 4 */ +#define ED_P1_PAR5 0x06 /* Physical Address Register 5 */ +#define ED_P1_CURR 0x07 /* Current RX ring-buffer page */ +#define ED_P1_MAR0 0x08 /* Multicast Address Register 0 */ +#define ED_P1_MAR1 0x09 /* Multicast Address Register 1 */ +#define ED_P1_MAR2 0x0a /* Multicast Address Register 2 */ +#define ED_P1_MAR3 0x0b /* Multicast Address Register 3 */ +#define ED_P1_MAR4 0x0c /* Multicast Address Register 4 */ +#define ED_P1_MAR5 0x0d /* Multicast Address Register 5 */ +#define ED_P1_MAR6 0x0e /* Multicast Address Register 6 */ +#define ED_P1_MAR7 0x0f /* Multicast Address Register 7 */ + +/* + * Page 2 register offsets + */ +#define ED_P2_CR 0x00 /* Command Register */ +#define ED_P2_PSTART 0x01 /* Page Start (read) */ +#define ED_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */ +#define ED_P2_PSTOP 0x02 /* Page Stop (read) */ +#define ED_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */ +#define ED_P2_RNPP 0x03 /* Remote Next Packet Pointer */ +#define ED_P2_TPSR 0x04 /* Transmit Page Start (read) */ +#define ED_P2_LNPP 0x05 /* Local Next Packet Pointer */ +#define ED_P2_ACU 0x06 /* Address Counter Upper */ +#define ED_P2_ACL 0x07 /* Address Counter Lower */ +#define ED_P2_RCR 0x0c /* Receive Configuration Register (read) */ +#define ED_P2_TCR 0x0d /* Transmit Configuration Register (read) */ +#define ED_P2_DCR 0x0e /* Data Configuration Register (read) */ +#define ED_P2_IMR 0x0f /* Interrupt Mask Register (read) */ + +/* + * Command Register (CR) definitions + */ + +/* + * STP: SToP. Software reset command. Takes the controller offline. No + * packets will be received or transmitted. Any reception or transmission in + * progress will continue to completion before entering reset state. To exit + * this state, the STP bit must reset and the STA bit must be set. The + * software reset has executed only when indicated by the RST bit in the ISR + * being set. + */ +#define ED_CR_STP 0x01 + +/* + * STA: STArt. This bit is used to activate the NIC after either power-up, or + * when the NIC has been put in reset mode by software command or error. + */ +#define ED_CR_STA 0x02 + +/* + * TXP: Transmit Packet. This bit must be set to indicate transmission of a + * packet. TXP is internally reset either after the transmission is completed + * or aborted. This bit should be set only after the Transmit Byte Count and + * Transmit Page Start register have been programmed. + */ +#define ED_CR_TXP 0x04 + +/* + * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation + * of the remote DMA channel. RD2 can be set to abort any remote DMA command + * in progress. The Remote Byte Count registers should be cleared when a + * remote DMA has been aborted. The Remote Start Addresses are not restored + * to the starting address if the remote DMA is aborted. + * + * RD2 RD1 RD0 function + * 0 0 0 not allowed + * 0 0 1 remote read + * 0 1 0 remote write + * 0 1 1 send packet + * 1 X X abort + */ +#define ED_CR_RD0 0x08 +#define ED_CR_RD1 0x10 +#define ED_CR_RD2 0x20 + +/* + * PS0, PS1: Page Select. The two bits select which register set or 'page' to + * access. + * + * PS1 PS0 page + * 0 0 0 + * 0 1 1 + * 1 0 2 + * 1 1 reserved + */ +#define ED_CR_PS0 0x40 +#define ED_CR_PS1 0x80 +/* bit encoded aliases */ +#define ED_CR_PAGE_0 0x00 /* (for consistency) */ +#define ED_CR_PAGE_1 0x40 +#define ED_CR_PAGE_2 0x80 + +/* + * Interrupt Status Register (ISR) definitions + */ + +/* + * PRX: Packet Received. Indicates packet received with no errors. + */ +#define ED_ISR_PRX 0x01 + +/* + * PTX: Packet Transmitted. Indicates packet transmitted with no errors. + */ +#define ED_ISR_PTX 0x02 + +/* + * RXE: Receive Error. Indicates that a packet was received with one or more + * the following errors: CRC error, frame alignment error, FIFO overrun, + * missed packet. + */ +#define ED_ISR_RXE 0x04 + +/* + * TXE: Transmission Error. Indicates that an attempt to transmit a packet + * resulted in one or more of the following errors: excessive collisions, FIFO + * underrun. + */ +#define ED_ISR_TXE 0x08 + +/* + * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network + * would exceed (has exceeded?) the boundary pointer, resulting in data that + * was previously received and not yet read from the buffer to be overwritten. + */ +#define ED_ISR_OVW 0x10 + +/* + * CNT: Counter Overflow. Set when the MSB of one or more of the Network Tally + * Counters has been set. + */ +#define ED_ISR_CNT 0x20 + +/* + * RDC: Remote Data Complete. Indicates that a Remote DMA operation has + * completed. + */ +#define ED_ISR_RDC 0x40 + +/* + * RST: Reset status. Set when the NIC enters the reset state and cleared when + * a Start Command is issued to the CR. This bit is also set when a receive + * ring-buffer overrun (OverWrite) occurs and is cleared when one or more + * packets have been removed from the ring. This is a read-only bit. + */ +#define ED_ISR_RST 0x80 + +/* + * Interrupt Mask Register (IMR) definitions + */ + +/* + * PRXE: Packet Received interrupt Enable. If set, a received packet will + * cause an interrupt. + */ +#define ED_IMR_PRXE 0x01 + +/* + * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated + * when a packet transmission completes. + */ +#define ED_IMR_PTXE 0x02 + +/* + * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur + * whenever a packet is received with an error. + */ +#define ED_IMR_RXEE 0x04 + +/* + * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur + * whenever a transmission results in an error. + */ +#define ED_IMR_TXEE 0x08 + +/* + * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated + * whenever the receive ring-buffer is overrun. i.e. when the boundary pointer + * is exceeded. + */ +#define ED_IMR_OVWE 0x10 + +/* + * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated + * whenever the MSB of one or more of the Network Statistics counters has been + * set. + */ +#define ED_IMR_CNTE 0x20 + +/* + * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is + * generated when a remote DMA transfer has completed. + */ +#define ED_IMR_RDCE 0x40 + +/* + * Bit 7 is unused/reserved. + */ + +/* + * Data Configuration Register (DCR) definitions + */ + +/* + * WTS: Word Transfer Select. WTS establishes byte or word transfers for both + * remote and local DMA transfers + */ +#define ED_DCR_WTS 0x01 + +/* + * BOS: Byte Order Select. BOS sets the byte order for the host. Should be 0 + * for 80x86, and 1 for 68000 series processors + */ +#define ED_DCR_BOS 0x02 + +/* + * LAS: Long Address Select. When LAS is 1, the contents of the remote DMA + * registers RSAR0 and RSAR1 are used to provide A16-A31. + */ +#define ED_DCR_LAS 0x04 + +/* + * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2 of + * the TCR must also be programmed for loopback operation. When 1, normal + * operation is selected. + */ +#define ED_DCR_LS 0x08 + +/* + * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer + * under program control. When 1, remote DMA is automatically initiated and + * the boundary pointer is automatically updated. + */ +#define ED_DCR_AR 0x10 + +/* + * FT0, FT1: Fifo Threshold select. + * + * FT1 FT0 Word-width Byte-width + * 0 0 1 word 2 bytes + * 0 1 2 words 4 bytes + * 1 0 4 words 8 bytes + * 1 1 8 words 12 bytes + * + * During transmission, the FIFO threshold indicates the number of bytes or + * words that the FIFO has filled from the local DMA before BREQ is asserted. + * The transmission threshold is 16 bytes minus the receiver threshold. + */ +#define ED_DCR_FT0 0x20 +#define ED_DCR_FT1 0x40 + +/* + * bit 7 (0x80) is unused/reserved + */ + +/* + * Transmit Configuration Register (TCR) definitions + */ + +/* + * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC + * is not appended by the transmitter. + */ +#define ED_TCR_CRC 0x01 + +/* + * LB0, LB1: Loopback control. These two bits set the type of loopback that is + * to be performed. + * + * LB1 LB0 mode + * 0 0 0 - normal operation (DCR_LS = 0) + * 0 1 1 - internal loopback (DCR_LS = 0) + * 1 0 2 - external loopback (DCR_LS = 1) + * 1 1 3 - external loopback (DCR_LS = 0) + */ +#define ED_TCR_LB0 0x02 +#define ED_TCR_LB1 0x04 + +/* + * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows + * another station to disable the NIC's transmitter by transmitting to a + * multicast address hashing to bit 62. Reception of a multicast address + * hashing to bit 63 enables the transmitter. + */ +#define ED_TCR_ATD 0x08 + +/* + * OFST: Collision Offset enable. This bit when set modifies the backoff + * algorithm to allow prioritization of nodes. + */ +#define ED_TCR_OFST 0x10 + +/* + * bits 5, 6, and 7 are unused/reserved + */ + +/* + * Transmit Status Register (TSR) definitions + */ + +/* + * PTX: Packet Transmitted. Indicates successful transmission of packet. + */ +#define ED_TSR_PTX 0x01 + +/* + * bit 1 (0x02) is unused/reserved + */ + +/* + * COL: Transmit Collided. Indicates that the transmission collided at least + * once with another station on the network. + */ +#define ED_TSR_COL 0x04 + +/* + * ABT: Transmit aborted. Indicates that the transmission was aborted due to + * excessive collisions. + */ +#define ED_TSR_ABT 0x08 + +/* + * CRS: Carrier Sense Lost. Indicates that carrier was lost during the + * transmission of the packet. (Transmission is not aborted because of a loss + * of carrier). + */ +#define ED_TSR_CRS 0x10 + +/* + * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/ + * transmission memory before the FIFO emptied. Transmission of the packet was + * aborted. + */ +#define ED_TSR_FU 0x20 + +/* + * CDH: CD Heartbeat. Indicates that the collision detection circuitry isn't + * working correctly during a collision heartbeat test. + */ +#define ED_TSR_CDH 0x40 + +/* + * OWC: Out of Window Collision: Indicates that a collision occurred after a + * slot time (51.2us). The transmission is rescheduled just as in normal + * collisions. + */ +#define ED_TSR_OWC 0x80 + +/* + * Receiver Configuration Register (RCR) definitions + */ + +/* + * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1, + * packets with CRC and frame errors are not discarded. + */ +#define ED_RCR_SEP 0x01 + +/* + * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded. + * If set to 1, packets with less than 64 byte are not discarded. + */ +#define ED_RCR_AR 0x02 + +/* + * AB: Accept Broadcast. If set, packets sent to the broadcast address will be + * accepted. + */ +#define ED_RCR_AB 0x04 + +/* + * AM: Accept Multicast. If set, packets sent to a multicast address are + * checked for a match in the hashing array. If clear, multicast packets are + * ignored. + */ +#define ED_RCR_AM 0x08 + +/* + * PRO: Promiscuous Physical. If set, all packets with a physical addresses + * are accepted. If clear, a physical destination address must match this + * station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM must + * also be set. In addition, the multicast hashing array must be set to all + * 1's so that all multicast addresses are accepted. + */ +#define ED_RCR_PRO 0x10 + +/* + * MON: Monitor Mode. If set, packets will be checked for good CRC and + * framing, but are not stored in the ring-buffer. If clear, packets are + * stored (normal operation). + */ +#define ED_RCR_MON 0x20 + +/* + * Bits 6 and 7 are unused/reserved. + */ + +/* + * Receiver Status Register (RSR) definitions + */ + +/* + * PRX: Packet Received without error. + */ +#define ED_RSR_PRX 0x01 + +/* + * CRC: CRC error. Indicates that a packet has a CRC error. Also set for + * frame alignment errors. + */ +#define ED_RSR_CRC 0x02 + +/* + * FAE: Frame Alignment Error. Indicates that the incoming packet did not end + * on a byte boundary and the CRC did not match at the last byte boundary. + */ +#define ED_RSR_FAE 0x04 + +/* + * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local + * DMA) causing it to overrun. Reception of the packet is aborted. + */ +#define ED_RSR_FO 0x08 + +/* + * MPA: Missed Packet. Indicates that the received packet couldn't be stored + * in the ring-buffer because of insufficient buffer space (exceeding the + * boundary pointer), or because the transfer to the ring-buffer was inhibited + * by RCR_MON - monitor mode. + */ +#define ED_RSR_MPA 0x10 + +/* + * PHY: Physical address. If 0, the packet received was sent to a physical + * address. If 1, the packet was accepted because of a multicast/broadcast + * address match. + */ +#define ED_RSR_PHY 0x20 + +/* + * DIS: Receiver Disabled. Set to indicate that the receiver has enetered + * monitor mode. Cleared when the receiver exits monitor mode. + */ +#define ED_RSR_DIS 0x40 + +/* + * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL + * inputs are active, and the transceiver has set the CD line as a result of + * the jabber. + */ +#define ED_RSR_DFR 0x80 + +/* + * receive ring discriptor + * + * The National Semiconductor DS8390 Network interface controller uses the + * following receive ring headers. The way this works is that the memory on + * the interface card is chopped up into 256 bytes blocks. A contiguous + * portion of those blocks are marked for receive packets by setting start and + * end block #'s in the NIC. For each packet that is put into the receive + * ring, one of these headers (4 bytes each) is tacked onto the front. The + * first byte is a copy of the receiver status register at the time the packet + * was received. + */ +struct ed_ring { +#if BYTE_ORDER == BIG_ENDIAN + u_char next_packet; /* pointer to next packet */ + u_char rsr; /* receiver status */ +#else + u_char rsr; /* receiver status */ + u_char next_packet; /* pointer to next packet */ +#endif + u_short count; /* bytes in packet (length + 4) */ +}; + +/* + * Common constants + */ +#define ED_PAGE_SIZE 256 /* Size of RAM pages in bytes */ +#define ED_PAGE_MASK 255 +#define ED_PAGE_SHIFT 8 + +#define ED_TXBUF_SIZE 6 /* Size of TX buffer in pages */ diff --git a/sys/dev/ic/i8042reg.h b/sys/dev/ic/i8042reg.h new file mode 100644 index 00000000000..b2fc306d4d5 --- /dev/null +++ b/sys/dev/ic/i8042reg.h @@ -0,0 +1,44 @@ +/* $NetBSD: i8042reg.h,v 1.6 1995/04/21 09:16:16 mycroft Exp $ */ + +#define KBSTATP 0x64 /* kbd controller status port (I) */ +#define KBS_DIB 0x01 /* kbd data in buffer */ +#define KBS_IBF 0x02 /* kbd input buffer low */ +#define KBS_WARM 0x04 /* kbd input buffer low */ +#define KBS_OCMD 0x08 /* kbd output buffer has command */ +#define KBS_NOSEC 0x10 /* kbd security lock not engaged */ +#define KBS_TERR 0x20 /* kbd transmission error */ +#define KBS_RERR 0x40 /* kbd receive error */ +#define KBS_PERR 0x80 /* kbd parity error */ + +#define KBCMDP 0x64 /* kbd controller port (O) */ +#define KBC_RAMREAD 0x20 /* read from RAM */ +#define KBC_RAMWRITE 0x60 /* write to RAM */ +#define KBC_AUXDISABLE 0xa7 /* disable auxiliary port */ +#define KBC_AUXENABLE 0xa8 /* enable auxiliary port */ +#define KBC_AUXTEST 0xa9 /* test auxiliary port */ +#define KBC_KBDECHO 0xd2 /* echo to keyboard port */ +#define KBC_AUXECHO 0xd3 /* echo to auxiliary port */ +#define KBC_AUXWRITE 0xd4 /* write to auxiliary port */ +#define KBC_SELFTEST 0xaa /* start self-test */ +#define KBC_KBDTEST 0xab /* test keyboard port */ +#define KBC_KBDDISABLE 0xad /* disable keyboard port */ +#define KBC_KBDENABLE 0xae /* enable keyboard port */ +#define KBC_PULSE0 0xfe /* pulse output bit 0 */ +#define KBC_PULSE1 0xfd /* pulse output bit 1 */ +#define KBC_PULSE2 0xfb /* pulse output bit 2 */ +#define KBC_PULSE3 0xf7 /* pulse output bit 3 */ + +#define KBDATAP 0x60 /* kbd data port (I) */ +#define KBOUTP 0x60 /* kbd data port (O) */ + +#define K_RDCMDBYTE 0x20 +#define K_LDCMDBYTE 0x60 + +#define KC8_TRANS 0x40 /* convert to old scan codes */ +#define KC8_MDISABLE 0x20 /* disable mouse */ +#define KC8_KDISABLE 0x10 /* disable keyboard */ +#define KC8_IGNSEC 0x08 /* ignore security lock */ +#define KC8_CPU 0x04 /* exit from protected mode reset */ +#define KC8_MENABLE 0x02 /* enable mouse interrupt */ +#define KC8_KENABLE 0x01 /* enable keyboard interrupt */ +#define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) diff --git a/sys/dev/ic/i8237reg.h b/sys/dev/ic/i8237reg.h new file mode 100644 index 00000000000..68a4e767930 --- /dev/null +++ b/sys/dev/ic/i8237reg.h @@ -0,0 +1,13 @@ +/* $NetBSD: i8237reg.h,v 1.4 1994/10/27 04:18:39 cgd Exp $ */ + +/* + * Intel 8237 DMA Controller + */ + +#define DMA37MD_SINGLE 0x40 /* single pass mode */ +#define DMA37MD_CASCADE 0xc0 /* cascade mode */ +#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */ +#define DMA37MD_READ 0x08 /* write the device, read memory operation */ + +#define DMA37SM_CLEAR 0x00 /* clear mask bit */ +#define DMA37SM_SET 0x04 /* set mask bit */ diff --git a/sys/dev/ic/i82586reg.h b/sys/dev/ic/i82586reg.h new file mode 100644 index 00000000000..fefaed3e346 --- /dev/null +++ b/sys/dev/ic/i82586reg.h @@ -0,0 +1,289 @@ +/* $NetBSD: i82586reg.h,v 1.5 1995/04/04 01:59:34 mycroft Exp $ */ + +/*- + * Copyright (c) 1992, University of Vermont and State Agricultural College. + * Copyright (c) 1992, Garrett A. Wollman. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * Vermont and State Agricultural College and Garrett A. Wollman. + * 4. Neither the name of the University nor the name of the author + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Intel 82586 Ethernet chip + * Register, bit, and structure definitions. + * + * Written by GAW with reference to the Clarkson Packet Driver code for this + * chip written by Russ Nelson and others. + */ + +struct ie_en_addr { + u_char data[6]; +}; + +/* + * This is the master configuration block. It tells the hardware where all + * the rest of the stuff is. + */ +struct ie_sys_conf_ptr { + u_short mbz; /* must be zero */ + u_char ie_bus_use; /* true if 8-bit only */ + u_char mbz2[5]; /* must be zero */ + caddr_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */ +}; + +/* + * Note that this is wired in hardware; the SCP is always located here, no + * matter what. + */ +#define IE_SCP_ADDR 0xfffff4 + +/* + * The tells the hardware where all the rest of the stuff is, too. + * FIXME: some of these should be re-commented after we figure out their + * REAL function. + */ +struct ie_int_sys_conf_ptr { + u_char ie_busy; /* zeroed after init */ + u_char mbz; + u_short ie_scb_offset; /* 16-bit physaddr of next struct */ + caddr_t ie_base; /* 24-bit physaddr for all 16-bit vars */ +}; + +/* + * This FINALLY tells the hardware what to do and where to put it. + */ +struct ie_sys_ctl_block { + u_short ie_status; /* status word */ + u_short ie_command; /* command word */ + u_short ie_command_list; /* 16-pointer to command block list */ + u_short ie_recv_list; /* 16-pointer to receive frame list */ + u_short ie_err_crc; /* CRC errors */ + u_short ie_err_align; /* Alignment errors */ + u_short ie_err_resource; /* Resource errors */ + u_short ie_err_overrun; /* Overrun errors */ +}; + +/* Command values */ +#define IE_RU_COMMAND 0x0070 /* mask for RU command */ +#define IE_RU_NOP 0 /* for completeness */ +#define IE_RU_START 0x0010 /* start receive unit command */ +#define IE_RU_ENABLE 0x0020 /* enable receiver command */ +#define IE_RU_DISABLE 0x0030 /* disable receiver command */ +#define IE_RU_ABORT 0x0040 /* abort current receive operation */ + +#define IE_CU_COMMAND 0x0700 /* mask for CU command */ +#define IE_CU_NOP 0 /* included for completeness */ +#define IE_CU_START 0x0100 /* do-command command */ +#define IE_CU_RESUME 0x0200 /* resume a suspended cmd list */ +#define IE_CU_STOP 0x0300 /* SUSPEND was already taken */ +#define IE_CU_ABORT 0x0400 /* abort current command */ + +#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */ +#define IE_ACK_CX 0x8000 /* ack IE_ST_CX */ +#define IE_ACK_FR 0x4000 /* ack IE_ST_FR */ +#define IE_ACK_CNA 0x2000 /* ack IE_ST_CNA */ +#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */ + +#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START) + /* is this command an action command? */ + +/* Status values */ +#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */ +#define IE_ST_CX 0x8000 /* command with I bit completed */ +#define IE_ST_FR 0x4000 /* frame received */ +#define IE_ST_CNA 0x2000 /* all commands completed */ +#define IE_ST_RNR 0x1000 /* receive not ready */ + +#define IE_CU_STATUS 0x700 /* mask for command unit status */ +#define IE_CU_ACTIVE 0x200 /* command unit is active */ +#define IE_CU_SUSPEND 0x100 /* command unit is suspended */ + +#define IE_RU_STATUS 0x70 /* mask for receiver unit status */ +#define IE_RU_SUSPEND 0x10 /* receiver is suspended */ +#define IE_RU_NOSPACE 0x20 /* receiver has no resources */ +#define IE_RU_READY 0x40 /* reveiver is ready */ + +/* + * This is filled in partially by the chip, partially by us. + */ +struct ie_recv_frame_desc { + u_short ie_fd_status; /* status for this frame */ + u_short ie_fd_last; /* end of frame list flag */ + u_short ie_fd_next; /* 16-pointer to next RFD */ + u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */ + struct ie_en_addr dest; /* destination ether */ + struct ie_en_addr src; /* source ether */ + u_short ie_length; /* 802 length/Ether type */ + u_short mbz; /* must be zero */ +}; + +#define IE_FD_LAST 0x8000 /* last rfd in list */ +#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */ + +#define IE_FD_COMPLETE 0x8000 /* frame is complete */ +#define IE_FD_BUSY 0x4000 /* frame is busy */ +#define IE_FD_OK 0x2000 /* frame is bad */ +#define IE_FD_RNR 0x0200 /* receiver out of resources here */ + +/* + * linked list of buffers... + */ +struct ie_recv_buf_desc { + u_short ie_rbd_actual; /* status for this buffer */ + u_short ie_rbd_next; /* 16-pointer to next RBD */ + caddr_t ie_rbd_buffer; /* 24-pointer to buffer for this RBD */ + u_short ie_rbd_length; /* length of the buffer */ + u_short mbz; /* must be zero */ +}; + +#define IE_RBD_LAST 0x8000 /* last buffer */ +#define IE_RBD_USED 0x4000 /* this buffer has data */ +/* + * All commands share this in common. + */ +struct ie_cmd_common { + u_short ie_cmd_status; /* status of this command */ + u_short ie_cmd_cmd; /* command word */ + u_short ie_cmd_link; /* link to next command */ +}; + +#define IE_STAT_COMPL 0x8000 /* command is completed */ +#define IE_STAT_BUSY 0x4000 /* command is running now */ +#define IE_STAT_OK 0x2000 /* command completed successfully */ +#define IE_STAT_ABORT 0x1000 /* command was aborted */ + +#define IE_CMD_NOP 0x0000 /* NOP */ +#define IE_CMD_IASETUP 0x0001 /* initial address setup */ +#define IE_CMD_CONFIG 0x0002 /* configure command */ +#define IE_CMD_MCAST 0x0003 /* multicast setup command */ +#define IE_CMD_XMIT 0x0004 /* transmit command */ +#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */ +#define IE_CMD_DUMP 0x0006 /* dump command */ +#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */ + +#define IE_CMD_LAST 0x8000 /* this is the last command in the list */ +#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */ +#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */ + +/* + * This is the command to transmit a frame. + */ +struct ie_xmit_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_xmit_status com.ie_cmd_status + + u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */ + struct ie_en_addr ie_xmit_addr; /* destination address */ + + u_short ie_xmit_length; /* 802.3 length/Ether type field */ +}; + +#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */ +#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */ +#define IE_XS_SQE 0x0040 /* SQE positive */ +#define IE_XS_DEFERRED 0x0080 /* transmission deferred */ +#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */ +#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */ +#define IE_XS_NOCARRIER 0x0400 /* No Carrier */ +#define IE_XS_LATECOLL 0x0800 /* Late collision */ + +/* + * This is a buffer descriptor for a frame to be transmitted. + */ + +struct ie_xmit_buf { + u_short ie_xmit_flags; /* see below */ + u_short ie_xmit_next; /* 16-pointer to next desc. */ + caddr_t ie_xmit_buf; /* 24-pointer to the actual buffer */ +}; + +#define IE_XMIT_LAST 0x8000 /* this TBD is the last one */ +/* The rest of the `flags' word is actually the length. */ + +/* + * Multicast setup command. + */ + +#define MAXMCAST 250 /* must fit in transmit buffer */ + +struct ie_mcast_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_mcast_status com.ie_cmd_status + + u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */ + struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */ +}; + +/* + * Time Domain Reflectometer command. + */ + +struct ie_tdr_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_tdr_status com.ie_cmd_status + + u_short ie_tdr_time; /* error bits and time */ +}; + +#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */ +#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */ +#define IE_TDR_OPEN 0x2000 /* detected an open */ +#define IE_TDR_SHORT 0x1000 /* TDR detected a short */ +#define IE_TDR_TIME 0x07ff /* mask for reflection time */ + +/* + * Initial Address Setup command + */ +struct ie_iasetup_cmd { + struct ie_cmd_common com; +#define ie_iasetup_status com.ie_cmd_status + + struct ie_en_addr ie_address; +}; + +/* + * Configuration command + */ +struct ie_config_cmd { + struct ie_cmd_common com; /* common part */ +#define ie_config_status com.ie_cmd_status + + u_char ie_config_count; /* byte count (0x0c) */ + u_char ie_fifo; /* fifo (8) */ + u_char ie_save_bad; /* save bad frames (0x40) */ + u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */ + u_char ie_priority; /* priority and backoff (0x0) */ + u_char ie_ifs; /* inter-frame spacing (0x60) */ + u_char ie_slot_low; /* slot time, LSB (0x0) */ + u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */ + u_char ie_promisc; /* 1 if promiscuous, else 0 */ + u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */ + u_char ie_min_len; /* min frame length (0x40) */ + u_char ie_junk; /* stuff for 82596 (0xff) */ +}; diff --git a/sys/dev/ic/ics2101reg.h b/sys/dev/ic/ics2101reg.h new file mode 100644 index 00000000000..12d944af910 --- /dev/null +++ b/sys/dev/ic/ics2101reg.h @@ -0,0 +1,79 @@ +/* $NetBSD: ics2101reg.h,v 1.1 1995/07/19 19:58:33 brezak Exp $ */ +/* + * Copyright (c) 1994, 1995 Ken Hornstein. All rights reserved. + * Copyright (c) 1995 John T. Kohl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ken Hornstein. + * 4. The name of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: ics2101reg.h,v 1.1 1995/10/18 08:52:31 deraadt Exp $ + */ + +/* + * Register defs for Integrated Circuit Systems, Inc. ICS-2101 mixer + * chip, used on Gravis UltraSound cards. + * + * Block diagram: + * port # + * 0 +----+ + * Mic in (Right/Left) -->--->---| | + * 1 | | amp --->---- amp out + * Line in (Right/Left) -->--->---| | | + * 2 | | | + * CD in (Right/Left) -->--->---| |--->---+---+----->---- line out + * 3 | | | + * GF1 Out (Right/Left) -->--->---| | | + * 4 | | | + * Unused (Right/Left) -->--->---| | | + * +----+ v + * ICS 2101 | + * | + * To GF1 Sample Input ---<---------------+ + * + * Master output volume: mixer channel #5 + */ + +/* + * ICS Mixer registers + */ + +#define ICSMIX_CTRL_LEFT 0x00 /* Control left channel */ +#define ICSMIX_CTRL_RIGHT 0x01 /* Control right channel */ +#define ICSMIX_ATTN_LEFT 0x02 /* Attenuate left channel */ +#define ICSMIX_ATTN_RIGHT 0x03 /* Attenutate right channel */ +#define ICSMIX_PAEN 0x04 /* Panning control */ +#define ICSMIX_CHAN_0 0 /* Values for mixer channels */ +#define ICSMIX_CHAN_1 1 +#define ICSMIX_CHAN_2 2 +#define ICSMIX_CHAN_3 3 +#define ICSMIX_CHAN_4 4 +#define ICSMIX_CHAN_5 5 + +#define ICSMIX_MIN_ATTN 0x7f +#define ICSMIX_MAX_ATTN 0x00 +/* + * The ICS mixer is write-only--it cannot be queried for current settings. + * Drivers must keep track of current values themselves. + */ diff --git a/sys/dev/ic/mb86960reg.h b/sys/dev/ic/mb86960reg.h new file mode 100644 index 00000000000..ebbb0ea70aa --- /dev/null +++ b/sys/dev/ic/mb86960reg.h @@ -0,0 +1,320 @@ +/* + * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 + * + * This software may be used, modified, copied, distributed, and sold, in + * both source and binary form provided that the above copyright, these + * terms and the following disclaimer are retained. The name of the author + * and/or the contributor may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define FE_MB86960_H_VERSION "mb86960.h ver. 0.8" + +/* + * Registers of Fujitsu MB86960A/MB86965A Ethernet controller. + * Written and contributed by M.S. <seki@sysrap.cs.fujitsu.co.jp> + */ + +/* + * Notes on register naming: + * + * Fujitsu documents for MB86960A/MB86965A uses no mnemorable names + * for their registers. They defined only three names for 32 + * registers and appended numbers to distinguish registers of + * same name. Surprisingly, the numbers represent I/O address + * offsets of the registers from the base addresses, and their + * names correspond to the "bank" the registers are allocated. + * All this means that, for example, to say "read DLCR8" has no more + * than to say "read a register at offset 8 on bank DLCR." + * + * The following definitions may look silly, but that's what Fujitsu + * did, and it is necessary to know these names to read Fujitsu + * documents.. + */ + +/* Data Link Control Registrs, on invaliant port addresses. */ +#define FE_DLCR0 0 +#define FE_DLCR1 1 +#define FE_DLCR2 2 +#define FE_DLCR3 3 +#define FE_DLCR4 4 +#define FE_DLCR5 5 +#define FE_DLCR6 6 +#define FE_DLCR7 7 + +/* More DLCRs, on register bank #0. */ +#define FE_DLCR8 8 +#define FE_DLCR9 9 +#define FE_DLCR10 10 +#define FE_DLCR11 11 +#define FE_DLCR12 12 +#define FE_DLCR13 13 +#define FE_DLCR14 14 +#define FE_DLCR15 15 + +/* Malticast Address Registers. On register bank #1. */ +#define FE_MAR8 8 +#define FE_MAR9 9 +#define FE_MAR10 10 +#define FE_MAR11 11 +#define FE_MAR12 12 +#define FE_MAR13 13 +#define FE_MAR14 14 +#define FE_MAR15 15 + +/* Buffer Memory Port Registers. On register back #2. */ +#define FE_BMPR8 8 +#define FE_BMPR9 9 +#define FE_BMPR10 10 +#define FE_BMPR11 11 +#define FE_BMPR12 12 +#define FE_BMPR13 13 +#define FE_BMPR14 14 +#define FE_BMPR15 15 + +/* More BMPRs, only on MB86965A, accessible only when JLI mode. */ +#define FE_BMPR16 16 +#define FE_BMPR17 17 +#define FE_BMPR18 18 +#define FE_BMPR19 19 + +#define FE_RESET 31 + +/* + * Definitions of registers. + * I don't have Fujitsu documents of MB86960A/MB86965A, so I don't + * know the official names for each flags and fields. The following + * names are assigned by me (the author of this file,) since I cannot + * mnemorize hexadecimal constants for all of these functions. + * Comments? FIXME. + */ + +/* DLCR0 -- transmitter status */ +#define FE_D0_BUSERR 0x01 /* Bus write error */ +#define FE_D0_COLL16 0x02 /* Collision limit (16) encountered */ +#define FE_D0_COLLID 0x04 /* Collision on last transmission */ +#define FE_D0_JABBER 0x08 /* Jabber */ +#define FE_D0_CRLOST 0x10 /* Carrier lost on last transmission */ +#define FE_D0_PKTRCD 0x20 /* No corrision on last transmission */ +#define FE_D0_NETBSY 0x40 /* Network Busy (Carrier Detected) */ +#define FE_D0_TXDONE 0x80 /* Transmission complete */ + +/* DLCR1 -- receiver status */ +#define FE_D1_OVRFLO 0x01 /* Receiver buffer overflow */ +#define FE_D1_CRCERR 0x02 /* CRC error on last packet */ +#define FE_D1_ALGERR 0x04 /* Alignment error on last packet */ +#define FE_D1_SRTPKT 0x08 /* Short (RUNT) packet is received */ +#define FE_D1_RMTRST 0x10 /* Remote reset packet (type = 0x0900) */ +#define FE_D1_DMAEOP 0x20 /* Host asserted End of DMA OPeration */ +#define FE_D1_BUSERR 0x40 /* Bus read error */ +#define FE_D1_PKTRDY 0x80 /* Packet(s) ready on receive buffer */ + +#define FE_D1_ERRBITS "\20\4SRTPKT\3ALGERR\2CRCERR\1OVRFLO" + +/* DLCR2 -- transmitter interrupt control; same layout as DLCR0 */ +#define FE_D2_BUSERR FE_D0_BUSERR +#define FE_D2_COLL16 FE_D0_COLL16 +#define FE_D2_COLLID FE_D0_COLLID +#define FE_D2_JABBER FE_D0_JABBER +#define FE_D2_TXDONE FE_D0_TXDONE + +#define FE_D2_RESERVED 0x70 + +/* DLCR3 -- receiver interrupt control; same layout as DLCR1 */ +#define FE_D3_OVRFLO FE_D1_OVRFLO +#define FE_D3_CRCERR FE_D1_CRCERR +#define FE_D3_ALGERR FE_D1_ALGERR +#define FE_D3_SRTPKT FE_D1_SRTPKT +#define FE_D3_RMTRST FE_D1_RMTRST +#define FE_D3_DMAEOP FE_D1_DMAEOP +#define FE_D3_BUSERR FE_D1_BUSERR +#define FE_D3_PKTRDY FE_D1_PKTRDY + +/* DLCR4 -- transmitter operation mode */ +#define FE_D4_DSC 0x01 /* Disable carrier sense on trans. */ +#define FE_D4_LBC 0x02 /* Loop back test control */ +#define FE_D4_CNTRL 0x04 /* - ??? */ +#define FE_D4_TEST1 0x08 /* Test output #1 */ +#define FE_D4_COL 0xF0 /* Collision counter */ + +#define FE_D4_LBC_ENABLE 0x00 /* Perform loop back test */ +#define FE_D4_LBC_DISABLE 0x02 /* Normal operation */ + +#define FE_D4_COL_SHIFT 4 + +/* DLCR5 -- receiver operation mode */ +#define FE_D5_AFM0 0x01 /* Receive packets for other stations */ +#define FE_D5_AFM1 0x02 /* Receive packets for this station */ +#define FE_D5_RMTRST 0x04 /* Enable remote reset operation */ +#define FE_D5_SRTPKT 0x08 /* Accept short (RUNT) packets */ +#define FE_D5_SRTADR 0x10 /* Short (16 bits?) MAC address */ +#define FE_D5_BADPKT 0x20 /* Accept packets with error */ +#define FE_D5_BUFEMP 0x40 /* Receive buffer is empty */ +#define FE_D5_TEST2 0x80 /* Test output #2 */ + +/* DLCR6 -- hardware configuration #0 */ +#define FE_D6_BUFSIZ 0x03 /* Size of NIC buffer SRAM */ +#define FE_D6_TXBSIZ 0x0C /* Size (and config)of trans. buffer */ +#define FE_D6_BBW 0x10 /* Buffer SRAM bus width */ +#define FE_D6_SBW 0x20 /* System bus width */ +#define FE_D6_SRAM 0x40 /* Buffer SRAM access time */ +#define FE_D6_DLC 0x80 /* Disable DLC (recever/transmitter) */ + +#define FE_D6_BUFSIZ_8KB 0x00 /* The board has 8KB SRAM */ +#define FE_D6_BUFSIZ_16KB 0x01 /* The board has 16KB SRAM */ +#define FE_D6_BUFSIZ_32KB 0x02 /* The board has 32KB SRAM */ +#define FE_D6_BUFSIZ_64KB 0x03 /* The board has 64KB SRAM */ + +#define FE_D6_TXBSIZ_1x2KB 0x00 /* Single 2KB buffer for trans. */ +#define FE_D6_TXBSIZ_2x2KB 0x04 /* Double 2KB buffers */ +#define FE_D6_TXBSIZ_2x4KB 0x08 /* Double 4KB buffers */ +#define FE_D6_TXBSIZ_2x8KB 0x0C /* Double 8KB buffers */ + +#define FE_D6_BBW_WORD 0x00 /* SRAM has 16 bit data line */ +#define FE_D6_BBW_BYTE 0x10 /* SRAM has 8 bit data line */ + +#define FE_D6_SBW_WORD 0x00 /* Access with 16 bit (AT) bus */ +#define FE_D6_SBW_BYTE 0x20 /* Access with 8 bit (XT) bus */ + +#define FE_D6_SRAM_150ns 0x00 /* The board has slow SRAM */ +#define FE_D6_SRAM_100ns 0x40 /* The board has fast SRAM */ + +#define FE_D6_DLC_ENABLE 0x00 /* Normal operation */ +#define FE_D6_DLC_DISABLE 0x80 /* Stop sending/receiving */ + +/* DLC7 -- hardware configuration #1 */ +#define FE_D7_BYTSWP 0x01 /* Host byte order control */ +#define FE_D7_EOPPOL 0x02 /* Polarity of DMA EOP signal */ +#define FE_D7_RBS 0x0C /* Register bank select */ +#define FE_D7_RDYPNS 0x10 /* Senses RDYPNSEL input signal */ +#define FE_D7_POWER 0x20 /* Stand-by (power down) mode control */ +#define FE_D7_IDENT 0xC0 /* Chip identification */ + +#define FE_D7_BYTSWP_LH 0x00 /* DEC/Intel byte order */ +#define FE_D7_BYTSWP_HL 0x01 /* IBM/Motorolla byte order */ + +#define FE_D7_RBS_DLCR 0x00 /* Select DLCR8-15 */ +#define FE_D7_RBS_MAR 0x04 /* Select MAR8-15 */ +#define FE_D7_RBS_BMPR 0x08 /* Select BMPR8-15 */ + +#define FE_D7_POWER_DOWN 0x00 /* Power down (stand-by) mode */ +#define FE_D7_POWER_UP 0x20 /* Normal operation */ + +#define FE_D7_IDENT_NICE 0x80 +#define FE_D7_IDENT_EC 0xC0 + +/* DLCR8 thru DLCR13 are for Ethernet station address. */ + +/* DLCR14 and DLCR15 are for TDR. (BTW, what is TDR? FIXME.) */ + +/* MAR8 thru MAR15 are for Multicast address filter. */ + +/* BMPR8 and BMPR9 are for packet data. */ + +/* BMPR10 -- transmitter start trigger */ +#define FE_B10_START 0x80 /* Start transmitter */ +#define FE_B10_COUNT 0x7F /* Packet count */ + +/* BMPR11 -- 16 collisions control */ +#define FE_B11_CTRL 0x01 /* Skip or resend errored packets */ +#define FE_B11_MODE1 0x02 /* Restart transmitter after COLL16 */ +#define FE_B11_MODE2 0x04 /* Automatic restart enable */ + +#define FE_B11_CTRL_RESEND 0x00 /* Re-send the collided packet */ +#define FE_B11_CTRL_SKIP 0x01 /* Skip the collided packet */ + +/* BMPR12 -- DMA enable */ +#define FE_B12_TXDMA 0x01 /* Enable transmitter DMA */ +#define FE_B12_RXDMA 0x02 /* Enable receiver DMA */ + +/* BMPR13 -- DMA control */ +#define FE_B13_BSTCTL 0x03 /* DMA burst mode control */ +#define FE_B13_TPTYPE 0x04 /* Twisted pair cable impedance */ +#define FE_B13_PORT 0x18 /* Port (TP/AUI) selection */ +#define FE_B13_LNKTST 0x20 /* Link test enable */ +#define FE_B13_SQTHLD 0x40 /* Lower squelch threshold */ +#define FE_B13_IOUNLK 0x80 /* Change I/O base address */ + +#define FE_B13_BSTCTL_1 0x00 +#define FE_B13_BSTCTL_4 0x01 +#define FE_B13_BSTCTL_8 0x02 +#define FE_B13_BSTCLT_12 0x03 + +#define FE_B13_TPTYPE_UTP 0x00 /* Unshielded (standard) cable */ +#define FE_B13_TPTYPE_STP 0x04 /* Shielded (IBM) cable */ + +#define FE_B13_PORT_AUTO 0x00 /* Auto detected */ +#define FE_B13_PORT_TP 0x08 /* Force TP */ +#define FE_B13_PORT_AUI 0x18 /* Force AUI */ + +/* BMPR14 -- More receiver control and more transmission interrupts */ +#define FE_B14_FILTER 0x01 /* Filter out self-originated packets */ +#define FE_B14_SQE 0x02 /* SQE interrupt enable */ +#define FE_B14_SKIP 0x04 /* Skip a received packet */ +#define FE_B14_RJAB 0x20 /* RJAB interrupt enable */ +#define FE_B14_LLD 0x40 /* Local-link-down interrupt enable */ +#define FE_B14_RLD 0x80 /* Remote-link-down interrupt enable */ + +/* BMPR15 -- More transmitter status; basically same layout as BMPR14 */ +#define FE_B15_SQE FE_B14_SQE +#define FE_B15_RCVPOL 0x08 /* Reversed receive line polarity */ +#define FE_B15_RMTPRT 0x10 /* ??? */ +#define FE_B15_RAJB FE_B14_RJAB +#define FE_B15_LLD FE_B14_LLD +#define FE_B15_RLD FE_B14_RLD + +/* BMPR16 -- EEPROM control */ +#define FE_B16_DOUT 0x04 /* EEPROM Data in (CPU to EEPROM) */ +#define FE_B16_SELECT 0x20 /* EEPROM chip select */ +#define FE_B16_CLOCK 0x40 /* EEPROM shift clock */ +#define FE_B16_DIN 0x80 /* EEPROM data out (EEPROM to CPU) */ + +/* BMPR17 -- EEPROM data */ +#define FE_B17_DATA 0x80 /* EEPROM data bit */ + +/* BMPR18 ??? */ + +/* BMPR19 -- ISA interface configuration */ +#define FE_B19_IRQ 0xC0 +#define FE_B19_IRQ_SHIFT 6 + +#define FE_B19_ROM 0x38 +#define FE_B19_ROM_SHIFT 3 + +#define FE_B19_ADDR 0x07 +#define FE_B19_ADDR_SHIFT 0 + +/* + * EEPROM specification (of JLI mode). + */ + +/* Number of bytes in an EEPROM accessible through 86965. */ +#define FE_EEPROM_SIZE 32 + +/* Offset for JLI config; automatically copied into BMPR19 at startup. */ +#define FE_EEPROM_CONF 0 + +/* + * Some 86960 specific constants. + */ + +/* Length (in bytes) of a Multicast Address Filter. */ +#define FE_FILTER_LEN 8 + +/* How many packets we can put in the transmission buffer on NIC memory. */ +#define FE_QUEUEING_MAX 127 + +/* Length (in bytes) of a "packet length" word in transmission buffer. */ +#define FE_DATA_LEN_LEN 2 diff --git a/sys/dev/ic/mc146818reg.h b/sys/dev/ic/mc146818reg.h new file mode 100644 index 00000000000..27a3ba20e6a --- /dev/null +++ b/sys/dev/ic/mc146818reg.h @@ -0,0 +1,194 @@ +/* $NetBSD: mc146818reg.h,v 1.1 1995/05/04 19:31:18 cgd Exp $ */ + +/* + * Copyright (c) 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Definitions for the Motorola MC146818A Real Time Clock. + * They also apply for the (compatible) Dallas Semicontuctor DS1287A RTC. + * + * Though there are undoubtedly other (better) sources, this material was + * culled from the DEC "KN121 System Module Programmer's Reference + * Information." + * + * The MC146818A has 16 registers. The first 10 contain time-of-year + * and alarm data. The rest contain various control and status bits. + * + * To read or write the registers, one writes the register number to + * the RTC's control port, then either reads from or writes the new + * data to the RTC's data port. Since the locations of these ports + * and the method used to access them can be machine-dependent, the + * low-level details of reading and writing the RTC's registers are + * handled by machine-specific functions. + * + * The time-of-year and alarm data can be expressed in either binary + * or BCD, and they are selected by a bit in register B. + * + * The "hour" time-of-year and alarm fields can either be expressed in + * AM/PM format, or in 24-hour format. If AM/PM format is chosen, the + * hour fields can have the values: 1-12 and 81-92 (the latter being + * PM). If the 24-hour format is chosen, they can have the values + * 0-24. The hour format is selectable by a bit in register B. + * (XXX IS AM/PM MODE DESCRIPTION CORRECT?) + * + * It is assumed the if systems are going to use BCD (rather than + * binary) mode, or AM/PM hour format, they'll do the appropriate + * conversions in machine-dependent code. Also, if the clock is + * switched between BCD and binary mode, or between AM/PM mode and + * 24-hour mode, the time-of-day and alarm registers are NOT + * automatically reset; they must be reprogrammed with correct values. + */ + +/* + * The registers, and the bits within each register. + */ + +#define MC_SEC 0x0 /* Time of year: seconds (0-59) */ +#define MC_ASEC 0x1 /* Alarm: seconds */ +#define MC_MIN 0x2 /* Time of year: minutes (0-59) */ +#define MC_AMIN 0x3 /* Alarm: minutes */ +#define MC_HOUR 0x4 /* Time of year: hour (see above) */ +#define MC_AHOUR 0x5 /* Alarm: hour */ +#define MC_DOW 0x6 /* Time of year: day of week (1-7) */ +#define MC_DOM 0x7 /* Time of year: day of month (1-31) */ +#define MC_MONTH 0x8 /* Time of year: month (1-12) */ +#define MC_YEAR 0x9 /* Time of year: year in century (0-99) */ + +#define MC_REGA 0xa /* Control register A */ + +#define MC_REGA_RSMASK 0x0f /* Interrupt rate select mask (see below) */ +#define MC_REGA_DVMASK 0x70 /* Divisor select mask (see below) */ +#define MC_REGA_UIP 0x80 /* Update in progress; read only. */ + +#define MC_REGB 0xb /* Control register B */ + +#define MC_REGB_DSE 0x01 /* Daylight Savings Enable */ +#define MC_REGB_24HR 0x02 /* 24-hour mode (AM/PM mode when clear) */ +#define MC_REGB_BINARY 0x04 /* Binary mode (BCD mode when clear) */ +/* MC_REGB_UNUSED 0x08 UNUSED */ +#define MC_REGB_UIE 0x10 /* Update End interrupt enable */ +#define MC_REGB_AIE 0x20 /* Alarm interrupt enable */ +#define MC_REGB_PIE 0x40 /* Periodic interrupt enable */ +#define MC_REGB_SET 0x80 /* Allow time to be set; stops updates */ + +#define MC_REGC 0xc /* Control register C */ + +/* MC_REGC_UNUSED 0x0f UNUSED */ +#define MC_REGC_UF 0x10 /* Update End interrupt flag */ +#define MC_REGC_AF 0x20 /* Alarm interrupt flag */ +#define MC_REGC_PF 0x40 /* Periodic interrupt flag */ +#define MC_REGC_IRQF 0x80 /* Interrupt request pending flag */ + +#define MC_REGD 0xd /* Control register D */ + +/* MC_REGD_UNUSED 0x7f UNUSED */ +#define MC_REGD_VRT 0x80 /* Valid RAM and Time bit */ + + +#define MC_NREGS 0xe /* 14 registers; CMOS follows */ +#define MC_NTODREGS 0xa /* 10 of those regs are for TOD and alarm */ + +#define MC_NVRAM_START 0xe /* start of NVRAM: offset 14 */ +#define MC_NVRAM_SIZE 50 /* 50 bytes of NVRAM */ + +/* + * Periodic Interrupt Rate Select constants (Control register A) + */ +#define MC_RATE_NONE 0x0 /* No periodic interrupt */ +#define MC_RATE_1 0x1 /* 256 Hz if MC_BASE_32_KHz, else 32768 Hz */ +#define MC_RATE_2 0x2 /* 128 Hz if MC_BASE_32_KHz, else 16384 Hz */ +#define MC_RATE_8192_Hz 0x3 /* 122.070 us period */ +#define MC_RATE_4096_Hz 0x4 /* 244.141 us period */ +#define MC_RATE_2048_Hz 0x5 /* 488.281 us period */ +#define MC_RATE_1024_Hz 0x6 /* 976.562 us period */ +#define MC_RATE_512_Hz 0x7 /* 1.953125 ms period */ +#define MC_RATE_256_Hz 0x8 /* 3.90625 ms period */ +#define MC_RATE_128_Hz 0x9 /* 7.8125 ms period */ +#define MC_RATE_64_Hz 0xa /* 15.625 ms period */ +#define MC_RATE_32_Hz 0xb /* 31.25 ms period */ +#define MC_RATE_16_Hz 0xc /* 62.5 ms period */ +#define MC_RATE_8_Hz 0xd /* 125 ms period */ +#define MC_RATE_4_Hz 0xe /* 250 ms period */ +#define MC_RATE_2_Hz 0xf /* 500 ms period */ + +/* + * Time base (divisor select) constants (Control register A) + */ +#define MC_BASE_4_MHz 0x00 /* 4MHz crystal */ +#define MC_BASE_1_MHz 0x10 /* 1MHz crystal */ +#define MC_BASE_32_KHz 0x20 /* 32KHz crystal */ +#define MC_BASE_NONE 0x60 /* actually, both of these reset */ +#define MC_BASE_RESET 0x70 + + +/* + * RTC register/NVRAM read and write functions -- machine-dependent. + * Appropriately manipulate RTC registers to get/put data values. + */ +u_int mc146818_read __P((void *sc, u_int reg)); +void mc146818_write __P((void *sc, u_int reg, u_int datum)); + +/* + * A collection of TOD/Alarm registers. + */ +typedef u_int mc_todregs[MC_NTODREGS]; + +/* + * Get all of the TOD/Alarm registers + * Must be called at splhigh(), and with the RTC properly set up. + */ +#define MC146818_GETTOD(sc, regs) \ + do { \ + int i; \ + \ + /* update in progress; spin loop */ \ + while (mc146818_read(sc, MC_REGA) & MC_REGA_UIP) \ + ; \ + \ + /* read all of the tod/alarm regs */ \ + for (i = 0; i < MC_NTODREGS; i++) \ + (*regs)[i] = mc146818_read(sc, i); \ + } while (0); + +/* + * Set all of the TOD/Alarm registers + * Must be called at splhigh(), and with the RTC properly set up. + */ +#define MC146818_PUTTOD(sc, regs) \ + do { \ + int i; \ + \ + /* stop updates while setting */ \ + mc146818_write(sc, MC_REGB, \ + mc146818_read(sc, MC_REGB) | MC_REGB_SET); \ + \ + /* write all of the tod/alarm regs */ \ + for (i = 0; i < MC_NTODREGS; i++) \ + mc146818_write(sc, i, (*regs)[i]); \ + \ + /* reenable updates */ \ + mc146818_write(sc, MC_REGB, \ + mc146818_read(sc, MC_REGB) & ~MC_REGB_SET); \ + } while (0); diff --git a/sys/dev/ic/ncr5380.c b/sys/dev/ic/ncr5380.c new file mode 100644 index 00000000000..bbc68d483f4 --- /dev/null +++ b/sys/dev/ic/ncr5380.c @@ -0,0 +1,729 @@ +/* $NetBSD: ncr5380.c,v 1.3 1995/09/26 21:04:27 pk Exp $ */ + +/* + * Copyright (C) 1994 Adam Glass, Gordon W. Ross + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Alice Group. + * 4. The names of the Alice Group or any of its members may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * NOTE: This is 99% Sun 3 `si' driver. I've made the probe and attach + * routines a little minimalistic, and adjusted them slightly for the Sun 4. + * Also, fixed some logic in ncr5380_select_target(). + * Jason R. Thorpe <thorpej@nas.nasa.gov> + */ + +static int +ncr5380_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + int flags, s, r; + + flags = xs->flags; + if (xs->bp) flags |= (SCSI_NOSLEEP); + if ( flags & ITSDONE ) { + printf("Already done?"); + xs->flags &= ~ITSDONE; + } + if ( ! ( flags & INUSE ) ) { + printf("Not in use?"); + xs->flags |= INUSE; + } + + s = splbio(); + + if ( flags & SCSI_RESET ) { + printf("flags & SCSIRESET.\n"); + ncr5380_reset_scsibus(xs->sc_link->adapter_softc); + r = COMPLETE; + } else { + r = ncr5380_send_cmd(xs); + xs->flags |= ITSDONE; + scsi_done(xs); + } + + splx(s); + + switch(r) { + case COMPLETE: + case SUCCESSFULLY_QUEUED: + r = SUCCESSFULLY_QUEUED; + if (xs->flags & SCSI_POLL) + r = COMPLETE; + break; + default: + break; + } + return r; +} + +#ifdef DEBUG +static int +ncr5380_show_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + u_char *b = (u_char *) xs->cmd; + int i = 0; + + if ( ! ( xs->flags & SCSI_RESET ) ) { + printf("si(%d:%d:%d)-", + xs->sc_link->scsibus, + xs->sc_link->target, + xs->sc_link->lun); + while (i < xs->cmdlen) { + if (i) printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } else { + printf("si(%d:%d:%d)-RESET-\n", + xs->sc_link->scsibus, + xs->sc_link->target, + xs->sc_link->lun); + } +} +#endif + +/* + * Actual chip control. + */ + +static void +ncr5380_sbc_intr(ncr5380) + struct ncr5380_softc *ncr5380; +{ + volatile sci_regmap_t *regs = ncr5380->sc_regs; + + if ((regs->sci_csr & SCI_CSR_INT) == 0) { +#ifdef DEBUG + printf (" ncr5380_sbc_intr: spurious\n"); +#endif + return; + } + + SCI_CLR_INTR(regs); +#ifdef DEBUG + printf (" ncr5380_sbc_intr\n"); +#endif +} + +static int +ncr5380_reset_scsibus(ncr5380) + struct ncr5380_softc *ncr5380; +{ + volatile sci_regmap_t *regs = ncr5380->sc_regs; + +#ifdef DEBUG + if (ncr5380_debug) { + printf("ncr5380_reset_scsibus\n"); + } +#endif + + regs->sci_icmd = SCI_ICMD_RST; + delay(100); + regs->sci_icmd = 0; + + regs->sci_mode = 0; + regs->sci_tcmd = SCI_PHASE_DISC; + regs->sci_sel_enb = 0; + + SCI_CLR_INTR(regs); + /* XXX - Need long delay here! */ +} + +static int +ncr5380_poll(adapter, timeout) + int adapter, timeout; +{ +} + +static int +ncr5380_send_cmd(xs) + struct scsi_xfer *xs; +{ + int sense; + +#ifdef DEBUG + if (ncr5380_debug & 2) + ncr5380_show_scsi_cmd(xs); +#endif + + sense = ncr5380_generic( xs->sc_link->adapter_softc, + xs->sc_link->target, xs->sc_link->lun, xs->cmd, + xs->cmdlen, xs->data, xs->datalen ); + + switch (sense) { + case 0: /* success */ + xs->resid = 0; + xs->error = XS_NOERROR; + break; + + case 0x02: /* Check condition */ +#ifdef DEBUG + if (ncr5380_debug) + printf("check cond. target %d.\n", + xs->sc_link->target); +#endif + delay(10); /* Phil's fix for slow devices. */ + ncr5380_group0(xs->sc_link->adapter_softc, + xs->sc_link->target, + xs->sc_link->lun, + 0x3, 0x0, + sizeof(struct scsi_sense_data), + 0, (caddr_t) &(xs->sense), + sizeof(struct scsi_sense_data)); + xs->error = XS_SENSE; + break; + case 0x08: /* Busy - common code will delay, retry. */ + xs->error = XS_BUSY; + break; + default: /* Dead - tell common code to give up. */ + xs->error = XS_DRIVER_STUFFUP; + break; + + } + return (COMPLETE); +} + +static int +ncr5380_select_target(regs, myid, tid, with_atn) + register volatile sci_regmap_t *regs; + u_char myid, tid; + int with_atn; +{ + register u_char bid, icmd; + int ret = SCSI_RET_RETRY; + int arb_retries, arb_wait; + int i; + + /* for our purposes.. */ + myid = 1 << myid; + tid = 1 << tid; + + regs->sci_sel_enb = 0; /* we don't want any interrupts. */ + regs->sci_tcmd = 0; /* get into a harmless state */ + + arb_retries = ARBITRATION_RETRIES; + +retry_arbitration: + regs->sci_mode = 0; /* get into a harmless state */ +wait_for_bus_free: + if (--arb_retries <= 0) { +#ifdef DEBUG + if (ncr5380_debug) { + printf("ncr5380_select: arb_retries expended; resetting...\n"); + } +#endif + ret = SCSI_RET_NEED_RESET; + goto nosel; + } + + icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); + + if (regs->sci_bus_csr & (SCI_BUS_BSY|SCI_BUS_SEL)) { + /* Something is sitting on the SCSI bus... */ +#ifdef DEBUG + /* Only complain once (the last time through). */ + if (ncr5380_debug && (arb_retries <= 1)) { + printf("si_select_target: still BSY+SEL\n"); + } +#endif + /* Give it a little time, then try again. */ + delay(10); + goto wait_for_bus_free; + } + + regs->sci_odata = myid; + regs->sci_mode = SCI_MODE_ARB; +/* regs->sci_mode |= SCI_MODE_ARB; XXX? */ + + /* AIP might not set if BSY went true after we checked */ + /* Wait up to about 100 usec. for it to appear. */ + arb_wait = 50; /* X2 */ + do { + if (regs->sci_icmd & SCI_ICMD_AIP) + goto got_aip; + delay(2); + } while (--arb_wait > 0); + /* XXX - Could have missed it? */ +#ifdef DEBUG + if (ncr5380_debug) + printf("ncr5380_select_target: API did not appear\n"); +#endif + goto retry_arbitration; + + got_aip: +#ifdef DEBUG + if (ncr5380_debug & 4) { + printf("ncr5380_select_target: API after %d tries (last wait %d)\n", + ARBITRATION_RETRIES - arb_retries, + (50 - arb_wait)); + } +#endif + + delay(3); /* 2.2 uSec. arbitration delay */ + + if (regs->sci_icmd & SCI_ICMD_LST) { +#ifdef DEBUG + if (ncr5380_debug) + printf ("lost 1\n"); +#endif + goto retry_arbitration; /* XXX */ + } + + regs->sci_mode &= ~SCI_MODE_PAR_CHK; + bid = regs->sci_data; + + if ((bid & ~myid) > myid) { +#ifdef DEBUG + if (ncr5380_debug) + printf ("lost 2\n"); +#endif + /* Trying again will not help. */ + goto lost; + } + if (regs->sci_icmd & SCI_ICMD_LST) { +#ifdef DEBUG + if (ncr5380_debug) + printf ("lost 3\n"); +#endif + goto lost; + } + + /* Won arbitration, enter selection phase now */ + icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); + icmd |= (with_atn ? (SCI_ICMD_SEL|SCI_ICMD_ATN) : SCI_ICMD_SEL); + regs->sci_icmd = icmd; + + if (regs->sci_icmd & SCI_ICMD_LST) { +#ifdef DEBUG + if (ncr5380_debug) + printf ("nosel\n"); +#endif + goto nosel; + } + + /* XXX a target that violates specs might still drive the bus XXX */ + /* XXX should put our id out, and after the delay check nothi XXX */ + /* XXX ng else is out there. XXX */ + + delay(3); + + regs->sci_sel_enb = 0; + + regs->sci_odata = myid | tid; + + icmd |= SCI_ICMD_BSY|SCI_ICMD_DATA; + regs->sci_icmd = icmd; + +/* regs->sci_mode &= ~SCI_MODE_ARB; 2 deskew delays, too */ + regs->sci_mode = 0; /* 2 deskew delays, too */ + + icmd &= ~SCI_ICMD_BSY; + regs->sci_icmd = icmd; + + /* bus settle delay, 400ns */ + delay(3); + + regs->sci_mode |= SCI_MODE_PAR_CHK; + + { + register int timeo = 2500;/* 250 msecs in 100 usecs chunks */ + while ((regs->sci_bus_csr & SCI_BUS_BSY) == 0) { + if (--timeo > 0) { + delay(100); + } else { + /* This is the "normal" no-such-device select error. */ +#ifdef DEBUG + if (ncr5380_debug) + printf("ncr5380_select: not BSY (nothing there)\n"); +#endif + goto nodev; + } + } + } + + icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_SEL); + regs->sci_icmd = icmd; +/* regs->sci_sel_enb = myid;*/ /* looks like we should NOT have it */ + /* XXX - SCI_MODE_PAR_CHK ? */ + return SCSI_RET_SUCCESS; + +nodev: + ret = SCSI_RET_DEVICE_DOWN; + regs->sci_sel_enb = myid; +nosel: + regs->sci_icmd = 0; + regs->sci_mode = 0; + return ret; + +lost: + regs->sci_icmd = 0; + regs->sci_mode = 0; +#ifdef DEBUG + if (ncr5380_debug) { + printf("ncr5380_select: lost arbitration\n"); + } +#endif + return ret; +} + +sci_data_out(regs, phase, count, data) + register volatile sci_regmap_t *regs; + unsigned char *data; +{ + register unsigned char icmd; + register int cnt=0; + + /* ..checks.. */ + + icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); +loop: + /* SCSI bus phase not valid until REQ is true. */ + WAIT_FOR_REQ(regs); + if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) + return cnt; + + icmd |= SCI_ICMD_DATA; + regs->sci_icmd = icmd; + regs->sci_odata = *data++; + icmd |= SCI_ICMD_ACK; + regs->sci_icmd = icmd; + + icmd &= ~(SCI_ICMD_DATA|SCI_ICMD_ACK); + WAIT_FOR_NOT_REQ(regs); + regs->sci_icmd = icmd; + ++cnt; + if (--count > 0) + goto loop; +scsi_timeout_error: + return cnt; +} + +static int +sci_data_in(regs, phase, count, data) + register volatile sci_regmap_t *regs; + unsigned char *data; +{ + register unsigned char icmd; + register int cnt=0; + + /* ..checks.. */ + + icmd = regs->sci_icmd & ~(SCI_ICMD_DIFF|SCI_ICMD_TEST); + +loop: + /* SCSI bus phase not valid until REQ is true. */ + WAIT_FOR_REQ(regs); + if (SCI_CUR_PHASE(regs->sci_bus_csr) != phase) + return cnt; + + *data++ = regs->sci_data; + icmd |= SCI_ICMD_ACK; + regs->sci_icmd = icmd; + + icmd &= ~SCI_ICMD_ACK; + WAIT_FOR_NOT_REQ(regs); + regs->sci_icmd = icmd; + ++cnt; + if (--count > 0) + goto loop; + +scsi_timeout_error: + return cnt; +} + +/* + * Return -1 (error) or number of bytes sent (>=0). + */ +static int +ncr5380_command_transfer(regs, maxlen, data, status, msg) + register volatile sci_regmap_t *regs; + int maxlen; + u_char *data; + u_char *status; + u_char *msg; +{ + int xfer, phase; + + xfer = 0; + regs->sci_icmd = 0; + + while (1) { + + WAIT_FOR_REQ(regs); + + phase = SCI_CUR_PHASE(regs->sci_bus_csr); + + switch (phase) { + case SCSI_PHASE_CMD: + SCI_ACK(regs,SCSI_PHASE_CMD); + xfer += sci_data_out(regs, SCSI_PHASE_CMD, + maxlen, data); + goto out; + + case SCSI_PHASE_DATA_IN: + printf("command_transfer: Data in phase?\n"); + goto err; + + case SCSI_PHASE_DATA_OUT: + printf("command_transfer: Data out phase?\n"); + goto err; + + case SCSI_PHASE_STATUS: + SCI_ACK(regs,SCSI_PHASE_STATUS); + printf("command_transfer: status in...\n"); + sci_data_in(regs, SCSI_PHASE_STATUS, + 1, status); + printf("command_transfer: status=0x%x\n", *status); + goto err; + + case SCSI_PHASE_MESSAGE_IN: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); + printf("command_transfer: msg in?\n"); + sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, + 1, msg); + break; + + case SCSI_PHASE_MESSAGE_OUT: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); + sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, + 1, msg); + break; + + default: + printf("command_transfer: Unexpected phase 0x%x\n", phase); + goto err; + } + } +scsi_timeout_error: +err: + xfer = -1; +out: + return xfer; +} + +static int +ncr5380_data_transfer(regs, maxlen, data, status, msg) + register volatile sci_regmap_t *regs; + int maxlen; + u_char *data, *status, *msg; +{ + int retlen = 0, xfer, phase; + + regs->sci_icmd = 0; + + *status = 0; + + while (1) { + + WAIT_FOR_REQ(regs); + + phase = SCI_CUR_PHASE(regs->sci_bus_csr); + + switch (phase) { + case SCSI_PHASE_CMD: + printf("Command phase in data_transfer().\n"); + return retlen; + case SCSI_PHASE_DATA_IN: + SCI_ACK(regs,SCSI_PHASE_DATA_IN); +#if PSEUDO_DMA + xfer = sci_pdma_in(regs, SCSI_PHASE_DATA_IN, + maxlen, data); +#else + xfer = sci_data_in(regs, SCSI_PHASE_DATA_IN, + maxlen, data); +#endif + retlen += xfer; + maxlen -= xfer; + break; + case SCSI_PHASE_DATA_OUT: + SCI_ACK(regs,SCSI_PHASE_DATA_OUT); +#if PSEUDO_DMA + xfer = sci_pdma_out(regs, SCSI_PHASE_DATA_OUT, + maxlen, data); +#else + xfer = sci_data_out(regs, SCSI_PHASE_DATA_OUT, + maxlen, data); +#endif + retlen += xfer; + maxlen -= xfer; + break; + case SCSI_PHASE_STATUS: + SCI_ACK(regs,SCSI_PHASE_STATUS); + sci_data_in(regs, SCSI_PHASE_STATUS, + 1, status); + break; + case SCSI_PHASE_MESSAGE_IN: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_IN); + sci_data_in(regs, SCSI_PHASE_MESSAGE_IN, + 1, msg); + if (*msg == 0) { + return retlen; + } else { + printf( "message 0x%x in " + "data_transfer.\n", *msg); + } + break; + case SCSI_PHASE_MESSAGE_OUT: + SCI_ACK(regs,SCSI_PHASE_MESSAGE_OUT); + sci_data_out(regs, SCSI_PHASE_MESSAGE_OUT, + 1, msg); + break; + default: + printf( "Unexpected phase 0x%x in " + "data_transfer().\n", phase); +scsi_timeout_error: + return retlen; + break; + } + } +} + +/* + * Returns 0 on success, -1 on internal error, or the status byte + */ +static int +ncr5380_dorequest(sc, target, lun, cmd, cmdlen, databuf, datalen, sent) + struct ncr5380_softc *sc; + int target, lun; + u_char *cmd; + int cmdlen; + char *databuf; + int datalen, *sent; +{ + register volatile sci_regmap_t *regs = sc->sc_regs; + int cmd_bytes_sent, r; + u_char stat, msg, c; + +#ifdef DEBUG + if (ncr5380_debug) { + printf("ncr5380_dorequest: target=%d, lun=%d\n", target, lun); + } +#endif + + *sent = 0; + + if ( ( r = ncr5380_select_target(regs, 7, target, 1) ) != SCSI_RET_SUCCESS) { +#ifdef DEBUG + if (ncr5380_debug) { + printf("ncr5380_dorequest: select returned %d\n", r); + } +#endif + + SCI_CLR_INTR(regs); + switch (r) { + + case SCSI_RET_NEED_RESET: + printf("ncr5380_dorequest: target=%d, lun=%d, r=%d resetting...\n", + target, lun, r); + reset_adapter(sc); + ncr5380_reset_scsibus(sc); + /* fall through */ + case SCSI_RET_RETRY: + return 0x08; /* Busy - tell common code to retry. */ + + default: + printf("ncr5380_dorequest: target=%d, lun=%d, error=%d.\n", + target, lun, r); + /* fall through */ + case SCSI_RET_DEVICE_DOWN: + return -1; /* Dead - tell common code to give up. */ + } + } + + c = 0x80 | lun; + + if ((cmd_bytes_sent = ncr5380_command_transfer(regs, cmdlen, + (u_char *) cmd, &stat, &c)) != cmdlen) + { + SCI_CLR_INTR(regs); + if (cmd_bytes_sent >= 0) { + printf("Data underrun sending CCB (%d bytes of %d, sent).\n", + cmd_bytes_sent, cmdlen); + } + return -1; + } + + *sent = ncr5380_data_transfer(regs, datalen, (u_char *)databuf, + &stat, &msg); +#ifdef DEBUG + if (ncr5380_debug) { + printf("ncr5380_dorequest: data transfered = %d\n", *sent); + } +#endif + + return stat; +} + +static int +ncr5380_generic(adapter, id, lun, cmd, cmdlen, databuf, datalen) + void *adapter; + int id, lun; + struct scsi_generic *cmd; + int cmdlen; + void *databuf; + int datalen; +{ + register struct ncr5380_softc *sc = adapter; + int i, j, sent; + + if (cmd->opcode == TEST_UNIT_READY) /* XXX */ + cmd->bytes[0] = ((u_char) lun << 5); + + i = ncr5380_dorequest(sc, id, lun, (u_char *) cmd, cmdlen, + databuf, datalen, &sent); + + return i; +} + +static int +ncr5380_group0(adapter, id, lun, opcode, addr, len, flags, databuf, datalen) + void *adapter; + int id, lun, opcode, addr, len, flags; + caddr_t databuf; + int datalen; +{ + register struct ncr5380_softc *sc = adapter; + unsigned char cmd[6]; + int i, j, sent; + + cmd[0] = opcode; /* Operation code */ + cmd[1] = (lun << 5) | ((addr >> 16) & 0x1F); /* Lun & MSB of addr */ + cmd[2] = (addr >> 8) & 0xFF; /* addr */ + cmd[3] = addr & 0xFF; /* LSB of addr */ + cmd[4] = len; /* Allocation length */ + cmd[5] = flags; /* Link/Flag */ + + i = ncr5380_dorequest(sc, id, lun, cmd, 6, databuf, datalen, &sent); + + return i; +} diff --git a/sys/dev/ic/ncr5380reg.h b/sys/dev/ic/ncr5380reg.h new file mode 100644 index 00000000000..600a26f9b3b --- /dev/null +++ b/sys/dev/ic/ncr5380reg.h @@ -0,0 +1,135 @@ +/* $NetBSD: ncr5380reg.h,v 1.1 1995/07/08 21:30:43 pk Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY (mach3) + * Revision 2.3 91/08/24 12:25:10 af + * Moved padding of regmap in impl file. + * [91/08/02 04:22:39 af] + * + * Revision 2.2 91/06/19 16:28:35 rvb + * From the NCR data sheets + * "NCR 5380 Family, SCSI Protocol Controller Data Manual" + * NCR Microelectronics Division, Colorado Spring, 6/98 T01891L + * [91/04/21 af] + * + */ + +/* + * File: scsi_5380.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 5/91 + * + * Defines for the NCR 5380 (SCSI chip), aka Am5380 + */ + +/* + * Register map + */ +typedef struct { + volatile unsigned char sci_data; /* r: Current data */ +#define sci_odata sci_data /* w: Out data */ + volatile unsigned char sci_icmd; /* rw: Initiator command */ + volatile unsigned char sci_mode; /* rw: Mode */ + volatile unsigned char sci_tcmd; /* rw: Target command */ + volatile unsigned char sci_bus_csr; /* r: Bus Status */ +#define sci_sel_enb sci_bus_csr /* w: Select enable */ + volatile unsigned char sci_csr; /* r: Status */ +#define sci_dma_send sci_csr /* w: Start dma send data */ + volatile unsigned char sci_idata; /* r: Input data */ +#define sci_trecv sci_idata /* w: Start dma receive, target */ + volatile unsigned char sci_iack; /* r: Interrupt Acknowledge */ +#define sci_irecv sci_iack /* w: Start dma receive, initiator */ +} sci_regmap_t; + + +/* + * Initiator command register + */ +#define SCI_ICMD_DATA 0x01 /* rw: Assert data bus */ +#define SCI_ICMD_ATN 0x02 /* rw: Assert ATN signal */ +#define SCI_ICMD_SEL 0x04 /* rw: Assert SEL signal */ +#define SCI_ICMD_BSY 0x08 /* rw: Assert BSY signal */ +#define SCI_ICMD_ACK 0x10 /* rw: Assert ACK signal */ +#define SCI_ICMD_LST 0x20 /* r: Lost arbitration */ +#define SCI_ICMD_DIFF SCI_ICMD_LST /* w: Differential cable */ +#define SCI_ICMD_AIP 0x40 /* r: Arbitration in progress */ +#define SCI_ICMD_TEST SCI_ICMD_AIP /* w: Test mode */ +#define SCI_ICMD_RST 0x80 /* rw: Assert RST signal */ + + +/* + * Mode register + */ +#define SCI_MODE_ARB 0x01 /* rw: Start arbitration */ +#define SCI_MODE_DMA 0x02 /* rw: Enable DMA xfers */ +#define SCI_MODE_MONBSY 0x04 /* rw: Monitor BSY signal */ +#define SCI_MODE_DMA_IE 0x08 /* rw: Enable DMA complete interrupt */ +#define SCI_MODE_PERR_IE 0x10 /* rw: Interrupt on parity errors */ +#define SCI_MODE_PAR_CHK 0x20 /* rw: Check parity */ +#define SCI_MODE_TARGET 0x40 /* rw: Target mode (Initiator if 0) */ +#define SCI_MODE_BLOCKDMA 0x80 /* rw: Block-mode DMA handshake (MBZ) */ + + +/* + * Target command register + */ +#define SCI_TCMD_IO 0x01 /* rw: Assert I/O signal */ +#define SCI_TCMD_CD 0x02 /* rw: Assert C/D signal */ +#define SCI_TCMD_MSG 0x04 /* rw: Assert MSG signal */ +#define SCI_TCMD_PHASE_MASK 0x07 /* r: Mask for current bus phase */ +#define SCI_TCMD_REQ 0x08 /* rw: Assert REQ signal */ +#define SCI_TCMD_LAST_SENT 0x80 /* ro: Last byte was xferred + * (not on 5380/1) */ + +#define SCI_PHASE(x) ((x)&0x7) + +/* + * Current (SCSI) Bus status + */ +#define SCI_BUS_DBP 0x01 /* r: Data Bus parity */ +#define SCI_BUS_SEL 0x02 /* r: SEL signal */ +#define SCI_BUS_IO 0x04 /* r: I/O signal */ +#define SCI_BUS_CD 0x08 /* r: C/D signal */ +#define SCI_BUS_MSG 0x10 /* r: MSG signal */ +#define SCI_BUS_REQ 0x20 /* r: REQ signal */ +#define SCI_BUS_BSY 0x40 /* r: BSY signal */ +#define SCI_BUS_RST 0x80 /* r: RST signal */ + +#define SCI_CUR_PHASE(x) SCI_PHASE((x)>>2) + +/* + * Bus and Status register + */ +#define SCI_CSR_ACK 0x01 /* r: ACK signal */ +#define SCI_CSR_ATN 0x02 /* r: ATN signal */ +#define SCI_CSR_DISC 0x04 /* r: Disconnected (BSY==0) */ +#define SCI_CSR_PHASE_MATCH 0x08 /* r: Bus and SCI_TCMD match */ +#define SCI_CSR_INT 0x10 /* r: Interrupt request */ +#define SCI_CSR_PERR 0x20 /* r: Parity error */ +#define SCI_CSR_DREQ 0x40 /* r: DMA request */ +#define SCI_CSR_DONE 0x80 /* r: DMA count is zero */ diff --git a/sys/dev/ic/ncr5380var.h b/sys/dev/ic/ncr5380var.h new file mode 100644 index 00000000000..df0cb788df8 --- /dev/null +++ b/sys/dev/ic/ncr5380var.h @@ -0,0 +1,115 @@ +/* $NetBSD: ncr5380var.h,v 1.3 1995/09/26 19:24:26 thorpej Exp $ */ + +/* + * Copyright (C) 1994 Adam Glass, Gordon W. Ross + * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, + * Michael L. Finch, Bradley A. Grantham, and + * Lawrence A. Kesteloot + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Alice Group. + * 4. The names of the Alice Group or any of its members may not be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define SCI_PHASE_DISC 0 /* sort of ... */ +#define SCI_CLR_INTR(regs) ((volatile)(regs->sci_iack)) +#define SCI_ACK(ptr,phase) (ptr)->sci_tcmd = (phase) +#define SCSI_TIMEOUT_VAL 1000000 +#define WAIT_FOR_NOT_REQ(ptr) { \ + int scsi_timeout = SCSI_TIMEOUT_VAL; \ + while ( ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ + ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ + ((ptr)->sci_bus_csr & SCI_BUS_REQ) && \ + (--scsi_timeout) ); \ + if (!scsi_timeout) { \ + printf("scsi timeout--WAIT_FOR_NOT_REQ---%s, line %d.\n", \ + __FILE__, __LINE__); \ + goto scsi_timeout_error; \ + } \ + } +#define WAIT_FOR_REQ(ptr) { \ + int scsi_timeout = SCSI_TIMEOUT_VAL; \ + while ( (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_REQ) == 0) && \ + (--scsi_timeout) ); \ + if (!scsi_timeout) { \ + printf("scsi timeout--WAIT_FOR_REQ---%s, line %d.\n", \ + __FILE__, __LINE__); \ + goto scsi_timeout_error; \ + } \ + } +#define WAIT_FOR_BSY(ptr) { \ + int scsi_timeout = SCSI_TIMEOUT_VAL; \ + while ( (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ + (((ptr)->sci_bus_csr & SCI_BUS_BSY) == 0) && \ + (--scsi_timeout) ); \ + if (!scsi_timeout) { \ + printf("scsi timeout--WAIT_FOR_BSY---%s, line %d.\n", \ + __FILE__, __LINE__); \ + goto scsi_timeout_error; \ + } \ + } + +#define ARBITRATION_RETRIES 1000 + +#ifndef DDB +#define Debugger() panic("Should call Debugger here %s:%d", \ + __FILE__, __LINE__) +#endif /* ! DDB */ + +struct ncr5380_softc { + struct device sc_dev; + struct intrhand sc_ih; /* interrupt info */ + volatile void *sc_regs; + int sc_adapter_type; + int sc_adapter_iv_am; /* int. vec + address modifier */ + struct scsi_link sc_link; +}; + +static int ncr5380_reset_scsibus __P((struct ncr5380_softc *)); +static int ncr5380_poll __P((int, int)); +static void ncr5380_sbc_intr __P((struct ncr5380_softc *)); +static int ncr5380_send_cmd __P((struct scsi_xfer *)); +static int ncr5380_scsi_cmd __P((struct scsi_xfer *)); +static int ncr5380_data_in __P((sci_regmap_t *, int, int, u_char *)); +static int ncr5380_data_out __P((sci_regmap_t *, int, int, u_char *)); +static int ncr5380_select_target __P((volatile sci_regmap_t *, u_char, + u_char, int)); +static int ncr5380_command_transfer __P((volatile sci_regmap_t *, int, + u_char *, u_char *, u_char *)); +static int ncr5380_data_transfer __P((volatile sci_regmap_t *, int, + u_char *, u_char *, u_char *)); +static int ncr5380_dorequest __P((struct ncr5380_softc *, int, int, + u_char *, int, char *, int, int *)); + +static int ncr5380_generic __P((void *, int, int, struct scsi_generic *, + int, void *, int)); +static int ncr5380_group0 __P((void *, int, int, int, int, int, + int, caddr_t, int)); + + diff --git a/sys/dev/ic/nec765reg.h b/sys/dev/ic/nec765reg.h new file mode 100644 index 00000000000..670117f43db --- /dev/null +++ b/sys/dev/ic/nec765reg.h @@ -0,0 +1,73 @@ +/* $NetBSD: nec765reg.h,v 1.3 1994/10/27 04:18:41 cgd Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)nec765.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * Nec 765 floppy disc controller definitions + */ + +/* Main status register */ +#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */ +#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */ +#define NE7_CB 0x10 /* Diskette Controller Busy */ +#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */ +#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */ +#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */ + +/* Status register ST0 */ +#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head" + +/* Status register ST1 */ +#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am" + +/* Status register ST2 */ +#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam" + +/* Status register ST3 */ +#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002" + +/* Commands */ +#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit + parameters byte */ +#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */ +#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */ +#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */ +#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */ +#define NE7CMD_RECAL 7 /* recalibrate drive - requires + unit select byte */ +#define NE7CMD_SENSEI 8 /* sense controller interrupt status */ +#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte + and new cyl byte */ diff --git a/sys/dev/ic/ns16450reg.h b/sys/dev/ic/ns16450reg.h new file mode 100644 index 00000000000..3b6372c994d --- /dev/null +++ b/sys/dev/ic/ns16450reg.h @@ -0,0 +1,51 @@ +/* $NetBSD: ns16450reg.h,v 1.3 1994/10/27 04:18:42 cgd Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns16450.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * NS16450 UART registers + */ + +#define com_data 0 /* data register (R/W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_dlbh 1 /* divisor latch high (W) */ +#define com_ier 1 /* interrupt enable (W) */ +#define com_iir 2 /* interrupt identification (R) */ +#define com_lctl 3 /* line control register (R/W) */ +#define com_cfcr 3 /* line control register (R/W) */ +#define com_mcr 4 /* modem control register (R/W) */ +#define com_lsr 5 /* line status register (R/W) */ +#define com_msr 6 /* modem status register (R/W) */ diff --git a/sys/dev/ic/ns16550reg.h b/sys/dev/ic/ns16550reg.h new file mode 100644 index 00000000000..b9cf9726851 --- /dev/null +++ b/sys/dev/ic/ns16550reg.h @@ -0,0 +1,53 @@ +/* $NetBSD: ns16550reg.h,v 1.4 1994/10/27 04:18:43 cgd Exp $ */ + +/*- + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ns16550.h 7.1 (Berkeley) 5/9/91 + */ + +/* + * NS16550 UART registers + */ + +#define com_data 0 /* data register (R/W) */ +#define com_dlbl 0 /* divisor latch low (W) */ +#define com_dlbh 1 /* divisor latch high (W) */ +#define com_ier 1 /* interrupt enable (W) */ +#define com_iir 2 /* interrupt identification (R) */ +#define com_fifo 2 /* FIFO control (W) */ +#define com_lctl 3 /* line control register (R/W) */ +#define com_cfcr 3 /* line control register (R/W) */ +#define com_mcr 4 /* modem control register (R/W) */ +#define com_lsr 5 /* line status register (R/W) */ +#define com_msr 6 /* modem status register (R/W) */ +#define com_scratch 7 /* scratch register (R/W) */ diff --git a/sys/dev/ic/pdq.c b/sys/dev/ic/pdq.c new file mode 100644 index 00000000000..27001b0890a --- /dev/null +++ b/sys/dev/ic/pdq.c @@ -0,0 +1,1549 @@ +/* $NetBSD: pdq.c,v 1.2 1995/08/19 04:35:18 cgd Exp $ */ + +/*- + * Copyright (c) 1995 Matt Thomas (matt@lkg.dec.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * DEC PDQ FDDI Controller O/S independent code + * + * Written by Matt Thomas <matt@lkg.dec.com> + * + * This module should work any PDQ based board. Note that changes for + * MIPS and Alpha architectures (or any other architecture which requires + * a flushing of memory or write buffers and/or has incoherent caches) + * have yet to be made. + */ + +#define PDQ_HWSUPPORT /* for pdq.h */ + +#include "pdqreg.h" +#ifndef __NetBSD__ +#include "pdq_os.h" +#else +#include "pdqvar.h" +#endif + +#define PDQ_ROUNDUP(n, x) (((n) + ((x) - 1)) & ~((x) - 1)) +#define PDQ_CMD_RX_ALIGNMENT 16 + +#if defined(PDQTEST) && !defined(PDQ_NOPRINTF) +#define PDQ_PRINTF(x) printf x +#else +#define PDQ_PRINTF(x) do { } while (0) +#endif + +const char * const pdq_halt_codes[] = { + "Selftest Timeout", "Host Bus Parity Error", "Host Directed Fault", + "Software Fault", "Hardware Fault", "PC Trace Path Test", + "DMA Error", "Image CRC Error", "Adapter Processer Error" +}; + +const char * const pdq_adapter_states[] = { + "Reset", "Upgrade", "DMA Unavailable", "DMA Available", + "Link Available", "Link Unavailable", "Halted", "Ring Member" +}; + +/* + * The following are used in conjunction with + * unsolicited events + */ +const char * const pdq_entities[] = { + "Station", "Link", "Phy Port" +}; + +const char * const pdq_station_events[] = { + "Trace Received" +}; + +const char * const pdq_station_arguments[] = { + "Reason" +}; + +const char * const pdq_link_events[] = { + "Transmit Underrun", + "Transmit Failed", + "Block Check Error (CRC)", + "Frame Status Error", + "PDU Length Error", + NULL, + NULL, + "Receive Data Overrun", + NULL, + "No User Buffer", + "Ring Initialization Initiated", + "Ring Initialization Received", + "Ring Beacon Initiated", + "Duplicate Address Failure", + "Duplicate Token Detected", + "Ring Purger Error", + "FCI Strip Error", + "Trace Initiated", + "Directed Beacon Received", +}; + +const char * const pdq_link_arguments[] = { + "Reason", + "Data Link Header", + "Source", + "Upstream Neighbor" +}; + +const char * const pdq_phy_events[] = { + "LEM Error Monitor Reject", + "Elasticy Buffer Error", + "Link Confidence Test Reject" +}; + +const char * const pdq_phy_arguments[] = { + "Direction" +}; + +const char * const * const pdq_event_arguments[] = { + pdq_station_arguments, + pdq_link_arguments, + pdq_phy_arguments +}; + +const char * const * const pdq_event_codes[] = { + pdq_station_events, + pdq_link_events, + pdq_phy_events +}; + +const char * const pdq_station_types[] = { + "SAS", "DAC", "SAC", "NAC", "DAS" +}; + +const char * const pdq_smt_versions[] = { "", "V6.2", "V7.2", "V7.3" }; + +const char pdq_phy_types[] = "ABSM"; + +const char * const pdq_pmd_types0[] = { + "ANSI Multi-Mode", "ANSI Single-Mode Type 1", "ANSI Single-Mode Type 2", + "ANSI Sonet" +}; + +const char * const pdq_pmd_types100[] = { + "Low Power", "Thin Wire", "Shielded Twisted Pair", + "Unshielded Twisted Pair" +}; + +const char * const * const pdq_pmd_types[] = { + pdq_pmd_types0, pdq_pmd_types100 +}; + +const char * const pdq_descriptions[] = { + "DEFPA PCI", + "DEFEA EISA", +}; + +void +pdq_print_fddi_chars( + pdq_t *pdq, + const pdq_response_status_chars_get_t *rsp) +{ + const char hexchars[] = "0123456789abcdef"; + + printf( +#if !defined(__bsdi__) && !defined(__NetBSD__) + PDQ_OS_PREFIX +#else + ": " +#endif + "DEC %s FDDI %s Controller\n", +#if !defined(__bsdi__) && !defined(__NetBSD__) + PDQ_OS_PREFIX_ARGS, +#endif + pdq_descriptions[pdq->pdq_type], + pdq_station_types[rsp->status_chars_get.station_type]); + + printf(PDQ_OS_PREFIX "FDDI address %c%c:%c%c:%c%c:%c%c:%c%c:%c%c, FW=%c%c%c%c, HW=%c", + PDQ_OS_PREFIX_ARGS, + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] >> 4], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[0] & 0x0F], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] >> 4], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[1] & 0x0F], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] >> 4], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[2] & 0x0F], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] >> 4], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[3] & 0x0F], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] >> 4], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[4] & 0x0F], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] >> 4], + hexchars[pdq->pdq_hwaddr.lanaddr_bytes[5] & 0x0F], + pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1], + pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3], + rsp->status_chars_get.module_rev.fwrev_bytes[0]); + + if (rsp->status_chars_get.smt_version_id < PDQ_ARRAY_SIZE(pdq_smt_versions)) { + printf(", SMT %s\n", pdq_smt_versions[rsp->status_chars_get.smt_version_id]); + } + + printf(PDQ_OS_PREFIX "FDDI Port%s = %c (PMD = %s)", + PDQ_OS_PREFIX_ARGS, + rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS ? "[A]" : "", + pdq_phy_types[rsp->status_chars_get.phy_type[0]], + pdq_pmd_types[rsp->status_chars_get.pmd_type[0] / 100][rsp->status_chars_get.pmd_type[0] % 100]); + + if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS) + printf(", FDDI Port[B] = %c (PMD = %s)", + pdq_phy_types[rsp->status_chars_get.phy_type[1]], + pdq_pmd_types[rsp->status_chars_get.pmd_type[1] / 100][rsp->status_chars_get.pmd_type[1] % 100]); + + printf("\n"); +} + +void +pdq_init_csrs( + pdq_csrs_t *csrs, + void *csr_va, + size_t csrsize) +{ + volatile pdq_uint32_t *csr_base = (volatile pdq_uint32_t *) csr_va; + + csrs->csr_port_reset = &csr_base[0 * csrsize]; + csrs->csr_host_data = &csr_base[1 * csrsize]; + csrs->csr_port_control = &csr_base[2 * csrsize]; + csrs->csr_port_data_a = &csr_base[3 * csrsize]; + csrs->csr_port_data_b = &csr_base[4 * csrsize]; + csrs->csr_port_status = &csr_base[5 * csrsize]; + csrs->csr_host_int_type_0 = &csr_base[6 * csrsize]; + csrs->csr_host_int_enable = &csr_base[7 * csrsize]; + csrs->csr_type_2_producer = &csr_base[8 * csrsize]; + csrs->csr_cmd_response_producer = &csr_base[10 * csrsize]; + csrs->csr_cmd_request_producer = &csr_base[11 * csrsize]; + csrs->csr_host_smt_producer = &csr_base[12 * csrsize]; + csrs->csr_unsolicited_producer = &csr_base[13 * csrsize]; +} + +void +pdq_init_pci_csrs( + pdq_pci_csrs_t *csrs, + void *csr_va, + size_t csrsize) +{ + volatile pdq_uint32_t *csr_base = (volatile pdq_uint32_t *) csr_va; + + csrs->csr_pfi_mode_control = &csr_base[16 * csrsize]; + csrs->csr_pfi_status = &csr_base[17 * csrsize]; + csrs->csr_fifo_write = &csr_base[18 * csrsize]; + csrs->csr_fifo_read = &csr_base[19 * csrsize]; +} + +void +pdq_flush_databuf_queue( + pdq_databuf_queue_t *q) +{ + PDQ_OS_DATABUF_T *pdu; + for (;;) { + PDQ_OS_DATABUF_DEQUEUE(q, pdu); + if (pdu == NULL) + return; + PDQ_OS_DATABUF_FREE(pdu); + } +} + +pdq_boolean_t +pdq_do_port_control( + const pdq_csrs_t * const csrs, + pdq_uint32_t cmd) +{ + int cnt = 0; + *csrs->csr_host_int_type_0 = PDQ_HOST_INT_CSR_CMD_DONE; + *csrs->csr_port_control = PDQ_PCTL_CMD_ERROR | cmd; + while ((*csrs->csr_host_int_type_0 & PDQ_HOST_INT_CSR_CMD_DONE) == 0 && cnt < 33000000) + cnt++; + PDQ_PRINTF(("CSR cmd spun %d times\n", cnt)); + if (*csrs->csr_host_int_type_0 & PDQ_HOST_INT_CSR_CMD_DONE) { + *csrs->csr_host_int_type_0 = PDQ_HOST_INT_CSR_CMD_DONE; + return (*csrs->csr_port_control & PDQ_PCTL_CMD_ERROR) ? PDQ_FALSE : PDQ_TRUE; + } + /* adapter failure */ + PDQ_ASSERT(0); + return PDQ_FALSE; +} + +void +pdq_read_mla( + const pdq_csrs_t * const csrs, + pdq_lanaddr_t *hwaddr) +{ + pdq_uint32_t data; + + *csrs->csr_port_data_a = 0; + pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ); + data = *csrs->csr_host_data; + + hwaddr->lanaddr_bytes[0] = (data >> 0) & 0xFF; + hwaddr->lanaddr_bytes[1] = (data >> 8) & 0xFF; + hwaddr->lanaddr_bytes[2] = (data >> 16) & 0xFF; + hwaddr->lanaddr_bytes[3] = (data >> 24) & 0xFF; + + *csrs->csr_port_data_a = 1; + pdq_do_port_control(csrs, PDQ_PCTL_MLA_READ); + data = *csrs->csr_host_data; + + hwaddr->lanaddr_bytes[4] = (data >> 0) & 0xFF; + hwaddr->lanaddr_bytes[5] = (data >> 8) & 0xFF; +} + +void +pdq_read_fwrev( + const pdq_csrs_t * const csrs, + pdq_fwrev_t *fwrev) +{ + pdq_uint32_t data; + + pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ); + data = *csrs->csr_host_data; + + fwrev->fwrev_bytes[3] = (data >> 0) & 0xFF; + fwrev->fwrev_bytes[2] = (data >> 8) & 0xFF; + fwrev->fwrev_bytes[1] = (data >> 16) & 0xFF; + fwrev->fwrev_bytes[0] = (data >> 24) & 0xFF; +} + +pdq_boolean_t +pdq_read_error_log( + pdq_t *pdq, + pdq_response_error_log_get_t *log_entry) +{ + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + pdq_uint32_t *ptr = (pdq_uint32_t *) log_entry; + + pdq_do_port_control(csrs, PDQ_PCTL_ERROR_LOG_START); + + while (pdq_do_port_control(csrs, PDQ_PCTL_FW_REV_READ) == PDQ_TRUE) { + *ptr++ = *csrs->csr_host_data; + if ((pdq_uint8_t *) ptr - (pdq_uint8_t *) log_entry == sizeof(*log_entry)) + break; + } + return (ptr == (pdq_uint32_t *) log_entry) ? PDQ_FALSE : PDQ_TRUE; +} + +pdq_chip_rev_t +pdq_read_chiprev( + const pdq_csrs_t * const csrs) +{ + pdq_uint32_t data; + + *csrs->csr_port_data_a = PDQ_SUB_CMD_PDQ_REV_GET; + pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD); + data = *csrs->csr_host_data; + + return (pdq_chip_rev_t) data; +} + +static const struct { + size_t cmd_len; + size_t rsp_len; + const char *cmd_name; +} pdq_cmd_info[] = { + { sizeof(pdq_cmd_generic_t), /* 0 - PDQC_START */ + sizeof(pdq_response_generic_t), + "Start" + }, + { sizeof(pdq_cmd_filter_set_t), /* 1 - PDQC_FILTER_SET */ + sizeof(pdq_response_generic_t), + "Filter Set" + }, + { sizeof(pdq_cmd_generic_t), /* 2 - PDQC_FILTER_GET */ + sizeof(pdq_response_filter_get_t), + "Filter Get" + }, + { sizeof(pdq_cmd_chars_set_t), /* 3 - PDQC_CHARS_SET */ + sizeof(pdq_response_generic_t), + "Chars Set" + }, + { sizeof(pdq_cmd_generic_t), /* 4 - PDQC_STATUS_CHARS_GET */ + sizeof(pdq_response_status_chars_get_t), + "Status Chars Get" + }, +#if 0 + { sizeof(pdq_cmd_generic_t), /* 5 - PDQC_COUNTERS_GET */ + sizeof(pdq_response_counters_get_t), + "Counters Get" + }, + { sizeof(pdq_cmd_counters_set_t), /* 6 - PDQC_COUNTERS_SET */ + sizeof(pdq_response_generic_t), + "Counters Set" + }, +#else + { 0, 0, "Counters Get" }, + { 0, 0, "Counters Set" }, +#endif + { sizeof(pdq_cmd_addr_filter_set_t), /* 7 - PDQC_ADDR_FILTER_SET */ + sizeof(pdq_response_generic_t), + "Addr Filter Set" + }, + { sizeof(pdq_cmd_generic_t), /* 8 - PDQC_ADDR_FILTER_GET */ + sizeof(pdq_response_addr_filter_get_t), + "Addr Filter Get" + }, +#if 0 + { sizeof(pdq_cmd_generic_t), /* 9 - PDQC_ERROR_LOG_CLEAR */ + sizeof(pdq_response_generic_t), + "Error Log Clear" + }, + { sizeof(pdq_cmd_generic_t), /* 10 - PDQC_ERROR_LOG_SET */ + sizeof(pdq_response_generic_t), + "Error Log Set" + }, + { sizeof(pdq_cmd_generic_t), /* 11 - PDQC_FDDI_MIB_GET */ + sizeof(pdq_response_generic_t), + "FDDI MIB Get" + }, + { sizeof(pdq_cmd_generic_t), /* 12 - PDQC_DEC_EXT_MIB_GET */ + sizeof(pdq_response_generic_t), + "DEC Ext MIB Get" + }, + { sizeof(pdq_cmd_generic_t), /* 13 - PDQC_DEC_SPECIFIC_GET */ + sizeof(pdq_response_generic_t), + "DEC Specific Get" + }, + { sizeof(pdq_cmd_generic_t), /* 14 - PDQC_SNMP_SET */ + sizeof(pdq_response_generic_t), + "SNMP Set" + }, + { 0, 0, "N/A" }, + { sizeof(pdq_cmd_generic_t), /* 16 - PDQC_SMT_MIB_GET */ + sizeof(pdq_response_generic_t), + "SMT MIB Get" + }, + { sizeof(pdq_cmd_generic_t), /* 17 - PDQC_SMT_MIB_SET */ + sizeof(pdq_response_generic_t), + "SMT MIB Set", + }, +#endif +}; + +void +pdq_queue_commands( + pdq_t *pdq) +{ + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + pdq_command_info_t * const ci = &pdq->pdq_command_info; + pdq_descriptor_block_t * const dbp = pdq->pdq_dbp; + pdq_cmd_code_t op; + pdq_uint32_t cmdlen, rsplen, mask; + + /* + * If there are commands or responses active or there aren't + * any pending commands, then don't queue any more. + */ + if (ci->ci_command_active || ci->ci_pending_commands == 0) + return; + + /* + * Determine which command needs to be queued. + */ + op = PDQC_SMT_MIB_SET; + for (mask = 1 << ((int) op); (mask & ci->ci_pending_commands) == 0; mask >>= 1) + op = (pdq_cmd_code_t) ((int) op - 1); + /* + * Obtain the sizes needed for the command and response. + * Round up to PDQ_CMD_RX_ALIGNMENT so the receive buffer is + * always properly aligned. + */ + cmdlen = PDQ_ROUNDUP(pdq_cmd_info[op].cmd_len, PDQ_CMD_RX_ALIGNMENT); + rsplen = PDQ_ROUNDUP(pdq_cmd_info[op].rsp_len, PDQ_CMD_RX_ALIGNMENT); + if (cmdlen < rsplen) + cmdlen = rsplen; + /* + * Since only one command at a time will be queued, there will always + * be enough space. + */ + + /* + * Obtain and fill in the descriptor for the command (descriptor is + * pre-initialized) + */ + dbp->pdqdb_command_requests[ci->ci_request_producer].txd_seg_len = cmdlen; + PDQ_ADVANCE(ci->ci_request_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests)); + + /* + * Obtain and fill in the descriptor for the response (descriptor is + * pre-initialized) + */ + dbp->pdqdb_command_responses[ci->ci_response_producer].rxd_seg_len_hi = cmdlen / 16; + PDQ_ADVANCE(ci->ci_response_producer, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses)); + + /* + * Clear the command area, set the opcode, and the command from the pending + * mask. + */ + + PDQ_OS_MEMZERO(ci->ci_bufstart, cmdlen); + *(pdq_cmd_code_t *) ci->ci_bufstart = op; + ci->ci_pending_commands &= ~mask; + + /* + * Fill in the command area, if needed. + */ + switch (op) { + case PDQC_FILTER_SET: { + pdq_cmd_filter_set_t *filter_set = (pdq_cmd_filter_set_t *) ci->ci_bufstart; + unsigned idx = 0; + filter_set->filter_set_items[idx].item_code = PDQI_IND_GROUP_PROM; + filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PROMISC ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK); + idx++; + filter_set->filter_set_items[idx].item_code = PDQI_GROUP_PROM; + filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_ALLMULTI ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK); + idx++; + filter_set->filter_set_items[idx].item_code = PDQI_SMT_PROM; + filter_set->filter_set_items[idx].filter_state = ((pdq->pdq_flags & (PDQ_PROMISC|PDQ_PASS_SMT)) == (PDQ_PROMISC|PDQ_PASS_SMT) ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK); + idx++; + filter_set->filter_set_items[idx].item_code = PDQI_SMT_USER; + filter_set->filter_set_items[idx].filter_state = (pdq->pdq_flags & PDQ_PASS_SMT ? PDQ_FILTER_PASS : PDQ_FILTER_BLOCK); + idx++; + filter_set->filter_set_items[idx].item_code = PDQI_EOL; + break; + } + case PDQC_ADDR_FILTER_SET: { + pdq_cmd_addr_filter_set_t *addr_filter_set = (pdq_cmd_addr_filter_set_t *) ci->ci_bufstart; + pdq_lanaddr_t *addr = addr_filter_set->addr_filter_set_addresses; + addr->lanaddr_bytes[0] = 0xFF; + addr->lanaddr_bytes[1] = 0xFF; + addr->lanaddr_bytes[2] = 0xFF; + addr->lanaddr_bytes[3] = 0xFF; + addr->lanaddr_bytes[4] = 0xFF; + addr->lanaddr_bytes[5] = 0xFF; + addr++; + pdq_os_addr_fill(pdq, addr, 61); + break; + } + } + /* + * At this point the command is done. All that needs to be done is to + * produce it to the PDQ. + */ + PDQ_PRINTF(("PDQ Queue Command Request: %s queued\n", + pdq_cmd_info[op].cmd_name)); + + ci->ci_command_active++; + *csrs->csr_cmd_response_producer = ci->ci_response_producer | (ci->ci_response_completion << 8); + *csrs->csr_cmd_request_producer = ci->ci_request_producer | (ci->ci_request_completion << 8); +} + +void +pdq_process_command_responses( + pdq_t * const pdq) +{ + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + pdq_command_info_t * const ci = &pdq->pdq_command_info; + volatile const pdq_consumer_block_t * const cbp = pdq->pdq_cbp; + pdq_descriptor_block_t * const dbp = pdq->pdq_dbp; + pdq_txdesc_t *txd; + pdq_rxdesc_t *rxd; + const pdq_response_generic_t *rspgen; + + /* + * We have to process the command and response in tandem so + * just wait for the response to be consumed. If it has been + * consumed then the command must have been as well. + */ + + if (cbp->pdqcb_command_response == ci->ci_response_completion) + return; + + PDQ_ASSERT (cbp->pdqcb_command_request != ci->ci_request_completion); + + txd = &dbp->pdqdb_command_requests[ci->ci_request_completion]; + rxd = &dbp->pdqdb_command_responses[ci->ci_response_completion]; + + rspgen = (const pdq_response_generic_t *) ci->ci_bufstart; + PDQ_ASSERT(rspgen->generic_status == PDQR_SUCCESS); + PDQ_PRINTF(("PDQ Process Command Response: %s completed\n", + pdq_cmd_info[rspgen->generic_op].cmd_name)); + + if (rspgen->generic_op == PDQC_STATUS_CHARS_GET && (pdq->pdq_flags & PDQ_PRINTCHARS)) { + pdq->pdq_flags &= ~PDQ_PRINTCHARS; + pdq_print_fddi_chars(pdq, (const pdq_response_status_chars_get_t *) rspgen); + } + + PDQ_ADVANCE(ci->ci_request_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_requests)); + PDQ_ADVANCE(ci->ci_response_completion, 1, PDQ_RING_MASK(dbp->pdqdb_command_responses)); + ci->ci_command_active = 0; + + if (ci->ci_pending_commands != 0) { + pdq_queue_commands(pdq); + } else { + *csrs->csr_cmd_response_producer = ci->ci_response_producer | (ci->ci_response_completion << 8); + *csrs->csr_cmd_request_producer = ci->ci_request_producer | (ci->ci_request_completion << 8); + } +} + +/* + * This following routine processes unsolicited events. + * In addition, it also fills the unsolicited queue with + * event buffers so it can be used to initialize the queue + * as well. + */ +void +pdq_process_unsolicited_events( + pdq_t *pdq) +{ + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + pdq_unsolicited_info_t *ui = &pdq->pdq_unsolicited_info; + volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp; + pdq_descriptor_block_t *dbp = pdq->pdq_dbp; + const pdq_unsolicited_event_t *event; + pdq_rxdesc_t *rxd; + + /* + * Process each unsolicited event (if any). + */ + + while (cbp->pdqcb_unsolicited_event != ui->ui_completion) { + rxd = &dbp->pdqdb_unsolicited_events[ui->ui_completion]; + event = &ui->ui_events[ui->ui_completion & (PDQ_NUM_UNSOLICITED_EVENTS-1)]; + + switch (event->event_type) { + case PDQ_UNSOLICITED_EVENT: { + printf(PDQ_OS_PREFIX "Unsolicited Event: %s: %s", + PDQ_OS_PREFIX_ARGS, + pdq_entities[event->event_entity], + pdq_event_codes[event->event_entity][event->event_code.value]); + if (event->event_type == PDQ_ENTITY_PHY_PORT) + printf("[%d]", event->event_index); + printf("\n"); + break; + } + case PDQ_UNSOLICITED_COUNTERS: { + break; + } + } + PDQ_ADVANCE(ui->ui_completion, 1, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events)); + ui->ui_free++; + } + + /* + * Now give back the event buffers back to the PDQ. + */ + PDQ_ADVANCE(ui->ui_producer, ui->ui_free, PDQ_RING_MASK(dbp->pdqdb_unsolicited_events)); + ui->ui_free = 0; + + *csrs->csr_unsolicited_producer = ui->ui_producer | (ui->ui_completion << 8); +} + +void +pdq_process_received_data( + pdq_t *pdq, + pdq_rx_info_t *rx, + pdq_rxdesc_t *receives, + pdq_uint32_t completion_goal, + pdq_uint32_t ring_mask) +{ + pdq_uint32_t completion = rx->rx_completion; + pdq_uint32_t producer = rx->rx_producer; + PDQ_OS_DATABUF_T **buffers = (PDQ_OS_DATABUF_T **) rx->rx_buffers; + pdq_rxdesc_t *rxd; + pdq_uint32_t idx; + + while (completion != completion_goal) { + PDQ_OS_DATABUF_T *fpdu, *lpdu, *npdu; + pdq_uint8_t *dataptr; + pdq_uint32_t fc, datalen, pdulen, segcnt; + pdq_rxstatus_t status; + + fpdu = lpdu = buffers[completion]; + PDQ_ASSERT(fpdu != NULL); + + dataptr = PDQ_OS_DATABUF_PTR(fpdu); + status = *(pdq_rxstatus_t *) dataptr; + if ((status.rxs_status & 0x200000) == 0) { + datalen = status.rxs_status & 0x1FFF; + fc = dataptr[PDQ_RX_FC_OFFSET]; + switch (fc & (PDQ_FDDIFC_C|PDQ_FDDIFC_L|PDQ_FDDIFC_F)) { + case PDQ_FDDI_LLC_ASYNC: + case PDQ_FDDI_LLC_SYNC: + case PDQ_FDDI_IMP_ASYNC: + case PDQ_FDDI_IMP_SYNC: { + if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_LLC_MIN) { + PDQ_PRINTF(("discard: bad length %d\n", datalen)); + goto discard_frame; + } + break; + } + case PDQ_FDDI_SMT: { + if (datalen > PDQ_FDDI_MAX || datalen < PDQ_FDDI_SMT_MIN) + goto discard_frame; + break; + } + default: { + PDQ_PRINTF(("discard: bad fc 0x%x\n", fc)); + goto discard_frame; + } + } + /* + * Update the lengths of the data buffers now that we know + * the real length. + */ + pdulen = datalen - 4 /* CRC */; + segcnt = (pdulen + PDQ_RX_FC_OFFSET + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE; + PDQ_OS_DATABUF_ALLOC(npdu); + if (npdu == NULL) { + PDQ_PRINTF(("discard: no databuf #0\n")); + goto discard_frame; + } + buffers[completion] = npdu; + for (idx = 1; idx < segcnt; idx++) { + PDQ_OS_DATABUF_ALLOC(npdu); + if (npdu == NULL) { + PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL); + PDQ_OS_DATABUF_FREE(fpdu); + goto discard_frame; + } + PDQ_OS_DATABUF_NEXT_SET(lpdu, buffers[(completion + idx) & ring_mask]); + lpdu = PDQ_OS_DATABUF_NEXT(lpdu); + buffers[(completion + idx) & ring_mask] = npdu; + } + PDQ_OS_DATABUF_NEXT_SET(lpdu, NULL); + for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) { + buffers[(producer + idx) & ring_mask] = + buffers[(completion + idx) & ring_mask]; + buffers[(completion + idx) & ring_mask] = NULL; + } + PDQ_OS_DATABUF_ADJ(fpdu, PDQ_RX_FC_OFFSET); + if (segcnt == 1) { + PDQ_OS_DATABUF_LEN_SET(fpdu, pdulen); + } else { + PDQ_OS_DATABUF_LEN_SET(lpdu, pdulen + PDQ_RX_FC_OFFSET - (segcnt - 1) * PDQ_OS_DATABUF_SIZE); + } + pdq_os_receive_pdu(pdq, fpdu, pdulen); + rx->rx_free += PDQ_RX_SEGCNT; + PDQ_ADVANCE(producer, PDQ_RX_SEGCNT, ring_mask); + PDQ_ADVANCE(completion, PDQ_RX_SEGCNT, ring_mask); + continue; + } else { + PDQ_PRINTF(("discard: bad pdu 0x%x(%d.%d.%d.%d.%d)\n", status.rxs_status, + status.rxs_rcc_badpdu, status.rxs_rcc_badcrc, + status.rxs_rcc_reason, status.rxs_fsc, status.rxs_fsb_e)); + if (status.rxs_rcc_reason == 7) + goto discard_frame; + if (status.rxs_rcc_reason != 0) + /* hardware fault */ + if (status.rxs_rcc_badcrc) { + printf(PDQ_OS_PREFIX " MAC CRC error (source=%x-%x-%x-%x-%x-%x)\n", + PDQ_OS_PREFIX_ARGS, + dataptr[PDQ_RX_FC_OFFSET+1], + dataptr[PDQ_RX_FC_OFFSET+2], + dataptr[PDQ_RX_FC_OFFSET+3], + dataptr[PDQ_RX_FC_OFFSET+4], + dataptr[PDQ_RX_FC_OFFSET+5], + dataptr[PDQ_RX_FC_OFFSET+6]); + /* rx->rx_badcrc++; */ + } else if (status.rxs_fsc == 0 | status.rxs_fsb_e == 1) { + /* rx->rx_frame_status_errors++; */ + } else { + /* hardware fault */ + } + } + discard_frame: + /* + * Discarded frames go right back on the queue; therefore + * ring entries were freed. + */ + for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) { + buffers[producer] = buffers[completion]; + buffers[completion] = NULL; + rxd = &receives[rx->rx_producer]; + if (idx == 0) { + rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1; + } else { + rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0; + } + rxd->rxd_pa_hi = 0; + rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16; + rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(PDQ_OS_DATABUF_PTR(buffers[rx->rx_producer])); + PDQ_ADVANCE(rx->rx_producer, 1, ring_mask); + PDQ_ADVANCE(producer, 1, ring_mask); + PDQ_ADVANCE(completion, 1, ring_mask); + } + } + rx->rx_completion = completion; + + while (rx->rx_free > PDQ_RX_SEGCNT && rx->rx_free > rx->rx_target) { + PDQ_OS_DATABUF_T *pdu; + /* + * Allocate the needed number of data buffers. + * Try to obtain them from our free queue before + * asking the system for more. + */ + for (idx = 0; idx < PDQ_RX_SEGCNT; idx++) { + if ((pdu = buffers[(rx->rx_producer + idx) & ring_mask]) == NULL) { + PDQ_OS_DATABUF_ALLOC(pdu); + if (pdu == NULL) + break; + buffers[(rx->rx_producer + idx) & ring_mask] = pdu; + } + rxd = &receives[(rx->rx_producer + idx) & ring_mask]; + if (idx == 0) { + rxd->rxd_sop = 1; rxd->rxd_seg_cnt = PDQ_RX_SEGCNT - 1; + } else { + rxd->rxd_sop = 0; rxd->rxd_seg_cnt = 0; + } + rxd->rxd_pa_hi = 0; + rxd->rxd_seg_len_hi = PDQ_OS_DATABUF_SIZE / 16; + rxd->rxd_pa_lo = PDQ_OS_VA_TO_PA(PDQ_OS_DATABUF_PTR(pdu)); + } + if (idx < PDQ_RX_SEGCNT) { + /* + * We didn't get all databufs required to complete a new + * receive buffer. Keep the ones we got and retry a bit + * later for the rest. + */ + break; + } + PDQ_ADVANCE(rx->rx_producer, PDQ_RX_SEGCNT, ring_mask); + rx->rx_free -= PDQ_RX_SEGCNT; + } +} + +pdq_boolean_t +pdq_queue_transmit_data( + pdq_t *pdq, + PDQ_OS_DATABUF_T *pdu) +{ + pdq_tx_info_t *tx = &pdq->pdq_tx_info; + pdq_descriptor_block_t *dbp = pdq->pdq_dbp; + pdq_uint32_t producer = tx->tx_producer; + pdq_txdesc_t *eop = NULL; + PDQ_OS_DATABUF_T *pdu0; + pdq_uint32_t freecnt; + + if (tx->tx_free < 1) + return PDQ_FALSE; + + dbp->pdqdb_transmits[producer] = tx->tx_hdrdesc; + PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits)); + + for (freecnt = tx->tx_free - 1, pdu0 = pdu; pdu0 != NULL && freecnt > 0;) { + pdq_uint32_t fraglen, datalen = PDQ_OS_DATABUF_LEN(pdu0); + const pdq_uint8_t *dataptr = PDQ_OS_DATABUF_PTR(pdu0); + + /* + * The first segment is limited to the space remaining in + * page. All segments after that can be up to a full page + * in size. + */ + fraglen = PDQ_OS_PAGESIZE - ((dataptr - (pdq_uint8_t *) NULL) & (PDQ_OS_PAGESIZE-1)); + while (datalen > 0 && freecnt > 0) { + pdq_uint32_t seglen = (fraglen < datalen ? fraglen : datalen); + + /* + * Initialize the transmit descriptor + */ + eop = &dbp->pdqdb_transmits[producer]; + eop->txd_seg_len = seglen; + eop->txd_pa_lo = PDQ_OS_VA_TO_PA(dataptr); + eop->txd_sop = eop->txd_eop = eop->txd_pa_hi = 0; + + datalen -= seglen; + dataptr += seglen; + fraglen = PDQ_OS_PAGESIZE; + freecnt--; + PDQ_ADVANCE(producer, 1, PDQ_RING_MASK(dbp->pdqdb_transmits)); + } + pdu0 = PDQ_OS_DATABUF_NEXT(pdu0); + } + if (pdu0 != NULL) { + PDQ_ASSERT(freecnt == 0); + /* + * If we still have data to process then the ring was too full + * to store the PDU. Return FALSE so the caller will requeue + * the PDU for later. + */ + return PDQ_FALSE; + } + /* + * Everything went fine. Finish it up. + */ + tx->tx_descriptor_count[tx->tx_producer] = tx->tx_free - freecnt; + eop->txd_eop = 1; + PDQ_OS_DATABUF_ENQUEUE(&tx->tx_txq, pdu); + tx->tx_producer = producer; + tx->tx_free = freecnt; + PDQ_DO_TYPE2_PRODUCER(pdq); + return PDQ_TRUE; +} + +void +pdq_process_transmitted_data( + pdq_t *pdq) +{ + pdq_tx_info_t *tx = &pdq->pdq_tx_info; + volatile const pdq_consumer_block_t *cbp = pdq->pdq_cbp; + pdq_descriptor_block_t *dbp = pdq->pdq_dbp; + pdq_uint32_t completion = tx->tx_completion; + + while (completion != cbp->pdqcb_transmits) { + PDQ_OS_DATABUF_T *pdu; + pdq_uint32_t descriptor_count = tx->tx_descriptor_count[completion]; + PDQ_ASSERT(dbp->pdqdb_transmits[completion].txd_sop == 1); + PDQ_ASSERT(dbp->pdqdb_transmits[(completion + descriptor_count - 1) & PDQ_RING_MASK(dbp->pdqdb_transmits)].txd_eop == 1); + PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu); + pdq_os_transmit_done(pdq, pdu); + tx->tx_free += descriptor_count; + + PDQ_ADVANCE(completion, descriptor_count, PDQ_RING_MASK(dbp->pdqdb_transmits)); + } + if (tx->tx_completion != completion) { + tx->tx_completion = completion; + pdq_os_restart_transmitter(pdq); + } + PDQ_DO_TYPE2_PRODUCER(pdq); +} + +void +pdq_flush_transmitter( + pdq_t *pdq) +{ + volatile pdq_consumer_block_t *cbp = pdq->pdq_cbp; + pdq_tx_info_t *tx = &pdq->pdq_tx_info; + + for (;;) { + PDQ_OS_DATABUF_T *pdu; + PDQ_OS_DATABUF_DEQUEUE(&tx->tx_txq, pdu); + if (pdu == NULL) + break; + /* + * Don't call transmit done since the packet never made it + * out on the wire. + */ + PDQ_OS_DATABUF_FREE(pdu); + } + + tx->tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits); + tx->tx_completion = cbp->pdqcb_transmits = tx->tx_producer; + + PDQ_DO_TYPE2_PRODUCER(pdq); +} + +void +pdq_hwreset( + pdq_t *pdq) +{ + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + pdq_state_t state; + int cnt; + + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + if (state == PDQS_DMA_UNAVAILABLE) + return; + *csrs->csr_port_data_a = (state == PDQS_HALTED) ? 0 : PDQ_PRESET_SKIP_SELFTEST; + *csrs->csr_port_reset = 1; + PDQ_OS_USEC_DELAY(100); + *csrs->csr_port_reset = 0; + for (cnt = 45000;;cnt--) { + PDQ_OS_USEC_DELAY(1000); + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + if (state == PDQS_DMA_UNAVAILABLE || cnt == 0) + break; + } + PDQ_PRINTF(("PDQ Reset spun %d cycles\n", 45000 - cnt)); + PDQ_OS_USEC_DELAY(10000); + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE); + PDQ_ASSERT(cnt > 0); +} + +/* + * The following routine brings the PDQ from whatever state it is + * in to DMA_UNAVAILABLE (ie. like a RESET but without doing a RESET). + */ +pdq_state_t +pdq_stop( + pdq_t *pdq) +{ + pdq_state_t state; + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + int cnt, pass = 0, idx; + PDQ_OS_DATABUF_T **buffers; + + restart: + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + if (state != PDQS_DMA_UNAVAILABLE) { + pdq_hwreset(pdq); + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE); + } +#if 0 + switch (state) { + case PDQS_RING_MEMBER: + case PDQS_LINK_UNAVAILABLE: + case PDQS_LINK_AVAILABLE: { + *csrs->csr_port_data_a = PDQ_SUB_CMD_LINK_UNINIT; + *csrs->csr_port_data_b = 0; + pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD); + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + PDQ_ASSERT(state == PDQS_DMA_AVAILABLE); + /* FALL THROUGH */ + } + case PDQS_DMA_AVAILABLE: { + *csrs->csr_port_data_a = 0; + *csrs->csr_port_data_b = 0; + pdq_do_port_control(csrs, PDQ_PCTL_DMA_UNINIT); + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + PDQ_ASSERT(state == PDQS_DMA_UNAVAILABLE); + /* FALL THROUGH */ + } + case PDQS_DMA_UNAVAILABLE: { + break; + } + } +#endif + /* + * Now we should be in DMA_UNAVAILABLE. So bring the PDQ into + * DMA_AVAILABLE. + */ + + /* + * Obtain the hardware address and firmware revisions + * (MLA = my long address which is FDDI speak for hardware address) + */ + pdq_read_mla(&pdq->pdq_csrs, &pdq->pdq_hwaddr); + pdq_read_fwrev(&pdq->pdq_csrs, &pdq->pdq_fwrev); + pdq->pdq_chip_rev = pdq_read_chiprev(&pdq->pdq_csrs); + + if (pdq->pdq_type == PDQ_DEFPA) { + /* + * Disable interrupts and DMA. + */ + *pdq->pdq_pci_csrs.csr_pfi_mode_control = 0; + *pdq->pdq_pci_csrs.csr_pfi_status = 0x10; + } + + /* + * Flush all the databuf queues. + */ + pdq_flush_databuf_queue(&pdq->pdq_tx_info.tx_txq); + buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_rx_info.rx_buffers; + for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_receives); idx++) { + if (buffers[idx] != NULL) { + PDQ_OS_DATABUF_FREE(buffers[idx]); + buffers[idx] = NULL; + } + } + pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives); + buffers = (PDQ_OS_DATABUF_T **) pdq->pdq_host_smt_info.rx_buffers; + for (idx = 0; idx < PDQ_RING_SIZE(pdq->pdq_dbp->pdqdb_host_smt); idx++) { + if (buffers[idx] != NULL) { + PDQ_OS_DATABUF_FREE(buffers[idx]); + buffers[idx] = NULL; + } + } + pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt); + + /* + * Reset the consumer indexes to 0. + */ + pdq->pdq_cbp->pdqcb_receives = 0; + pdq->pdq_cbp->pdqcb_transmits = 0; + pdq->pdq_cbp->pdqcb_host_smt = 0; + pdq->pdq_cbp->pdqcb_unsolicited_event = 0; + pdq->pdq_cbp->pdqcb_command_response = 0; + pdq->pdq_cbp->pdqcb_command_request = 0; + + /* + * Reset the producer and completion indexes to 0. + */ + pdq->pdq_command_info.ci_request_producer = 0; + pdq->pdq_command_info.ci_response_producer = 0; + pdq->pdq_command_info.ci_request_completion = 0; + pdq->pdq_command_info.ci_response_completion = 0; + pdq->pdq_unsolicited_info.ui_producer = 0; + pdq->pdq_unsolicited_info.ui_completion = 0; + pdq->pdq_rx_info.rx_producer = 0; + pdq->pdq_rx_info.rx_completion = 0; + pdq->pdq_tx_info.tx_producer = 0; + pdq->pdq_tx_info.tx_completion = 0; + pdq->pdq_host_smt_info.rx_producer = 0; + pdq->pdq_host_smt_info.rx_completion = 0; + + pdq->pdq_command_info.ci_command_active = 0; + pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS; + pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits); + + /* + * Allow the DEFPA to do DMA. Then program the physical + * addresses of the consumer and descriptor blocks. + */ + if (pdq->pdq_type == PDQ_DEFPA) { +#ifdef PDQTEST + *pdq->pdq_pci_csrs.csr_pfi_mode_control = PDQ_PFI_MODE_DMA_ENABLE; +#else + *pdq->pdq_pci_csrs.csr_pfi_mode_control = PDQ_PFI_MODE_DMA_ENABLE + |PDQ_PFI_MODE_PFI_PCI_INTR|PDQ_PFI_MODE_PDQ_PCI_INTR; +#endif + } + + /* + * Make the unsolicited queue has events ... + */ + pdq_process_unsolicited_events(pdq); + + *csrs->csr_port_data_b = PDQ_DMA_BURST_8LW; + *csrs->csr_port_data_a = PDQ_SUB_CMD_DMA_BURST_SIZE_SET; + pdq_do_port_control(csrs, PDQ_PCTL_SUB_CMD); + + *csrs->csr_port_data_b = 0; + *csrs->csr_port_data_a = PDQ_OS_VA_TO_PA(pdq->pdq_cbp); + pdq_do_port_control(csrs, PDQ_PCTL_CONSUMER_BLOCK); + + *csrs->csr_port_data_b = 0; + *csrs->csr_port_data_a = PDQ_OS_VA_TO_PA(pdq->pdq_dbp) | PDQ_DMA_INIT_LW_BSWAP_DATA; + pdq_do_port_control(csrs, PDQ_PCTL_DMA_INIT); + + for (cnt = 0; cnt < 1000; cnt++) { + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + if (state == PDQS_HALTED) { + if (pass > 0) + return PDQS_HALTED; + pass = 1; + goto restart; + } + if (state == PDQS_DMA_AVAILABLE) { + PDQ_PRINTF(("Transition to DMA Available took %d spins\n", cnt)); + break; + } + PDQ_OS_USEC_DELAY(1000); + } + PDQ_ASSERT(state == PDQS_DMA_AVAILABLE); + + *csrs->csr_host_int_type_0 = 0xFF; + *csrs->csr_host_int_enable = 0 /* PDQ_HOST_INT_STATE_CHANGE + |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE + |PDQ_HOST_INT_UNSOL_ENABLE */; + + /* + * Any other command but START should be valid. + */ + pdq->pdq_command_info.ci_pending_commands &= ~(PDQ_BITMASK(PDQC_START)); + if (pdq->pdq_flags & PDQ_PRINTCHARS) + pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET); + pdq_queue_commands(pdq); + + if (pdq->pdq_flags & PDQ_PRINTCHARS) { + /* + * Now wait (up to 100ms) for the command(s) to finish. + */ + for (cnt = 0; cnt < 1000; cnt++) { + pdq_process_command_responses(pdq); + if (pdq->pdq_command_info.ci_response_producer == pdq->pdq_command_info.ci_response_completion) + break; + PDQ_OS_USEC_DELAY(1000); + } + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + } + + return state; +} + +void +pdq_run( + pdq_t *pdq) +{ + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + pdq_state_t state; + + state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + PDQ_ASSERT(state != PDQS_DMA_UNAVAILABLE); + PDQ_ASSERT(state != PDQS_RESET); + PDQ_ASSERT(state != PDQS_HALTED); + PDQ_ASSERT(state != PDQS_UPGRADE); + PDQ_ASSERT(state != PDQS_RING_MEMBER); + switch (state) { + case PDQS_DMA_AVAILABLE: { + /* + * The PDQ after being reset screws up some of its state. + * So we need to clear all the errors/interrupts so the real + * ones will get through. + */ + *csrs->csr_host_int_type_0 = 0xFF; + *csrs->csr_host_int_enable = PDQ_HOST_INT_STATE_CHANGE|PDQ_HOST_INT_XMT_DATA_FLUSH + |PDQ_HOST_INT_FATAL_ERROR|PDQ_HOST_INT_CMD_RSP_ENABLE|PDQ_HOST_INT_UNSOL_ENABLE + |PDQ_HOST_INT_RX_ENABLE|PDQ_HOST_INT_TX_ENABLE|PDQ_HOST_INT_HOST_SMT_ENABLE; + /* + * Set the MAC and address filters and start up the PDQ. + */ + pdq_process_unsolicited_events(pdq); + pdq_process_received_data(pdq, &pdq->pdq_rx_info, + pdq->pdq_dbp->pdqdb_receives, + pdq->pdq_cbp->pdqcb_receives, + PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives)); + PDQ_DO_TYPE2_PRODUCER(pdq); + if (pdq->pdq_flags & PDQ_PASS_SMT) { + pdq_process_received_data(pdq, &pdq->pdq_host_smt_info, + pdq->pdq_dbp->pdqdb_host_smt, + pdq->pdq_cbp->pdqcb_host_smt, + PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt)); + *csrs->csr_host_smt_producer = pdq->pdq_host_smt_info.rx_producer | (pdq->pdq_host_smt_info.rx_completion << 8); + } + pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET) + | PDQ_BITMASK(PDQC_ADDR_FILTER_SET) | PDQ_BITMASK(PDQC_START); + if (pdq->pdq_flags & PDQ_PRINTCHARS) + pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET); + pdq_queue_commands(pdq); + break; + } + case PDQS_LINK_UNAVAILABLE: + case PDQS_LINK_AVAILABLE: { + pdq->pdq_command_info.ci_pending_commands = PDQ_BITMASK(PDQC_FILTER_SET) + | PDQ_BITMASK(PDQC_ADDR_FILTER_SET); + if (pdq->pdq_flags & PDQ_PRINTCHARS) + pdq->pdq_command_info.ci_pending_commands |= PDQ_BITMASK(PDQC_STATUS_CHARS_GET); + if (pdq->pdq_flags & PDQ_PASS_SMT) { + pdq_process_received_data(pdq, &pdq->pdq_host_smt_info, + pdq->pdq_dbp->pdqdb_host_smt, + pdq->pdq_cbp->pdqcb_host_smt, + PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt)); + *csrs->csr_host_smt_producer = pdq->pdq_host_smt_info.rx_producer | (pdq->pdq_host_smt_info.rx_completion << 8); + } + pdq_process_unsolicited_events(pdq); + pdq_queue_commands(pdq); + break; + } + case PDQS_RING_MEMBER: { + } + } +} + +int +pdq_interrupt( + pdq_t *pdq) +{ + const pdq_csrs_t * const csrs = &pdq->pdq_csrs; + pdq_uint32_t data; + int progress = 0; + + if (pdq->pdq_type == PDQ_DEFPA) + if (*pdq->pdq_pci_csrs.csr_pfi_status & 0x10) + *pdq->pdq_pci_csrs.csr_pfi_status = 0x10; + + while ((data = *csrs->csr_port_status) & PDQ_PSTS_INTR_PENDING) { + progress = 1; + PDQ_PRINTF(("PDQ Interrupt: Status = 0x%08x\n", data)); + if (data & PDQ_PSTS_RCV_DATA_PENDING) { + pdq_process_received_data(pdq, &pdq->pdq_rx_info, + pdq->pdq_dbp->pdqdb_receives, + pdq->pdq_cbp->pdqcb_receives, + PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives)); + PDQ_DO_TYPE2_PRODUCER(pdq); + } + if (data & PDQ_PSTS_HOST_SMT_PENDING) { + pdq_process_received_data(pdq, &pdq->pdq_host_smt_info, + pdq->pdq_dbp->pdqdb_host_smt, + pdq->pdq_cbp->pdqcb_host_smt, + PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt)); + *csrs->csr_host_smt_producer = pdq->pdq_host_smt_info.rx_producer | (pdq->pdq_host_smt_info.rx_completion << 8); + } + if (data & PDQ_PSTS_XMT_DATA_PENDING) + pdq_process_transmitted_data(pdq); + if (data & PDQ_PSTS_UNSOL_PENDING) + pdq_process_unsolicited_events(pdq); + if (data & PDQ_PSTS_CMD_RSP_PENDING) + pdq_process_command_responses(pdq); + if (data & PDQ_PSTS_TYPE_0_PENDING) { + data = *csrs->csr_host_int_type_0; + if (data & PDQ_HOST_INT_STATE_CHANGE) { + pdq_state_t state = PDQ_PSTS_ADAPTER_STATE(*csrs->csr_port_status); + printf(PDQ_OS_PREFIX "%s", PDQ_OS_PREFIX_ARGS, pdq_adapter_states[state]); + if (state == PDQS_LINK_UNAVAILABLE) { + pdq->pdq_flags &= ~PDQ_TXOK; + } else if (state == PDQS_LINK_AVAILABLE) { + pdq->pdq_flags |= PDQ_TXOK; + pdq_os_restart_transmitter(pdq); + } else if (state == PDQS_HALTED) { + pdq_response_error_log_get_t log_entry; + pdq_halt_code_t halt_code = PDQ_PSTS_HALT_ID(*csrs->csr_port_status); + printf(": halt code = %d (%s)\n", + halt_code, pdq_halt_codes[halt_code]); + if (halt_code == PDQH_DMA_ERROR) { + PDQ_PRINTF(("\tPFI status = 0x%x, Host 0 Fatal Interrupt = 0x%x\n", + *pdq->pdq_pci_csrs.csr_pfi_status, + data & PDQ_HOST_INT_FATAL_ERROR)); + } + pdq_read_error_log(pdq, &log_entry); + pdq_stop(pdq); + if (pdq->pdq_flags & PDQ_RUNNING) + pdq_run(pdq); + return 1; + } + printf("\n"); + *csrs->csr_host_int_type_0 = PDQ_HOST_INT_STATE_CHANGE; + } + if (data & PDQ_HOST_INT_FATAL_ERROR) { + pdq_stop(pdq); + if (pdq->pdq_flags & PDQ_RUNNING) + pdq_run(pdq); + return 1; + } + if (data & PDQ_HOST_INT_XMT_DATA_FLUSH) { + printf(PDQ_OS_PREFIX "Flushing transmit queue\n", PDQ_OS_PREFIX_ARGS); + pdq->pdq_flags &= ~PDQ_TXOK; + pdq_flush_transmitter(pdq); + pdq_do_port_control(csrs, PDQ_PCTL_XMT_DATA_FLUSH_DONE); + *csrs->csr_host_int_type_0 = PDQ_HOST_INT_XMT_DATA_FLUSH; + } + } + if (pdq->pdq_type == PDQ_DEFPA) + if (*pdq->pdq_pci_csrs.csr_pfi_status & 0x10) + *pdq->pdq_pci_csrs.csr_pfi_status = 0x10; + } + return progress; +} + +pdq_t * +pdq_initialize( + void *csr_va, + const char *name, + int unit, + void *ctx, + pdq_type_t type) +{ + pdq_t *pdq; + pdq_state_t state; + const pdq_uint32_t contig_bytes = (sizeof(pdq_descriptor_block_t) * 2) - PDQ_OS_PAGESIZE; + pdq_uint8_t *p; + int idx; + + PDQ_ASSERT(sizeof(pdq_descriptor_block_t) == 8192); + PDQ_ASSERT(sizeof(pdq_consumer_block_t) == 64); + PDQ_ASSERT(sizeof(pdq_response_filter_get_t) == PDQ_SIZE_RESPONSE_FILTER_GET); + PDQ_ASSERT(sizeof(pdq_cmd_addr_filter_set_t) == PDQ_SIZE_CMD_ADDR_FILTER_SET); + PDQ_ASSERT(sizeof(pdq_response_addr_filter_get_t) == PDQ_SIZE_RESPONSE_ADDR_FILTER_GET); + PDQ_ASSERT(sizeof(pdq_response_status_chars_get_t) == PDQ_SIZE_RESPONSE_STATUS_CHARS_GET); + PDQ_ASSERT(sizeof(pdq_response_fddi_mib_get_t) == PDQ_SIZE_RESPONSE_FDDI_MIB_GET); + PDQ_ASSERT(sizeof(pdq_response_dec_ext_mib_get_t) == PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET); + PDQ_ASSERT(sizeof(pdq_unsolicited_event_t) == 512); + + pdq = (pdq_t *) PDQ_OS_MEMALLOC(sizeof(pdq_t)); + if (pdq == NULL) { + PDQ_PRINTF(("malloc(%d) failed\n", sizeof(*pdq))); + return NULL; + } + PDQ_OS_MEMZERO(pdq, sizeof(pdq_t)); + pdq->pdq_type = type; + pdq->pdq_unit = unit; + pdq->pdq_os_ctx = (void *) ctx; + pdq->pdq_os_name = name; + pdq->pdq_flags = PDQ_PRINTCHARS; + /* + * Allocate the additional data structures required by + * the PDQ driver. Allocate a contiguous region of memory + * for the descriptor block. We need to allocated enough + * to guarantee that we will a get 8KB block of memory aligned + * on a 8KB boundary. This turns to require that we allocate + * (N*2 - 1 page) pages of memory. On machine with less than + * a 8KB page size, it mean we will allocate more memory than + * we need. The extra will be used for the unsolicited event + * buffers (though on machines with 8KB pages we will to allocate + * them separately since there will be nothing left overs.) + */ + p = (pdq_uint8_t *) PDQ_OS_MEMALLOC_CONTIG(contig_bytes); + if (p != NULL) { + pdq_physaddr_t physaddr = PDQ_OS_VA_TO_PA(p) & 0x1FFF; + if (physaddr) { + pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) p; + pdq->pdq_dbp = (pdq_descriptor_block_t *) &p[0x2000 - physaddr]; + } else { + pdq->pdq_dbp = (pdq_descriptor_block_t *) p; + pdq->pdq_unsolicited_info.ui_events = (pdq_unsolicited_event_t *) &p[0x2000]; + } + } + if (contig_bytes == sizeof(pdq_descriptor_block_t)) { + pdq->pdq_unsolicited_info.ui_events = + (pdq_unsolicited_event_t *) PDQ_OS_MEMALLOC( + PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t)); + } + + /* + * Make sure everything got allocated. If not, free what did + * get allocated and return. + */ + if (pdq->pdq_dbp == NULL || pdq->pdq_unsolicited_info.ui_events == NULL) { + cleanup_and_return: + if (pdq->pdq_dbp != NULL) + PDQ_OS_MEMFREE_CONTIG(pdq->pdq_dbp, contig_bytes); + if (contig_bytes == sizeof(pdq_descriptor_block_t) && pdq->pdq_unsolicited_info.ui_events != NULL) + PDQ_OS_MEMFREE(pdq->pdq_unsolicited_info.ui_events, + PDQ_NUM_UNSOLICITED_EVENTS * sizeof(pdq_unsolicited_event_t)); + PDQ_OS_MEMFREE(pdq, sizeof(pdq_t)); + return NULL; + } + + pdq->pdq_cbp = (volatile pdq_consumer_block_t *) &pdq->pdq_dbp->pdqdb_consumer; + pdq->pdq_command_info.ci_bufstart = (pdq_uint8_t *) pdq->pdq_dbp->pdqdb_command_pool; + pdq->pdq_rx_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_receive_buffers; + + pdq->pdq_host_smt_info.rx_buffers = (void *) pdq->pdq_dbp->pdqdb_host_smt_buffers; + + PDQ_PRINTF(("PDQ Descriptor Block = %x\n", pdq->pdq_dbp)); + PDQ_PRINTF((" Recieve Queue = %x\n", pdq->pdq_dbp->pdqdb_receives)); + PDQ_PRINTF((" Transmit Queue = %x\n", pdq->pdq_dbp->pdqdb_transmits)); + PDQ_PRINTF((" Host SMT Queue = %x\n", pdq->pdq_dbp->pdqdb_host_smt)); + PDQ_PRINTF((" Command Response Queue = %x\n", pdq->pdq_dbp->pdqdb_command_responses)); + PDQ_PRINTF((" Command Request Queue = %x\n", pdq->pdq_dbp->pdqdb_command_requests)); + PDQ_PRINTF(("PDQ Consumer Block = %x\n", pdq->pdq_cbp)); + + /* + * Zero out the descriptor block. Not really required but + * it pays to be neat. This will also zero out the consumer + * block, command pool, and buffer pointers for the receive + * host_smt rings. + */ + PDQ_OS_MEMZERO(pdq->pdq_dbp, sizeof(*pdq->pdq_dbp)); + + /* + * Initialize the CSR references. + */ + pdq_init_csrs(&pdq->pdq_csrs, csr_va, 1); + switch (pdq->pdq_type) { + case PDQ_DEFPA: pdq_init_pci_csrs(&pdq->pdq_pci_csrs, csr_va, 1); break; +#ifdef PDQ_DO_EISA + case PDQ_DEFEA: pdq_init_esia_csrs(&pdq->pdq_eisa_csrs, csr_va, 1); break; +#endif + } + + PDQ_PRINTF(("PDQ CSRs:\n")); + PDQ_PRINTF((" Port Reset = %x [0x%08x]\n", + pdq->pdq_csrs.csr_port_reset, *pdq->pdq_csrs.csr_port_reset)); + PDQ_PRINTF((" Host Data = %x [0x%08x]\n", + pdq->pdq_csrs.csr_host_data, *pdq->pdq_csrs.csr_host_data)); + PDQ_PRINTF((" Port Control = %x [0x%08x]\n", + pdq->pdq_csrs.csr_port_control, *pdq->pdq_csrs.csr_port_control)); + PDQ_PRINTF((" Port Data A = %x [0x%08x]\n", + pdq->pdq_csrs.csr_port_data_a, *pdq->pdq_csrs.csr_port_data_a)); + PDQ_PRINTF((" Port Data B = %x [0x%08x]\n", + pdq->pdq_csrs.csr_port_data_b, *pdq->pdq_csrs.csr_port_data_b)); + PDQ_PRINTF((" Port Status = %x [0x%08x]\n", + pdq->pdq_csrs.csr_port_status, *pdq->pdq_csrs.csr_port_status)); + PDQ_PRINTF((" Host Int Type 0 = %x [0x%08x]\n", + pdq->pdq_csrs.csr_host_int_type_0, *pdq->pdq_csrs.csr_host_int_type_0)); + PDQ_PRINTF((" Host Int Enable = %x [0x%08x]\n", + pdq->pdq_csrs.csr_host_int_enable, *pdq->pdq_csrs.csr_host_int_enable)); + PDQ_PRINTF((" Type 2 Producer = %x [0x%08x]\n", + pdq->pdq_csrs.csr_type_2_producer, *pdq->pdq_csrs.csr_type_2_producer)); + PDQ_PRINTF((" Command Response Producer = %x [0x%08x]\n", + pdq->pdq_csrs.csr_cmd_response_producer, *pdq->pdq_csrs.csr_cmd_response_producer)); + PDQ_PRINTF((" Command Request Producer = %x [0x%08x]\n", + pdq->pdq_csrs.csr_cmd_request_producer, *pdq->pdq_csrs.csr_cmd_request_producer)); + PDQ_PRINTF((" Host SMT Producer = %x [0x%08x]\n", + pdq->pdq_csrs.csr_host_smt_producer, *pdq->pdq_csrs.csr_host_smt_producer)); + PDQ_PRINTF((" Unsolicited Producer = %x [0x%08x]\n", + pdq->pdq_csrs.csr_unsolicited_producer, *pdq->pdq_csrs.csr_unsolicited_producer)); + + /* + * Initialize the command information block + */ + pdq->pdq_command_info.ci_pa_bufstart = PDQ_OS_VA_TO_PA(pdq->pdq_command_info.ci_bufstart); + for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_requests)/sizeof(pdq->pdq_dbp->pdqdb_command_requests[0]); idx++) { + pdq_txdesc_t *txd = &pdq->pdq_dbp->pdqdb_command_requests[idx]; + + txd->txd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart; + txd->txd_eop = txd->txd_sop = 1; + txd->txd_pa_hi = 0; + } + for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_command_responses)/sizeof(pdq->pdq_dbp->pdqdb_command_responses[0]); idx++) { + pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_command_responses[idx]; + + rxd->rxd_pa_lo = pdq->pdq_command_info.ci_pa_bufstart; + rxd->rxd_sop = 1; + rxd->rxd_seg_cnt = 0; + rxd->rxd_seg_len_lo = 0; + } + + /* + * Initialize the unsolicited event information block + */ + pdq->pdq_unsolicited_info.ui_free = PDQ_NUM_UNSOLICITED_EVENTS; + pdq->pdq_unsolicited_info.ui_pa_bufstart = PDQ_OS_VA_TO_PA(pdq->pdq_unsolicited_info.ui_events); + for (idx = 0; idx < sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events)/sizeof(pdq->pdq_dbp->pdqdb_unsolicited_events[0]); idx++) { + pdq_rxdesc_t *rxd = &pdq->pdq_dbp->pdqdb_unsolicited_events[idx]; + pdq_unsolicited_event_t *event = &pdq->pdq_unsolicited_info.ui_events[idx & (PDQ_NUM_UNSOLICITED_EVENTS-1)]; + + rxd->rxd_sop = 1; + rxd->rxd_seg_cnt = 0; + rxd->rxd_seg_len_hi = sizeof(pdq_unsolicited_event_t) / 16; + rxd->rxd_pa_lo = pdq->pdq_unsolicited_info.ui_pa_bufstart + (const pdq_uint8_t *) event + - (const pdq_uint8_t *) pdq->pdq_unsolicited_info.ui_events; + rxd->rxd_pa_hi = 0; + } + /* + * Initialize the receive information blocks (normal and SMT). + */ + pdq->pdq_rx_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_receives); + pdq->pdq_rx_info.rx_target = pdq->pdq_rx_info.rx_free - PDQ_RX_SEGCNT * 8; + + pdq->pdq_host_smt_info.rx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_host_smt); + pdq->pdq_host_smt_info.rx_target = pdq->pdq_host_smt_info.rx_free - PDQ_RX_SEGCNT * 3; + + /* + * Initialize the transmit information block. + */ + pdq->pdq_tx_hdr[0] = PDQ_FDDI_PH0; + pdq->pdq_tx_hdr[1] = PDQ_FDDI_PH1; + pdq->pdq_tx_hdr[2] = PDQ_FDDI_PH2; + pdq->pdq_tx_info.tx_free = PDQ_RING_MASK(pdq->pdq_dbp->pdqdb_transmits); + pdq->pdq_tx_info.tx_hdrdesc.txd_seg_len = sizeof(pdq->pdq_tx_hdr); + pdq->pdq_tx_info.tx_hdrdesc.txd_sop = 1; + pdq->pdq_tx_info.tx_hdrdesc.txd_pa_lo = PDQ_OS_VA_TO_PA(pdq->pdq_tx_hdr); + + state = PDQ_PSTS_ADAPTER_STATE(*pdq->pdq_csrs.csr_port_status); + PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state])); + + /* + * Stop the PDQ if it is running and put it into a known state. + */ + state = pdq_stop(pdq); + + /* state = PDQ_PSTS_ADAPTER_STATE(*pdq->pdq_csrs.csr_port_status); */ + PDQ_PRINTF(("PDQ Adapter State = %s\n", pdq_adapter_states[state])); + PDQ_ASSERT(state == PDQS_DMA_AVAILABLE); + /* + * If the adapter is not the state we expect, then the initialization + * failed. Cleanup and exit. + */ + if (state == PDQS_RESET || state == PDQS_HALTED || state == PDQS_UPGRADE) + goto cleanup_and_return; + + PDQ_PRINTF(("PDQ Hardware Address = %02x-%02x-%02x-%02x-%02x-%02x\n", + pdq->pdq_hwaddr.lanaddr_bytes[0], pdq->pdq_hwaddr.lanaddr_bytes[1], + pdq->pdq_hwaddr.lanaddr_bytes[2], pdq->pdq_hwaddr.lanaddr_bytes[3], + pdq->pdq_hwaddr.lanaddr_bytes[4], pdq->pdq_hwaddr.lanaddr_bytes[5])); + PDQ_PRINTF(("PDQ Firmware Revision = %c%c%c%c\n", + pdq->pdq_fwrev.fwrev_bytes[0], pdq->pdq_fwrev.fwrev_bytes[1], + pdq->pdq_fwrev.fwrev_bytes[2], pdq->pdq_fwrev.fwrev_bytes[3])); + PDQ_PRINTF(("PDQ Chip Revision = ")); + switch (pdq->pdq_chip_rev) { + case PDQ_CHIP_REV_A_B_OR_C: PDQ_PRINTF(("Rev C or below")); break; + case PDQ_CHIP_REV_D: PDQ_PRINTF(("Rev D")); break; + case PDQ_CHIP_REV_E: PDQ_PRINTF(("Rev E")); break; + default: PDQ_PRINTF(("Unknown Rev %d", (int) pdq->pdq_chip_rev)); + } + PDQ_PRINTF(("\n")); + + return pdq; +} diff --git a/sys/dev/ic/pdqreg.h b/sys/dev/ic/pdqreg.h new file mode 100644 index 00000000000..71ce819e348 --- /dev/null +++ b/sys/dev/ic/pdqreg.h @@ -0,0 +1,1061 @@ +/* $NetBSD: pdqreg.h,v 1.2 1995/08/19 04:35:21 cgd Exp $ */ + +/*- + * Copyright (c) 1995 Matt Thomas (thomas@lkg.dec.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * DEC PDQ FDDI Controller; PDQ port driver definitions + * + * Written by Matt Thomas + */ + +#ifndef _PDQREG_H +#define _PDQREG_H + +#include <stddef.h> +#if defined(PDQTEST) && !defined(PDQ_NDEBUG) +#include <assert.h> +#define PDQ_ASSERT assert +#else +#define PDQ_ASSERT(x) do { } while(0) +#endif + +#define PDQ_RING_SIZE(array) ((sizeof(array) / sizeof(array[0]))) +#define PDQ_ARRAY_SIZE(array) ((sizeof(array) / sizeof(array[0]))) +#define PDQ_RING_MASK(array) (PDQ_RING_SIZE(array) - 1) +#define PDQ_BITMASK(n) (1L << (pdq_uint32_t) (n)) + +#define PDQ_FDDI_MAX 4495 +#define PDQ_FDDI_LLC_MIN 20 +#define PDQ_FDDI_SMT_MIN 37 + +#define PDQ_FDDI_SMT 0x40 +#define PDQ_FDDI_LLC_ASYNC 0x50 +#define PDQ_FDDI_LLC_SYNC 0xD0 +#define PDQ_FDDI_IMP_ASYNC 0x60 +#define PDQ_FDDI_IMP_SYNC 0xE0 + +#define PDQ_FDDIFC_C 0x80 +#define PDQ_FDDIFC_L 0x40 +#define PDQ_FDDIFC_F 0x30 +#define PDQ_FDDIFC_Z 0x0F + +#define PDQ_FDDI_PH0 0x20 +#define PDQ_FDDI_PH1 0x38 +#define PDQ_FDDI_PH2 0x00 + +typedef unsigned int pdq_uint32_t; +typedef unsigned short pdq_uint16_t; +typedef unsigned char pdq_uint8_t; + +typedef pdq_uint32_t pdq_physaddr_t; + +typedef struct { + pdq_uint8_t lanaddr_bytes[8]; +} pdq_lanaddr_t; + +typedef struct { + pdq_uint8_t fwrev_bytes[4]; +} pdq_fwrev_t; + +typedef enum { + PDQS_RESET=0, + PDQS_UPGRADE=1, + PDQS_DMA_UNAVAILABLE=2, + PDQS_DMA_AVAILABLE=3, + PDQS_LINK_AVAILABLE=4, + PDQS_LINK_UNAVAILABLE=5, + PDQS_HALTED=6, + PDQS_RING_MEMBER=7 +} pdq_state_t; + +typedef struct { + volatile pdq_uint32_t *csr_port_reset; /* 0x00 [RW] */ + volatile pdq_uint32_t *csr_host_data; /* 0x04 [R] */ + volatile pdq_uint32_t *csr_port_control; /* 0x08 [RW] */ + volatile pdq_uint32_t *csr_port_data_a; /* 0x0C [RW] */ + volatile pdq_uint32_t *csr_port_data_b; /* 0x10 [RW] */ + volatile pdq_uint32_t *csr_port_status; /* 0x14 [R] */ + volatile pdq_uint32_t *csr_host_int_type_0; /* 0x18 [RW] */ + volatile pdq_uint32_t *csr_host_int_enable; /* 0x1C [RW] */ + volatile pdq_uint32_t *csr_type_2_producer; /* 0x20 [RW] */ + volatile pdq_uint32_t *csr_cmd_response_producer; /* 0x28 [RW] */ + volatile pdq_uint32_t *csr_cmd_request_producer; /* 0x2C [RW] */ + volatile pdq_uint32_t *csr_host_smt_producer; /* 0x30 [RW] */ + volatile pdq_uint32_t *csr_unsolicited_producer; /* 0x34 [RW] */ +} pdq_csrs_t; + +typedef struct { + volatile pdq_uint32_t *csr_pfi_mode_control; /* 0x40 [RW] */ + volatile pdq_uint32_t *csr_pfi_status; /* 0x44 [RW] */ + volatile pdq_uint32_t *csr_fifo_write; /* 0x48 [RW] */ + volatile pdq_uint32_t *csr_fifo_read; /* 0x4C [RW] */ +} pdq_pci_csrs_t; + +#define PDQ_PFI_MODE_DMA_ENABLE 0x01 /* DMA Enable */ +#define PDQ_PFI_MODE_PFI_PCI_INTR 0x02 /* PFI-to-PCI Int Enable */ +#define PDQ_PFI_MODE_PDQ_PCI_INTR 0x04 /* PDQ-to-PCI Int Enable */ + +#define PDQ_PFI_STATUS_PDQ_INTR 0x10 /* PDQ Int received */ +#define PDQ_PFI_STATUS_DMA_ABORT 0x08 /* PDQ DMA Abort asserted */ + +#define PDQ_EISA_BURST_HOLDOFF 0x0040 +#define PDQ_EISA_SLOT_ID 0x0C80 +#define PDQ_EISA_SLOT_CTRL 0x0C84 +#define PDQ_EISA_MEM_ADD_CMP_0 0x0C85 +#define PDQ_EISA_MEM_ADD_CMP_1 0x0C86 +#define PDQ_EISA_MEM_ADD_CMP_2 0x0C87 +#define PDQ_EISA_MEM_ADD_HI_CMP_0 0x0C88 +#define PDQ_EISA_MEM_ADD_HI_CMP_1 0x0C89 +#define PDQ_EISA_MEM_ADD_HI_CMP_2 0x0C8A +#define PDQ_EISA_MEM_ADD_MASK_0 0x0C8B +#define PDQ_EISA_MEM_ADD_MASK_1 0x0C8C +#define PDQ_EISA_MEM_ADD_MASK_2 0x0C8D +#define PDQ_EISA_MEM_ADD_LO_CMP_0 0x0C8E +#define PDQ_EISA_MEM_ADD_LO_CMP_1 0x0C8F +#define PDQ_EISA_MEM_ADD_LO_CMP_2 0x0C90 +#define PDQ_EISA_IO_CMP_0_0 0x0C91 +#define PDQ_EISA_IO_CMP_0_1 0x0C92 +#define PDQ_EISA_IO_CMP_1_0 0x0C93 +#define PDQ_EISA_IO_CMP_1_1 0x0C94 +#define PDQ_EISA_IO_CMP_2_0 0x0C95 +#define PDQ_EISA_IO_CMP_2_1 0x0C96 +#define PDQ_EISA_IO_CMP_3_0 0x0C97 +#define PDQ_EISA_IO_CMP_3_1 0x0C98 +#define PDQ_EISA_IO_ADD_MASK_0_0 0x0C99 +#define PDQ_EISA_IO_ADD_MASK_0_1 0x0C9A +#define PDQ_EISA_IO_ADD_MASK_1_0 0x0C9B +#define PDQ_EISA_IO_ADD_MASK_1_1 0x0C9C +#define PDQ_EISA_IO_ADD_MASK_2_0 0x0C9D +#define PDQ_EISA_IO_ADD_MASK_2_1 0x0C9E +#define PDQ_EISA_IO_ADD_MASK_3_0 0x0C9F +#define PDQ_EISA_IO_ADD_MASK_3_1 0x0CA0 +#define PDQ_EISA_MOD_CONFIG_1 0x0CA1 +#define PDQ_EISA_MOD_CONFIG_2 0x0CA2 +#define PDQ_EISA_MOD_CONFIG_3 0x0CA3 +#define PDQ_EISA_MOD_CONFIG_4 0x0CA4 +#define PDQ_EISA_MOD_CONFIG_5 0x0CA5 +#define PDQ_EISA_MOD_CONFIG_6 0x0CA6 +#define PDQ_EISA_MOD_CONFIG_7 0x0CA7 +#define PDQ_EISA_DIP_SWITCH 0x0CA8 +#define PDQ_EISA_IO_CONFIG_STAT_0 0x0CA9 +#define PDQ_EISA_IO_CONFIG_STAT_1 0x0CAA +#define PDQ_EISA_DMA_CONFIG 0x0CAB +#define PDQ_EISA_INPUT_PORT 0x0CAC +#define PDQ_EISA_OUTPUT_PORT 0x0CAD +#define PDQ_EISA_FUNCTION_CTRL 0x0CAE + +/* + * Port Reset Data A Definitions + */ +#define PDQ_PRESET_SKIP_SELFTEST 0x0004 +#define PDQ_PRESET_SOFT_RESET 0x0002 +#define PDQ_PRESET_UPGRADE 0x0001 +/* + * Port Control Register Definitions + */ +#define PDQ_PCTL_CMD_ERROR 0x8000 +#define PDQ_PCTL_FLASH_BLAST 0x4000 +#define PDQ_PCTL_HALT 0x2000 +#define PDQ_PCTL_COPY_DATA 0x1000 +#define PDQ_PCTL_ERROR_LOG_START 0x0800 +#define PDQ_PCTL_ERROR_LOG_READ 0x0400 +#define PDQ_PCTL_XMT_DATA_FLUSH_DONE 0x0200 +#define PDQ_PCTL_DMA_INIT 0x0100 +#define PDQ_DMA_INIT_LW_BSWAP_DATA 0x02 +#define PDQ_DMA_INIT_LW_BSWAP_LITERAL 0x01 +#define PDQ_PCTL_INIT_START 0x0080 +#define PDQ_PCTL_CONSUMER_BLOCK 0x0040 +#define PDQ_PCTL_DMA_UNINIT 0x0020 +#define PDQ_PCTL_RING_MEMBER 0x0010 +#define PDQ_PCTL_MLA_READ 0x0008 +#define PDQ_PCTL_FW_REV_READ 0x0004 +#define PDQ_PCTL_DEVICE_SPECIFIC 0x0002 +#define PDQ_PCTL_SUB_CMD 0x0001 + +typedef enum { + PDQ_SUB_CMD_LINK_UNINIT=1, + PDQ_SUB_CMD_DMA_BURST_SIZE_SET=2, + PDQ_SUB_CMD_PDQ_REV_GET=4 +} pdq_sub_cmd_t; + +typedef enum { + PDQ_DMA_BURST_4LW=0, + PDQ_DMA_BURST_8LW=1, + PDQ_DMA_BURST_16LW=2, + PDQ_DMA_BURST_32LW=3 +} pdq_dma_burst_size_t; + +typedef enum { + PDQ_CHIP_REV_A_B_OR_C=0, + PDQ_CHIP_REV_D=2, + PDQ_CHIP_REV_E=4 +} pdq_chip_rev_t; +/* + * Port Status Register Definitions + */ +#define PDQ_PSTS_RCV_DATA_PENDING 0x80000000ul +#define PDQ_PSTS_XMT_DATA_PENDING 0x40000000ul +#define PDQ_PSTS_HOST_SMT_PENDING 0x20000000ul +#define PDQ_PSTS_UNSOL_PENDING 0x10000000ul +#define PDQ_PSTS_CMD_RSP_PENDING 0x08000000ul +#define PDQ_PSTS_CMD_REQ_PENDING 0x04000000ul +#define PDQ_PSTS_TYPE_0_PENDING 0x02000000ul +#define PDQ_PSTS_INTR_PENDING 0xFE000000ul +#define PDQ_PSTS_ADAPTER_STATE(sts) ((pdq_state_t) (((sts) >> 8) & 0x07)) +#define PDQ_PSTS_HALT_ID(sts) ((pdq_halt_code_t) ((sts) & 0xFF)) +/* + * Host Interrupt Register Definitions + */ +#define PDQ_HOST_INT_TX_ENABLE 0x80000000ul +#define PDQ_HOST_INT_RX_ENABLE 0x40000000ul +#define PDQ_HOST_INT_UNSOL_ENABLE 0x20000000ul +#define PDQ_HOST_INT_HOST_SMT_ENABLE 0x10000000ul +#define PDQ_HOST_INT_CMD_RSP_ENABLE 0x08000000ul +#define PDQ_HOST_INT_CMD_RQST_ENABLE 0x04000000ul + +#define PDQ_HOST_INT_1MS 0x80 +#define PDQ_HOST_INT_20MS 0x40 +#define PDQ_HOST_INT_CSR_CMD_DONE 0x20 +#define PDQ_HOST_INT_STATE_CHANGE 0x10 +#define PDQ_HOST_INT_XMT_DATA_FLUSH 0x08 +#define PDQ_HOST_INT_NXM 0x04 +#define PDQ_HOST_INT_PM_PARITY_ERROR 0x02 +#define PDQ_HOST_INT_HOST_BUS_PARITY_ERROR 0x01 +#define PDQ_HOST_INT_FATAL_ERROR 0x07 + +typedef enum { + PDQH_SELFTEST_TIMEOUT=0, + PDQH_HOST_BUS_PARITY_ERROR=1, + PDQH_HOST_DIRECTED_HALT=2, + PDQH_SOFTWARE_FAULT=3, + PDQH_HARDWARE_FAULT=4, + PDQH_PC_TRACE_PATH_TEST=5, + PDQH_DMA_ERROR=6, + PDQH_IMAGE_CRC_ERROR=7, + PDQH_ADAPTER_PROCESSOR_ERROR=8, + PDQH_MAX=9 +} pdq_halt_code_t; + +typedef struct { + pdq_uint16_t pdqcb_receives; + pdq_uint16_t pdqcb_transmits; + pdq_uint32_t pdqcb__filler1; + pdq_uint32_t pdqcb_host_smt; + pdq_uint32_t pdqcb__filler2; + pdq_uint32_t pdqcb_unsolicited_event; + pdq_uint32_t pdqcb__filler3; + pdq_uint32_t pdqcb_command_response; + pdq_uint32_t pdqcb__filler4; + pdq_uint32_t pdqcb_command_request; + pdq_uint32_t pdqcb__filler5[7]; +} pdq_consumer_block_t; + +#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN +#define PDQ_BITFIELD2(a, b) b, a +#define PDQ_BITFIELD3(a, b, c) c, b, a +#define PDQ_BITFIELD4(a, b, c, d) d, c, b, a +#define PDQ_BITFIELD5(a, b, c, d, e) e, d, c, b, a +#define PDQ_BITFIELD12(a, b, c, d, e, f, g, h, i, j, k, l) \ + l, k, j, i, h, g, f, e, d, c, b, a +#else +#define PDQ_BITFIELD2(a, b) a, b +#define PDQ_BITFIELD3(a, b, c) a, b, c +#define PDQ_BITFIELD4(a, b, c, d) a, b, c, d +#define PDQ_BITFIELD5(a, b, c, d, e) a, b, c, d, e +#define PDQ_BITFIELD12(a, b, c, d, e, f, g, h, i, j, k, l) \ + a, b, c, d, e, f, g, h, i, j, k, l +#endif + +typedef struct { + pdq_uint32_t PDQ_BITFIELD5(rxd_pa_hi : 16, + rxd_seg_cnt : 4, + rxd_seg_len_hi : 9, + rxd_seg_len_lo : 2, + rxd_sop : 1); + pdq_uint32_t rxd_pa_lo; +} pdq_rxdesc_t; + +typedef union { + pdq_uint32_t rxs_status; + pdq_uint32_t PDQ_BITFIELD12(rxs_len : 13, + rxs_rcc_ss : 2, + rxs_rcc_dd : 2, + rxs_rcc_reason : 3, + rxs_rcc_badcrc : 1, + rxs_rcc_badpdu : 1, + rxs_fsb__reserved : 2, + rxs_fsb_c : 1, + rxs_fsb_a : 1, + rxs_fsb_e : 1, + rxs_fsc : 3, + rxs__reserved : 2); +} pdq_rxstatus_t; + +typedef struct { + pdq_uint32_t PDQ_BITFIELD5(txd_pa_hi : 16, + txd_seg_len : 13, + txd_mbz : 1, + txd_eop : 1, + txd_sop : 1); + pdq_uint32_t txd_pa_lo; +} pdq_txdesc_t; + +typedef struct { + pdq_rxdesc_t pdqdb_receives[256]; /* 2048; 0x0000..0x07FF */ + pdq_txdesc_t pdqdb_transmits[256]; /* 2048; 0x0800..0x0FFF */ + pdq_rxdesc_t pdqdb_host_smt[64]; /* 512; 0x1000..0x11FF */ + pdq_rxdesc_t pdqdb_unsolicited_events[16]; /* 128; 0x1200..0x127F */ + pdq_rxdesc_t pdqdb_command_responses[16]; /* 128; 0x1280..0x12FF */ + pdq_txdesc_t pdqdb_command_requests[16]; /* 128; 0x1300..0x137F */ + /* + * The rest of the descriptor block is unused. + * As such we could use it for other things. + */ + pdq_consumer_block_t pdqdb_consumer; /* 64; 0x1380..0x13BF */ + void *pdqdb_receive_buffers[256]; /* 1024/2048; 0x13C0..0x17BF 0x13C0..0x1BBF */ + void *pdqdb_host_smt_buffers[64]; /* 256/ 512; 0x17C0..0x18BF 0x1BC0..0x1DBF */ + /* + * The maximum command size is 512 so as long as thes + * command is at least that long all will be fine. + */ +#if defined(__alpha) || defined(__alpha__) + pdq_uint32_t pdqdb_command_pool[144]; +#else + pdq_uint32_t pdqdb_command_pool[464]; +#endif +} pdq_descriptor_block_t; + +typedef enum { + PDQ_DEFPA, /* PCI-bus */ + PDQ_DEFEA, /* EISA-bus */ + PDQ_DEFTA, /* TurboChannel */ + PDQ_DEFAA, /* FutureBus+ */ + PDQ_DEFQA /* Q-bus */ +} pdq_type_t; + +typedef struct { + /* + * These value manage the available space in command/response + * buffer area. + */ + pdq_physaddr_t ci_pa_bufstart; + pdq_uint8_t *ci_bufstart; + /* + * Bitmask of commands to sent to the PDQ + */ + pdq_uint32_t ci_pending_commands; + /* + * Variables to maintain the PDQ queues. + */ + pdq_uint32_t ci_command_active; + pdq_uint32_t ci_request_producer; + pdq_uint32_t ci_response_producer; + pdq_uint32_t ci_request_completion; + pdq_uint32_t ci_response_completion; +} pdq_command_info_t; + +#define PDQ_SIZE_UNSOLICITED_EVENT 512 +#define PDQ_NUM_UNSOLICITED_EVENTS (PDQ_OS_PAGESIZE / PDQ_SIZE_UNSOLICITED_EVENT) + +typedef struct _pdq_unsolicited_event_t pdq_unsolicited_event_t; + +typedef struct { + pdq_physaddr_t ui_pa_bufstart; + pdq_unsolicited_event_t *ui_events; + + pdq_uint32_t ui_free; + pdq_uint32_t ui_producer; + pdq_uint32_t ui_completion; +} pdq_unsolicited_info_t; + +#define PDQ_RX_FC_OFFSET (sizeof(pdq_rxstatus_t) + 3) +#define PDQ_RX_SEGCNT ((PDQ_FDDI_MAX + PDQ_OS_DATABUF_SIZE - 1) / PDQ_OS_DATABUF_SIZE) +#define PDQ_DO_TYPE2_PRODUCER(pdq) \ + (*pdq->pdq_csrs.csr_type_2_producer = (pdq->pdq_rx_info.rx_producer << 0) \ + | (pdq->pdq_tx_info.tx_producer << 8) \ + | (pdq->pdq_rx_info.rx_completion << 16) \ + | (pdq->pdq_tx_info.tx_completion << 24)) +#define PDQ_ADVANCE(n, a, m) ((n) = ((n) + (a)) & (m)) + +typedef struct { + void *q_head; + void *q_tail; +} pdq_databuf_queue_t; + +typedef struct { + void *rx_buffers; + + pdq_uint32_t rx_target; + pdq_uint32_t rx_free; + pdq_uint32_t rx_producer; + pdq_uint32_t rx_completion; +} pdq_rx_info_t; + +typedef struct { + pdq_databuf_queue_t tx_txq; + pdq_txdesc_t tx_hdrdesc; + pdq_uint8_t tx_descriptor_count[256]; + + pdq_uint32_t tx_free; + pdq_uint32_t tx_producer; + pdq_uint32_t tx_completion; +} pdq_tx_info_t; + +typedef struct { + pdq_csrs_t pdq_csrs; + pdq_pci_csrs_t pdq_pci_csrs; + pdq_type_t pdq_type; + pdq_chip_rev_t pdq_chip_rev; + pdq_lanaddr_t pdq_hwaddr; + pdq_fwrev_t pdq_fwrev; + pdq_descriptor_block_t *pdq_dbp; + volatile pdq_consumer_block_t *pdq_cbp; + pdq_uint32_t pdq_flags; +#define PDQ_PROMISC 0x0001 +#define PDQ_ALLMULTI 0x0002 +#define PDQ_PASS_SMT 0x0004 +#define PDQ_RUNNING 0x0008 +#define PDQ_PRINTCHARS 0x0010 +#define PDQ_TXOK 0x0020 + const char *pdq_os_name; + void *pdq_os_ctx; + pdq_uint32_t pdq_unit; + pdq_command_info_t pdq_command_info; + pdq_unsolicited_info_t pdq_unsolicited_info; + pdq_tx_info_t pdq_tx_info; + pdq_rx_info_t pdq_rx_info; + pdq_rx_info_t pdq_host_smt_info; + pdq_uint8_t pdq_tx_hdr[3]; +} pdq_t; + +typedef enum { + PDQC_START=0, + PDQC_FILTER_SET=1, + PDQC_FILTER_GET=2, + PDQC_CHARS_SET=3, + PDQC_STATUS_CHARS_GET=4, + PDQC_COUNTERS_GET=5, + PDQC_COUNTERS_SET=6, + PDQC_ADDR_FILTER_SET=7, + PDQC_ADDR_FILTER_GET=8, + PDQC_ERROR_LOG_CLEAR=9, + PDQC_ERROR_LOG_GET=10, + PDQC_FDDI_MIB_GET=11, + PDQC_DEC_EXT_MIB_GET=12, + PDQC_DEV_SPECIFIC_GET=13, + PDQC_SNMP_SET=14, + PDQC_SMT_MIB_GET=16, + PDQC_SMT_MIB_SET=17 +} pdq_cmd_code_t; + +typedef enum { + PDQR_SUCCESS=0, + PDQR_FAILURE=1, + PDQR_WARNING=2, + PDQR_LOOP_MODE_BAD=3, + PDQR_ITEM_CODE_BAD=4, + PDQR_TVX_BAD=5, + PDQR_TREQ_BAD=6, + PDQR_RESTRICTED_TOKEN_BAD=7, + PDQR_NO_EOL=12, + PDQR_FILTER_STATE_BAD=13, + PDQR_CMD_TYPE_BAD=14, + PDQR_ADAPTER_STATE_BAD=15, + PDQR_RING_PURGER_BAD=16, + PDQR_LEM_THRESHOLD_BAD=17, + PDQR_LOOP_NOT_SUPPORTED=18, + PDQR_FLUSH_TIME_BAD=19, + PDQR_NOT_YET_IMPLEMENTED=20, + PDQR_CONFIG_POLICY_BAD=21, + PDQR_STATION_ACTION_BAD=22, + PDQR_MAC_ACTION_BAD=23, + PDQR_CON_POLICIES_BAD=24, + PDQR_MAC_LOOP_TIME_BAD=25, + PDQR_TB_MAX_BAD=26, + PDQR_LER_CUTOFF_BAD=27, + PDQR_LER_ALARM_BAD=28, + PDQR_MAC_PATHS_REQ_BAD=29, + PDQR_MAC_T_REQ_BAD=30, + PDQR_EMAC_RING_PURGER_BAD=31, + PDQR_EMAC_RTOKEN_TIMOUT_AD=32, + PDQR_NO_SUCH_ENTRY=33, + PDQR_T_NOTIFY_BAD=34, + PDQR_TR_MAX_EXP_BAD=35, + PDQR_FRAME_ERR_THRESHOLD_BAD=36, + PDQR_MAX_TREQ_BAD=37, + PDQR_FULL_DUPLEX_ENABLE_BAD=38, + PDQR_ITEM_INDEX_BAD=39 +} pdq_response_code_t; + +typedef enum { + PDQI_EOL=0, + PDQI_T_REQ=1, + PDQI_TVX=2, + PDQI_RESTRICTED_TOKEN=3, + PDQI_LEM_THRESHOLD=4, + PDQI_RING_PURGER=5, + PDQI_COUNTER_INTERVAL=6, + PDQI_IND_GROUP_PROM=7, + PDQI_GROUP_PROM=8, + PDQI_BROADCAST=9, + PDQI_SMT_PROM=10, + PDQI_SMT_USER=11, + PDQI_RESERVED=12, + PDQI_IMPLEMENTOR=13, + PDQI_LOOPBACK_MODE=14, + PDQI_SMT_CONFIG_POLICY=16, + PDQI_SMT_CONNECTION_POLICY=17, + PDQI_SMT_T_NOTIFY=18, + PDQI_SMT_STATION_ACTION=19, + PDQI_MAC_PATHS_REQUESTED=21, + PDQI_MAC_ACTION=23, + PDQI_PORT_CONNECTION_POLICIES=24, + PDQI_PORT_PATHS_REQUESTED=25, + PDQI_PORT_MAC_LOOP_TIME=26, + PDQI_PORT_TB_MAX=27, + PDQI_PORT_LER_CUTOFF=28, + PDQI_PORT_LER_ALARM=29, + PDQI_PORT_ACTION=30, + PDQI_FLUSH_TIME=32, + PDQI_SMT_USER_DATA=33, + PDQI_SMT_STATUS_REPORT_POLICY=34, + PDQI_SMT_TRACE_MAX_EXPIRATION=35, + PDQI_MAC_FRAME_ERR_THRESHOLD=36, + PDQI_MAC_UNIT_DATA_ENABLE=37, + PDQI_PATH_TVX_LOWER_BOUND=38, + PDQI_PATH_TMAX_LOWER_BOUND=39, + PDQI_PATH_MAX_TREQ=40, + PDQI_MAC_TREQ=41, + PDQI_EMAC_RING_PURGER=42, + PDQI_EMAC_RTOKEN_TIMEOUT=43, + PDQI_FULL_DUPLEX_ENABLE=44 +} pdq_item_code_t; + +typedef enum { + PDQ_FALSE=0, + PDQ_TRUE=1 +} pdq_boolean_t; + +typedef enum { + PDQ_FILTER_BLOCK=0, + PDQ_FILTER_PASS=1 +} pdq_filter_state_t; + +typedef enum { + PDQ_STATION_TYPE_SAS=0, + PDQ_STATION_TYPE_DAC=1, + PDQ_STATION_TYPE_SAC=2, + PDQ_STATION_TYPE_NAC=3, + PDQ_STATION_TYPE_DAS=4 +} pdq_station_type_t; + +typedef enum { + PDQ_STATION_STATE_OFF=0, + PDQ_STATION_STATE_ON=1, + PDQ_STATION_STATE_LOOPBACK=2 +} pdq_station_state_t; + +typedef enum { + PDQ_LINK_STATE_OFF_READY=1, + PDQ_LINK_STATE_OFF_FAULT_RECOVERY=2, + PDQ_LINK_STATE_ON_RING_INIT=3, + PDQ_LINK_STATE_ON_RING_RUN=4, + PDQ_LINK_STATE_BROKEN=5 +} pdq_link_state_t; + +typedef enum { + PDQ_DA_TEST_STATE_UNKNOWN=0, + PDQ_DA_TEST_STATE_SUCCESS=1, + PDQ_DA_TEST_STATE_DUPLICATE=2 +} pdq_da_test_state_t; + +typedef enum { + PDQ_RING_PURGER_STATE_OFF=0, + PDQ_RING_PURGER_STATE_CANDIDATE=1, + PDQ_RING_PURGER_STATE_NON_PURGER=2, + PDQ_RING_PURGER_STATE_PURGER=3 +} pdq_ring_purger_state_t; + +typedef enum { + PDQ_FRAME_STRING_MODE_SA_MATCH=0, + PDQ_FRAME_STRING_MODE_FCI_STRIP=1 +} pdq_frame_strip_mode_t; + +typedef enum { + PDQ_RING_ERROR_REASON_NO_ERROR=0, + PDQ_RING_ERROR_REASON_RING_INIT_INITIATED=5, + PDQ_RING_ERROR_REASON_RING_INIT_RECEIVED=6, + PDQ_RING_ERROR_REASON_RING_BEACONING_INITIATED=7, + PDQ_RING_ERROR_REASON_DUPLICATE_ADDRESS_DETECTED=8, + PDQ_RING_ERROR_REASON_DUPLICATE_TOKEN_DETECTED=9, + PDQ_RING_ERROR_REASON_RING_PURGER_ERROR=10, + PDQ_RING_ERROR_REASON_FCI_STRIP_ERROR=11, + PDQ_RING_ERROR_REASON_RING_OP_OSCILLATION=12, + PDQ_RING_ERROR_REASON_DIRECTED_BEACON_RECEVIED=13, + PDQ_RING_ERROR_REASON_PC_TRACE_INITIATED=14, + PDQ_RING_ERROR_REASON_PC_TRACE_RECEVIED=15 +} pdq_ring_error_reason_t; + +typedef enum { + PDQ_STATION_MODE_NORMAL=0, + PDQ_STATION_MODE_INTERNAL_LOOPBACK=1 +} pdq_station_mode_t; + +typedef enum { + PDQ_PHY_TYPE_A=0, + PDQ_PHY_TYPE_B=1, + PDQ_PHY_TYPE_S=2, + PDQ_PHY_TYPE_M=3, + PDQ_PHY_TYPE_UNKNOWN=4 +} pdq_phy_type_t; + +typedef enum { + PDQ_PMD_TYPE_ANSI_MUTLI_MODE=0, + PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1=1, + PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2=2, + PDQ_PMD_TYPE_ANSI_SONET=3, + PDQ_PMD_TYPE_LOW_POWER=100, + PDQ_PMD_TYPE_THINWIRE=101, + PDQ_PMD_TYPE_SHIELDED_TWISTED_PAIR=102, + PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR=103 +} pdq_pmd_type_t; + +typedef enum { + PDQ_PMD_CLASS_ANSI_MULTI_MODE=0, + PDQ_PMD_CLASS_SINGLE_MODE_TYPE_1=1, + PDQ_PMD_CLASS_SINGLE_MODE_TYPE_2=2, + PDQ_PMD_CLASS_SONET=3, + PDQ_PMD_CLASS_LOW_COST_POWER_FIBER=4, + PDQ_PMD_CLASS_TWISTED_PAIR=5, + PDQ_PMD_CLASS_UNKNOWN=6, + PDQ_PMD_CLASS_UNSPECIFIED=7 +} pdq_pmd_class_t; + +typedef enum { + PDQ_PHY_STATE_INTERNAL_LOOPBACK=0, + PDQ_PHY_STATE_BROKEN=1, + PDQ_PHY_STATE_OFF_READY=2, + PDQ_PHY_STATE_WAITING=3, + PDQ_PHY_STATE_STARTING=4, + PDQ_PHY_STATE_FAILED=5, + PDQ_PHY_STATE_WATCH=6, + PDQ_PHY_STATE_INUSE=7 +} pdq_phy_state_t; + +typedef enum { + PDQ_REJECT_REASON_NONE=0, + PDQ_REJECT_REASON_LOCAL_LCT=1, + PDQ_REJECT_REASON_REMOTE_LCT=2, + PDQ_REJECT_REASON_LCT_BOTH_SIDES=3, + PDQ_REJECT_REASON_LEM_REJECT=4, + PDQ_REJECT_REASON_TOPOLOGY_ERROR=5, + PDQ_REJECT_REASON_NOISE_REJECT=6, + PDQ_REJECT_REASON_REMOTE_REJECT=7, + PDQ_REJECT_REASON_TRACE_IN_PROGRESS=8, + PDQ_REJECT_REASON_TRACE_RECEIVED_DISABLED=9, + PDQ_REJECT_REASON_STANDBY=10, + PDQ_REJECT_REASON_LCT_PROTOCOL_ERROR=11 +} pdq_reject_reason_t; + +typedef enum { + PDQ_BROKEN_REASON_NONE=0 +} pdq_broken_reason_t; + +typedef enum { + PDQ_RI_REASON_TVX_EXPIRED=0, + PDQ_RI_REASON_TRT_EXPIRED=1, + PDQ_RI_REASON_RING_PURGER_ELECTION_ATTEMPT_LIMIT_EXCEEDED=2, + PDQ_RI_REASON_PURGE_ERROR_LIMIT_EXCEEDED=3, + PDQ_RI_REASON_RESTRICTED_TOKEN_TIMEOUT=4 +} pdq_ri_reason_t; + +typedef enum { + PDQ_LCT_DIRECTION_LOCAL_LCT=0, + PDQ_LCT_DIRECTION_REMOTE_LCT=1, + PDQ_LCT_DIRECTION_LCT_BOTH_SIDES=2 +} pdq_lct_direction_t; + +typedef enum { + PDQ_PORT_A=0, + PDQ_PORT_B=1 +} pdq_port_type_t; + +typedef struct { + pdq_uint8_t station_id_bytes[8]; +} pdq_station_id_t; + +typedef pdq_uint32_t pdq_fdditimer_t; +/* + * Command format for Start, Filter_Get, ... commands + */ +typedef struct { + pdq_cmd_code_t generic_op; +} pdq_cmd_generic_t; + +/* + * Response format for Start, Filter_Set, ... commands + */ +typedef struct { + pdq_uint32_t generic_reserved; + pdq_cmd_code_t generic_op; + pdq_response_code_t generic_status; +} pdq_response_generic_t; + +/* + * Command format for Filter_Set command + */ +typedef struct { + pdq_cmd_code_t filter_set_op; + struct { + pdq_item_code_t item_code; + pdq_filter_state_t filter_state; + } filter_set_items[7]; + pdq_item_code_t filter_set_eol_item_code; +} pdq_cmd_filter_set_t; + +/* + * Response format for Filter_Get command. + */ +typedef struct { + pdq_uint32_t filter_get_reserved; + pdq_cmd_code_t filter_get_op; + pdq_response_code_t filter_get_status; + pdq_filter_state_t filter_get_ind_group_prom; + pdq_filter_state_t filter_get_group_prom; + pdq_filter_state_t filter_get_broadcast_all; + pdq_filter_state_t filter_get_smt_prom; + pdq_filter_state_t filter_get_smt_user; + pdq_filter_state_t filter_get_reserved_all; + pdq_filter_state_t filter_get_implementor_all; +} pdq_response_filter_get_t; + +#define PDQ_SIZE_RESPONSE_FILTER_GET 0x28 + +typedef struct { + pdq_cmd_code_t chars_set_op; + struct { + pdq_item_code_t item_code; + pdq_uint32_t item_value; + pdq_port_type_t item_port; + } chars_set_items[1]; + pdq_item_code_t chars_set_eol_item_code; +} pdq_cmd_chars_set_t; + +typedef struct { + pdq_cmd_code_t addr_filter_set_op; + pdq_lanaddr_t addr_filter_set_addresses[62]; +} pdq_cmd_addr_filter_set_t; + +#define PDQ_SIZE_CMD_ADDR_FILTER_SET 0x1F4 + +typedef struct { + pdq_uint32_t addr_filter_get_reserved; + pdq_cmd_code_t addr_filter_get_op; + pdq_response_code_t addr_filter_get_status; + pdq_lanaddr_t addr_filter_get_addresses[62]; +} pdq_response_addr_filter_get_t; + +#define PDQ_SIZE_RESPONSE_ADDR_FILTER_GET 0x1FC + +typedef struct { + pdq_uint32_t status_chars_get_reserved; + pdq_cmd_code_t status_chars_get_op; + pdq_response_code_t status_chars_get_status; + struct { + /* Station Characteristic Attributes */ + pdq_station_id_t station_id; + pdq_station_type_t station_type; + pdq_uint32_t smt_version_id; + pdq_uint32_t smt_max_version_id; + pdq_uint32_t smt_min_version_id; + /* Station Status Attributes */ + pdq_station_state_t station_state; + /* Link Characteristic Attributes */ + pdq_lanaddr_t link_address; + pdq_fdditimer_t t_req; + pdq_fdditimer_t tvx; + pdq_fdditimer_t restricted_token_timeout; + pdq_boolean_t ring_purger_enable; + pdq_link_state_t link_state; + pdq_fdditimer_t negotiated_trt; + pdq_da_test_state_t dup_addr_flag; + /* Link Status Attributes */ + pdq_lanaddr_t upstream_neighbor; + pdq_lanaddr_t old_upstream_neighbor; + pdq_boolean_t upstream_neighbor_dup_addr_flag; + pdq_lanaddr_t downstream_neighbor; + pdq_lanaddr_t old_downstream_neighbor; + pdq_ring_purger_state_t ring_purger_state; + pdq_frame_strip_mode_t frame_strip_mode; + pdq_ring_error_reason_t ring_error_reason; + pdq_boolean_t loopback; + pdq_fdditimer_t ring_latency; + pdq_lanaddr_t last_dir_beacon_sa; + pdq_lanaddr_t last_dir_beacon_una; + /* Phy Characteristic Attributes */ + pdq_phy_type_t phy_type[2]; + pdq_pmd_type_t pmd_type[2]; + pdq_uint32_t lem_threshold[2]; + /* Phy Status Attributes */ + pdq_phy_state_t phy_state[2]; + pdq_phy_type_t neighbor_phy_type[2]; + pdq_uint32_t link_error_estimate[2]; + pdq_broken_reason_t broken_reason[2]; + pdq_reject_reason_t reject_reason[2]; + /* Miscellaneous */ + pdq_uint32_t counter_interval; + pdq_fwrev_t module_rev; + pdq_fwrev_t firmware_rev; + pdq_uint32_t mop_device_type; + pdq_uint32_t fddi_led[2]; + pdq_uint32_t flush; + } status_chars_get; +} pdq_response_status_chars_get_t; + +#define PDQ_SIZE_RESPONSE_STATUS_CHARS_GET 0xF0 + +typedef struct { + pdq_uint32_t fddi_mib_get_reserved; + pdq_cmd_code_t fddi_mib_get_op; + pdq_response_code_t fddi_mib_get_status; + struct { + /* SMT Objects */ + pdq_station_id_t smt_station_id; + pdq_uint32_t smt_op_version_id; + pdq_uint32_t smt_hi_version_id; + pdq_uint32_t smt_lo_version_id; + pdq_uint32_t smt_mac_ct; + pdq_uint32_t smt_non_master_ct; + pdq_uint32_t smt_master_ct; + pdq_uint32_t smt_paths_available; + pdq_uint32_t smt_config_capabilities; + pdq_uint32_t smt_config_policy; + pdq_uint32_t smt_connection_policy; + pdq_uint32_t smt_t_notify; + pdq_uint32_t smt_status_reporting; + pdq_uint32_t smt_ecm_state; + pdq_uint32_t smt_cf_state; + pdq_uint32_t smt_hold_state; + pdq_uint32_t smt_remote_disconnect_flag; + pdq_uint32_t smt_station_action; + /* MAC Objects */ + pdq_uint32_t mac_frame_status_capabilities; + pdq_uint32_t mac_t_max_greatest_lower_bound; + pdq_uint32_t mac_tvx_greatest_lower_bound; + pdq_uint32_t mac_paths_available; + pdq_uint32_t mac_current_path; + pdq_lanaddr_t mac_upstream_neighbor; + pdq_lanaddr_t mac_old_upstream_neighbor; + pdq_uint32_t mac_dup_addr_test; + pdq_uint32_t mac_paths_requested; + pdq_uint32_t mac_downstream_port_type; + pdq_lanaddr_t mac_smt_address; + pdq_uint32_t mac_t_req; + pdq_uint32_t mac_t_neg; + pdq_uint32_t mac_t_max; + pdq_uint32_t mac_tvx_value; + pdq_uint32_t mac_t_min; + pdq_uint32_t mac_current_frame_status; + pdq_uint32_t mac_frame_error_threshold; + pdq_uint32_t mac_frame_error_ratio; + pdq_uint32_t mac_rmt_state; + pdq_uint32_t mac_da_flag; + pdq_uint32_t mac_una_da_flag; + pdq_uint32_t mac_frame_condition; + pdq_uint32_t mac_chip_set; + pdq_uint32_t mac_action; + /* Port Objects */ + pdq_uint32_t port_pc_type[2]; + pdq_uint32_t port_pc_neighbor[2]; + pdq_uint32_t port_connection_policies[2]; + pdq_uint32_t port_remote_mac_indicated[2]; + pdq_uint32_t port_ce_state[2]; + pdq_uint32_t port_paths_requested[2]; + pdq_uint32_t port_mac_placement[2]; + pdq_uint32_t port_available_paths[2]; + pdq_uint32_t port_mac_loop_time[2]; + pdq_uint32_t port_tb_max[2]; + pdq_uint32_t port_bs_flag[2]; + pdq_uint32_t port_ler_estimate[2]; + pdq_uint32_t port_ler_cutoff[2]; + pdq_uint32_t port_ler_alarm[2]; + pdq_uint32_t port_connect_state[2]; + pdq_uint32_t port_pcm_state[2]; + pdq_uint32_t port_pc_withhold[2]; + pdq_uint32_t port_ler_condition[2]; + pdq_uint32_t port_chip_set[2]; + pdq_uint32_t port_action[2]; + /* Attachment Objects */ + pdq_uint32_t attachment_class; + pdq_uint32_t attachment_optical_bypass_present; + pdq_uint32_t attachment_imax_expiration; + pdq_uint32_t attachment_inserted_status; + pdq_uint32_t attachment_insert_policy; + } fddi_mib_get; +} pdq_response_fddi_mib_get_t; + +#define PDQ_SIZE_RESPONSE_FDDI_MIB_GET 0x17C + +typedef enum { + PDQ_FDX_STATE_IDLE=0, + PDQ_FDX_STATE_REQUEST=1, + PDQ_FDX_STATE_CONFIRM=2, + PDQ_FDX_STATE_OPERATION=3 +} pdq_fdx_state_t; + +typedef struct { + pdq_uint32_t dec_ext_mib_get_reserved; + pdq_cmd_code_t dec_ext_mib_get_op; + pdq_response_code_t dec_ext_mib_get_response; + struct { + /* SMT Objects */ + pdq_uint32_t esmt_station_type; + /* MAC Objects */ + pdq_uint32_t emac_link_state; + pdq_uint32_t emac_ring_purger_state; + pdq_uint32_t emac_ring_purger_enable; + pdq_uint32_t emac_frame_strip_mode; + pdq_uint32_t emac_ring_error_reason; + pdq_uint32_t emac_upstream_nbr_dupl_address_flag; + pdq_uint32_t emac_restricted_token_timeout; + /* Port Objects */ + pdq_uint32_t eport_pmd_type[2]; + pdq_uint32_t eport_phy_state[2]; + pdq_uint32_t eport_reject_reason[2]; + /* Full Duplex Objects */ + pdq_boolean_t fdx_enable; + pdq_boolean_t fdx_operational; + pdq_fdx_state_t fdx_state; + } dec_ext_mib_get; +} pdq_response_dec_ext_mib_get_t; + +#define PDQ_SIZE_RESPONSE_DEC_EXT_MIB_GET 0x50 + +typedef enum { + PDQ_CALLER_ID_NONE=0, + PDQ_CALLER_ID_SELFTEST=1, + PDQ_CALLER_ID_MFG=2, + PDQ_CALLER_ID_FIRMWARE=5, + PDQ_CALLER_ID_CONSOLE=8 +} pdq_caller_id_t; + +typedef struct { + pdq_uint32_t error_log_get__reserved; + pdq_cmd_code_t error_log_get_op; + pdq_response_code_t error_log_get_status; + /* Error Header */ + pdq_uint32_t error_log_get_event_status; + /* Event Information Block */ + pdq_caller_id_t error_log_get_caller_id; + pdq_uint32_t error_log_get_timestamp[2]; + pdq_uint32_t error_log_get_write_count; + /* Diagnostic Information */ + pdq_uint32_t error_log_get_fru_implication_mask; + pdq_uint32_t error_log_get_test_id; + pdq_uint32_t error_log_get_diag_reserved[6]; + /* Firmware Information */ + pdq_uint32_t error_log_get_fw_reserved[112]; +} pdq_response_error_log_get_t; + + +/* + * Definitions for the Unsolicited Event Queue. + */ +typedef enum { + PDQ_UNSOLICITED_EVENT=0, + PDQ_UNSOLICITED_COUNTERS=1 +} pdq_event_t; + +typedef enum { + PDQ_ENTITY_STATION=0, + PDQ_ENTITY_LINK=1, + PDQ_ENTITY_PHY_PORT=2 +} pdq_entity_t; + +typedef enum { + PDQ_STATION_EVENT_TRACE_RECEIVED=1 +} pdq_station_event_t; + +typedef enum { + PDQ_STATION_EVENT_ARGUMENT_REASON=0, /* pdq_uint32_t */ + PDQ_STATION_EVENT_ARGUMENT_EOL=0xFF +} pdq_station_event_argument_t; + +typedef enum { + PDQ_LINK_EVENT_TRANSMIT_UNDERRUN=0, + PDQ_LINK_EVENT_TRANSMIT_FAILED=1, + PDQ_LINK_EVENT_BLOCK_CHECK_ERROR=2, + PDQ_LINK_EVENT_FRAME_STATUS_ERROR=3, + PDQ_LINK_EVENT_PDU_LENGTH_ERROR=4, + PDQ_LINK_EVENT_RECEIVE_DATA_OVERRUN=7, + PDQ_LINK_EVENT_NO_USER_BUFFER=9, + PDQ_LINK_EVENT_RING_INITIALIZATION_INITIATED=10, + PDQ_LINK_EVENT_RING_INITIALIZATION_RECEIVED=11, + PDQ_LINK_EVENT_RING_BEACON_INITIATED=12, + PDQ_LINK_EVENT_DUPLICATE_ADDRESS_FAILURE=13, + PDQ_LINK_EVENT_DUPLICATE_TOKEN_DETECTED=14, + PDQ_LINK_EVENT_RING_PURGE_ERROR=15, + PDQ_LINK_EVENT_FCI_STRIP_ERROR=16, + PDQ_LINK_EVENT_TRACE_INITIATED=17, + PDQ_LINK_EVENT_DIRECTED_BEACON_RECEIVED=18 +} pdq_link_event_t; + +typedef enum { + PDQ_LINK_EVENT_ARGUMENT_REASON=0, /* pdq_rireason_t */ + PDQ_LINK_EVENT_ARGUMENT_DATA_LINK_HEADER=1, /* pdq_dlhdr_t */ + PDQ_LINK_EVENT_ARGUMENT_SOURCE=2, /* pdq_lanaddr_t */ + PDQ_LINK_EVENT_ARGUMENT_UPSTREAM_NEIGHBOR=3,/* pdq_lanaddr_t */ + PDQ_LINK_EVENT_ARGUMENT_EOL=0xFF +} pdq_link_event_argument_t; + +typedef enum { + PDQ_PHY_EVENT_LEM_ERROR_MONITOR_REJECT=0, + PDQ_PHY_EVENT_ELASTICITY_BUFFER_ERROR=1, + PDQ_PHY_EVENT_LINK_CONFIDENCE_TEST_REJECT=2 +} pdq_phy_event_t; + +typedef enum { + PDQ_PHY_EVENT_ARGUMENT_DIRECTION=0, /* pdq_lct_direction_t */ + PDQ_PHY_EVENT_ARGUMENT_EOL=0xFF +} pdq_phy_event_arguments; + +struct _pdq_unsolicited_event_t { + pdq_uint32_t rvent_reserved; + pdq_event_t event_type; + pdq_entity_t event_entity; + pdq_uint32_t event_index; + union { + pdq_station_event_t station_event; + pdq_link_event_t link_event; + pdq_phy_event_t phy_event; + pdq_uint32_t value; + } event_code; + /* + * The remainder of this event is an argument list. + */ + pdq_uint32_t event__filler[123]; +}; + +#endif /* _PDQREG_H */ diff --git a/sys/dev/ic/pdqvar.h b/sys/dev/ic/pdqvar.h new file mode 100644 index 00000000000..4f4c85901dc --- /dev/null +++ b/sys/dev/ic/pdqvar.h @@ -0,0 +1,252 @@ +/* $NetBSD: pdqvar.h,v 1.2 1995/08/19 04:35:22 cgd Exp $ */ + +/*- + * Copyright (c) 1995 Matt Thomas (thomas@lkg.dec.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * DEC PDQ FDDI Controller; PDQ O/S dependent definitions + * + * Written by Matt Thomas + */ + +#ifndef _PDQ_OS_H +#define _PDQ_OS_H + +#define PDQ_OS_TX_TIMEOUT 5 /* seconds */ + +#if defined(PDQTEST) +#include <pdq_os_test.h> +#elif defined(__FreeBSD__) || defined(__bsdi__) || defined(__NetBSD__) + +#include <sys/param.h> +#ifndef M_MCAST +#include <sys/mbuf.h> +#endif /* M_CAST */ +#include <sys/malloc.h> +#include <vm/vm.h> +#include <vm/vm_kern.h> + +#define PDQ_USE_MBUFS +#define PDQ_OS_PREFIX "%s%d: " +#define PDQ_OS_PREFIX_ARGS pdq->pdq_os_name, pdq->pdq_unit + +#define PDQ_OS_PAGESIZE NBPG +#define PDQ_OS_USEC_DELAY(n) DELAY(n) +#define PDQ_OS_MEMZERO(p, n) bzero((caddr_t)(p), (n)) +#define PDQ_OS_VA_TO_PA(p) vtophys(p) +#define PDQ_OS_MEMALLOC(n) malloc(n, M_DEVBUF, M_NOWAIT) +#define PDQ_OS_MEMFREE(p, n) free((void *) p, M_DEVBUF) +#ifdef __FreeBSD__ +#define PDQ_OS_MEMALLOC_CONTIG(n) vm_page_alloc_contig(n, 0, 0xffffffff, PAGE_SIZE) +#define PDQ_OS_MEMFREE_CONTIG(p, n) kmem_free(kernel_map, (vm_offset_t) p, n) +#else +#define PDQ_OS_MEMALLOC_CONTIG(n) kmem_alloc(kernel_map, round_page(n)) +#define PDQ_OS_MEMFREE_CONTIG(p, n) kmem_free(kernel_map, (vm_offset_t) p, n) +#endif /* __FreeBSD__ */ + +#if !defined(PDQ_HWSUPPORT) +#if defined(__FreeBSD__) +#include <machine/cpufunc.h> +typedef void ifnet_ret_t; +typedef int ioctl_cmd_t; +#elif defined(__bsdi__) +#include <machine/inline.h> +typedef int ifnet_ret_t; +typedef int ioctl_cmd_t; +#elif defined(__NetBSD__) +typedef void ifnet_ret_t; +typedef u_long ioctl_cmd_t; +#endif +#define PDQ_OS_IORD_32(port) inl(port) +#define PDQ_OS_IOWR_32(port, data) outl(port, data) +#define PDQ_OS_IORD_8(port) inb(port) +#define PDQ_OS_IOWR_8(port, data) outb(port, data) + +typedef struct { +#ifdef __bsdi__ + struct device sc_dev; /* base device */ + struct isadev sc_id; /* ISA device */ + struct intrhand sc_ih; /* intrrupt vectoring */ + struct atshutdown sc_ats; /* shutdown routine */ +#elif defined(__NetBSD__) + struct device sc_dev; /* base device */ + void *sc_ih; /* intrrupt vectoring */ + void *sc_ats; /* shutdown hook */ +#endif + struct arpcom sc_ac; + pdq_t *sc_pdq; + unsigned sc_iobase; +} pdq_softc_t; + +#define sc_if sc_ac.ac_if +#define sc_bpf sc_if.if_bpf + +extern void pdq_ifreset(pdq_softc_t *sc); +extern void pdq_ifinit(pdq_softc_t *sc); +extern void pdq_ifwatchdog(pdq_softc_t *sc); +extern ifnet_ret_t pdq_ifstart(struct ifnet *ifp); +extern int pdq_ifioctl(struct ifnet *ifp, ioctl_cmd_t cmd, caddr_t data); +extern void pdq_ifattach(pdq_softc_t *sc, ifnet_ret_t (*ifinit)(int unit), + ifnet_ret_t (*ifwatchdog)(int unit)); +#endif /* PDQ_HWSUPPORT */ +#elif defined(DLPI_PDQ) +#include <sys/param.h> +#include <sys/kmem.h> +#include <sys/ddi.h> +#include <sys/stream.h> + +#define PDQ_USE_STREAMS +#define PDQ_OS_PREFIX "%s board %d " +#define PDQ_OS_PREFIX_ARGS pdq->pdq_os_name, pdq->pdq_unit + +#define PDQ_OS_PAGESIZE PAGESIZE +#define PDQ_OS_USEC_DELAY(n) drv_usecwait(n) +#define PDQ_OS_MEMZERO(p, n) bzero((caddr_t)(p), (n)) +#define PDQ_OS_VA_TO_PA(p) vtop((caddr_t)p, NULL) +#define PDQ_OS_MEMALLOC(n) kmem_zalloc(n, KM_NOSLEEP) +#define PDQ_OS_MEMFREE(p, n) kmem_free((caddr_t) p, n) +#define PDQ_OS_MEMALLOC_CONTIG(n) kmem_zalloc_physreq(n, decfddiphysreq_db, KM_NOSLEEP) +#define PDQ_OS_MEMFREE_CONTIG(p, n) PDQ_OS_MEMFREE(p, n) + +extern physreq_t *decfddiphysreq_db; +extern physreq_t *decfddiphysreq_mblk; + +#define PDQ_OS_DATABUF_ALLOC(b) ((void) (((b) = allocb_physreq(PDQ_OS_DATABUF_SIZE, BPRI_MED, decfddiphysreq_mblk)) && ((b)->b_wptr = (b)->b_rptr + PDQ_OS_DATABUF_SIZE))) + +#define PDQ_OS_IORD_8(port) inb(port) +#define PDQ_OS_IOWR_8(port, data) outb(port, data) +#endif + + +#ifdef PDQ_USE_MBUFS +#define PDQ_OS_DATABUF_SIZE (MCLBYTES) +#define PDQ_OS_DATABUF_FREE(b) (m_freem(b)) +#define PDQ_OS_DATABUF_NEXT(b) ((b)->m_next) +#define PDQ_OS_DATABUF_NEXT_SET(b, b1) ((b)->m_next = (b1)) +#define PDQ_OS_DATABUF_NEXTPKT(b) ((b)->m_nextpkt) +#define PDQ_OS_DATABUF_NEXTPKT_SET(b, b1) ((b)->m_nextpkt = (b1)) +#define PDQ_OS_DATABUF_LEN(b) ((b)->m_len) +#define PDQ_OS_DATABUF_LEN_SET(b, n) ((b)->m_len = (n)) +/* #define PDQ_OS_DATABUF_LEN_ADJ(b, n) ((b)->m_len += (n)) */ +#define PDQ_OS_DATABUF_PTR(b) (mtod((b), pdq_uint8_t *)) +#define PDQ_OS_DATABUF_ADJ(b, n) ((b)->m_data += (n), (b)->m_len -= (n)) +typedef struct mbuf PDQ_OS_DATABUF_T; + +#define PDQ_OS_DATABUF_ALLOC(b) do { \ + PDQ_OS_DATABUF_T *x_m0; \ + MGETHDR(x_m0, M_DONTWAIT, MT_DATA); \ + if (x_m0 != NULL) { \ + MCLGET(x_m0, M_DONTWAIT); \ + if ((x_m0->m_flags & M_EXT) == 0) { \ + m_free(x_m0); \ + (b) = NULL; \ + } else { \ + (b) = x_m0; \ + x_m0->m_len = PDQ_OS_DATABUF_SIZE; \ + } \ + } else { \ + (b) = NULL; \ + } \ +} while (0) +#define PDQ_OS_DATABUF_RESET(b) ((b)->m_data = (b)->m_ext.ext_buf, (b)->m_len = MCLBYTES) +#endif /* PDQ_USE_MBUFS */ + +#ifdef PDQ_USE_STREAMS +#define PDQ_OS_DATABUF_SIZE (2048) +#define PDQ_OS_DATABUF_FREE(b) (freemsg(b)) +#define PDQ_OS_DATABUF_NEXT(b) ((b)->b_cont) +#define PDQ_OS_DATABUF_NEXT_SET(b, b1) ((b)->b_cont = (b1)) +#define PDQ_OS_DATABUF_NEXTPKT(b) ((b)->b_next) +#define PDQ_OS_DATABUF_NEXTPKT_SET(b, b1) ((b)->b_next = (b1)) +#define PDQ_OS_DATABUF_LEN(b) ((b)->b_wptr - (b)->b_rptr) +#define PDQ_OS_DATABUF_LEN_SET(b, n) ((b)->b_wptr = (b)->b_rptr + (n)) +/*#define PDQ_OS_DATABUF_LEN_ADJ(b, n) ((b)->b_wptr += (n))*/ +#define PDQ_OS_DATABUF_PTR(b) ((pdq_uint8_t *) (b)->b_rptr) +#define PDQ_OS_DATABUF_ADJ(b, n) ((b)->b_rptr += (n)) +typedef mblk_t PDQ_OS_DATABUF_T; + +#ifndef PDQ_OS_DATABUF_ALLOC +#define PDQ_OS_DATABUF_ALLOC(b) ((void) (((b) = allocb(PDQ_OS_DATABUF_SIZE, BPRI_MED)) && ((b)->b_wptr = (b)->b_rptr + PDQ_OS_DATABUF_SIZE))) +#endif /* PDQ_OS_DATABUF_ALLOC */ +#endif /* PDQ_USE_STREAMS */ + +#define PDQ_OS_TX_TRANSMIT 5 + +#define PDQ_OS_DATABUF_ENQUEUE(q, b) do { \ + PDQ_OS_DATABUF_NEXTPKT_SET(b, NULL); \ + if ((q)->q_tail == NULL) \ + (q)->q_head = (b); \ + else \ + PDQ_OS_DATABUF_NEXTPKT_SET(((PDQ_OS_DATABUF_T *)(q)->q_tail), b); \ + (q)->q_tail = (b); \ +} while (0) + +#define PDQ_OS_DATABUF_DEQUEUE(q, b) do { \ + if (((b) = (PDQ_OS_DATABUF_T *) (q)->q_head) != NULL) { \ + if (((q)->q_head = PDQ_OS_DATABUF_NEXTPKT(b)) == NULL) \ + (q)->q_tail = NULL; \ + PDQ_OS_DATABUF_NEXTPKT_SET(b, NULL); \ + } \ +} while (0) + +extern void pdq_os_addr_fill(pdq_t *pdq, pdq_lanaddr_t *addrs, size_t numaddrs); +extern void pdq_os_receive_pdu(pdq_t *, PDQ_OS_DATABUF_T *pdu, size_t pdulen); +extern void pdq_os_restart_transmitter(pdq_t *pdq); +extern void pdq_os_transmit_done(pdq_t *pdq, PDQ_OS_DATABUF_T *pdu); + +extern void pdq_print_fddi_chars(pdq_t *pdq, const pdq_response_status_chars_get_t *rsp); + +extern void pdq_init_csrs(pdq_csrs_t *csrs, void *csrs_va, size_t csr_size); +extern void pdq_init_pci_csrs(pdq_pci_csrs_t *csrs, void *csrs_va, size_t csr_size); + +extern void pdq_flush_databuf_queue(pdq_databuf_queue_t *q); + +extern pdq_boolean_t pdq_do_port_control(const pdq_csrs_t * const csrs, pdq_uint32_t cmd); +extern void pdq_read_mla(const pdq_csrs_t * const csrs, pdq_lanaddr_t *hwaddr); +extern void pdq_read_fwrev(const pdq_csrs_t * const csrs, pdq_fwrev_t *fwrev); +extern pdq_boolean_t pdq_read_error_log(pdq_t *pdq, pdq_response_error_log_get_t *log_entry); +extern pdq_chip_rev_t pdq_read_chiprev(const pdq_csrs_t * const csrs); + +extern void pdq_queue_commands(pdq_t *pdq); +extern void pdq_process_command_responses(pdq_t *pdq); +extern void pdq_process_unsolicited_events(pdq_t *pdq); + +extern void pdq_process_received_data(pdq_t *pdq, pdq_rx_info_t *rx, + pdq_rxdesc_t *receives, + pdq_uint32_t completion_goal, + pdq_uint32_t ring_mask); + +extern pdq_boolean_t pdq_queue_transmit_data(pdq_t *pdq, PDQ_OS_DATABUF_T *pdu); +extern void pdq_process_transmitted_data(pdq_t *pdq); +extern void pdq_flush_transmitter(pdq_t *pdq); + + +extern void pdq_hwreset(pdq_t *pdq); +extern pdq_state_t pdq_stop(pdq_t *pdq); +extern void pdq_run(pdq_t *pdq); + +extern int pdq_interrupt(pdq_t *pdq); +extern pdq_t *pdq_initialize(void *csr_va, const char *name, int unit, void *ctx, pdq_type_t type); + +#endif /* _PDQ_OS_H */ diff --git a/sys/dev/ic/z8530reg.h b/sys/dev/ic/z8530reg.h new file mode 100644 index 00000000000..30abf6206b2 --- /dev/null +++ b/sys/dev/ic/z8530reg.h @@ -0,0 +1,432 @@ +/* $NetBSD: z8530reg.h,v 1.4 1995/08/20 13:24:05 leo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)zsreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Zilog SCC registers, as implemented on the Sun-4c. + * + * Each Z8530 implements two channels (called `a' and `b'). + * + * The damnable chip was designed to fit on Z80 I/O ports, and thus + * has everything multiplexed out the wazoo. We have to select + * a register, then read or write the register, and so on. Worse, + * the parameter bits are scattered all over the register space. + * This thing is full of `miscellaneous' control registers. + * + * Worse yet, the registers have incompatible functions on read + * and write operations. We describe the registers below according + * to whether they are `read registers' (RR) or `write registers' (WR). + * As if this were not enough, some of the channel B status bits show + * up in channel A, and vice versa. The blasted thing shares write + * registers 2 and 9 across both channels, and reads registers 2 and 3 + * differently for the two channels. We can, however, ignore this much + * of the time. + */ +#ifndef LOCORE +struct zschan { +#if (BYTE_ORDER == BIG_ENDIAN) && !defined(atari) + volatile u_char zc_csr; /* ctrl,status, and indirect access */ + u_char zc_xxx0; + volatile u_char zc_data; /* data */ + u_char zc_xxx1; +#else + u_char zc_xxx0; + volatile u_char zc_csr; /* ctrl,status, and indirect access */ + u_char zc_xxx1; + volatile u_char zc_data; /* data */ +#endif +}; + +struct zsdevice { + struct zschan zs_chan[2]; +}; +#endif + +/* + * Some of the names in this files were chosen to make the hsis driver + * work unchanged (which means that they will match some in SunOS). + * + * `S.C.' stands for Special Condition, which is any of these: + * receiver overrun (aka silo overflow) + * framing error (missing stop bit, etc) + * end of frame (in synchronous modes) + * parity error (when `parity error is S.C.' is set) + */ + +/* + * Registers with only a single `numeric value' get a name. + * Other registers hold bits and are only numbered; the bit + * definitions imply the register number (see below). + * + * We never use the receive and transmit data registers as + * indirects (choosing instead the zc_data register), so they + * are not defined here. + */ +#define ZSRR_IVEC 2 /* interrupt vector (channel 0) */ +#define ZSRR_IPEND 3 /* interrupt pending (ch. 0 only) */ +#define ZSRR_BAUDLO 12 /* baud rate generator (low half) */ +#define ZSRR_BAUDHI 13 /* baud rate generator (high half) */ + +#define ZSWR_IVEC 2 /* interrupt vector (shared) */ +#define ZSWR_TXSYNC 6 /* sync transmit char (monosync mode) */ +#define ZSWR_RXSYNC 7 /* sync receive char (monosync mode) */ +#define ZSWR_SYNCLO 6 /* sync low byte (bisync mode) */ +#define ZSWR_SYNCHI 7 /* sync high byte (bisync mode) */ +#define ZSWR_SDLC_ADDR 6 /* SDLC address (SDLC mode) */ +#define ZSWR_SDLC_FLAG 7 /* SDLC flag 0x7E (SDLC mode) */ +#define ZSWR_BAUDLO 12 /* baud rate generator (low half) */ +#define ZSWR_BAUDHI 13 /* baud rate generator (high half) */ + +/* + * Registers 0 through 7 may be written with any one of the 8 command + * modifiers, and/or any one of the 4 reset modifiers, defined below. + * To write registers 8 through 15, however, the command modifier must + * always be `point high'. Rather than track this bizzareness all over + * the driver, we try to avoid using any modifiers, ever (but they are + * defined here if you want them). + */ +#define ZSM_RESET_TXUEOM 0xc0 /* reset xmit underrun / eom latch */ +#define ZSM_RESET_TXCRC 0x80 /* reset xmit crc generator */ +#define ZSM_RESET_RXCRC 0x40 /* reset recv crc checker */ +#define ZSM_NULL 0x00 /* nothing special */ + +#define ZSM_RESET_IUS 0x38 /* reset interrupt under service */ +#define ZSM_RESET_ERR 0x30 /* reset error cond */ +#define ZSM_RESET_TXINT 0x28 /* reset xmit interrupt pending */ +#define ZSM_EI_NEXTRXC 0x20 /* enable int. on next rcvd char */ +#define ZSM_SEND_ABORT 0x18 /* send abort (SDLC) */ +#define ZSM_RESET_STINT 0x10 /* reset external/status interrupt */ +#define ZSM_POINTHIGH 0x08 /* `point high' (use r8-r15) */ +#define ZSM_NULL 0x00 /* nothing special */ + +/* + * Commands for Write Register 0 (`Command Register'). + * These are just the command modifiers or'ed with register number 0 + * (which of course equals the command modifier). + */ +#define ZSWR0_RESET_EOM ZSM_RESET_TXUEOM +#define ZSWR0_RESET_TXCRC ZSM_RESET_TXCRC +#define ZSWR0_RESET_RXCRC ZSM_RESET_RXCRC +#define ZSWR0_CLR_INTR ZSM_RESET_IUS +#define ZSWR0_RESET_ERRORS ZSM_RESET_ERR +#define ZSWR0_EI_NEXTRXC ZSM_EI_NEXTRXC +#define ZSWR0_SEND_ABORT ZSM_SEND_ABORT +#define ZSWR0_RESET_STATUS ZSM_RESET_STINT +#define ZSWR0_RESET_TXINT ZSM_RESET_TXINT + +/* + * Bits in Write Register 1 (`Transmit/Receive Interrupt and Data + * Transfer Mode Definition'). Note that bits 3 and 4 are taken together + * as a single unit, and bits 5 and 6 are useful only if bit 7 is set. + */ +#define ZSWR1_REQ_WAIT 0x80 /* WAIT*-REQ* pin gives WAIT* */ +#define ZSWR1_REQ_REQ 0xc0 /* WAIT*-REQ* pin gives REQ* */ +#define ZSWR1_REQ_TX 0x00 /* WAIT*-REQ* pin follows xmit buf */ +#define ZSWR1_REQ_RX 0x20 /* WAIT*-REQ* pin follows recv buf */ + +#define ZSWR1_RIE_NONE 0x00 /* disable rxint entirely */ +#define ZSWR1_RIE_FIRST 0x08 /* rxint on first char & on S.C. */ +#define ZSWR1_RIE 0x10 /* rxint per char & on S.C. */ +#define ZSWR1_RIE_SPECIAL_ONLY 0x18 /* rxint on S.C. only */ + +#define ZSWR1_PE_SC 0x04 /* parity error is special condition */ +#define ZSWR1_TIE 0x02 /* transmit interrupt enable */ +#define ZSWR1_SIE 0x01 /* external/status interrupt enable */ + +/* HSIS compat */ +#define ZSWR1_REQ_ENABLE (ZSWR1_REQ_WAIT | ZSWR1_REQ_TX) + +/* + * Bits in Write Register 3 (`Receive Parameters and Control'). + * Bits 7 and 6 are taken as a unit. Note that the receive bits + * per character ordering is insane. + * + * Here `hardware flow control' means CTS enables the transmitter + * and DCD enables the receiver. The latter is neither interesting + * nor useful, and gets in our way, making it almost unusable. + */ +#define ZSWR3_RX_5 0x00 /* receive 5 bits per char */ +#define ZSWR3_RX_7 0x40 /* receive 7 bits per char */ +#define ZSWR3_RX_6 0x80 /* receive 6 bits per char */ +#define ZSWR3_RX_8 0xc0 /* receive 8 bits per char */ + +#define ZSWR3_HFC 0x20 /* hardware flow control */ +#define ZSWR3_HUNT 0x10 /* enter hunt mode */ +#define ZSWR3_RXCRC_ENABLE 0x08 /* enable recv crc calculation */ +#define ZSWR3_ADDR_SEARCH_MODE 0x04 /* address search mode (SDLC only) */ +#define ZSWR3_SYNC_LOAD_INH 0x02 /* sync character load inhibit */ +#define ZSWR3_RX_ENABLE 0x01 /* receiver enable */ + +/* + * Bits in Write Register 4 (`Transmit/Receive Miscellaneous Parameters + * and Modes'). Bits 7&6, 5&4, and 3&2 are taken as units. + */ +#define ZSWR4_CLK_X1 0x00 /* clock divisor = 1 */ +#define ZSWR4_CLK_X16 0x40 /* clock divisor = 16 */ +#define ZSWR4_CLK_X32 0x80 /* clock divisor = 32 */ +#define ZSWR4_CLK_X64 0xc0 /* clock divisor = 64 */ + +#define ZSWR4_MONOSYNC 0x00 /* 8 bit sync char (sync only) */ +#define ZSWR4_BISYNC 0x10 /* 16 bit sync char (sync only) */ +#define ZSWR4_SDLC 0x20 /* SDLC mode */ +#define ZSWR4_EXTSYNC 0x30 /* external sync mode */ + +#define ZSWR4_SYNCMODE 0x00 /* one of the above sync modes */ +#define ZSWR4_ONESB 0x04 /* 1 stop bit */ +#define ZSWR4_1P5SB 0x08 /* 1.5 stop bits (clk cannot be 1x) */ +#define ZSWR4_TWOSB 0x0c /* 2 stop bits */ + +#define ZSWR4_EVENP 0x02 /* check for even parity */ +#define ZSWR4_PARENB 0x01 /* enable parity checking */ + +/* + * Bits in Write Register 5 (`Transmit Parameter and Controls'). + * Bits 6 and 5 are taken as a unit; the ordering is, as with RX + * bits per char, not sensible. + */ +#define ZSWR5_DTR 0x80 /* assert (set to -12V) DTR */ + +#define ZSWR5_TX_5 0x00 /* transmit 5 or fewer bits */ +#define ZSWR5_TX_7 0x20 /* transmit 7 bits */ +#define ZSWR5_TX_6 0x40 /* transmit 6 bits */ +#define ZSWR5_TX_8 0x60 /* transmit 8 bits */ + +#define ZSWR5_BREAK 0x10 /* send break (continuous 0s) */ +#define ZSWR5_TX_ENABLE 0x08 /* enable transmitter */ +#define ZSWR5_CRC16 0x04 /* use CRC16 (off => use SDLC) */ +#define ZSWR5_RTS 0x02 /* assert RTS */ +#define ZSWR5_TXCRC_ENABLE 0x01 /* enable xmit crc calculation */ + +#ifdef not_done_here +/* + * Bits in Write Register 7 when the chip is in SDLC mode. + */ +#define ZSWR7_SDLCFLAG 0x7e /* this value makes SDLC mode work */ +#endif + +/* + * Bits in Write Register 9 (`Master Interrupt Control'). Bits 7 & 6 + * are taken as a unit and indicate the type of reset; 00 means no reset + * (and is not defined here). + */ +#define ZSWR9_HARD_RESET 0xc0 /* force hardware reset */ +#define ZSWR9_A_RESET 0x80 /* reset channel A (0) */ +#define ZSWR9_B_RESET 0x40 /* reset channel B (1) */ + /* 0x20 unused */ + +#define ZSWR9_STATUS_HIGH 0x10 /* status in high bits of intr vec */ +#define ZSWR9_MASTER_IE 0x08 /* master interrupt enable */ +#define ZSWR9_DLC 0x04 /* disable lower chain */ +#define ZSWR9_NO_VECTOR 0x02 /* no vector */ +#define ZSWR9_VECTOR_INCL_STAT 0x01 /* vector includes status */ + +/* + * Bits in Write Register 10 (`Miscellaneous Transmitter/Receiver Control + * Bits'). Bits 6 & 5 are taken as a unit, and some of the bits are + * meaningful only in certain modes. Bleah. + */ +#define ZSWR10_PRESET_ONES 0x80 /* preset CRC to all 1 (else all 0) */ + +#define ZSWR10_NRZ 0x00 /* NRZ encoding */ +#define ZSWR10_NRZI 0x20 /* NRZI encoding */ +#define ZSWR10_FM1 0x40 /* FM1 encoding */ +#define ZSWR10_FM0 0x60 /* FM0 encoding */ + +#define ZSWR10_GA_ON_POLL 0x10 /* go active on poll (loop mode) */ +#define ZSWR10_MARK_IDLE 0x08 /* all 1s (vs flag) when idle (SDLC) */ +#define ZSWR10_ABORT_ON_UNDERRUN 0x4 /* abort on xmit underrun (SDLC) */ +#define ZSWR10_LOOP_MODE 0x02 /* loop mode (SDLC) */ +#define ZSWR10_6_BIT_SYNC 0x01 /* 6 bits per sync char (sync modes) */ + +/* + * Bits in Write Register 11 (`Clock Mode Control'). Bits 6&5, 4&3, and + * 1&0 are taken as units. Various bits depend on other bits in complex + * ways; see the Zilog manual. + */ +#define ZSWR11_XTAL 0x80 /* have xtal between RTxC* and SYNC* */ + /* (else have TTL oscil. on RTxC*) */ +#define ZSWR11_RXCLK_RTXC 0x00 /* recv clock taken from TRxC* pin */ +#define ZSWR11_RXCLK_TRXC 0x20 /* recv clock taken from TRxC* pin */ +#define ZSWR11_RXCLK_BAUD 0x40 /* recv clock taken from BRG */ +#define ZSWR11_RXCLK_DPLL 0x60 /* recv clock taken from DPLL */ + +#define ZSWR11_TXCLK_RTXC 0x00 /* xmit clock taken from TRxC* pin */ +#define ZSWR11_TXCLK_TRXC 0x08 /* xmit clock taken from RTxC* pin */ +#define ZSWR11_TXCLK_BAUD 0x10 /* xmit clock taken from BRG */ +#define ZSWR11_TXCLK_DPLL 0x18 /* xmit clock taken from DPLL */ + +#define ZSWR11_TRXC_OUT_ENA 0x04 /* TRxC* pin will be an output */ + /* (unless it is being used above) */ +#define ZSWR11_TRXC_XTAL 0x00 /* TRxC output from xtal oscillator */ +#define ZSWR11_TRXC_XMIT 0x01 /* TRxC output from xmit clock */ +#define ZSWR11_TRXC_BAUD 0x02 /* TRxC output from BRG */ +#define ZSWR11_TRXC_DPLL 0x03 /* TRxC output from DPLL */ + +/* + * Formula for Write Registers 12 and 13 (`Lower Byte of Baud Rate + * Generator Time Constant' and `Upper Byte of ...'). Inputs: + * + * f BRG input clock frequency (in Hz) AFTER division + * by 1, 16, 32, or 64 (per clock divisor in WR4) + * bps desired rate in bits per second (9600, etc) + * + * We want + * + * f + * ----- + 0.5 - 2 + * 2 bps + * + * rounded down to an integer. This can be computed entirely + * in integer arithemtic as: + * + * f + bps + * ------- - 2 + * 2 bps + */ +#define BPS_TO_TCONST(f, bps) ((((f) + (bps)) / (2 * (bps))) - 2) + +/* inverse of above: given a BRG Time Constant, return Bits Per Second */ +#define TCONST_TO_BPS(f, tc) ((f) / 2 / ((tc) + 2)) + +/* + * Bits in Write Register 14 (`Miscellaneous Control Bits'). + * Bits 7 through 5 are taken as a unit and make up a `DPLL command'. + */ +#define ZSWR14_DPLL_NOOP 0x00 /* leave DPLL alone */ +#define ZSWR14_DPLL_SEARCH 0x20 /* enter search mode */ +#define ZSWR14_DPLL_RESET_CM 0x40 /* reset `clock missing' in RR10 */ +#define ZSWR14_DPLL_DISABLE 0x60 /* disable DPLL (continuous search) */ +#define ZSWR14_DPLL_SRC_BAUD 0x80 /* set DPLL src = BRG */ +#define ZSWR14_DPLL_SRC_RTXC 0xa0 /* set DPLL src = RTxC* or xtal osc */ +#define ZSWR14_DPLL_FM 0xc0 /* operate in FM mode */ +#define ZSWR14_DPLL_NRZI 0xe0 /* operate in NRZI mode */ + +#define ZSWR14_LOCAL_LOOPBACK 0x10 /* set local loopback mode */ +#define ZSWR14_AUTO_ECHO 0x08 /* set auto echo mode */ +#define ZSWR14_DTR_REQ 0x04 /* DTR* / REQ* pin gives REQ* */ +#define ZSWR14_BAUD_FROM_PCLK 0x02 /* BRG clock taken from PCLK */ + /* (else from RTxC* pin or xtal osc) */ +#define ZSWR14_BAUD_ENA 0x01 /* enable BRG countdown */ + +/* + * Bits in Write Register 15 (`External/Status Interrupt Control'). + * Most of these cause status interrupts whenever the corresponding + * bit or pin changes state (i.e., any rising or falling edge). + */ +#define ZSWR15_BREAK_IE 0x80 /* enable break/abort status int */ +#define ZSWR15_TXUEOM_IE 0x40 /* enable TX underrun/EOM status int */ +#define ZSWR15_CTS_IE 0x20 /* enable CTS* pin status int */ +#define ZSWR15_SYNCHUNT_IE 0x10 /* enable SYNC* pin/hunt status int */ +#define ZSWR15_DCD_IE 0x08 /* enable DCD* pin status int */ + /* 0x04 unused, must be zero */ +#define ZSWR15_ZERO_COUNT_IE 0x02 /* enable BRG-counter = 0 status int */ + /* 0x01 unused, must be zero */ + +/* + * Bits in Read Register 0 (`Transmit/Receive Buffer Status and External + * Status'). + */ +#define ZSRR0_BREAK 0x80 /* break/abort detected */ +#define ZSRR0_TXUNDER 0x40 /* transmit underrun/EOM (sync) */ +#define ZSRR0_CTS 0x20 /* clear to send */ +#define ZSRR0_SYNC_HUNT 0x10 /* sync/hunt (sync mode) */ +#define ZSRR0_DCD 0x08 /* data carrier detect */ +#define ZSRR0_TX_READY 0x04 /* transmit buffer empty */ +#define ZSRR0_ZERO_COUNT 0x02 /* zero count in baud clock */ +#define ZSRR0_RX_READY 0x01 /* received character ready */ + +/* + * Bits in Read Register 1 (the Zilog book does not name this one). + */ +#define ZSRR1_EOF 0x80 /* end of frame (SDLC mode) */ +#define ZSRR1_FE 0x40 /* CRC/framing error */ +#define ZSRR1_DO 0x20 /* data (receiver) overrun */ +#define ZSRR1_PE 0x10 /* parity error */ +#define ZSRR1_RC0 0x08 /* residue code 0 (SDLC mode) */ +#define ZSRR1_RC1 0x04 /* residue code 1 (SDLC mode) */ +#define ZSRR1_RC2 0x02 /* residue code 2 (SDLC mode) */ +#define ZSRR1_ALL_SENT 0x01 /* all chars out of xmitter (async) */ + +/* + * Read Register 2 in B channel contains status bits if VECTOR_INCL_STAT + * is set. + */ + +/* + * Bits in Read Register 3 (`Interrupt Pending'). Only channel A + * has an RR3. + */ + /* 0x80 unused, returned as 0 */ + /* 0x40 unused, returned as 0 */ +#define ZSRR3_IP_A_RX 0x20 /* channel A recv int pending */ +#define ZSRR3_IP_A_TX 0x10 /* channel A xmit int pending */ +#define ZSRR3_IP_A_STAT 0x08 /* channel A status int pending */ +#define ZSRR3_IP_B_RX 0x04 /* channel B recv int pending */ +#define ZSRR3_IP_B_TX 0x02 /* channel B xmit int pending */ +#define ZSRR3_IP_B_STAT 0x01 /* channel B status int pending */ + +/* + * Bits in Read Register 10 (`contains some miscellaneous status bits'). + */ +#define ZSRR10_1_CLOCK_MISSING 0x80 /* 1 clock edge missing (FM mode) */ +#define ZSRR10_2_CLOCKS_MISSING 0x40 /* 2 clock edges missing (FM mode) */ + /* 0x20 unused */ +#define ZSRR10_LOOP_SENDING 0x10 /* xmitter controls loop (SDLC loop) */ + /* 0x08 unused */ + /* 0x04 unused */ +#define ZSRR10_ON_LOOP 0x02 /* SCC is on loop (SDLC/X.21 modes) */ + +/* + * Bits in Read Register 15. This register is one of the few that + * simply reads back the corresponding Write Register. + */ +#define ZSRR15_BREAK_IE 0x80 /* break/abort status int enable */ +#define ZSRR15_TXUEOM_IE 0x40 /* TX underrun/EOM status int enable */ +#define ZSRR15_CTS_IE 0x20 /* CTS* pin status int enable */ +#define ZSRR15_SYNCHUNT_IE 0x10 /* SYNC* pin/hunt status int enable */ +#define ZSRR15_DCD_IE 0x08 /* DCD* pin status int enable */ + /* 0x04 unused, returned as zero */ +#define ZSRR15_ZERO_COUNT_IE 0x02 /* BRG-counter = 0 status int enable */ + /* 0x01 unused, returned as zero */ |