home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Troubleshooting Netware Systems
/
CSTRIAL0196.BIN
/
attach
/
pcc
/
v08n03
/
netwrk.exe
/
WDPOST.ZIP
/
WDPOST.TAR
/
wdpost.dir
/
sample.drv
/
macmod.c
< prev
next >
Wrap
Text File
|
1988-06-21
|
20KB
|
695 lines
/************************************************************************
* RCS $Revision$ $Date$ *
* *
* MACMOD.C *
* (c) Copyright 1987 Western Digital Corporation (R). *
* All rights reserved. Contains confidential information and trade *
* secrets proprietary to Western Digital.
* *
* Environment: *
* MS-DOS, WD8003 *
* *
* *
* Module Description: *
* This file contains the interface routines to the LLC sublayer, *
* and the 8390 based WD8003 LAN controller card. *
* *
* Function: *
* -------- *
* There are six routines in this C file *
* *
* 1. init_lanc one time LAN controller set up routine *
* 2. stop_mac reset 8390, take it off line *
* 3.a init_mac MAC sublayer initialization routine *
* 3.b start_mac MAC sublayer start routine *
* 4. M_DATArequest handle a msdu from LLC layer *
* 5. do_mac_queue process rx_queue until it is empty *
* *
* History: *
* ------- *
* DATE: 3/18/87 * *
* LEVEL: et.bb.00 *
* WHO: KC *
* CHANGE: create macmod.c for wd8003 *
* *
* DATE: 6/18/87 * *
* LEVEL: et.bb.01 *
* WHO: KC *
* CHANGE: [01] WDBPR# 762 *
* PROBLEM:hw int gets in before init_all() completed. System halts *
* during NETBIOS loading with fatal code 12 (bad work entry).*
* FIX: use in_diags to block the hw int form entering osi module. *
* set in_diags at beginning of init_lanc() and stop_mac, *
* reset in_diags at end of start_mac(). *
* *
* DATE: 9/24/87 * *
* LEVEL: et.bb.05 *
* WHO: KC *
* CHANGE: [02] WDBPR# 823 *
* PROBLEM:add delay before tx frame in order to run 8003S with 8000S *
* FIX: init_lanc() calls starlan_wait() before calls init_8390 *
* to set up the wait loop count for different speed machine *
* when using start lan board. *
* *
* Date: 10/6/87
* Level:etbb05
* WHO: Steve Chen
* CHANGE: porting to microsoft c compiler 4.0
*
************************************************************************/
#include "mac.h"
#define COMMENTOUT
/* defined some hardware dependent value, should put into lancons.h
and MACcons.h later on */
/* #define IO_BASE_OF_WD8003 0x0280 */ /* default base */
#define MAX_WD8003_DATA 1518 /* should be other value,chip depnendent value */
#define W83CREG 0x00 /* I/O port definition */
#define ADDROM 0x08
#define CMDR 0x10
#define RCR 0x1C
#define MSK_RESET 0x80 /* W83CREG masks */
#define MSK_ENASH 0x40
#define MSK_STP 0x01 /* 8390 CMDR masks */
#define MSK_STA 0x02
#define MSK_RD2 0x20
#define MSK_AB 0x04 /* 8390 RCR */
#define TB_SIZE 0x02 /* number of tx buff in shard memory */
extern hdw_isr(); /* network interrupt service routine */
extern long get_vec(); /* returns interrupt vectors */
extern int debug;
extern char phreaque;
extern node_address *my_eaddr;
extern int bufsize;
extern int WD8_base;
extern int SM_base;
extern char adapter_irq;
extern char in_diags; /* [01] */
/* %%5%%+ */
extern int m_channel; /*[8] micro channel flag */
/* %%5%%- */
/* OSI version info */
char version[] = VERSION;
char licensee[] = LICENSEE;
char machine[] = MACHINE;
buf_type tx_buf; /* transmit buffer */
buf_type rx_buf; /* receive buffer */
struct db_list tx_queue; /* mac tx queue */
struct db_list rx_queue; /* mac rx queue */
unsigned char tb_cur; /* curr tx buf of shr mem being tx */
unsigned char tb_use; /* no of tx buf's being occupied */
unsigned int tb_lnth[TB_SIZE]; /* an array for byte count of each tb in shr mem */
unsigned char OSI_RST = 0; /* flag for OSI reset, set by stop_mac, reset by init_mac */
/* broadcast node address (used by network layer) */
node_address brd_node = {
{0xff,0xff,0xff,0xff,0xff,0xff}
};
char mac_type=3; /* MAC type in 802 family */
/* %%4%%+ */
int int_mask_reg; /*[8] interrupt mask register */
extern int int_reg; /* [8] interrupt register */
int int_base; /* base vector # for controller */
/* %%4%%- */
/*
* MAC sublayer statistics counters. The order of counters 0-12 should
* not be changed from one driver to the next since the Netbios uses
* these statistics in all drivers for it's STATUS command.
*/
struct mstat MACstat;
struct sminfo macinfo[] = {
{0, &MACstat.t0},
{1, &MACstat.txok},
{2, &MACstat.collsn},
{3, &MACstat.txbad},
{4, &MACstat.collsn},
{5, &MACstat.underrun},
{6, &MACstat.rxrd},
{7, &MACstat.rxok},
{8, &MACstat.crcerr},
{9, &MACstat.rxblkd},
{10,&MACstat.algerr},
{11,&MACstat.srtfrm},
{12,&MACstat.rxnom},
{13,&MACstat.lostcrs},
{14,&MACstat.lostcts},
{15,&MACstat.overrun},
{-1, NULL}
};
/************************************************************************
* *
* init_lanc(max_tpdu, base, uirq, page, node, fnode) *
* *
* One time LANC setup. *
* Setup and enable MAC interrupts and lanc control structures. *
* Should be called before "terminate & stay resident" is called. *
* *
* *
* Description : *
* ----------- *
* check if hw can accommodate proposed max frame size *
* if not, exit 1 *
* overwrite default SM_base(c000h) if page specified by user *
* overwrite default WD8_base(280h) if base specified by user *
* Sumcheck the LAN addr *
* if failed, exit 2 *
* if uirq specified by user *
* if range check failed, exit 2 *
* if range ok, write to adapter_irq & irq *
* if uirq not specified by user *
* read irq level from status reg or use default value *
* write to adpter_irq *
* set up LAN interrupt vector & enable LAN interrupt *
* clr rx_q & tx_q *
* clr phreaque *
* write MAX_BFSZ into bufsize *
* set up my_eaddr(ptr) useing user specified addr 'node' or *
* read from ADDROM. and return value to fnode(ptr) *
* reset WD 8003 *
* do dgn test here if available *
* if failed, reset 8003 and restore old irq vector, exit2*
* call init_8390() to initial the 8390 *
* *
* Error Exit : 1 'unable to accomdate the user specified frame' *
* ---------- or 'network irq already in use' *
* 2 'bad ROM checksum' or *
* 'bad user irq' or * *
* 'bad dgn test' (not available now) * *
* * *
* Call: init_8390() *
* ---- *
* *
************************************************************************/
init_lanc(max_tpdu, base, uirq, page, node, fnode)
int max_tpdu; /* includes transport header */
unsigned base; /* I/O base of WD8000 */
char uirq; /* interrupt level selected by user */
unsigned page; /* page addr of shared memory */
register node_address *node; /* node address selected by user */
node_address *fnode; /* return addr for node address */
{
struct cpuaddr netvec;
long oldnetvec; /* old network interrupt vector */
char oldmask, newmask;
unsigned char irq;
unsigned char adrsum;
register int i;
in_diags = 1; /* [01] */
debug = 1;
#ifdef DEBUG
if (debug)
{
printf("<ilanc base %x uirq %b node ", base, uirq);
print_addr(node);
}
#endif
/* see if the hardware can accommodate proposed max frame size */
if ((max_tpdu + MPCI_LEN + LPCI_LEN + NPCI_LEN) > MAX_WD8003_DATA)
{
printf("Unable to accommodate frame size (%d)\n", max_tpdu);
_exit(1);
}
/* set up SM_base if value selected by the user otherwise use default */
if (page != 0xffff)
SM_base = page << 4; /* page number into paragragh number */
/* set up WD8_base using value selected by the user or default value */
if (base != 0xffff)
WD8_base = base; /* WD8_base default to 280h */
/* if (uirq == 0xff)
uirq = INTVEC; */
/* sumcheck the addr ROM */
adrsum = 0;
for (i= 0; i < 8; i++)
adrsum = adrsum + in(ADDROM + WD8_base + i);
if (adrsum != 0xff)
{
printf("Checksum error in LAN address ROM\n");
printf("Possible error in I/O base address (%x)\n", WD8_base);
printf(" --- Netbios Emulator installation aborted.\n");
_exit(2);
}
/*
* Set up and enable lanc interrupts, uirq is set to 0xff
* if the interrupt level should be read from the board
*/
/* set up irq level from user selected uirq(parm3) or from Board
or use default INTVEC = 3, write irq into adapter_irq */
irq = uirq;
if ( irq != 0xff) /* user selected */
/* %%4%%+ */
{ /*[8] different irq allowed for micro channel */
if ( (!m_channel && (irq < 2 || irq > 7)) || ( m_channel && (irq != 3) && (irq != 4) && (irq != 10) && (irq != 15)) )
/* %%4%%- */
{
printf("Invalid interrupt level (%x)\n", irq);
printf (" --- Netbios Emulator installation aborted.\n");
_exit(2);
}
adapter_irq = irq;
}
else
{
/* read from status reg or use default value */
/* irq = in( WD8_base + W83SREG); */
/* irq = irq & 0x07; */
irq = INTVEC; /* use default value */
adapter_irq = INTVEC;
}
#ifdef DEBUG
if (debug) printf("<getirq irq%bH>", irq);
#endif
/* %%4%%+ */
if ( irq > 7) { /*[8]micro channel level 10, 15 */
int_mask_reg = P8259_2; /* interrupt controller 2 */
int_reg = INTREG_2;
newmask = 1 << (irq - 8);
int_base = INTBASE_2 - 8; /* interrupt base vector */
}
else {
int_mask_reg = P8259; /* interrupt controller 1 */
int_reg = INTREG;
newmask = 1 << irq;
int_base = INTBASE; /* interrupt base vector */
}
/* use interrupt level to set up 8259 controller mask */
/* newmask = 1 << irq;*/
oldmask = in(int_mask_reg);
/* for micro channel irq = 3, 4, 10,15
use int vector # 11,12,0x72,0x77
for Non micro channel machine irq = 2, 3, 4, 5, 6, 7
use vector # 10,11,12,13,14,15 */
#ifndef COMMENTOUT
/* Check if the interrupt is already in use */
if ( !(oldmask & newmask))
{
printf("Network interrupt already in use (%bH)\n",
irq+int_base);
_exit(1);
}
#endif
/* Setup the controller interrupt vector */
oldnetvec = get_vec(irq+int_base); /* get old interrupt vec */
netvec.offs = (unsigned) hdw_isr; /* make new net vector */
netvec.seg = (unsigned) get_cs();
set_vec(irq+int_base, netvec); /* set new vector up */
/* Enable network interrupts */
out(int_mask_reg, oldmask & ~newmask);
/* %%4%%- */
/*
* Initialize the controller. Controller needs to test OSI's
* maximum buffer size in it's self-test, our node address is
* then copied to fnode.
*/
/* initialize queues for use in hdw_init */
tx_queue.first = tx_queue.last = (buf_type) &tx_queue;
rx_queue.first = rx_queue.last = (buf_type) &rx_queue;
/* clear phreaque */
phreaque = 0;
/* write max buf size (defined in comcons.h) into bufsize */
bufsize = MAXBFSZ;
/* set up my_eaddr from user(parm4:node) or from addr ROM */
my_eaddr = fnode;
for (i = 0; i< NODSIZ ; i++) /* test if user select nd adr */
if( node->addr[i] != 0xff ) break;
if ( i == NODSIZ ) /* node = 0xffff..., read from ROM */
for (i = 0; i< NODSIZ; i++)
fnode->addr[i] = in(WD8_base + ADDROM + i);
else /* user selected adr (parm4 != 0xffffffffffff) */
for (i = 0; i< NODSIZ; i++)
fnode->addr[i] = node->addr[i];
/* reset WD8003 board, and then enable the shared memory */
/* use SM_base to calculate the MSK_DECOD */
out(WD8_base + W83CREG, MSK_RESET);
out(WD8_base + W83CREG, 0);
/* %%1%%+ */
if ( m_channel) /*[8] micro channel machine */
out(WD8_base + W83CREG, MSK_ENASH);
else
out(WD8_base + W83CREG, MSK_ENASH + (SM_base>>9 & 0x3f));
/* %%1%%- */
/* clear MACstat if there is some DGN test performed in hdw_init */
/* status = init_dgn()
MACstat.t0 = 0;
MACstat.txok = 0;
MACstat.txbad = 0;
MACstat.collsn = 0;
MACstat.lostcrs = 0;
MACstat.lostcts = 0;
MACstat.underrun = 0;
MACstat.rxrd = 0;
MACstat.rxok = 0;
MACstat.rxnrd = 0;
MACstat.crcerr = 0;
MACstat.overrun = 0;
MACstat.algerr = 0;
MACstat.srtfrm = 0;
MACstat.rxnom = 0;
MACstat.rxblkd = 0;
MACstat.ex_lockup = 0;
MACstat.ia_corrup = 0;
MACstat.spur_int = 0;
#ifdef DEBUG
if (debug) printf("<init_dgn stat%xH>", status);
#endif
*/
/* Check for hardware init_dgn failure. if failed, reset 8003 and restore old int */
/* if (status < 0)
{
out (WD8_base + W83CREG, MSK_RESET);
out (WD8_base + W83CREG, 0);
printf (" --- OSI protocol layer installation aborted.\n");
set_vec(irq+int_base, oldnetvec);
_exit(2);
}
*/
/* [02] */
starlan_wait(); /* initialize LAN type and Starlan write wait states */
/* call init_8390 */
init_8390();
#ifdef DEBUG
if (debug) printf("<init_lanc done>\n");
#endif
}
/************************************************************************
* *
* stop_mac - reset 8390, reinitial LAN controller register. *
* and take 8390 off line, init_mac will activate it *
* later. *
* *
************************************************************************/
stop_mac ()
{
in_diags = 1; /* [01] */
/* set flag OSI_RST for init_8390 */
OSI_RST = 1;
/* do a software reset */
out (WD8_base + CMDR, MSK_STP + MSK_RD2); /* take 8390 off line */
/* call init_8390 */
init_8390();
#ifdef DEBUG
if (debug)
printf("<stop_mac done>");
#endif
}
#ifdef DEBUG
print_addr(node)
register node_address *node;
{
register int j;
for (j=0; j<NODSIZ; j++)
printf("%b", node->addr[j]);
}
#endif
/************************************************************************
* *
* init_mac() *
* Media Access Control Sublayer initialization routine. *
* Called whenever the OSI module is reset (ie. via a Netbios RESET *
* command). Init_mac should only be called after stop_mac. *
* *
************************************************************************/
init_mac ()
{
tx_buf = NULL;
tx_queue.first = tx_queue.last = (buf_type) &tx_queue;
rx_queue.first = rx_queue.last = (buf_type) &rx_queue;
tb_use = 0; /* clr flag and phreaque */
tb_cur = 0;
phreaque = 0;
/* reset the OSI_RST flag and put 8390 on line */
OSI_RST = 0;
}
/************************************************************************
* *
* start_mac() *
* Media Access Control Sublayer start routine. *
* put 8390 on line and enables the receiver *
* *
************************************************************************/
start_mac()
{
/* put 8390 on line and enable the receiver */
out(CMDR + WD8_base, MSK_STA + MSK_RD2); /* activate the 8390 */
out(RCR + WD8_base, MSK_AB); /* enable the rxer */
in_diags = 0; /* [01] */
}
/************************************************************************
* *
* M_DATArequest(remote_st, msdu) *
* *
* Input: remote_st, pointer of the remote station address *
* mpdu, media access protocol data unit *
* Output: no error, if the msdu has a valid length *
* LONG_SDU_ERROR if length > max *
* *
* This routine is called every time there is an mpdu to be *
* transmitted. *
* *
* Add padding (if data < 46 bytes), data lenth, source addr, *
* remote addr, txblk length into the msdu. *
* *
* If tb_use = 0 (txer not busy), call xmt_frm. *
* If 0 < tb_use < n, queue it into shared memory tb. *
* If tb_use = n (tb of shr mem full), queue it into tx_queue *
* *
* Call: cp_frm (tx_buff), xmt_frm (), QInsert (tx_buff, &tx_q) *
* *
* Note: xmt_frm () : tx frm in tb_cur *
* cp_frm (tx_buff) : copy tx_buff to (tb_cur+tb_use)%TB_SIZE *
* *
************************************************************************/
M_DATArequest (remote_st, msdu)
node_address *remote_st; /* remote station address */
register buf_type msdu; /* MAC protocol data unit */
{
union swap sw;
register char *msdup;
int psw;
register int msdu_len, txblk_len;
#ifdef DEBUG
int i;
#endif
msdu_len = BuffSize (msdu); /* save the msdu length */
if (msdu_len > MAX_MSDU)
/* return error if too large */
return (SDU_LONG_ERROR);
#ifdef DEBUG
if (debug){
printf("<mactx length= %x> remadr= ", msdu_len);
print_addr(remote_st);
printf(" DATA= ");
msdup = BuffData (msdu);
for (i=0; i<msdu_len; i++)
printf("%b",*msdup++);
}
#endif
/*
* Construct the transmit data block. Point to the start of the
* tx block; 2 for total tx block size, NODSIZ for destination
* addres, 2 for llc data length.
*/
BuffPrepend (msdu, NODSIZ + 2 + 2);
msdup = BuffData (msdu);
txblk_len = msdu_len + NODSIZ + 2; /* tx block length */
/* pad the frame to min len */
if (txblk_len < MIN_FRM - NODSIZ - CRC_LEN)
txblk_len = MIN_FRM - NODSIZ - CRC_LEN;
/* save the block length in cpu order, others in network order */
* (unsigned short *) msdup = txblk_len; /* save the block length */
msdup += sizeof(short);
/* add2 (msdup, txblk_len); */ /* save the block length */
bcopy (remote_st->addr, msdup, NODSIZ); /* save the destination address */
skip (msdup, NODSIZ);
add2 (msdup, msdu_len); /* set the msdu length */
/* tx or queue this frm. */
psw = disave (); /* must disable interrupts while checking */
if (tb_use == 0) /* txer idle */
{
cp_frm (msdu);
tb_use ++;
/* restor (psw); */ /* the rep movs should not be int */
xmt_frm (); /* tx now */
MACstat.t0++; /* increment the initial tx attemp */
#ifdef DEBUG
if (debug) printf("<xmt_frm>");
#endif
}
else if (tb_use < TB_SIZE) /* txer busy, tb not full */
{
cp_frm (msdu); /* queue it into tb of shr mem */
tb_use ++;
/* restor (psw); */
#ifdef DEBUG
if (debug) printf("<Q:tb of shr mem>");
#endif
}
else /* tb's of shr mem full */
{
QInsert (msdu, &tx_queue); /* put into tx_q */
/* restor (psw); */ /* restore the cpu status */
#ifdef DEBUG
if (debug) printf("<Q:tx_queue>");
#endif
}
restor (psw);
}
/************************************************************************
* *
* do_mac_queue() *
* *
* Handle MAC background activities (ie. processing receives). *
* Process rx_queue until it is empty. *
* *
* Call: M_DATAindication (&loc_adr, &rem_adr, bp), QRemove(rx_buff) *
* *
************************************************************************/
do_mac_queue ()
{
register buf_type bp;
node_address loc_adr, rem_adr;
union swap sw;
register char *mpdup;
int psw, msdu_len;
#ifdef DEBUG
int i;
#endif
psw = disave ();
/* Are there any messages in the rx queue ? */
while ((bp = rx_queue.first) != (buf_type) &rx_queue)
{
#ifdef DEBUG
if (debug) printf("<mac_rcv>");
#endif
QRemove (bp); /* remove it from queue */
restor (psw);
mpdup = BuffData (bp); /* mpdup -> received DA */
BuffStrip (bp, 2*NODSIZ+2);
bcopy (mpdup, loc_adr.addr, NODSIZ);
skip (mpdup, NODSIZ);
bcopy (mpdup, rem_adr.addr, NODSIZ);
skip (mpdup, NODSIZ);
get2 (msdu_len, mpdup);
BuffAdjust (bp, BuffSize (bp) - msdu_len);
#ifdef DEBUG
if (debug)
{
printf("\n");
printf("DA "); print_addr(&loc_adr);
printf("\tSA "); print_addr(&rem_adr);
printf("\tmsdulen\t%d", msdu_len);
printf("\n");
printf("data\t");
for (i=0; i<msdu_len; i++)
printf("%b",*mpdup++);
printf("\n");
}
#endif
M_DATAindication (&loc_adr, &rem_adr, bp);
psw = disave ();
} /* end of while */
restor (psw);
}