4.3BSD/usr/contrib/np100/np.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1986 MICOM-Interlan, Inc., Boxborough Mass
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	@(#)np.c	7.1 (Berkeley) 6/5/86
 */

		/******************************************
 		*					  *
 		*		NPDRIVER		  *
 		*					  *
 		******************************************/

/*
 * The NP Driver is used to route requests, independent of protocol type,
 * to the NP series Intelligent Board. The facilities it provides are
 * used for board maintainance by the superuser and by protocol pseudo-drivers, 
 * such as WN, for sending requests to a board. The board maintainance and
 * control functions are accessed via npioctl() by the NP support utilities.
 */


/*
 * Include Files
 */

#include "np.h"
#if NNP > 0
#include "param.h"
#include "buf.h"
#include "signal.h"
#include "systm.h"
#include "dir.h"
#include "user.h"
#include "proc.h"
#include "uio.h"
#include "errno.h"

#include "../vaxuba/ubavar.h"
#include "../vaxuba/npreg.h"

/*
 * Global variables for pseudo-drivers.
 */

int WnInitFlag;
int IsInitFlag;

/*
 * Debugging level.
 */

int	NpDebug = 0;		

/* Driver Wide State used by the ICP */

int NpState = NPCLEAR;


/*
 * Master structure, one per board, contains request queue header,
 * shared memory address, and memory mapping information.
 */

struct npmaster npmasters[NNP];

/* Structure of the shared memory area */

static struct npspace npspaces[NNP];

/* Panic Message data structures */

static int panicmap;			/* Mapping information */
static char	NpPbuf[PANLEN] = 0;	/* Panic message buffer */
static caddr_t pstring;			/* Panic string address on board, absolute */
static unsign16 panaddr[2];		/* Panic string address on board (seg/offset) */

/* Driver Wide Connection Table */

static struct npconn npcnxtab[NNP][NNPCNN];

/* Head of the request queue, one per board */

static struct npreq reqhdr[NNP];

/* The request structures, one pool per board */

static struct npreq npreqs[NNP][NUMCQE];


/*
 * Data structures needed for BSD 4.2 Device Drivers
 */

int	npprobe(), npattach(), npintr();
struct	uba_device *npdinfo[NNP];

/* UNIBUS address of Network Processors */

u_short	npstd[] = { 0166000, 0166020, 0 };

/* Interrupt vectors used by the Network Processors */

static unsign16 npvectors[NNP];

struct	uba_driver npdriver =
    { npprobe, 0, npattach, 0, npstd, "np", npdinfo };
struct	buf	np_tab[NNP];


/*
 * External function and data structure declarations.
 */

struct npreq * NpGetReq();
struct npmaster	*NpBoardChange();
int NpTimer();
struct CQE * NpRemCQE();
int (*IxAttach)();
int (*IxReset)();

extern struct user u;

/*
 * Np_init() is responsible for hardware initializiation and the software 
 * initialization of the connection table and driver software data structures.
 */

npinit(unit)
int unit;
{
	register int j;


		/* Software Initialization */

	npmasters[unit].flags = NPCLEAR;

	NpSWinit(unit);

		/* Hardware Initialization */

	NpHWinit(unit);		

		/* Connection Table Initialization */

	for(j=0;j<NNPCNN;j++) {
		npcnxtab[unit][j].protocol = NPCLCONN;
		npcnxtab[unit][j].unit = &npmasters[unit];
	}
}

/*
 * Np_open establishes a connection to the NP Driver using the minor
 * device number as an identifier. A default protocol, NPMAINT, is assigned
 * with the specified unit. Protocol and unit may be changed using the 
 * NpProtChange and NpBoardChange functions.
 * Since the maintainance protocol does not need a working I-Board, entries
 * are always made in the Connection Table, npcnxtab, if the board exists.
 */

/*ARGSUSED*/
npopen(dev,flag)
dev_t dev;
int flag;
{
	int unit;
	unsign16 conn;
	struct npmaster *mp;
	int error;

	if(NpDebug & DEBENTRY)
		printf("npopen\n");

	/* Clear error */

	error = 0;

	/* Make sure it's the superuser */

	if(u.u_uid) 
		return(EPERM);
	
	/* Get the connection identifier */

	if(((conn = NPCONN(dev)) >= NNPCNN) ||
	    ((unit = NPUNIT(dev)) >= NNP)) 
		return(ENODEV);
	

	if(NpDebug  & DEBOPEN)
		printf("conn = %x unit = %d\n",conn,unit);

	/* Get the board for the specified unit */

	mp = NpBoardChange(NPMAINT,unit);

	if(mp != (struct npmaster *) 0) {
		npcnxtab[unit][conn].unit = mp;
		npcnxtab[unit][conn].protocol = NPMAINT;
	}
	else error = ENXIO;

	if(NpDebug & DEBENTRY)
		printf("npopen...\n");

	return(error);
}

/*
 * Np_close is responsible updating the connection table for
 * that connection by marking it closed.
 */

npclose(dev)
dev_t dev;
{

	if(NpDebug & DEBENTRY)
		printf("npclose\n");

	/* Get the connection identifier */

	npcnxtab[NPUNIT(dev)][NPCONN(dev)].protocol = NPCLCONN;

	if(NpDebug & DEBENTRY)
		printf("npclose...\n");

	return(0);

}

/*
 * Npioctl is the main conduit of commands between the I-Board and the
 * NP support utilities. Relevant information for the request is found in the
 * cmd and addr parameters. Cmd specifies the function to perform, addr is 
 * command specific. Npioctl returns 0 if successful, or an error number
 * (which winds up in errno).
 */

/*ARGSUSED*/
npioctl(dev,cmd,addr,flag)
dev_t dev;
int cmd;
caddr_t *addr;
int flag;
{
	unsign16 protocol;
	unsign16 conn;
	unsign16 unit;
	int error;

	register struct npmaster *mp;
	register struct npreq *rp;
	unsigned usrarg;

	if(NpDebug & DEBENTRY)
		printf("npioctl\n");

	/* Clear error */

	error = 0;

	/* Strip off IOC_VOID bit */

	cmd &= CMDMASK;

	/* Get connection identifier */

	conn = NPCONN(dev);
	unit = NPUNIT(dev);

	/* Master pointer for this unit */

	mp = npcnxtab[unit][conn].unit;

	protocol = npcnxtab[unit][conn].protocol;

	/* Get a request structure from the pool and initialize it */

	while((rp = NpGetReq(mp->reqtab)) == NULL) {
		mp->reqtab->flags |= WANTREQ;
		sleep((caddr_t)(mp->reqtab),PZERO -1);
	}

	if(NpDebug & DEBREQ)
		printf("NP Reqp is %x\n",rp);

	/* Initializations of request structure */

	rp->intr = (int (*)())0;	/* Do not call interrupt routine */
	rp->bufoffset = 0;		/* Offset into data buffer */
	rp->flags = NPCLEAR;		/* Clear flags */
	rp->procp = u.u_procp; 	/* Process structure for this user */

	/* Copy in user's argument to ioctl() call */

	if(error = copyin(*addr,&usrarg,sizeof(usrarg)))
		return(error);
	

	if(NpDebug & DEBIOCTL)
		printf("arg = %x\n",usrarg);

	/* Execute the specified command */

	switch(cmd) {

	    case NPSETPROT:
	    	if((error = NpProtChange(usrarg,mp->unit)) == 0)
			npcnxtab[unit][conn].protocol = usrarg;
		break;
	    case NPSETBOARD:
		if(mp = NpBoardChange(protocol,usrarg))
			npcnxtab[unit][conn].unit = mp;
		else {
			mp = npcnxtab[unit][conn].unit;
			error = ENXIO;
		}
		break;
	    case NPRESET:
		error = NpReset(mp,rp);
		break;
	    case NPSETNPDEB:
		NpDebug = usrarg;
		break;
	    case NPINIT:
		error = NpSWinit(mp->unit);
		break;
	    case NPSTART:

#ifdef OLDROM
		/*
		 * Kludge to work around I-Board boot from Host. Read two bytes
		 * from the board into the Device Configuration Word
		 * in Shared Memory.
		 */

		NPIO(mp,(paddr_t)0x500,(paddr_t)(&mp->shmemp->statblock.sb_dcw),2,B_READ);

		mp->shmemp->statblock.sb_drw = 0;
#endif

		/* Set the Address at which to begin On-Board execution */

		error = NpSetXeqAddr(mp,(caddr_t)usrarg);
		break;
	    case NPSTATS:
		error = NpStats();
		break;
	    case NPGPANIC:
		error = copyout((caddr_t)NpPbuf,*addr,PANLEN);

		/* Clear panic request flag and leave */

		mp->flags &= ~PANICREQ;
		break;
	    case NPPOLL:
		error = NpPoll(mp,*addr);
		break;
	    case NPKILL:
		error = NpKill(mp,rp);
		break;
	    case NPSETADDR:
		error = NpSetMemAddr(mp,*addr);
		break;
	    case NPRCSR0:
		usrarg = RCSR0(mp->iobase);
		error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
		break;
	    case NPRCSR1:
		usrarg = RCSR1(mp->iobase);
		error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
		break;
	    case NPRCSR2:
		usrarg = RCSR2(mp->iobase);
		error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
		break;
	    case NPRCSR3:
		usrarg = RCSR3(mp->iobase);
		error = copyout((caddr_t)&usrarg,*addr,sizeof(usrarg));
		break;
	    case NPWCSR0:
		WCSR0(mp->iobase,usrarg);
		break;
	    case NPWCSR1:
		WCSR1(mp->iobase,usrarg);
		break;
	    case NPWCSR2:
		WCSR2(mp->iobase,usrarg);
		break;
	    case NPWCSR3:
		WCSR3(mp->iobase,usrarg);
		break;
	    case NPNETBOOT:
		error = NpSetIntLevel(mp,mp->vector);
		if(error) break;
		error = NpSetXeqAddr(mp,(caddr_t)INETBOOT);
		break;
	    default:
		printf("Bad Maintenance command: %d!\n",cmd);
		error = EIO;
		break;

	}
	if((cmd != NPRESET) && (cmd != NPINIT))
		NpFreeReq(mp->reqtab,rp);

	if(NpDebug & DEBENTRY)
		printf("npioctl...\n");

	return(error);
}

/*
 * np_start - start io activity
 */
npstart(mp)
register struct npmaster *mp;
{

	register struct buf	*bp;
	register struct npreq	*rp;

	int error;			/* Return from NPIO call */

	if(NpDebug & DEBENTRY)
		printf("npstart\n");

	if((bp = np_tab[mp->unit].b_actf) == (struct buf *)0) {
		np_tab[mp->unit].b_active = 0;
		return;
	}
	if((rp = (struct npreq *)(bp->av_back)) == (struct npreq *)0) {
		bp->b_flags = B_ERROR;
		iodone(bp);
		return;
	}
	np_tab[mp->unit].b_active = 1;

	if(NpDebug & DEBIO)
		printf("NP IO src %x dst = %x cnt = %x\n",bp->b_un.b_addr,bp->b_blkno << DEV_BSHIFT,bp->b_bcount);

	/* Send the request to the board via the CSR0 command interface */

	if(bp->b_flags & B_READ) 

		error = NPIO(mp,(paddr_t)((long)bp->b_blkno << DEV_BSHIFT),(paddr_t)(rp->bufaddr),
	    bp->b_bcount,(bp->b_flags & B_READ)); 

	else
		error = NPIO(mp,(paddr_t)(rp->bufaddr),(paddr_t)((long)bp->b_blkno << DEV_BSHIFT),
	    bp->b_bcount,(bp->b_flags & B_READ)); 
	

	/* Check return from I/O */

	if(error) {
		bp->b_flags |= B_ERROR;
		np_tab[mp->unit].b_actf = bp->av_forw;

		if(NpDebug & DEBIO)
			printf("NPIO return error: b_flags is %x \n",bp->b_flags);
		iodone(bp);
	}

	if(NpDebug & DEBENTRY)
		printf("npstart...\n");

}
/*
 * npstratagey - the strategy routine
 */

npstrategy(bp)
register struct buf *bp;
{

	register struct buf *ip;	/* quick pointer */
	register struct npmaster *mp;	/* master structure for this device */
	register struct npreq *rp;	/* reqest struct pointer */
	int s;				/* priority to return to */

	if(NpDebug & DEBENTRY)
		printf("npstrategy\n");
	if(NpDebug & DEBIO)
		printf("flag = %x count = %x paddr = %x %x blkno = %x %x\n",
		    bp->b_flags,bp->b_bcount,bp->b_un.b_addr,bp->b_un.b_addr,bp->b_blkno,bp->b_blkno);

	/* get master structure */

	mp = npcnxtab[NPUNIT(bp->b_dev)][NPCONN(bp->b_dev)].unit;

	/* make sure the boards ok */

	if (mp->flags & BADBOARD) {
		bp->b_flags |= B_ERROR;

		if(NpDebug & DEBMEM)
			printf("Bad Board %x bp %x\n",mp->flags,bp->b_flags);

		np_tab[mp->unit].b_actf = bp->av_forw;
		iodone(bp);
		return;
	}

	/* Initializations of request structure */

	while((rp = NpGetReq(mp->reqtab)) == NULL) {
		mp->reqtab->flags |= WANTREQ;
		sleep((caddr_t)(mp->reqtab),PZERO -1);
	}

	rp->bufoffset = 0;		/* This is the start of the buffer */
	ip = &np_tab[mp->unit];
	bp->av_forw = (struct buf *)0;
	bp->av_back = (struct buf *)rp;

	rp->flags |= KERNREQ;		/* Mark it as kernel so not to map */

	rp->mapbase = ubasetup(mp->devp->ui_ubanum,bp,0);
	rp->bufaddr = (caddr_t)((int)(rp->mapbase) & UBADDRMASK);

	s = spl5();
	if(ip->b_actf ==(struct buf *)0)
		ip->b_actf = bp;
	else {
		if(ip->b_actf->av_forw)
			printf("Panic NP100 bad buffer chain\n");
		ip->b_actf->av_forw = bp;
	}
	ip->b_actl = bp;

	NpAddReq(mp->reqtab,rp);		/* Queue onto active list */

	if(ip->b_active == 0) {

		if(NpDebug & DEBIO)
			printf("calling npstart %x\n",mp);

		npstart(mp);
	}
	splx(s);

	if(NpDebug & DEBIO)
		printf("back from npstart\n");

	/* Await completion of I/O */

	iowait(bp);

	if(NpDebug & DEBIO)
		printf("after iowait in npstrategy\n");

	/* Remove request from queue */

	NpRemReq(rp);

	/* Release mapping registers */

	ubarelse(mp->devp->ui_ubanum,&rp->mapbase);

	/* Free up request structure */

	NpFreeReq(mp->reqtab,rp);

	if(NpDebug & DEBENTRY)
		printf("Leaving npstrategy flags is %x\n",bp->b_flags);
}

unsigned
nptrim(bp)
register struct buf *bp;
{

	if(bp->b_bcount > NPMAXXFR)
		bp->b_bcount = NPMAXXFR;
}

/*
 * Npread dumps data from the board to the user's buffer
 */
npread(dev,uio)
dev_t dev;
struct uio *uio;
{

	if(NpDebug & DEBENTRY)
		printf("in npread\n");

	return(physio(npstrategy,&npcnxtab[NPUNIT(dev)][NPCONN(dev)].np_rbuf,dev,B_READ ,nptrim,uio));

}

/*
 * Npwrite loads the np100 board from the user's buffer
 */

npwrite(dev,uio)
dev_t dev;
struct uio *uio;
{
	struct buf *bp;
	bp = &npcnxtab[NPUNIT(dev)][NPCONN(dev)].np_wbuf;

	if(NpDebug & DEBENTRY)
		printf("in npwrite \n");

	return(physio(npstrategy,bp,dev,B_WRITE ,nptrim,uio));
}
/*

 * npreset - called as result of a UNIBUS reset.
 */

npreset(uban)
int uban;
{

	register struct npmaster *mp;
	register struct npreq *rp;
	register struct uba_device *ui;
	int i;

	for(i = 0; i < NNP; i++) {

		if(((ui = npdinfo[i]) == (struct uba_device *)NULL) ||
			(ui->ui_ubanum != uban))
			continue;

		mp = &npmasters[i];
		mp->iomapbase = 0;
		NpReset(mp,0);
	}
}

/*
 * Nppoll looks for work by polling each board. He goes to sleep if there are
 * no outstanding requests for him but reminds the board that he's there when
 * needed.
 */

NpPoll(mp,addr)
struct npmaster *mp;
caddr_t	addr;
{
	int error;

	struct {
		unsign16 request;
		unsign16 unit;
	}icpreq;

	if(NpDebug & DEBMAINT)
		printf("NpPoll: flags is %x.\n",mp->flags);

	while(TRUE) {

		for(mp = npmasters; mp; mp = mp->next) {

			if(mp->flags & BOARDREQ) {

				/* Get request type from master structure */

				if(mp->flags & BRDRESET) {
					icpreq.request = ICPPOLL;
					mp->reqtab->reqcnt--;

					if(NpDebug & DEBMAINT)
						printf("Waking NpResetter!\n");

					wakeup((caddr_t)(&mp->reqtab));
				}
				else if(mp->flags & PANICREQ)
					icpreq.request = ICPPANIC;
				else if(mp->flags & DUMPREQ)
					icpreq.request = ICPDUMP;
				else if(mp->flags & LOADREQ)
					icpreq.request = ICPLOAD;
				else {
					mp->flags &= ~BOARDREQ;
					continue;
				}

				if(NpDebug & DEBMAINT)
					printf("ProcICP servicing %d \n",icpreq.request );

				/* Request and unit number to be sent */

				icpreq.unit = mp->unit;

				/* Copy service request to calling process */

				error = copyout(&icpreq,addr,sizeof(icpreq));

				/* Mark Poller as being unavailable */

				NpState &= ~ICPAVAIL;

				return(error);
			}
		}

		/* Mark Poller as being available */

		NpState |= ICPAVAIL;

		sleep((caddr_t)&NpState, PZERO + 1);

		if(NpDebug & DEBMAINT)
			printf("wakeup in NpPoll\n");

	}
}

/*
 * Software initialization of Driver data structures for the specified unit.
 */

NpSWinit(unit)
int unit;
{

	register int j;
	register struct npmaster *mp;
	register struct npspace *npsp;
	register struct CmdQue *cqp;
	int offset;

	if(NpDebug & DEBINIT)
		printf("SW reset on unit %d.\n",unit);

	/* Initialize master structure pointer for this unit */

	mp = &npmasters[unit];

	/* Initialize unit buffer headers */

	np_tab[unit].b_active = 0;
	np_tab[unit].b_actf = 0;

	/* UBA device structure for this unit */

	mp->devp = npdinfo[unit];

	/* Interrupt vector for this unit */

	mp->vector = npvectors[unit];

	if(unit == (NNP -1))
		mp->next = (struct npmaster *)NULL;
	else mp->next = &npmasters[unit + 1];

	/*
	 * Guarantee alignment of shared memory area on a
         * 16 byte boundary as required by I-Board
	 */

	mp->shmemp = &npspaces[unit];
	mp->shmemp = (struct npspace *)ROUND16((int)(mp->shmemp));

	/* Base address of this controller */

	mp->iobase = (struct NPREG *)(mp->devp->ui_addr);

	if(NpDebug & DEBMEM) { 
		printf("Npspaces starts at %x.\n",npspaces);
		printf("Shared memory starts at %x.\n",mp->shmemp);
		printf("End of shared memory is %x.\n",&npspaces[unit + 1]);
		printf("Iobase is %x.\n",mp->iobase);
		printf("Npmasters start at %x\n",npmasters);
		printf("Reqhdr start at %x\n",reqhdr);
		printf("Npreqs start at %x\n",npreqs);
 	}

	/* Initialize the request header */

	mp->reqtab = &reqhdr[unit];

	/* Unit initialization */

	mp->unit = unit;

	/* Initialize Status Block */

	npsp = mp->shmemp;
	offset = (int) (mp->shmemp);

	npsp->statblock.sb_drw = 0;
	npsp->statblock.sb_hcw = HOSTCONF;
	npsp->statblock.sb_dcw = 0;
	npsp->statblock.sb_dpm = 0;

	npsp->statblock.sb_dcq = (unsign16)((int)(&npsp->devcq))-offset;

	npsp->statblock.sb_hcq = (unsign16)((int)(&npsp->hostcq))-offset;

	/* Initialize Device Command Queue */

	cqp = (struct CmdQue *) &npsp->devcq;

	if(NpDebug & DEBCQ) 
		printf("Device CQ at %x\n",cqp);

	cqp->scanflag = NPCLEAR;
	cqp->chngflag = NPCLEAR;

	cqp->cq_add = (unsign16)(int)(&cqp->cq_cqe[0]) - offset;
	cqp->cq_rem = cqp->cq_add;

	cqp->cq_wrap = (unsign16)(int)(&cqp->cq_cqe[NUMCQE]) - offset;

	for(j = 0; j < NUMCQE; j++)
		cqp->cq_cqe[j] = (unsign16)NULL;

	/* Initialize Host Command Queue */

	cqp = (struct CmdQue *) &npsp->hostcq;

	if(NpDebug & DEBCQ) 
		printf("HOST CQ at %x\n",cqp);

	cqp->scanflag = NPCLEAR;
	cqp->chngflag = NPCLEAR;

	cqp->cq_add = (unsign16)(int)(&cqp->cq_cqe[0]) - offset;
	cqp->cq_rem = cqp->cq_add;

	cqp->cq_wrap = (unsign16)(int)(&cqp->cq_cqe[NUMCQE]) - offset;

	for(j = 0; j < NUMCQE; j++)
		cqp->cq_cqe[j] = (unsign16)NULL;

	/*
	 * Initialize the reqid of the elements to the address
	 * of the corresponding Npreq structure. These don't change.
 	 */

	for(j = 0; j < NUMCQE; j++)
		npsp->elements[j].cqe_reqid = &npreqs[unit][j];

	/*
	 * Initialize the Request Header (reqhdr), free list of
 	 * npreqs, and pointers to CQEs.
 	 */

	reqhdr[unit].forw = reqhdr[unit].back = &reqhdr[unit];
	reqhdr[unit].free = &npreqs[unit][0];

	for(j = 0; j < NUMCQE; j++) {

		npreqs[unit][j].free = &npreqs[unit][j + 1];
		npreqs[unit][j].element = &npsp->elements[j];
		npreqs[unit][j].forw = npreqs[unit][j].back = (struct npreq *)NULL;
	}
	npreqs[unit][--j].free = &reqhdr[unit];

	/*
	 * Set up the UNIBUS I/O Map Registers for the
	 * Shared memory area.
 	 */

	mp->iomapbase = uballoc(mp->devp->ui_ubanum,(caddr_t)(mp->shmemp),sizeof(struct npspace),0);


	if(NpDebug & DEBENTRY)
		printf("SW_Init...\n");
}

/*
 * NpHWinit() issues a hardware reset to the specified board and waits
 * for on-board diagnostics to complete. It returns 0 if the board is
 * present and passed diagnostics, an error value otherwise.
 */

NpHWinit(unit)
int unit;
{
	register struct npmaster *mp;
	struct NPREG *REG;
	unsign16 status;
	int dflag;

	if(unit >= NNP)
		return(ENXIO);

	mp = &npmasters[unit];

	if(NpDebug & DEBENTRY)
		printf("NpHWinit\n");

	/* See if the board is out there */

	REG = (struct NPREG *)mp->iobase;

	if(NpDebug & DEBINIT)
		printf("REG in HWinit is %x.\n",mp->iobase);

	if(!(mp->flags & BRDRESET))

		if(badaddr(REG,2)) {
			mp->flags |= BADBOARD;
			printf("\nNP100 unit %d not found!\n",unit);
			return(ENXIO);
		}


#ifdef mc500
	if(setjmp(u.u_tsav) == 0) {
		u.u_nofault = TRUE;
		status = RCSR1(mp->iobase);
		u.u_nofault = FALSE;
	}
	else {
		np__addr[unit] = 0;
		mp->flags |= BADBOARD;
		u.u_error = ENXIO;
		printf("\nNP100 Unit %x not here!\n",unit);
		return(0);
	}
#endif

	if(NpDebug & DEBENTRY)
		printf("Resetting the NP100 Board at %x\n",mp->iobase);

	/* Reset the Board */

	RESET(mp);

	dflag = NPCLEAR;

	timeout(NpTimer,&dflag,DIAGTIME);

	/* Wait for Enable and Read Data Ready to go high */

	while(! ((RCSR1(mp->iobase) & NPENB) && (RCSR1(mp->iobase) & NPRDR))) {
		if(dflag)
			break;

	}

	untimeout(NpTimer,&dflag);

	if(NpDebug & DEBINIT)
		printf("np reset %d \n",dflag);

	if(dflag) {
		mp->flags |= BADBOARD;
		printf("NP100 Unit %d timed out!\n",unit);
		return(EIO);
	}

	status = RCSR0(mp->iobase);

	/* Check for Hardware OK */

	if(!(RCSR1(mp->iobase) & NPHOK)) {
		mp->flags |= BADBOARD;
		u.u_error = EIO;
		printf("NP100 Unit %d Failed diagnostics!\n",unit);
		printf("Status from CSR0: %x.\n",status);
		return(EIO);
	}

	if(NpDebug & DEBENTRY)
		printf("HWinit...\n");

	return(0);
}

/*
 * NP Driver Interrupt Handler
 */

npintr(unit)
int unit;
{
	register struct npmaster *mp;
	register struct buf	*bp;

	if(NpDebug & DEBENTRY)
		printf("npintr on unit %d!\n",unit);

	mp = &npmasters[unit];

	if(NpDebug & DEBINTR)
		printf("npintr mp->flags = %x\n",mp->flags);

	/* Wake up anyone sleeping on a CSR0 Command */

	if(mp->flags & CSRPEND) {

		mp->flags &= ~CSRPEND;
		if(np_tab[mp->unit].b_active) {
			np_tab[mp->unit].b_active = 0;
			bp = np_tab[mp->unit].b_actf;
			np_tab[mp->unit].b_actf = bp->av_forw;

			if(NpDebug & DEBINTR)
				printf("bp = %x resid = %d forw = %x\n",bp,
				    bp->b_resid,bp->av_forw);

			bp->b_resid = 0;
			iodone(bp);
		}
		if(mp->flags & PANIC3) {
			mp->flags &= ~PANIC3;
			mp->flags = AVAILABLE;
			ubarelse(mp->devp->ui_ubanum,&panicmap);
		}
		if(mp->flags & PANIC2) {
			mp->flags &= ~PANIC2;
			printf("Panic Message: %s",NpPbuf);
			mp->flags |= PANIC3;
			NpPbuf[0] = 0;
			NPIO(mp,(paddr_t)((int) panicmap & UBADDRMASK),(paddr_t)pstring,sizeof(NpPbuf),B_WRITE);
		}
		if(mp->flags & PANIC1) {
			mp->flags &= ~PANIC1;
			mp->flags |= PANIC2;
			ubarelse(mp->devp->ui_ubanum,&panicmap);
			panicmap = uballoc(mp->devp->ui_ubanum,(caddr_t)NpPbuf,sizeof(NpPbuf),0);
			pstring = (caddr_t)((panaddr[1] << 4) + panaddr[0]);
			NPIO(mp,(paddr_t)pstring,(paddr_t)((int) panicmap & UBADDRMASK),sizeof(NpPbuf),B_READ);
		}

		wakeup((caddr_t)mp);
		goto out;
	}

	/* Mark unit as being available if Device Protocol Mask set */

	if(!(mp->flags & AVAILABLE)) {

		if((mp->shmemp->statblock.sb_dpm) && (!(mp->flags & BRDRESET))){

			mp->flags = AVAILABLE;
			printf("\nNP100 unit #%d available!\n",mp->unit);
		}
	}

	/* Honor service requests from the device */

	switch(mp->shmemp->statblock.sb_drw) {

	    case NOREQ:
		break;

	    case NPPANIC:

		printf("\nPanic from NP100 unit %d!\n",mp->unit);
		mp->flags &= ~AVAILABLE;
		mp->flags |= PANIC1;

		/* Clear device request word */

		mp->shmemp->statblock.sb_drw = 0;

		panicmap = uballoc(mp->devp->ui_ubanum,(caddr_t)panaddr,sizeof(panaddr),0);
		NPIO(mp,(paddr_t)NPPSADDR,(paddr_t)((int)panicmap & UBADDRMASK),sizeof(panaddr),B_READ);
		goto out;
		break;

	    case NPDUMP:
		mp->flags |= (DUMPREQ | BOARDREQ);

		/* Clear device request word */

		mp->shmemp->statblock.sb_drw = 0;

		if(NpState & ICPAVAIL)
			wakeup((caddr_t)&NpState);
		break;

	    case NPLOAD:
		mp->flags |= (LOADREQ | BOARDREQ);

		/* Clear device request word */

		mp->shmemp->statblock.sb_drw = 0;

		if(NpState & ICPAVAIL)
			wakeup((caddr_t)&NpState);
		break;

	    default:
		printf("Bad Req: %x.\n",mp->shmemp->statblock.sb_drw);
		goto out;

	}

 	/* Process the Host Command Queue for this device */

	NpProcQueue(mp);

out:
	CLEARINT(mp);	/* Clear the interrupt */

	if(NpDebug & DEBENTRY)
		printf("npintr...\n");

	return(1);	/* Interrupt serviced */

}

/*
 * This routine, called from the interrupt handler, is used to process the
 * Host Command Queue for the specified device.
 */

NpProcQueue(mp)
struct npmaster *mp;
{
	register struct CmdQue *cqp;
	register struct CQE *ep;
	register struct npreq *rp;
	register int base;

	if(NpDebug & DEBENTRY)
		printf("NpProcQueue\n");

	cqp = &mp->shmemp->hostcq;	/* Command Queue pointer */

	if(cqp->scanflag & ON)
            	return;

	else cqp->scanflag | = ON;

	base = (int)mp->shmemp;		/* Shared memory base address */

	while(cqp->scanflag & ON) {

		while(ep = NpRemCQE(cqp,base)) {

			rp = ep->cqe_reqid;

			if(NpDebug & DEBCQE)
				printf("cqe_sts is %x ep = %x\n",ep->cqe_sts,ep);

			switch (ep->cqe_sts)  {

			    case NPDONE:
				rp->flags |= REQDONE;	/* Normal completion */
				break;
			    case NPIFC:			/* IFC Request */
				rp->flags |= IOIFC;
				break;
			    case NPPERR:		/* Protocol Error */
				rp->flags |= (NPPERR | REQDONE);
				break;
			    case NPMERR:		/* Memory allocation */
				rp->flags |= (NPMERR | REQDONE);
				break;
			    default:			/* Error on Board */
				rp->flags |= (IOERR | REQDONE);
				break;

			}

			if(NpDebug & DEBCQE) {
				printf("flag is %x reqid = %x\n",rp->flags,ep->cqe_reqid);
				printf("wakeup in procqueue\n");
			}

			if(rp->intr) {

				if(NpDebug & DEBINTR)
					printf("calling usr intr at %x\n",
						rp->intr);

				/* Call interrupt routine */

				(*rp->intr)(mp,rp);

			}
			else {

			if(NpDebug & DEBINTR)
				printf("waking up %x\n",rp);

				if(rp->flags & NPUIO)
					iodone(&rp->buf);
				else	wakeup((caddr_t) (rp)); /* Awaken */

			if(NpDebug & DEBINTR)
				printf("AWAKE\n");
			}

		}

		if(!(cqp->chngflag & ON))
			cqp->scanflag &= ~ON;

	}

	if(NpDebug & DEBENTRY)
		printf("NpProcQueue...\n");
}

/*
 * NpIFC - processes an IFC (Internal Fuction Call) request 
 *		NOTE: this function must be called from the user context
 *			on all virtual pageing systems
 *
 */
NpIFC(mp,rp)
register struct npmaster *mp;
register struct npreq *rp;
{
	register struct CQE	*ep;

	if(NpDebug & DEBENTRY)
		printf("NpIFC\n");

	ep = rp->element;
	rp->flags &= ~IOIFC;
	switch(ep->cqe_func) {

	    case NPUNLOCK:	/* Unlock process, free up mapping registers  */

		if(NpDebug & DEBIFC)
			printf("NPUNLOCK\n");

		if(rp->mapbase)
			NpUnMapMem(mp,rp);
		break;

	    case NPLOCK:	/* Lock process, get mapping registers */

		if(NpDebug & DEBIFC)
			printf("NPLOCK\n");
		NpMapMem(mp,rp,rp->virtmem,rp->bytecnt);
		ep->cqe_dma[0] = LOWORD(rp->bufaddr);
		ep->cqe_dma[1] = HIWORD(rp->bufaddr);
		break;

	    case NPREMAP:

		if(NpDebug & DEBIFC)
			printf("NPREMAP\n");

		/* Remap user buffer and update buffer offset */
#ifdef USG
		np_remapmem(rp,rp->virtmem); 
		ep->cqe_dma[0] = LOWORD(rp->bufaddr);
		ep->cqe_dma[1] = HIWORD(rp->bufaddr);
		break;
#endif

	    default:
		if(NpDebug & DEBIFC)
			printf("Bad case %x in IFC\n", ep->cqe_func);

		rp->flags |= (REQDONE | IOERR);
		break;
	}
}

/*
 * The following contains various routines for allocating and deallocating
 * structures used by the NP Driver. Routines are also here for addding
 * and removing Command Queue Elements from a Command Queue.
 */

/*
 * Get a free NP Request structure from the list pointed to by head. Returns
 * a pointer to a npreq or NULL if none left.
 */

struct npreq *
NpGetReq(head)
struct npreq *head;
{

	register struct npreq *p;

	p = head->free;
	head->free = p->free;
	return(p==head ? (struct npreq *)NULL : p);
}

/*
 * Return a NP Request structure to the free list pointed to by head.
 */

NpFreeReq(head,nprp)
register struct npreq *head, *nprp;
{

	if(NpDebug & DEBREQ)
		printf("NpFreeReq, head is %x rp is %x\n",head,nprp);

	nprp->forw = nprp->back = (struct npreq *)NULL;
	nprp->free = head->free;
	head->free = nprp;

	/* Wake up any processes waiting for a request structure */

	if(head->flags & WANTREQ) {
		head->flags &= ~WANTREQ;
		wakeup((caddr_t)head);
	}

	if(NpDebug & DEBENTRY)
		printf("NpFreeReq...\n");
}

/*
 * Add a Command Queue Element onto the specified Command Queue and
 * update its Add offset.
 */

NpAddCQE(ep,cqp,mp)
struct CQE *ep;
struct CmdQue *cqp;
struct npmaster *mp;
{

	register unsign16 *temp;
	register unsign16 cqe_offset;
	register int base;

	base = (int)mp->shmemp;		/* Shared memory base address */

	temp = (unsign16 *)(base + cqp->cq_add); /* Offset to add element */

	cqe_offset = (unsign16)((int)ep - base);

	if(*temp) {			/* Should never happen */

		printf("No more room on Command Queue!\n");
		u.u_error = EIO;
		return;
	}
	else *temp = cqe_offset;	/* Enter this request's offset */

	cqp->chngflag |= ON;		/* Set change flag unconditionally */

	/* Update cqe_add where next request is to be added */

	cqp->cq_add += sizeof(unsign16);

	if(cqp->cq_add == cqp->cq_wrap)	/* Wrap if necessary */
		cqp->cq_add = (unsign16)((int)cqp->cq_cqe - base);

	/* Interrupt the Board if his scan flag isn't on */

	if(!(cqp->scanflag & ON))

		INTNI(mp);		/* Interrupt the Board */

}

/*
 * The NpRemCQE routine is used to remove the next CQE from the Command Queue
 * specified by cqp. The common offset of shared memory used by the device
 * is specified by base. NpRemCQE returns a pointer to the next CQE or
 * NULL if there are none left. This routine will also update the cqe_rem
 * offset which specifies where the next element to be removed from the
 * queue is located.
 */

struct CQE *
NpRemCQE(cqp,base)
struct CmdQue *cqp;
int base;
{

	register unsign16 *temp;
	register unsign16 cqe_offset;

	cqp->chngflag &= ~ON;			/* Turn off unconditionally */

	/* Get address of element to remove */

	temp = (unsign16 *)(base +cqp->cq_rem);

	if(*temp == NULL)			/* If none left, go home */
		return((struct CQE *) NULL);

	else cqe_offset = *temp;		/* Offset of CQE to remove */

	/* Update the Command Queue's cqe_rem offset */

	*temp = NULL;				/* Clear out this entry */

	cqp->cq_rem += sizeof(unsign16);	/* Bump offset */

	if(cqp->cq_rem == cqp->cq_wrap)		/* Wrap if necessary */
		cqp->cq_rem = (unsign16)((int)cqp->cq_cqe - base);

	temp = (unsign16 *)(base + cqe_offset);	/* CQE address */
	return((struct CQE *)temp);		/* is returned */
}

/*
 * NpAddReq will add the specified npreq structure to the queue controlled
 * by head.
 */

NpAddReq(head,rp)
register struct npreq *head, *rp;
{

	if(NpDebug & DEBENTRY)
		printf("NpAddReq\n");

	if(NpDebug & DEBREQ)
		printf("NpAddReq: %x\n",rp);

	rp->forw = head->forw;
	rp->forw->back = rp;
	rp->back = head;
	head->forw = rp;

	if(NpDebug & DEBENTRY)
		printf("NpAddReq...\n");
}

/*
 * NpRemReq is used to remove a npreq structure from the queue specified by
 * head.
 */

NpRemReq(rp)
register struct npreq *rp;
{

	if(NpDebug & DEBENTRY)
		printf("NpRemReq\n");

	if(NpDebug & DEBREQ)
		printf("NpRemReq: %x\n",rp);

	rp->back->forw = rp->forw;
	rp->forw->back = rp->back;

	if(NpDebug & DEBENTRY)
		printf("NpRemReq...\n");
}


/*
 * The following routines are used to communicate with the
 * NI Hardware via the CSR0 commands. These commands are issued during
 * the hardware initializtion process and may also be used subsequently
 * by privileged processes who wish to communicate in this way. The
 * convention for passing data as a Command Block is discussed in detail
 * in the NI1510 UNIBUS Compatible Ethernet Communications Processor
 * Hardware Specification.
 */

NpSendCSR0(iobase,src,bcount)
struct NPREG *iobase;
register unsign16 *src;
int bcount;
{
	register int wcount;
	int i;
	int csrflag;
	unsign16 tmp;

	if(NpDebug & DEBENTRY)
		printf("NpSendCSR0\n");

	/* Jolt the board into CSR0 command mode if necessary */

	if(!(RCSR1(iobase) & NPENB)){   
		tmp = NPCLEAR;		/* MC68000 clr reads before writing */
		WCSR0(iobase,tmp); 	
	}

	wcount = (bcount +1) >> 1;	/* Convert byte count to word count */

	/* Clear timer flag before beginning the timer */

	csrflag = NPCLEAR;
	timeout(NpTimer,&csrflag,DIAGTIME);

	for(i = 0; (i < wcount) & (csrflag == NPCLEAR); i++) {
		while(! ((RCSR1(iobase) & NPENB) && (RCSR1(iobase) & NPRDY)))
			if(csrflag) break;
		WCSR0(iobase,*src);
		src++;			/* Better do this WCSR is a macro */
	}

	/* Clear the timer entry */

	untimeout(NpTimer,&csrflag);

	/* Error if timer went off */

	if(csrflag)
		return(EIO);	

	if(NpDebug & DEBENTRY)
		printf("NpSendCSR0...\n");
	return(0);
}

/*
 * NpSetIntLev sets the UNIBUS interrupt vector to be used by the NP board when
 * interupting the host. The board is specified by mp.
 */

NpSetIntLevel(mp,level)
struct npmaster *mp;
int level;
{

	struct {
		unsign16 cmd_word;
		unsign16 int_level;
	}cmd_block;

	cmd_block.cmd_word = NPCBI | CBICNT;
	cmd_block.int_level = level;

	return(NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block)));
}

/*
 * NpSetMemAddr is used to declare the shared memory area address to be used
 * for communication between the driver and the device. This address is used
 * to access data structures by acting as a base from which defined offsets
 * locate data. The board is specified by mp.
 */

NpSetMemAddr(mp,addr)
struct npmaster *mp;
caddr_t addr;
{

	caddr_t shmaddr;
	int error;

	struct {
		unsign16 cmd_word;
		unsign16 hi_addr;
		unsign16 lo_addr;
	} cmd_block;

	if(NpDebug & DEBENTRY)
		printf("NpSetMemAddr\n");

	shmaddr = addr;

	if(NpDebug & DEBMEM)
		printf("NpSetMemAddr, addr is %x shmaddr is %x.\n",addr,shmaddr);

	cmd_block.cmd_word = NPCMD | CMDCNT;
	cmd_block.hi_addr = HIWORD(shmaddr);
	cmd_block.lo_addr = LOWORD(shmaddr);

	error = NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block));

	if(NpDebug & DEBENTRY)
		printf("NpSetMemAddr...\n");

	return(error);
}


/*
 * NpSetXeqAddr specifies the address at which the board should begin
 * execution of its on-board software. It also indicates the shared memory
 * address to be used. The board is specified by mp.
 */

NpSetXeqAddr(mp,addr)
struct npmaster *mp;
caddr_t addr;
{
	caddr_t shmaddr;
	int error;

	struct {
		unsign16 cmd_word;
		unsign16 hi_addr;
		unsign16 lo_addr;
		unsign16 mhi_addr;
		unsign16 mlo_addr;
	} cmd_block;

	if(NpDebug & DEBENTRY)
		printf("NpSetXeqAddr\n");

	shmaddr = (caddr_t)((int)mp->iomapbase & UBADDRMASK);

	cmd_block.cmd_word = NPBGN | NPCMD | NPLST | (BGNCNT + CMDCNT);
	cmd_block.hi_addr = HIWORD(addr);
	cmd_block.lo_addr = LOWORD(addr);
	cmd_block.mhi_addr = HIWORD(shmaddr);
	cmd_block.mlo_addr = LOWORD(shmaddr);

	if(NpDebug & DEBINIT) {
		printf("NpSetXeqAdddr: hi: %x lo: %x\n",HIWORD(addr), LOWORD(addr));
		printf("NpSetXeqAdddr: mhi: %x mlo: %x\n",HIWORD(shmaddr),LOWORD(shmaddr));
	}

	error = NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block));

	if(NpDebug & DEBENTRY)
		printf("NpSetXeqAddr...\n");

	return(error);
}

/*
 * NPIO issues a CSR0 load or dump request to the I-Board after packaging a
 * CSR0 Command Block.
 */

NPIO(mp,src,dest,count,dir)
struct npmaster *mp;
paddr_t dest;
paddr_t src;
unsign16 count;
int dir;		/* Direction  READ/WRITE */
{

	int error;

	struct {
		unsign16 cmd_word;	/* Command Word */
		unsign16 shi_addr;	/* High word of Source Address */
		unsign16 slo_addr;	/* Low word of Source Address */
		unsign16 dhi_addr;	/* High word of Destination Address */
		unsign16 dlo_addr;	/* Low word of Destination Address */
		unsign16 count;		/* Byte count */
		unsign16 intlevel;	/* Interrupt level to host */
	} cmd_block;

	if(NpDebug & DEBENTRY)
		printf("NPIO\n");
	if(NpDebug & DEBMAINT) {
		printf("I/O src addr = %x, dest addr = %x \n",src,dest);
		printf("I/O count = %d \n",count);
	}

	cmd_block.cmd_word = NPCBI | NPLST | (CBICNT + IOCNT);
	cmd_block.intlevel = mp->vector;
	cmd_block.shi_addr = HIWORD(src);
	cmd_block.slo_addr = LOWORD(src);
	cmd_block.dhi_addr = HIWORD(dest);
	cmd_block.dlo_addr = LOWORD(dest);
	cmd_block.count = count;
	if(dir == B_READ)
		cmd_block.cmd_word |= NPDMP;
	else
		cmd_block.cmd_word |= NPLD;


	if(NpDebug & DEBIO) {
		printf("cmd: %x int: %o shi: %x slo: %x dhi: %x dlo: %x cnt: %x\n",
	cmd_block.cmd_word,cmd_block.intlevel,cmd_block.shi_addr,cmd_block.slo_addr,
	cmd_block.dhi_addr,cmd_block.dlo_addr,cmd_block.count);
	}
	
	mp->flags |= CSRPEND;		/* CSR0 command pending */

	error = NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block));
	if(NpDebug & DEBENTRY)
		printf("NPIO...\n");

	return(error);
}


/*
 * NpKill will terminate all outstanding requests for the specified board.
 */

NpKill(mp,curr_rp)
struct npmaster *mp;
struct npreq *curr_rp;
{
	struct npreq *rp;
	int s;

	if(NpDebug & DEBENTRY)
		printf("NpKill\n");

	mp->reqtab->reqcnt = 0;		/* Init request count */

	s = spl4();			/* Disable interrupts */

	/* Mark each active request as having an error and wake him up */

	for(rp = mp->reqtab->forw;rp != mp->reqtab;rp = rp->forw) {

		if(rp == curr_rp) continue;

		rp->flags |= (IOABORT | REQDONE);
		mp->reqtab->reqcnt++;
		if(rp->flags & NPUIO)
			iodone(&rp->buf);
		else wakeup((caddr_t)rp);
	}

	if(NpDebug & DEBMAINT)
		printf("NpKill, req count is %d\n",mp->reqtab->reqcnt);

	splx(s);

	if(NpDebug & DEBENTRY)
		printf("NpKill...\n");

	return(0);

}

/* Hardware and Software Initializations for the specified unit */

NpReset(mp,rp)
register struct npmaster *mp;
struct npreq *rp;
{
	int error;

	if(NpDebug & DEBENTRY)
		printf("NpReset!\n");

	/* Mark board as being reset and make unavailable */

	mp->flags = BRDRESET;

	/* Abort outstanding requests for this board */

	mp->reqtab->reqcnt = 0;		/* Init request count */

	/* Wakeup Poller if available and wait until he's gone */

	if(NpState & ICPAVAIL) {

		mp->flags |= BOARDREQ;
		mp->reqtab->reqcnt++;

		if(NpDebug & DEBMAINT)
			printf("Waking ICP in reset!\n");

		wakeup((caddr_t)&NpState);

		while(mp->reqtab->reqcnt)
			sleep((caddr_t)(&mp->reqtab),PZERO +1);

		if(NpDebug & DEBMAINT)
			printf("Reset:awoken by ICP senior!\n");

	}

	/* Abort outstanding requests and wait till they're gone */

	NpKill(mp,rp);

	while(mp->reqtab->reqcnt) {

		if(NpDebug & DEBMAINT) {
			printf("Sleeping in NpReset on reqtab!\n");
			printf("Reqcnt is %d.\n",mp->reqtab->reqcnt);
		}

		sleep((caddr_t)(&mp->reqtab),PZERO +1);

	}

	/* Free up I/O Map registers if any allocated */

	if(mp->iomapbase) {

		if(NpDebug & DEBMEM)
			printf("freeing shared memory map.\n");

		ubarelse(mp->devp->ui_ubanum,&mp->iomapbase);
		mp->iomapbase = 0;
	}

	/* Initialize S/W data structures in NP Driver */

	NpSWinit(mp->unit);		/* Software initialization */

	/* Hardware initialization of the board */

	error = NpHWinit(mp->unit);	/* Hardware initialization */

	mp->flags &= ~BRDRESET;		/* Initialization complete */

	/* Initialize Pseudo-Drivers */

	WnInitFlag = 0;			/* WN Pseudo-Driver */
	IsInitFlag = 0;			/* IS Pseudo-Driver */

	if (IxReset)
		(*IxReset)(mp->unit, mp->devp->ui_ubanum, rp);

	/* Clear Poller's State Flag */

	NpState = NPCLEAR;

	if(NpDebug & DEBENTRY)
		printf("NpReset...\n");
	
	return(error);
}

/*
 * General purpose timeout function which sets the flag passed to it
 * as argument.
 */

NpTimer(flagp)
int *flagp;
{
	*flagp = NPSET;
}

NpStats()
{
	if(NpDebug & DEBENTRY)
		printf("npstats\n");
	return(0);
}

/*
 * NpCloseConn is called to issue a close connection command to the I-Board.
 */

NpCloseConn(mp,protocol)
struct npmaster *mp;
unsign16 protocol;
{

	register struct npreq *rp;
	register struct CQE *ep;
	int pri;

	if(NpDebug & DEBENTRY)
		printf("NpCloseConn\n");

	/*
	 * Don't issue the Close Connection command if the Board
         * isn't up.
         */

	if(!((mp->shmemp->statblock.sb_dpm) & PROTOMASK(protocol))) {
		return;
	}

	/* Get a Request structure */

	while((rp = NpGetReq(mp->reqtab)) == NULL) {
		mp->reqtab->flags |= WANTREQ;
		sleep((caddr_t)(mp->reqtab),PZERO -1);
	}

	rp->intr = (int (*)())0;	/* Do not call interrupt routine */
	rp->flags = NPCLEAR;
	rp->mapbase = 0;		/* Clear mapping information */

	ep = rp->element;		/* Handy pointer */

	/* Fill in CQE */

	ep->cqe_wind = 0;		/* Entire buffer mapped */
	ep->cqe_nbuf = 1;		/* Must be 1, no buffer chaining */
	ep->cqe_char = 0;		/* Set to 0 for now */

	ep->cqe_func = NPSTOP;		/* OS_STP to I-Board */

	ep->cqe_prot = protocol;	/* Protocol of this connection */
	ep->cqe_lenrpb = 0;		/* Parameter block length */

	ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR;	/* Clear status flags */

	ep->cqe_famid = (unsign32)u.u_procp->p_pid;  /* Process ID */

	NpAddReq(mp->reqtab,rp);	/* Queue onto active list */

	pri = spl4();			/* Mask our interrupts */

	NpAddCQE(ep,&mp->shmemp->devcq,mp); /* Add CQE to device's queue */

	/* Wait for command to complete */

	while(!(rp->flags & REQDONE)) 
		sleep((caddr_t)rp,PZERO - 1);

	splx(pri);

	NpRemReq(rp);			/* Remove request from active list */

	NpFreeReq(mp->reqtab,rp);	/* Deallocate request structure */

	if(NpDebug & DEBENTRY)
		printf("NpCloseConn...\n");

}

/*
 * This function allows the protocol to be changed for a given connection.
 * It returns 0 for success, error code otherwise.
 */

NpProtChange(protocol,unit)
register unsign16 protocol;
register int unit;
{

	register struct npmaster *mp;

	/* Privileged users only for Maintenance Protocol */

	if((protocol == NPMAINT) && (u.u_uid != 0)) 
		return(EPERM);

	if(NpDebug & DEBMAINT)
		printf("NpProtChange = %x\n",protocol);

	if(protocol != NPMAINT) {

		/* Make sure the I-Board supports the protocol */

		mp = &npmasters[unit];

		if(!((mp->shmemp->statblock.sb_dpm) & PROTOMASK(protocol)))
			return(ENXIO);
	}

	return(0);
}

/*
 * This function allows for the changing of the unit for a given connection.
 */

struct npmaster *
NpBoardChange(protocol,unit)
register unsign16 protocol;
register int unit;			/* Unit number */
{
	register struct npmaster *mp;


	if(unit > NNP)
		return((struct npmaster *)0);

	if(protocol != NPMAINT) {

		/*
		 * Loop through the master structures finding a board which 
		 * supports the requested protocol.
		 */

		for(mp = npmasters; mp ; mp = mp->next) {

			if(mp->flags & BADBOARD)
				continue;

			if(((mp->shmemp->statblock.sb_dpm) & PROTOMASK(protocol)))
				return(mp);
		}
		return((struct npmaster *)0);
	}
	return(&npmasters[unit]);
}

/*
 * NpMapMem - maps the user's memory updating the fields in the npreq
 * structure and returning the mapped address in rp->buffaddr.
 */
NpMapMem(mp,rp,addr,count)
register struct npmaster *mp;
register struct npreq *rp;
caddr_t	addr;
int	count;
{

	if(NpDebug & DEBENTRY)
		printf("NpMapMem\n");
	if(NpDebug & DEBIO)
		printf("mp %x rp %x addr %x count %x\n",mp,rp,addr,count);

	rp->virtmem = addr;
	rp->bytecnt = count;

	rp->buf.b_un.b_addr = addr;
	rp->buf.b_flags = B_PHYS | B_BUSY;
	rp->buf.b_bcount = count;
	rp->buf.b_proc = rp->procp;
		
	rp->procp->p_flag |= SPHYSIO;
	vslock(addr,count);

	rp->mapbase = ubasetup(mp->devp->ui_ubanum,&rp->buf,0);

	rp->bufaddr = (caddr_t)(rp->mapbase & UBADDRMASK);

	if(NpDebug & DEBENTRY)
		printf("NpMapMem...\n");
}

/*
 * Unmap the user's memory and free up mapping registers 
 */

NpUnMapMem(mp,rp)
struct npmaster *mp;
struct npreq *rp;
{
	if(NpDebug & DEBENTRY)
		printf("NpUnMapMem\n");

	ubarelse(mp->devp->ui_ubanum,&rp->mapbase);
	rp->mapbase = 0;
	vsunlock(rp->virtmem,rp->bytecnt,B_READ);
	rp->procp->p_flag &= ~SPHYSIO;

	if(NpDebug & DEBENTRY)
		printf("NpUnMapMem...\n");
}

npprobe(reg, ui)
caddr_t reg;
struct uba_device *ui;
{
register int br,cvec;
u_short csraddr;
int i;

#ifdef lint
	br = 0; cvec = br; br = cvec;
#endif

	if(NpDebug & DEBINIT)
		printf("In npprobe, regaddr is %x!\n",reg);

	cvec = (uba_hd[numuba].uh_lastiv -= 4); 

#ifdef OLDBSD4_2
	/* Find unit number from npstd[] by matching the csr address */

	csraddr = (u_short)((int)reg & 0x0FFFF);

	for(i = 0; i < NNP; i++) {

		if(csraddr == npstd[i]) {
			npvectors[i] = cvec;
			break;
		}
	}
	if(i == NNP)
		printf("Couldn't find device in npstd[]!\n");
#else
	npvectors[ui->ui_unit] = cvec;
#endif
	br = 0x15;

	if(NpDebug & DEBINIT)
		printf("npprobe...\n");

	return(sizeof(struct NPREG));		/* CSR Registers */

}

npattach(ui)
register struct uba_device *ui;
{

	if(NpDebug & DEBINIT)
		printf("In npattach, ui is %x.\n",ui);

	npinit(ui->ui_unit);

	if (IxAttach)
		(*IxAttach)(ui);

	if(NpDebug & DEBINIT)
		printf("npattach...\n");
}

#endif