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
Author: Mark S. Lewis
Date: Thu, 17 Aug 1989 00:28
Date: Thu, 17 Aug 1989 00:28
1351 lines
38084 bytes
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 = ⊤
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