* 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 6.2 (Berkeley) %G%
/******************************************
******************************************/
* 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 "../vaxuba/ubavar.h"
#include "../vaxuba/npreg.h"
* Global variables for pseudo-drivers.
/* Driver Wide State used by the ICP */
* 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
};
* External function and data structure declarations.
struct npreq
* NpGetReq();
struct npmaster
*NpBoardChange();
* Np_init() is responsible for hardware initializiation and the software
* initialization of the connection table and driver software data structures.
/* Software Initialization */
npmasters
[unit
].flags
= NPCLEAR
;
/* Hardware Initialization */
/* Connection Table Initialization */
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.
/* Make sure it's the superuser */
/* Get the connection identifier */
if(((conn
= NPCONN(dev
)) >= NNPCNN
) ||
((unit
= NPUNIT(dev
)) >= NNP
))
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
;
* Np_close is responsible updating the connection table for
* that connection by marking it closed.
/* Get the connection identifier */
npcnxtab
[NPUNIT(dev
)][NPCONN(dev
)].protocol
= NPCLCONN
;
* 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).
npioctl(dev
,cmd
,addr
,flag
)
register struct npmaster
*mp
;
register struct npreq
*rp
;
/* Strip off IOC_VOID bit */
/* Get connection identifier */
/* 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);
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
)))
printf("arg = %x\n",usrarg
);
/* Execute the specified command */
if((error
= NpProtChange(usrarg
,mp
->unit
)) == 0)
npcnxtab
[unit
][conn
].protocol
= usrarg
;
if(mp
= NpBoardChange(protocol
,usrarg
))
npcnxtab
[unit
][conn
].unit
= mp
;
mp
= npcnxtab
[unit
][conn
].unit
;
error
= NpSWinit(mp
->unit
);
* Kludge to work around I-Board boot from Host. Read two bytes
* from the board into the Device Configuration Word
NPIO(mp
,(paddr_t
)0x500,(paddr_t
)(&mp
->shmemp
->statblock
.sb_dcw
),2,B_READ
);
mp
->shmemp
->statblock
.sb_drw
= 0;
/* Set the Address at which to begin On-Board execution */
error
= NpSetXeqAddr(mp
,(caddr_t
)usrarg
);
error
= copyout((caddr_t
)NpPbuf
,*addr
,PANLEN
);
/* Clear panic request flag and leave */
error
= NpPoll(mp
,*addr
);
error
= NpSetMemAddr(mp
,*addr
);
usrarg
= RCSR0(mp
->iobase
);
error
= copyout((caddr_t
)&usrarg
,*addr
,sizeof(usrarg
));
usrarg
= RCSR1(mp
->iobase
);
error
= copyout((caddr_t
)&usrarg
,*addr
,sizeof(usrarg
));
usrarg
= RCSR2(mp
->iobase
);
error
= copyout((caddr_t
)&usrarg
,*addr
,sizeof(usrarg
));
usrarg
= RCSR3(mp
->iobase
);
error
= copyout((caddr_t
)&usrarg
,*addr
,sizeof(usrarg
));
WCSR0(mp
->iobase
,usrarg
);
WCSR1(mp
->iobase
,usrarg
);
WCSR2(mp
->iobase
,usrarg
);
WCSR3(mp
->iobase
,usrarg
);
error
= NpSetIntLevel(mp
,mp
->vector
);
error
= NpSetXeqAddr(mp
,(caddr_t
)INETBOOT
);
printf("Bad Maintenance command: %d!\n",cmd
);
if((cmd
!= NPRESET
) && (cmd
!= NPINIT
))
NpFreeReq(mp
->reqtab
,rp
);
* np_start - start io activity
register struct npmaster
*mp
;
register struct npreq
*rp
;
int error
; /* Return from NPIO call */
if((bp
= np_tab
[mp
->unit
].b_actf
) == (struct buf
*)0) {
np_tab
[mp
->unit
].b_active
= 0;
if((rp
= (struct npreq
*)(bp
->av_back
)) == (struct npreq
*)0) {
np_tab
[mp
->unit
].b_active
= 1;
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 */
error
= NPIO(mp
,(paddr_t
)((long)bp
->b_blkno
<< DEV_BSHIFT
),(paddr_t
)(rp
->bufaddr
),
bp
->b_bcount
,(bp
->b_flags
& B_READ
));
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 */
np_tab
[mp
->unit
].b_actf
= bp
->av_forw
;
printf("NPIO return error: b_flags is %x \n",bp
->b_flags
);
* npstratagey - the strategy routine
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 */
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
) {
printf("Bad Board %x bp %x\n",mp
->flags
,bp
->b_flags
);
np_tab
[mp
->unit
].b_actf
= bp
->av_forw
;
/* 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 */
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
);
if(ip
->b_actf
==(struct buf
*)0)
printf("Panic NP100 bad buffer chain\n");
ip
->b_actf
->av_forw
= bp
;
NpAddReq(mp
->reqtab
,rp
); /* Queue onto active list */
printf("calling npstart %x\n",mp
);
printf("back from npstart\n");
/* Await completion of I/O */
printf("after iowait in npstrategy\n");
/* Remove request from queue */
/* Release mapping registers */
ubarelse(mp
->devp
->ui_ubanum
,&rp
->mapbase
);
/* Free up request structure */
NpFreeReq(mp
->reqtab
,rp
);
printf("Leaving npstrategy flags is %x\n",bp
->b_flags
);
if(bp
->b_bcount
> NPMAXXFR
)
* Npread dumps data from the board to the user's buffer
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
bp
= &npcnxtab
[NPUNIT(dev
)][NPCONN(dev
)].np_wbuf
;
return(physio(npstrategy
,bp
,dev
,B_WRITE
,nptrim
,uio
));
* npreset - called as result of a UNIBUS reset.
register struct npmaster
*mp
;
register struct npreq
*rp
;
register struct uba_device
*ui
;
for(i
= 0; i
< NNP
; i
++) {
if(((ui
= npdinfo
[i
]) == (struct uba_device
*)NULL
) ||
* 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
printf("NpPoll: flags is %x.\n",mp
->flags
);
for(mp
= npmasters
; mp
; mp
= mp
->next
) {
if(mp
->flags
& BOARDREQ
) {
/* Get request type from master structure */
if(mp
->flags
& BRDRESET
) {
icpreq
.request
= ICPPOLL
;
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
;
printf("ProcICP servicing %d \n",icpreq
.request
);
/* Request and unit number to be sent */
/* Copy service request to calling process */
error
= copyout(&icpreq
,addr
,sizeof(icpreq
));
/* Mark Poller as being unavailable */
/* Mark Poller as being available */
sleep((caddr_t
)&NpState
, PZERO
+ 1);
printf("wakeup in NpPoll\n");
* Software initialization of Driver data structures for the specified unit.
register struct npmaster
*mp
;
register struct npspace
*npsp
;
register struct CmdQue
*cqp
;
printf("SW reset on unit %d.\n",unit
);
/* Initialize master structure pointer for this unit */
/* Initialize unit buffer headers */
np_tab
[unit
].b_active
= 0;
/* UBA device structure for this unit */
mp
->devp
= npdinfo
[unit
];
/* Interrupt vector for this unit */
mp
->vector
= npvectors
[unit
];
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
);
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 */
/* Initialize Status Block */
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
;
printf("Device CQ at %x\n",cqp
);
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
;
printf("HOST CQ at %x\n",cqp
);
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
mp
->iomapbase
= uballoc(mp
->devp
->ui_ubanum
,(caddr_t
)(mp
->shmemp
),sizeof(struct npspace
),0);
* 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.
register struct npmaster
*mp
;
/* See if the board is out there */
REG
= (struct NPREG
*)mp
->iobase
;
printf("REG in HWinit is %x.\n",mp
->iobase
);
if(!(mp
->flags
& BRDRESET
))
printf("\nNP100 unit %d not found!\n",unit
);
if(setjmp(u
.u_tsav
) == 0) {
status
= RCSR1(mp
->iobase
);
printf("\nNP100 Unit %x not here!\n",unit
);
printf("Resetting the NP100 Board at %x\n",mp
->iobase
);
timeout(NpTimer
,&dflag
,DIAGTIME
);
/* Wait for Enable and Read Data Ready to go high */
while(! ((RCSR1(mp
->iobase
) & NPENB
) && (RCSR1(mp
->iobase
) & NPRDR
))) {
untimeout(NpTimer
,&dflag
);
printf("np reset %d \n",dflag
);
printf("NP100 Unit %d timed out!\n",unit
);
status
= RCSR0(mp
->iobase
);
/* Check for Hardware OK */
if(!(RCSR1(mp
->iobase
) & NPHOK
)) {
printf("NP100 Unit %d Failed diagnostics!\n",unit
);
printf("Status from CSR0: %x.\n",status
);
* NP Driver Interrupt Handler
register struct npmaster
*mp
;
printf("npintr on unit %d!\n",unit
);
printf("npintr mp->flags = %x\n",mp
->flags
);
/* Wake up anyone sleeping on a CSR0 Command */
if(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
;
printf("bp = %x resid = %d forw = %x\n",bp
,
bp
->b_resid
,bp
->av_forw
);
ubarelse(mp
->devp
->ui_ubanum
,&panicmap
);
printf("Panic Message: %s",NpPbuf
);
NPIO(mp
,(paddr_t
)((int) panicmap
& UBADDRMASK
),(paddr_t
)pstring
,sizeof(NpPbuf
),B_WRITE
);
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
);
/* Mark unit as being available if Device Protocol Mask set */
if(!(mp
->flags
& AVAILABLE
)) {
if((mp
->shmemp
->statblock
.sb_dpm
) && (!(mp
->flags
& BRDRESET
))){
printf("\nNP100 unit #%d available!\n",mp
->unit
);
/* Honor service requests from the device */
switch(mp
->shmemp
->statblock
.sb_drw
) {
printf("\nPanic from NP100 unit %d!\n",mp
->unit
);
/* 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
);
mp
->flags
|= (DUMPREQ
| BOARDREQ
);
/* Clear device request word */
mp
->shmemp
->statblock
.sb_drw
= 0;
wakeup((caddr_t
)&NpState
);
mp
->flags
|= (LOADREQ
| BOARDREQ
);
/* Clear device request word */
mp
->shmemp
->statblock
.sb_drw
= 0;
wakeup((caddr_t
)&NpState
);
printf("Bad Req: %x.\n",mp
->shmemp
->statblock
.sb_drw
);
/* Process the Host Command Queue for this device */
CLEARINT(mp
); /* Clear the interrupt */
return(1); /* Interrupt serviced */
* This routine, called from the interrupt handler, is used to process the
* Host Command Queue for the specified device.
register struct CmdQue
*cqp
;
register struct npreq
*rp
;
cqp
= &mp
->shmemp
->hostcq
; /* Command Queue pointer */
else cqp
->scanflag
| = ON
;
base
= (int)mp
->shmemp
; /* Shared memory base address */
while(cqp
->scanflag
& ON
) {
while(ep
= NpRemCQE(cqp
,base
)) {
printf("cqe_sts is %x ep = %x\n",ep
->cqe_sts
,ep
);
rp
->flags
|= REQDONE
; /* Normal completion */
case NPIFC
: /* IFC Request */
case NPPERR
: /* Protocol Error */
rp
->flags
|= (NPPERR
| REQDONE
);
case NPMERR
: /* Memory allocation */
rp
->flags
|= (NPMERR
| REQDONE
);
default: /* Error on Board */
rp
->flags
|= (IOERR
| REQDONE
);
printf("flag is %x reqid = %x\n",rp
->flags
,ep
->cqe_reqid
);
printf("wakeup in procqueue\n");
printf("calling usr intr at %x\n",
/* Call interrupt routine */
printf("waking up %x\n",rp
);
else wakeup((caddr_t
) (rp
)); /* Awaken */
if(!(cqp
->chngflag
& ON
))
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
register struct npmaster
*mp
;
register struct npreq
*rp
;
case NPUNLOCK
: /* Unlock process, free up mapping registers */
case NPLOCK
: /* Lock process, get mapping registers */
NpMapMem(mp
,rp
,rp
->virtmem
,rp
->bytecnt
);
ep
->cqe_dma
[0] = LOWORD(rp
->bufaddr
);
ep
->cqe_dma
[1] = HIWORD(rp
->bufaddr
);
/* Remap user buffer and update buffer offset */
np_remapmem(rp
,rp
->virtmem
);
ep
->cqe_dma
[0] = LOWORD(rp
->bufaddr
);
ep
->cqe_dma
[1] = HIWORD(rp
->bufaddr
);
printf("Bad case %x in IFC\n", ep
->cqe_func
);
rp
->flags
|= (REQDONE
| IOERR
);
* 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.
register struct npreq
*p
;
return(p
==head
? (struct npreq
*)NULL
: p
);
* Return a NP Request structure to the free list pointed to by head.
register struct npreq
*head
, *nprp
;
printf("NpFreeReq, head is %x rp is %x\n",head
,nprp
);
nprp
->forw
= nprp
->back
= (struct npreq
*)NULL
;
/* Wake up any processes waiting for a request structure */
if(head
->flags
& WANTREQ
) {
printf("NpFreeReq...\n");
* Add a Command Queue Element onto the specified Command Queue and
register unsign16 cqe_offset
;
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");
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
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
register struct npreq
*head
, *rp
;
printf("NpAddReq: %x\n",rp
);
* NpRemReq is used to remove a npreq structure from the queue specified by
register struct npreq
*rp
;
printf("NpRemReq: %x\n",rp
);
rp
->back
->forw
= rp
->forw
;
rp
->forw
->back
= rp
->back
;
* 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
)
/* Jolt the board into CSR0 command mode if necessary */
if(!(RCSR1(iobase
) & NPENB
)){
tmp
= NPCLEAR
; /* MC68000 clr reads before writing */
wcount
= (bcount
+1) >> 1; /* Convert byte count to word count */
/* Clear timer flag before beginning the timer */
timeout(NpTimer
,&csrflag
,DIAGTIME
);
for(i
= 0; (i
< wcount
) & (csrflag
== NPCLEAR
); i
++) {
while(! ((RCSR1(iobase
) & NPENB
) && (RCSR1(iobase
) & NPRDY
)))
src
++; /* Better do this WCSR is a macro */
/* Clear the timer entry */
untimeout(NpTimer
,&csrflag
);
/* Error if timer went off */
printf("NpSendCSR0...\n");
* NpSetIntLev sets the UNIBUS interrupt vector to be used by the NP board when
* interupting the host. The board is specified by mp.
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.
printf("NpSetMemAddr\n");
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
));
printf("NpSetMemAddr...\n");
* 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.
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
);
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
));
printf("NpSetXeqAddr...\n");
* NPIO issues a CSR0 load or dump request to the I-Board after packaging a
NPIO(mp
,src
,dest
,count
,dir
)
int dir
; /* Direction READ/WRITE */
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 */
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
.cmd_word
|= NPDMP
;
cmd_block
.cmd_word
|= NPLD
;
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
));
* NpKill will terminate all outstanding requests for the specified board.
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
);
else wakeup((caddr_t
)rp
);
printf("NpKill, req count is %d\n",mp
->reqtab
->reqcnt
);
/* Hardware and Software Initializations for the specified unit */
register struct npmaster
*mp
;
/* Mark board as being reset and make unavailable */
/* Abort outstanding requests for this board */
mp
->reqtab
->reqcnt
= 0; /* Init request count */
/* Wakeup Poller if available and wait until he's gone */
printf("Waking ICP in reset!\n");
wakeup((caddr_t
)&NpState
);
while(mp
->reqtab
->reqcnt
)
sleep((caddr_t
)(&mp
->reqtab
),PZERO
+1);
printf("Reset:awoken by ICP senior!\n");
/* Abort outstanding requests and wait till they're gone */
while(mp
->reqtab
->reqcnt
) {
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 */
printf("freeing shared memory map.\n");
ubarelse(mp
->devp
->ui_ubanum
,&mp
->iomapbase
);
/* 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 */
(*IxReset
)(mp
->unit
, mp
->devp
->ui_ubanum
, rp
);
/* Clear Poller's State Flag */
* General purpose timeout function which sets the flag passed to it
* NpCloseConn is called to issue a close connection command to the I-Board.
register struct npreq
*rp
;
* Don't issue the Close Connection command if the Board
if(!((mp
->shmemp
->statblock
.sb_dpm
) & PROTOMASK(protocol
))) {
/* 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
->mapbase
= 0; /* Clear mapping information */
ep
= rp
->element
; /* Handy pointer */
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);
NpRemReq(rp
); /* Remove request from active list */
NpFreeReq(mp
->reqtab
,rp
); /* Deallocate request structure */
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 struct npmaster
*mp
;
/* Privileged users only for Maintenance Protocol */
if((protocol
== NPMAINT
) && (u
.u_uid
!= 0))
printf("NpProtChange = %x\n",protocol
);
if(protocol
!= NPMAINT
) {
/* Make sure the I-Board supports the protocol */
if(!((mp
->shmemp
->statblock
.sb_dpm
) & PROTOMASK(protocol
)))
* This function allows for the changing of the unit for a given connection.
NpBoardChange(protocol
,unit
)
register unsign16 protocol
;
register int unit
; /* Unit number */
register struct npmaster
*mp
;
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
->shmemp
->statblock
.sb_dpm
) & PROTOMASK(protocol
)))
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
;
printf("mp %x rp %x addr %x count %x\n",mp
,rp
,addr
,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
;
rp
->mapbase
= ubasetup(mp
->devp
->ui_ubanum
,&rp
->buf
,0);
rp
->bufaddr
= (caddr_t
)(rp
->mapbase
& UBADDRMASK
);
* Unmap the user's memory and free up mapping registers
ubarelse(mp
->devp
->ui_ubanum
,&rp
->mapbase
);
vsunlock(rp
->virtmem
,rp
->bytecnt
,B_READ
);
rp
->procp
->p_flag
&= ~SPHYSIO
;
printf("NpUnMapMem...\n");
br
= 0; cvec
= br
; br
= cvec
;
printf("In npprobe, regaddr is %x!\n",reg
);
cvec
= (uba_hd
[numuba
].uh_lastiv
-= 4);
/* 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
]) {
printf("Couldn't find device in npstd[]!\n");
npvectors
[ui
->ui_unit
] = cvec
;
return(sizeof(struct NPREG
)); /* CSR Registers */
register struct uba_device
*ui
;
printf("In npattach, ui is %x.\n",ui
);