🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.sys.ibm.pc.rt
1 messages
1 total messages Started by Mark S. Lewis Thu, 17 Aug 1989 00:28
IBM/4.3 6152 Ethernet driver
#266
Author: Mark S. Lewis
Date: Thu, 17 Aug 1989 00:28
1351 lines
38084 bytes
Subject:  IBM/4.3 6152 Ethernet driver (V1.12)
Index:    sys/ca_atr/if_un.c

Description: 
          Included is a new 6152 ethernet driver for the
          Ungermann-Bass adapter.  It replaces the
          file sys/ca_atr/if_un.c.

          It fixes several problems related to the
          DEC 88 release of the ethernet driver.

Fix:      
          Copy sys/ca_atr/if_un.c to sys/ca_atr/if_un.c.orig.
          Copy this file less the header over
          sys/ca_atr/if_un.c and build an ATR kernel.  

          In your AUTOEXEC.BAT (or your unix start-up) file,
          you can comment out (REM) the call to NICPSHH.

          Also, you must have "IRQ +3" on your DOS
          call to UNIX.EXE.  This makes sure all ethernet
          interrupts are passed to the kernel.

          Reboot the new kernel with the modified
          start-up file.

----------------------- cut here ----------------------------------

/*
 * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1987
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header: if_un.c,v 12.3 89/08/14 16:41:21 mlewis Exp $ */

#ifndef lint
static char    *rcsid = "$Header: if_un.c,v 12.3 89/08/14 16:41:21 mlewis Exp $";
#endif lint


/*
 * this driver supports the NICPS2 adapter from Ungermann Bass
 * which is based on the Intel 82586 chip. See the Intel Microcomunications
 * handbook for hardware details.
 */


#define inb(port) IN(port)
#define outb(port,value) OUT(port,value)
#define swaph(value) ((((value)>>8)&0xff)|(((value)&0xff)<<8))
#define UNIRQ 3

#include	"un.h"
#include "../machine/pte.h"

#include "param.h"
#include "systm.h"
#include "mbuf.h"
#include "buf.h"
#include "protosw.h"
#include "socket.h"
#include "vmmac.h"
#include "ioctl.h"
#include "errno.h"

#include "../net/if.h"
#include "../net/netisr.h"
#include "../net/route.h"

#ifdef INET
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/in_var.h"
#include "../netinet/ip.h"
#include "../netinet/if_ether.h"
#endif INET

#ifdef NS
#include "../netns/ns.h"
#include "../netns/ns_if.h"
#endif NS

#include "../machine/io.h"
#include "../machineio/ioccvar.h"
#include "time.h"
#include "kernel.h"
#include "../machine/debug.h"
#include "../ca_atr/pcif.h"


#define ETH_ADDR_SIZE	6

#define		UNCARDID	0xEFF5		/* POS register ID */
/* bits in the CSR registers */
#define		INTPNDG		0x80
#define		CHINTENB	0x08
#define		TMINTENB	0x04
#define		LOOPBACK	0x02
#define		RESET		0x01


/* Bits in the Transmit Control Blocks */
#define 	BBIT		0x4000		/* Busy executing command */
#define		DONEBIT		0x8000		/* command completed */
#define		OKBIT		0x2000		/* error-free completion */
#define		ABORTED		0x1000		/* command aborted */
#define		NOCARRIER	0x0400		/* no carrier sense */
#define		XMIT_BAD	0x0200		/* transmit failed */
#define		XMIT_BAD_DMA	0x0100		/* transmit failed (DMA) */
#define		XMIT_DEFER	0x0080		/* transmit failed (traffic) */
#define		XMIT_HEART	0x0040		/* transmit failed (heartbeat) */
#define		XMIT_MAX_COL_16	0x0020		/* more than 16 collisions */
#define		XMIT_NCOL(status) ((((status)&XMIT_MAX_COL_16)>>1)|((status)&0xf))	/* number of colisions */

/* Bits in the System Control Block */
#define		CX		0x8000		/* the CU finished a command */
#define		FR		0x4000		/* the RU got a frame */
#define		CNA		0x2000		/* the CU left the ACT state */
#define		RNR		0x1000		/* the RU left the RDY state */
#define		NO_RESOURCES	0x0020		/* we got an illegal packet */
/* command bits. */
#define		CUCSTART	0x100
#define		RUCSTART	0x10
#define		RUCRESUME	0x20

/* Bits in the Receive Buffer Descriptor (rbd) */
#define ACT_MASK	0x3fff	/* received count */
#define	EOFBIT		0x8000	/* End of a Frame */

/* Bits in the Frame descriptor command */
#define	FDSUSPEND	0x4000	/* Tell receive unit to suspend */
#define	FDEOL		0x8000

 /* States of Chip */
#define		CRESET		0x0001		/* we just reset the chip */
#define		CREADY		0x0002		/* turned on rcvr */
#define		CBROKEN		0x8000		/* something's screwed */

#define		FREE	0
#define		BUSY	1

#define		RBUFFS	15	/* number of rcvr buffers */

#if NUN > 0

/*
 * Ethernet software status.
 */

struct	un_softc {
	struct	arpcom es_ac;		/* common Ethernet structures */
#define es_if	es_ac.ac_if		/* network-visable interfaces */
#define es_addr	es_ac.ac_enaddr	/* hardware ethernet addresses */
	long	if_buf0;		/* number of uses of buf0 */
	long	if_buf1;		/* number of uses of buf0 */
	long	if_nobuf;		/* number of times no buffer */
	unsigned short	state;		/* state of card */
	unsigned short tbuffstate[2];	/* transmit buffer state */
	unsigned short	rec_nm_buf;		/* next receive buffer to fill */
	unsigned short	csr;			/* port address */
	short		us_owatch;	/* output watch timer */
	short		us_iwatch;	/* input watch timer */
	short		us_watch;	/* watchdog running */
	unsigned int rom_addr;		/* address of ROM */
	unsigned int ram_addr;		/* RAM address */
	unsigned int ram_seg;		/* RAM segment */
	struct	scb *scbptr;		/* pointer to our scb */
	struct	buff *tbufptr[2];	/* transmit buffer pointer */
	struct	buff *rbufptr[RBUFFS];	/* recieve buffer pointers */
	struct	fd *fdptr[RBUFFS];	/* data pointer */
	struct	tcb *tcbptr[2];
	struct	rbd *rbdptr[RBUFFS];
	struct	tbd *tbdptr[2];
	int	fill[2];		/* align it conveniently */
} un_softc[NUN];

int un_size = sizeof (struct un_softc);
/* patch un_last to large number to disable claiming of stray interrupts */
int un_last = -1;

#ifndef UBIWATCH
#define UBIWATCH	0
#endif

#ifndef UBOWATCH
#define UBOWATCH	30
#endif

int uniwatch = UBIWATCH;			/* no input watchdog */
int unowatch = UBOWATCH;			/* 30 second output watchdog */

typedef int spl_t;

struct iroot {
	unsigned short sysbus;
	unsigned short not_used1;
	unsigned short not_used2;
	unsigned short iscp_low;
	unsigned short iscp_high;
};

struct iscp {
	unsigned short busy;
	unsigned short scb_offset;
	unsigned short scb_base_low;
	unsigned short scb_base_high;
};

struct scb {
	unsigned short status;
	unsigned short command;
	unsigned short cbl_offset;
	unsigned short rfa_offset;
	unsigned short crcerrs;
	unsigned short alnerrs;
	unsigned short rscerrs;
	unsigned short ovrnerrs;
};

struct setup {
	unsigned short status;
	unsigned short command;
	unsigned short link_offset;
	unsigned short addr0;
	unsigned short addr1;
	unsigned short addr2;
};

struct tcb {
	unsigned short status;
	unsigned short command;
	unsigned short link_offset;
	unsigned short tbd_offset;
	unsigned char dest[6];
	unsigned short type;
};

struct romaddr {
	unsigned short bytea;
	unsigned short byteb;
	unsigned short bytec;
	unsigned short byted;
	unsigned short bytee;
	unsigned short bytef;
};

/*
 * see Page 1-10 figure 8 for overall structure of RFD's, FD's, RBD's
 * and DB's.
 *
 */



/* recieve frame descriptor (fd) */
struct fd {
	unsigned short status;
	unsigned short command;
	unsigned short link_offset;
	unsigned short rbd_offset;
	unsigned short dest_addr[3];
	unsigned short source_addr[3];
	unsigned short type;			/* also known as "length" */
};

/* receive buffer descriptor (see page 1-10) */
struct rbd {
	unsigned short status;			/* recieve frame status */
	unsigned short nxt_rbd_offset;		/* link field */
	unsigned short buff_addr_l;		/* buffer address */
	unsigned short buff_addr_h;		/*   "	    "     */
	unsigned short size;			/* size buffer can hold */
};

/* transmist buffer (frame) descriptor */
struct tbd {
	unsigned short status;		/* eof & act count */
	unsigned short nxt_tbd_offset;
	unsigned short buff_addr_l;
	unsigned short buff_addr_h;
};

struct buff {
	struct ether_header hdr;
	char data[1518];
};


int unintr();
#ifdef DEBUG
#define ncprintf if (undebug) printf
#else
#define ncprintf if (0) printf
#endif

int 
unprobe(), unattach();

extern int pcif_512_fw;
#define PTOKV(addr) (set_512_window(addr) + pcif_512_fw);

caddr_t         unstd[] = {(caddr_t) 0x00001550, (caddr_t) 0x00001554,
			   (caddr_t) 0x00001558, (caddr_t) 0x0000155c, 0};

struct iocc_device *uninfo[NUN];

int 
uninit(), unioctl(), unoutput(), unreset(), unwatch();
int unsuspend();

struct iocc_driver undriver =
{unprobe, 0, unattach, 0, unstd, "un", uninfo,
 /*     int   csr chanrel flags 		suspend */
 0, 0, unintr, 0,    0,    DRIVER_SUSPEND,   unsuspend }; 


#define Offset(off)	((us->ram_addr + off) & 0x0ffff)

int undebug = 0;	/* debugging flags */
int unnoint = 0;	/* don't attempt to cause interrupt */
int noun = 0;		/* don't use un */

#define UB_GSFTINT      0x20    /* Generate software interrupt */

#define MAX_PACKET	1518	/* MAX PACKET SIZE */
#define DATA_OFFSET	0x800	/* where to start data buffers */


/*
 *  unprobe - This adapter can only be at interrupt 3
 */
unprobe(p)
	register caddr_t p;
{
	printf("unprobe called: port=%x\n", p);
	if (noun)
		return(PROBE_BAD);
	if (unnoint)
		return(PROBE_NOINT);	/* didn't attempt hardware int */
	outb(p,UB_GSFTINT);
	PROBE_DELAY(200000);
	outb(p, 0);
	outb(p+1,0xFF);			/* CA */
	return (PROBE_OK);		/* attempted hardware interrupt */
}

int un_output(), un_ioctl();

/*
 *  unattach - make the interface available to the network software
 *  (if the auto-configuration software determines that the interface
 *  exists).  The system will initialize the interface when it is
 *  ready to accept packets.
 */
unattach(iod)
	register struct iocc_device *iod;
{
	int unit = iod->iod_unit;
	register struct un_softc *us = &un_softc[unit];
	register struct ifnet *ifp = &us->es_if;
	int	old_window = get_512_window();
	char	*p = (char *) iod->iod_addr;
	int	x = inb(p+1);
	int	y = inb(p+3);
	int	ram = ((x << 8) | ((y & 0x3) << 6)) << 8;
	int	rom;

	if (unit > un_last)
		un_last = unit;		/* remember last unit */
	us->csr = (short) iod->iod_addr;
	p = (char *) set_512_window(ram) + pcif_512_fw;
	rom = p[0x29] << 12;		/* get the rom addr */
	printf("unattach called: port=%x ca=%x pos5=%x ram=%x rom=%x\n", us->csr, x, y,
		ram,rom);
	if (rom >= 0xc0000 && rom < 0xdffff)
		us->rom_addr = rom;		/* use it if it looks valid */
	else
		printf("unattach: couldn't find rom address\n");
	us->ram_addr = ram;
	us->ram_seg = us->ram_addr >> 16;	/* high order bits */
	ifp->if_unit = unit;
	ifp->if_name = "un";		/* use "un0" etc */
	ifp->if_mtu = ETHERMTU;

	set_512_window(old_window);
	ifp->if_init = uninit;
	ifp->if_ioctl = un_ioctl;
	ifp->if_output = un_output;
	ifp->if_reset = unreset;
	ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS;
	if_attach(ifp);
	DEBUGF(undebug, printf("un%d: attached\n", unit));
}


unsuspend(iod, idr, how)
	register struct iocc_device *iod;
	struct iocc_driver *idr;
{
	int unit = iod->iod_unit;
	register struct un_softc *us = &un_softc[unit];
	register struct ifnet *ifp = &us->es_if;

	if (how == SUSPEND_START) {
		if (ifp->if_flags & IFF_RUNNING) {
			unzap(unit);
			ifp->if_flags |= IFF_RUNNING;	/* remember we were running */
		}
	} else if (how == SUSPEND_DONE) {
		if (ifp->if_flags & IFF_RUNNING) {
			ifp->if_flags &= ~IFF_RUNNING;	/* pretend not running */
			uninit(unit);
		}
	}
}

uninit(iv)
int iv;
{
	spl_t ospl;
	int i; 
	int ii;
	int	old_window = get_512_window();
	struct un_softc *us = &un_softc[iv];
	struct ifnet *ifp = &us->es_if;
	struct iroot *initptr;
	struct iscp *iscpptr;
	struct romaddr *romaddrptr;
	struct setup *setupptr;

	if (ifp->if_addrlist == (struct ifaddr *) 0) {
		/* no address */
		return;
	}
	if (ifp->if_flags & IFF_RUNNING)
		return;		/* already running! */

	DEBUGF(undebug, printf("un%d: uninit ram=%x rom=%x\n", iv,us->ram_addr,us->rom_addr));
	ifp->if_flags |= IFF_RUNNING;

	/* 							 */
	/* System		D7FDE	STATUS			 */
	/* Control		D7FE0	COMMAND			 */
	/* Block		D7FE2	CBL OFFSET		 */
	/* 			D7FE4	RFA OFFSET		 */
	/* 			D7FE6	CRCERRS			 */
	/* 			D7FE8	ALNERRS			 */
	/* 			D7FEA	RSCERRS			 */
	/* 			D7FEC	OVRNERRS		 */
	/* 							 */
	/* Intermediate		D7FEE	BUSY = 1 (reset)	 */
	/* System		D7FF0	SCB OFFSET = 0x7FDE	 */
	/* Configuration	D7FF2	SCB BASE (lo) = 0x0000	 */
	/* Pointer		D7FF4	SCB BASE (hi) = 0x000D 	 */
	/* 							 */
	/* Initialization	D7FF6	SYSBUS = 0 (16 bit bus)	 */
	/* Root			D7FF8	not used		 */
	/* 			D7FFA	not used		 */
	/* 			D7FFC	ISCP ADDR (lo) = 0x7FEE	 */
	/* 			D7FFE	ISCP ADDR (hi) = 0x000D	 */
	/* 							 */
	set_pcvec_map(UNIRQ, 0);	/* disable int forwarding */
	initptr = (struct iroot *) PTOKV(us->ram_addr + 0x7FF6);
	initptr->sysbus = swaph(0);		/* 16 bit bus */
	initptr->not_used1 = swaph(0);
	initptr->not_used2 = swaph(0);
	initptr->iscp_low = swaph(Offset(0x7FEE));
	initptr->iscp_high = swaph(us->ram_seg);
	iscpptr = (struct iscp *) PTOKV(us->ram_addr + 0x7FEE);
	iscpptr->busy = swaph(0x01);		/* init in progress */
	iscpptr->scb_offset = swaph(Offset(0x7FDE));
	iscpptr->scb_base_low = swaph(Offset(0x0));
	iscpptr->scb_base_high = swaph(us->ram_seg);
	us->scbptr = (struct scb *) PTOKV(us->ram_addr + 0x7FDE);
	us->scbptr->status = 0;
	us->scbptr->command = 0;
	us->scbptr->cbl_offset = 0;
	us->scbptr->rfa_offset = 0;
	us->scbptr->crcerrs = 0;
	us->scbptr->alnerrs = 0;
	us->scbptr->rscerrs = 0;
	us->scbptr->ovrnerrs = 0;
	outb(us->csr,(CHINTENB | RESET));
	DELAY(10);
	outb(us->csr, CHINTENB);
	outb(us->csr+1,0xFF);			/* CA */
	while (!(inb(us->csr) & INTPNDG));
	DEBUGF(undebug, printf("un%d: uninit reset done\n", iv));
	us->state = CRESET;
	us->rec_nm_buf = 0;			/* which rcvr buffer we use */
	romaddrptr = (struct romaddr *) PTOKV(us->rom_addr + 0x10);
	setupptr = (struct setup *) PTOKV(us->ram_addr + 0x7FD2);
	setupptr->status = 0;
	setupptr->command = swaph(0x8001);    /* EL + SETUP */
	setupptr->link_offset = 0;
	setupptr->addr0 = ((romaddrptr->byteb) >> 8) | romaddrptr->bytea;
	setupptr->addr1 = ((romaddrptr->byted) >> 8) | romaddrptr->bytec;
	setupptr->addr2 = ((romaddrptr->bytef) >> 8) | romaddrptr->bytee;

#define LAN_ADDR_SIZE ETH_ADDR_SIZE
	bcopy((char *) &setupptr->addr0, us->es_addr, LAN_ADDR_SIZE);

	printf("un%d: ethernet address ", iv);
	unprintethaddr(us->es_addr);
	printf("\n");

	ospl = splimp();
	while (us->scbptr->command != 0);
	us->scbptr->command = swaph(CUCSTART);
	us->scbptr->cbl_offset = swaph(Offset(0x7FD2));
	outb(us->csr+1,0xFF);			/* CA */
	splx(ospl);
	DEBUGF(undebug, printf("un%d: uninit cucstart done\n", iv));
	for (i=0; !(setupptr->status & swaph(OKBIT));++i)
		if (i > 1000) {
			printf("un%d: timed out waiting for OKBIT\n",iv);
			break;
		} else
			delay(1);
	/* build fd's backwards from offset 7FBC */
	us->fdptr[0] = (struct fd *) PTOKV(us->ram_addr + 0x7FBC);
	for (i = 1; i < RBUFFS; i++)
		us->fdptr[i] = us->fdptr[i-1] - 1;
	/* allocate rbd's just before fd's */
	us->rbdptr[0] = ((struct rbd *) us->fdptr[RBUFFS-1]) - 1;
	for (i = 1; i < RBUFFS; i++)
		us->rbdptr[i] = us->rbdptr[i-1] - 1;
	/* allocate tcb's before rbd's */
	us->tcbptr[0] = ((struct tcb *) us->rbdptr[RBUFFS-1]) - 1;
	us->tcbptr[1] = us->tcbptr[0] - 1;
	/* allocate tbd's before tcb's */
	us->tbdptr[0] = ((struct tbd *) us->tcbptr[1]) - 1;
	us->tbdptr[1] = us->tbdptr[0] - 1;
	/* point scb's rfa_offset to first fd */
	us->scbptr->rfa_offset = swaph((unsigned short) us->fdptr[0]);
	/* chain the fd's together via the link_offset */
	for (i=0 ; i < RBUFFS; i++)
		us->fdptr[i]->link_offset = swaph((ushort) us->fdptr[((i+1)%RBUFFS)]);
	/* initialize the fd's to point to the appropriate rbd's */
	for (i = 0; i < RBUFFS; i++) {
		us->fdptr[i]->rbd_offset = swaph((ushort) us->rbdptr[i]);
		us->fdptr[i]->status = 0;
		us->fdptr[i]->command = 0;
		us->fdptr[i]->type = 0;
		for (ii = 0; ii < 3; ii++) {
			us->fdptr[i]->dest_addr[ii] = 0;
			us->fdptr[i]->source_addr[ii] = 0;
		}
	}
	/* suspend if we use the last fd */
	us->fdptr[RBUFFS-1]->command |= swaph(FDSUSPEND);	/* Overrun protection */
	/* initialize the first data buffer pointer to start of ram */
	us->rbufptr[0] = (struct buff *) PTOKV(us->ram_addr+DATA_OFFSET);
	/* initialize the rest of the data buffer pointers */
	for( i = 1; i < RBUFFS; i++)
		us->rbufptr[i] = us->rbufptr[i-1] + 1;
	for (i = 0; i < RBUFFS; i++) {
		us->rbdptr[i]->buff_addr_l = swaph((ushort) &(us->rbufptr[i]->data[0]));
		us->rbdptr[i]->buff_addr_h = swaph(us->ram_seg);
		us->rbdptr[i]->status = 0;
		us->rbdptr[i]->nxt_rbd_offset = 0;
		us->rbdptr[i]->size = swaph(0x85EE);   /* 1518(0x5ee)+last RBD(0x8000)*/
	}
	/* transmit buffers follows receive buffers */
	us->tbufptr[0] = us->rbufptr[RBUFFS-1] + 1;
	us->tbufptr[1] = us->tbufptr[0] + 1;
	DEBUGF(undebug, printf("un%d: free buffer space=%d\n", iv,
		(caddr_t) (us->tbdptr[1] - 1) - (caddr_t) (us->tbufptr[1]+1)));
	us->tbuffstate[0] = FREE;	/* mark xmit buffers as free */
	us->tbuffstate[1] = FREE;
	us->tcbptr[0]->status = 0;
	us->tcbptr[1]->status = 0;

	DEBUGF(undebug, printf("un%d: uninit calling ostart\n", iv));
	/* Attach this device to the outside world! */

	un_ostart(&us->es_if);

	if (!us->us_watch) {
		timeout(unwatch, (caddr_t) iv, hz);
		us->us_watch++;		/* timer running */
	}

done:
	set_pcvec_map(UNIRQ, 1);	/* enable int forwarding */
	set_512_window(old_window);
	DEBUGF(undebug, printf("un%d: uninit done\n", iv));
}

/*
 * note: since this adapter appears to cause stray interrupts that it
 * later disclaims, we use un_last to determine if we are the last un adapter
 * and always claims interrupts in this case.  This does not work if there is
 * anything else at this interrupt level, so the un addapter must be configured
 * so that it ends up last on the chain.
 */

unintr(iv)
int iv;		/* board we are going to service */
{
	unsigned short build_comm;
	int	old_window = get_512_window();
	struct un_softc *us = &un_softc[iv];
	struct scb *scb = us->scbptr;	/* get scb pointer */
	register struct ifnet *ifp = &us->es_if;

	if (! (inb(us->csr) & INTPNDG)) {
		DEBUGF(undebug&SHOW_INTR, printf("un%d: unintr - no int\n",iv));
		return(iv != un_last);		/* 1 = not our interrupt */
	}

	(void) set_512_window(us->ram_addr);	/* set to proper 512k window */
	DEBUGF(undebug&SHOW_INTR, printf("un%d: unintr\n",iv));
	build_comm = 0;
	if (us->state & CRESET) {
		ncprintf("unintr: CRESET was set (starting receiver)\n");
		ncprintf("unintr: CRESET board %d\n",iv);
		us->state = CREADY;
		while (scb->command != 0)
			;
		scb->command = swaph(CX | CNA | RUCSTART);	/* start rcvr */
		outb(us->csr+1, 0xff);		/* CA */
		while (scb->command != 0)
			;
		goto out;
	}

	if (scb->status & swaph(FR)) {     /* rcvd a frame */
		build_comm |= FR;
		unrint(iv);
	}
	if (scb->status & swaph(CX)) {     /* xmitted a frame */
		us->us_owatch = 0;	/* set watchdog timer */
		build_comm |= CX;
		if ((us->tbuffstate[0] == BUSY) && (us->tcbptr[0]->status & swaph(DONEBIT))) {
			int status = swaph(us->tcbptr[0]->status);
			us->tbuffstate[0] = FREE;
			ifp->if_collisions += XMIT_NCOL(status);
			if (status&OKBIT)
				ifp->if_opackets++;
			else
				ifp->if_oerrors++;
			us->tcbptr[0]->status = 0;
		}
		if ((us->tbuffstate[1] == BUSY) && (us->tcbptr[1]->status & swaph(DONEBIT))) {
			int status = swaph(us->tcbptr[1]->status);
			ifp->if_collisions += XMIT_NCOL(status);
			if (status&OKBIT)
				ifp->if_opackets++;
			else
				ifp->if_oerrors++;
			us->tbuffstate[1] = FREE;
			us->tcbptr[1]->status = 0;
		}
	}
	if (scb->status & swaph(CNA)) {
		build_comm |= CNA;
	}
	if (scb->status & swaph(NO_RESOURCES)) {
	       build_comm |= (RUCSTART|RNR);
	       scb->rfa_offset=swaph((unsigned short)us->fdptr[us->rec_nm_buf]);
	       ncprintf("unintr: restart after non-802.3 packet\n");
	}
	if ((scb->status & swaph(RNR)) && 
			(!(scb->status & swaph(NO_RESOURCES)))) {
		/* The receive unit ran out of frames... restart it, since
		 * unrint must have read in all the packets.
		 */
		ncprintf("unintr: restarting receiver (ran out of bufs)\n");
		build_comm |= (RUCRESUME|RNR);	/* resume receiving */
	}
	while (scb->command != 0)
		;
	scb->command = swaph(build_comm);
	outb(us->csr+1,0xFF);		/* CA */
	if (build_comm & CX)
		un_ostart(&us->es_if);
out:
	DEBUGF(undebug&SHOW_INTR, printf("un%d: unintr done crc=%d ovrn=%d aln=%d rsc=%d\n",iv,swaph(scb->crcerrs),swaph(scb->ovrnerrs),swaph(scb->alnerrs),swaph(scb->rscerrs)));
	if (scb->crcerrs || scb->alnerrs)
	{	/* got some input errors - count them */
		ifp->if_ierrors += swaph(scb->crcerrs) + swaph(scb->alnerrs);
		scb->crcerrs = 0;
		scb->alnerrs = 0;
	}
	set_512_window(old_window);
	return(0);
}


/*
 * Pegasus receive interrupt.
 */
unrint(iv)
int iv;		/* which board */
{
	spl_t s;
	int stat;
	int len, len_or_type;
	int prev_nm_buf;
	register struct ether_header *ehp;
	struct un_softc *us = &un_softc[iv];

	us->us_iwatch = uniwatch;		/* got an interrupt */
	DEBUGF(undebug&SHOW_INTR, printf("un%d: unrint\n",iv));
	for (; len = (us->rbdptr[us->rec_nm_buf]->status);
				us->rec_nm_buf=(us->rec_nm_buf+1)%RBUFFS) {
		len = swaph(len);		/* byte swap len */
		stat = (us->fdptr[us->rec_nm_buf]->status);
		stat = swaph(stat);	/* swap it */
		if (!(stat & DONEBIT)) {
			ncprintf("unrint: stat %x, not complete\n", stat);
			break;
		}
		/* NEEDSWORK: receiver should be shut down */
		if (! (us->es_if.if_flags & IFF_UP))
			goto discard;
		if (!(stat & (OKBIT|BBIT))) {
			/* Discard bad (not "ok") frames. */
			ncprintf("unintr: got not OK packet %x\n", stat);
			goto discard;
		}
		/*
		 * copy in the header to prefix the packet data to
		 * make access simple.
		 */
		bcopy(&(us->fdptr[us->rec_nm_buf]->dest_addr[0]),
			us->rbufptr[us->rec_nm_buf], sizeof(*ehp));
		/* clear flag bits in "len": its now length of data portion */
		len &= ACT_MASK;

		/*
		 * At this point we have the frame and the header
		 * If we want the whole frame we use rbufptr[x]
		 * If we want just the data rbufptr[x]->data[0]
		 * the packet type is in fdptr[x]->type
		 * as well as being in the header
		 * the size of the frame is in rbdptr[x]->status
		 * where x = rec_nm_buf
		 */

		/*
		 * Process the packet
		 */
		s = splimp();
		ehp = (struct ether_header *) us->rbufptr[us->rec_nm_buf];
		DEBUGF(undebug&SHOW_DATA, unprintpacket("unrint: ",ehp,"\n"));
#define eth_type ether_type
		len_or_type = ntohs(* (u_short *) &ehp->eth_type);
		if (len_or_type > ETHERMTU) {	/* KLUDGE!!! */
			struct mbuf *m = NULL;
			struct mbuf *unget();

			switch (len_or_type) {
#define LANTYPE_IP ETHERTYPE_IP
			case LANTYPE_IP:
				m = unget((char *) (ehp + 1), len,
					  &us->es_if);
				if (m == NULL)
					break;
				if (IF_QFULL(&ipintrq)) {
					IF_DROP(&ipintrq);
					m_freem(m);
					break;
				}
				IF_ENQUEUE(&ipintrq, m);
				schednetisr(NETISR_IP);
				break;
#define LANTYPE_ARP ETHERTYPE_ARP
			case LANTYPE_ARP:
				m = unget((char *) (ehp + 1), len,
					  &us->es_if);
				if (m == NULL)
					break;
				arpinput(&us->es_ac, m);
				break;
			default:
				DEBUGF(undebug, printf("un%d: unknown packet type %x\n",iv,len_or_type));

				break;
			}
		}
		else 
			DEBUGF(undebug, printf("un%d: unknown len or type %x\n",iv,len_or_type));
#ifdef notdef
		{
			struct mbuf *m = NULL;
			struct mbuf *unget();
#define eth_802_header ether_header
			struct eth_802_header *eh;

			eh = (struct eth_802_header *) ehp;
			len += sizeof(struct ether_header);
			if (len < sizeof(*eh)) {
				printf("unrint: short packet %d\n", len);
				splx(s);
				goto discard;
			}
#ifdef TEST_CONTROL
			switch (eh->eth_llc.llc_ctrl & ~CTRL_P_OR_F) {
			case TEST_CONTROL:
				m = unget((char *) eh, len,&us->es_if);
				if (m == NULL) {
					splx(s);
					goto discard;
				}
				lan_test_recv(&us->es_if, m);
				goto discard;
			case XID_CONTROL:
				m = unget((char *) eh, len,&us->es_if);
				if (m == NULL) {
					splx(s);
					goto discard;
				}
				lan_xid_recv(&us->es_if, m);
				goto discard;
			case UI_CONTROL:
				break;
			default:
				printf("unrint: bad LLC control field %d\n",
					eh->eth_llc.llc_ctrl);
				splx(s);
				goto discard;
			}
#endif
			switch (ntohs(* (u_short *) eh->eth_snap.snap_type)) {
#define eth_snap ether_snap
			case LANTYPE_IP:
				m = unget((char *) (eh + 1), len - sizeof(*eh),
					  &us->es_if);
				if (m == NULL)
					break;
				if (IF_QFULL(&ipintrq)) {
					IF_DROP(&ipintrq);
					m_freem(m);
					break;
				}
				IF_ENQUEUE(&ipintrq, m);
				schednetisr(NETISR_IP);
				break;
			case LANTYPE_ARP:
				m = unget((char *) (eh + 1), len - sizeof(*eh),
					  &us->es_if);
				if (m == NULL)
					break;
				arpinput(&us->es_if, m);
				break;
			default:
				break;
			}
		}
#endif notdef
		splx(s);
discard:
		/* So this driver knows we've read this frame. */
		us->rbdptr[us->rec_nm_buf]->status = 0;
		/* Now advance the "SUSPEND" indicator from previous buffer to
		 * the receive buffer we just read in.
		 */
		prev_nm_buf = us->rec_nm_buf? us->rec_nm_buf - 1: RBUFFS-1;
		us->fdptr[prev_nm_buf]->command &= ~swaph(FDSUSPEND);
		us->fdptr[us->rec_nm_buf]->command |= swaph(FDSUSPEND);
	}
}

/*
 * unxmit -- transmit a buffer -- before calling, you must:
 *	find a free buffer by checking tbuffstate[bufnum] ( 0 = free )
 *	copy your entire eth packet into tbufptr[bufnum]->{hdr,data}.
 */
unxmit(bufnum, len, iv)
u_int bufnum;
u_int len;	/* Length of entire packet, including header */
u_int iv;	/* which board */
{
	register struct tcb *tcbp;
	register struct tbd *tbdp;
	register struct buff *tbp;
	struct un_softc *us = &un_softc[iv];

	DEBUGF(undebug&SHOW_IO, printf("un%d: unxmit bufnum=%d len=%d\n",iv,bufnum,len));
	if (bufnum > 1)
		panic("unxmit");
	tcbp = us->tcbptr[bufnum];
	tbp = us->tbufptr[bufnum];
	tbdp = us->tbdptr[bufnum];

	/* Copy dest & type to where card expects to find them. */
#define eth_dhost ether_dhost
#define eth_shost ether_shost
	bcopy(tbp->hdr.eth_dhost, tcbp->dest, ETH_ADDR_SIZE);
/*	bcopy(&tbp->hdr.eth_type, tcbp->type, 2);	*/
	tcbp->type = (tbp->hdr.eth_type);	/* length ?? */
	DEBUGF(undebug&SHOW_IO, unprintpacket("unxmit: ",&tbp->hdr,"\n"));

	tcbp->command = swaph(0xA004);	/* EL & I & XMT */
	tcbp->link_offset = 0;
	tcbp->tbd_offset = swaph((unsigned short) tbdp);
/*	tbdp->status = swaph((len - sizeof(struct ether_header)) | EOFBIT); */
	tbdp->status = swaph((len) | EOFBIT);
	tbdp->nxt_tbd_offset = 0;
	tbdp->buff_addr_l = swaph((unsigned short) tbp->data);
	tbdp->buff_addr_h = swaph(us->ram_seg);
	while (us->scbptr->command != 0);
	us->scbptr->command = swaph(CUCSTART);
	us->scbptr->cbl_offset = swaph((unsigned short) tcbp);
	outb(us->csr+1,0xFF);	/* CA */
	us->us_owatch = unowatch;
}

struct mbuf *
unget(addr, totlen, ifp)
register u_char *addr;
register int totlen;
struct ifnet *ifp;
{
	register int len;
	register struct mbuf *m;
	struct mbuf *top = NULL, **mp = &top;
	u_char *mcp;

	++ifp->if_ipackets;

	DEBUGF(undebug&SHOW_IO, {
		int i;
		printf("un%d: unget addr=%x",ifp->if_unit,addr);
		if(undebug&SHOW_DATA)
			for (i=0; i<16; ++i)
				printf(" %x",addr[i]);
		printf("\n");});

	while (totlen > 0) {
		MGET(m, M_DONTWAIT, MT_DATA);
		if (m == NULL)
			goto bad;
		len = totlen;
		if (ifp != NULL)
			len += sizeof(ifp);
#ifdef notdef
		/* Should we try to use a cluster for efficiency? */
		if (len >= mincluster) {
			MCLGET(m);
			if (m->m_len == CLBYTES)
				m->m_len = len = MIN(CLBYTES, len);
			else
				m->m_len = len = MIN(MLEN, len);
		}
		else
#endif
		{
			m->m_len = len = MIN(MLEN, len);
			m->m_off = MMINOFF;
		}
		mcp = mtod(m, u_char *);
		if (ifp != NULL) {
			* (mtod(m, struct ifnet **)) = ifp;
			mcp += sizeof(ifp);
			len -= sizeof(ifp);
			ifp = NULL;
		}
		bcopy(addr, mcp, len);
		addr += len;
		*mp = m;
		mp = &m->m_next;
		totlen -= len;
	}
	return top;
bad:
	m_freem(top);
	DEBUGF(undebug&SHOW_IO, printf("un%d: unget BAD\n",ifp->if_unit));
	return NULL;
}

un_output(ifp, m0, dst)
struct ifnet *ifp;
struct mbuf *m0;
struct sockaddr *dst;
{
	int error;
	struct mbuf *m = m0, *mcopy = NULL;
	register struct ether_header *ec;
#ifdef notdef
	struct lan_arp *ah;
#endif
	char edst[LAN_ADDR_SIZE];
	int usetrailers;	/* N.B. this is currently ignored */
	struct in_addr idst;
	short type;
	spl_t s;
	extern struct ifnet loif;
	int	old_window = get_512_window();
	int iv = ifp->if_unit;
	struct un_softc *us = &un_softc[iv];

	(void) set_512_window(us->ram_addr);	/* set to proper 512k window */
	DEBUGF(undebug&SHOW_IO, printf("un%d: unoutput\n",iv));

	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
		error = ENETDOWN;
		goto bad;
	}

	switch (dst->sa_family) {
#ifdef INET
	case AF_INET:
		idst = ((struct sockaddr_in *) dst)->sin_addr;
		if (! arpresolve(&us->es_ac,m,&idst,edst,&usetrailers)) {
			set_512_window(old_window);
			return 0;		/* not resolved */
		}
		if (! bcmp(edst, etherbroadcastaddr, ETH_ADDR_SIZE))
			mcopy = m_copy(m, 0, M_COPYALL);
		type = LANTYPE_IP;
		break;
#endif INET
#ifdef AF_ARP
	case AF_ARP:
		ah = mtod(m, struct lan_arp *);
		bcopy(ah->arp_tha, edst, LAN_ADDR_SIZE);
		type = LANTYPE_ARP;
		break;
#endif
	case AF_UNSPEC:
		ec = (struct ether_header *) dst->sa_data;
		bcopy((caddr_t) ec->eth_dhost, (caddr_t) edst, sizeof(edst));
#ifdef notdef
		type = NO_SNAP;
#else
		type = ec->ether_type;
#endif
		break;
	default:
		ncprintf("un_output: cannot handle address family 0x%x\n",
			dst->sa_family);
		error = EAFNOSUPPORT;
		goto bad;
	}
#ifdef IFF_IEEE
	if (!(ifp->if_flags & IFF_IEEE)) /* Xerox ethernet header */
#endif
	{
		if ((m->m_off > MMAXOFF)
		||  ((MMINOFF + sizeof(struct ether_header)) > m->m_off)) {
			m = m_get(M_DONTWAIT, MT_HEADER);
			if (m == NULL) {
				error = ENOBUFS;
				goto bad;
			}
			m->m_next = m0;
			m->m_off = MMINOFF;
			m->m_len = sizeof(struct ether_header);
		}
		else {
			m->m_off -= sizeof(struct ether_header);
			m->m_len += sizeof(struct ether_header);
		}
		ec = mtod(m, struct ether_header *);
		bcopy(edst, (caddr_t) ec->eth_dhost, LAN_ADDR_SIZE);
		bcopy(us->es_addr, (caddr_t) ec->eth_shost, LAN_ADDR_SIZE);
		ec->eth_type = htons(type);
	}
#ifdef IFF_IEEE
	else
	{		/* IEEE802.3 header */
		register struct eth_mac_header *mh;
		register int header_size;

		header_size = sizeof(struct lan_llc_header)
				+ sizeof(struct lan_snap_header);

		switch (type) {
		case LANTYPE_IP:
		case LANTYPE_ARP:
			if ((m->m_off > MMAXOFF)
			||  ((MMINOFF + header_size) > m->m_off)) {
				m = m_get(M_DONTWAIT, MT_HEADER);
				if (m == NULL) {
					error = ENOBUFS;
					goto bad;
				}
				m->m_next = m0;
				m->m_off = MMINOFF;
				m->m_len = header_size;
				m0 = m;
			}
			else {
				m->m_off -= header_size;
				m->m_len += header_size;
			}
			fill_llc_header(mtod(m, struct lan_llc_header *), type);
			/* FALLSTHROUGH */
		case NO_SNAP:
			if ((m->m_off > MMAXOFF)
			||  ((MMINOFF + sizeof(*mh)) > m->m_off)) {
				m = m_get(M_DONTWAIT, MT_HEADER);
				if (m == NULL) {
					error = ENOBUFS;
					goto bad;
				}
				m->m_next = m0;
				m->m_off = MMINOFF;
				m->m_len = sizeof(*mh);
			}
			else {
				m->m_off -= sizeof(*mh);
				m->m_len += sizeof(*mh);
			}
			/* Fill in ethernet MAC header */
			mh = mtod(m, struct eth_mac_header *);
			bcopy(edst, (caddr_t) mh->eth_dhost, LAN_ADDR_SIZE);
			bcopy(us->es_addr, (caddr_t) mh->eth_shost,
				LAN_ADDR_SIZE);
			/* mh->eth_len = XXX; */	/* Set later */
		}
	}
#endif

	s = splimp();
	if (IF_QFULL(&ifp->if_snd)) {
		IF_DROP(&ifp->if_snd);
		error = ENOBUFS;
		m0 = m;
		splx(s);
		goto bad;
	}
	IF_ENQUEUE(&ifp->if_snd, m);
	un_ostart(ifp);
	splx(s);
	set_512_window(old_window);
	return (mcopy ? looutput(&loif, mcopy, dst) : NULL);
bad:
	m_freem(m0);
	if (mcopy)
		m_freem(mcopy);
	set_512_window(old_window);
	return error;
}

un_ostart(ifp)
register struct ifnet *ifp;
{
	int iv = ifp->if_unit;
	register struct un_softc *us = &un_softc[iv];
	int bufnum;
	struct mbuf *m, *m0;
	register char *bufp;
	register unsigned short length;
	spl_t s;

	s = splimp();

	DEBUGF(undebug&SHOW_IO, printf("un%d: unostart\n",iv));

#define IF_EMPTYQUEUE(queue) ((queue)->ifq_head == 0)
	while (! IF_EMPTYQUEUE(&ifp->if_snd)) {
		/* find a free buffer to put a packet in */
		if (us->tbuffstate[0] == FREE) {
			us->tbuffstate[0] = BUSY;
			bufnum = 0;
			++us->if_buf0;
		}
		else if (us->tbuffstate[1] == FREE) {
			us->tbuffstate[1] = BUSY;
			bufnum = 1;
			++us->if_buf1;
		}
		else {
			++us->if_nobuf;
			break;
		}
		IF_DEQUEUE(&ifp->if_snd, m);

		bufp = (char *) us->tbufptr[bufnum];
		length = 0;
		for (m0 = m; m0 != NULL; m0 = m0->m_next) {
			bcopy(mtod(m0, char *), bufp, m0->m_len);
			bufp += m0->m_len;
			length += m0->m_len;
		}
#ifdef IFF_IEEE
		/* For IEEE802.3 we need to fill in the length */
		if (ifp->if_flags & IFF_IEEE) {
			bufp = (char *) us->tbufptr[bufnum];
			((struct eth_mac_header *) bufp)->eth_len =
				htons(length - sizeof(struct eth_mac_header));
		}
#endif IFF_IEEE
		length = MAX(length, ETHERMIN);
		m_freem(m);

		unxmit(bufnum, length, iv); 
	}
	splx(s);
	DEBUGF(undebug&SHOW_IO, printf("un%d: unostart done\n",iv));
	return;
}

un_ioctl(ifp, cmd, data)
struct ifnet *ifp;
int cmd;
caddr_t data;
{
	register struct ifaddr *ifa = (struct ifaddr *) data;
	int error = 0;
	spl_t s;

	DEBUGF(undebug&SHOW_IO, printf("un%d: unioctl cmd=%x\n",ifp->if_unit,cmd));
	s = splimp();
	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;

		switch (ifa->ifa_addr.sa_family) {
#ifdef INET
		case AF_INET:
			uninit(ifp->if_unit);	/* before arpwhohas */
			((struct arpcom *)ifp)->ac_ipaddr=IA_SIN(ifa)->sin_addr;
			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
			break;
#endif INET
		default:
			uninit(ifp->if_unit);
			break;

		}
		break;
        case SIOCSIFFLAGS:
		ifp->if_flags |= IFF_NOTRAILERS;	/* kill trailers */
                if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags &
                    IFF_RUNNING) {
                        unzap(ifp->if_unit);
                } else if (ifp->if_flags & IFF_UP && (ifp->if_flags &
                                                      IFF_RUNNING) == 0)
                        uninit(ifp->if_unit);
                break;
	default:
		error = EINVAL;
		break;
	}
	splx(s);
	DEBUGF(undebug&SHOW_IO, printf("un%d: unioctl done\n",ifp->if_unit));
	return error;
}

unreset(unit)
        register unsigned int unit;
{
        register struct iocc_device *iod;
	if (unit < NUN && (iod = uninfo[unit]) != 0 && iod->iod_alive != 0) {
                if (un_softc[unit].es_if.if_flags & IFF_RUNNING) {
                        DEBUGF(undebug, printf("un%d: reset\n", unit));
                        unzap(unit);
                }

	}
}


/*
 * turn off the hardware via a reset thru the CSR 
 */
static unzap(unit)
        register unsigned int unit;
{
	register struct un_softc *us = &un_softc[unit];
	DEBUGF(undebug, printf("un%d: unzap\n", unit));

	un_softc[unit].es_if.if_flags &= ~IFF_RUNNING;	/* not running */
	outb(us->csr,(RESET));
	DELAY(10);
	outb(us->csr, 0);
	outb(us->csr+1,0xFF);			/* CA */
	delay(1);
	DEBUGF(undebug, printf("un%d: unzap done\n", unit));
}

/*
 *  unprintethaddr - print an ethernet address
 */
static unprintethaddr(p)
	register char  *p;
{
	register int    i;

	for (i = 0; i < ETH_ADDR_SIZE; i++) {
		if (i != 0)
			printf(":");
		printf("%x", *p++);
	}
}


#ifdef DEBUG
static char *ethertype(type)
{
	if (type == ETHERTYPE_IP)
		return("ip");
	if (type == ETHERTYPE_ARP)
		return("arp");
	return("?");
}

static unprintpacket(prefix,eh,postfix)
	register struct ether_header *eh;
	char *prefix, *postfix;
{
	char            cbuf[6];
	printf("%sfrom = ",prefix);
	bcopy(eh->ether_shost, cbuf, sizeof(cbuf));
	unprintethaddr(cbuf);
	printf("  to = ");
	bcopy(eh->ether_dhost, cbuf, sizeof(cbuf));
	unprintethaddr(cbuf);
	printf(" type=%s(%x) %s",ethertype(eh->ether_type),eh->ether_type,postfix);
}
#endif	/* DEBUG */

/*
 * watch routine. We check to see if we've not gotten any transmit or 
 * receive interrupts lately and attempt to restart if necessary.
 * We assume that on an ethernet with at least one other active machine
 * that we will get at least one broadcast packet per timeout period.
 */

unwatch(arg)
caddr_t arg;
{
	register int    unit = (int) arg;
	register struct un_softc *us = &un_softc[unit];
	register struct ifnet *ifp = &us->es_if;
	int restart = 0;

	if ((ifp->if_flags & IFF_RUNNING) != 0) {
		if (us->us_owatch && --us->us_owatch==0) {
			printf("un%d: lost output interrupt - restarting.\n", unit);
			++restart;
		}
		if (us->us_iwatch && --us->us_iwatch==0) {
			DEBUGF(undebug,
		 printf("un%d: lost input interrupt?? - restarting.\n", unit););
			++restart;
		}
		if (restart) {
			unzap(unit);	/* clears RUNNING */
			uninit(unit);
		}
		timeout(unwatch, (caddr_t) unit, hz);
	} else
		us->us_watch = 0;	/* if not running don't watch it */
}
#endif /* NUN > 0 */
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads