SysIII/usr/src/uts/vax/io/vpmb.c

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

/*Version 2*/
#include "sys/param.h"
#include "sys/tty.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/systm.h"
#include "sys/uba.h"
#include "sys/vpm.h"
#include "sys/vpmd.h"


#define BISYNC	6		/*BISYNC interpreter*/
#define VPMBS	4		/*Number of Virtual Protocol Machines*/
#define BUFSIZE	512		/*Buffer size*/
#define NOARG	0		/*Null argument*/
#define VPMPRI	(PZERO+5)
#define VPMVER2	1

/*vpm state bits*/

#define OPEN	01
#define WCLOSE	02
#define VPMERR	04
#define VPMOK	010
#define VPMRPTA	020
#define VPMOKCK	040
#define VPMECNT	0100

/*Interpreter Options*/

#define INTROP0	(01<<0)

/*Per vmp structure*/

struct vpmb {
	struct	clist	vb_xmtq;	/*Xmit queue*/
	struct	clist	vb_emptq;	/*Empty queue*/
	int	(*vb_rint)();		/*Called upon receive interupt*/
	short	vb_state;		/*Status info*/
	char	vb_xbkmc;		/*Number of xmit buffers kmc has*/
	char	vb_xmax;		/*Maximum xmit buffers kmc can take*/
	char	vb_rbkmc;		/*Number of rcv buffers kmc has*/
	char	vb_rmax;		/*Maximum rcv buffers kmc can take*/
	char	vb_rpt[4];
	char	vb_errs[8];
} vpmb[VPMBS];

extern struct vpmbd *vpmdeq();

/*
 * Vpmstart is called by the top half of driver once for each kmc-line 
 * combination. Dev has the format kklllvvv; where kk is the kmc no. 
 * (0-3); lll is the line no. (0-7); and vvv is the logical vpm no. 
 * (0-7). Type is a constant indicating the script running in the 
 * kmc. Rint is the address of the routine to be called when a 
 * receive buffer or an error report is to be delevered to the top 
 * half. 
 */
vpmstart(dev,type,rint)
int (*rint)();
{
	register struct vpmb  *vp;
	extern vpmbrint();
	extern vpmok();

	if(BDEV(dev) >= VPMBS)
		return(ENXIO);
	if((vp = &vpmb[BDEV(dev)])->vb_state&OPEN)
		return(EACCES);
	if(kmcset(dev,type,vpmbrint))
		return(EACCES);
	vp->vb_rint = rint;
	vp->vb_state |= OPEN;
	vp->vb_xmax = 1;
	vp->vb_rmax = 1;
	kmcload(dev,RUNCMD,VPMVER2,NOARG);
	timeout(vpmok,dev,5*HZ);
	vpmsave('s',dev,vp->vb_state,0);
	return(0);
}
/*
 * Vpmstop is called by the top half of the driver when the last 
 * process using the kmc-line combination closes the top half. It 
 * halts the kmc and clears the vpmb structure. 
 */
vpmstop(dev)
{
	register struct vpmb *vp;
	extern vpmclean();
	extern vpmwake();

	vp = &vpmb[BDEV(dev)];
	vp->vb_state |= WCLOSE;
	timeout(vpmwake,dev,5*HZ);
	while(vp->vb_xbkmc)
		sleep((caddr_t)&vp->vb_xbkmc, VPMPRI);
	timeout(vpmclean,dev,5*HZ);
	kmcload(dev,HALTCMD,NOARG,NOARG);
	vpmsave('t',dev,vp->vb_state,vp->vb_xbkmc);
}
/*
 * Vpmxmtq queues pointers to buffer descriptors for transmission. 
 * If the kmc currently does not have a xmit buffer, the buffer 
 * descriptor is given to the kmc; otherwise it is queued. The 
 * current queue level is returned. If bdp = 0, the current queue 
 * level is returned; nothing else is done. 
 */
vpmxmtq(dev,bdp)
struct vpmbd *bdp;
{
	register struct vpmb *vp;
	register int sps,ql;
	paddr_t	addr;

	vp = &vpmb[BDEV(dev)];
	sps = spl5();
	if(bdp == 0)
		ql = vp->vb_xmtq.c_cc/sizeof(struct vpmbd *) + vp->vb_xbkmc;
	else{
		vpmenq(bdp,&vp->vb_xmtq);
		if(vp->vb_xbkmc < vp->vb_xmax) {
			bdp = vpmdeq(&vp->vb_xmtq);
			addr = ubmdata(bdp);
			kmcload(dev,XBUFINCMD,loword(addr),hiword(addr));
			vp->vb_xbkmc++;
			ql = vp->vb_xmtq.c_cc/sizeof(struct vpmbd *) + vp->vb_xbkmc;
		}
	}
	splx(sps);
	return(ql);
}
/*
 * Vpmempt is called by the top half of the driver to queue empty 
 * buffers for use by the bottom half as receive buffers. At least 
 * one receive buffer should be available at all times. For bdp = 0, 
 * the queue level is returned; nothing is done. For bdp > 0, the 
 * pointer is queued and the queue level is returned. 
 */
vpmemptq(dev,bdp)
struct vpmbd *bdp;
{
	register struct vpmb *vp;
	register int sps,ql;
	paddr_t	addr;

	vp = &vpmb[BDEV(dev)];
	sps = spl5();
	if(bdp == 0)
		ql = vp->vb_emptq.c_cc/sizeof(struct vpmbd *) + vp->vb_rbkmc;
	else{
		vpmenq(bdp,&vp->vb_emptq);
		if(vp->vb_rbkmc < vp->vb_rmax) {
			bdp = vpmdeq(&vp->vb_emptq);
			addr = ubmdata(bdp);
			kmcload(dev,RBUFINCMD,loword(addr),hiword(addr));
			vp->vb_rbkmc++;
			ql = vp->vb_emptq.c_cc/sizeof(struct vpmbd *) + vp->vb_rbkmc;
		}
	}
	splx(sps);
	return(ql);
}
vpmbrint(dev,code,sel4,sel6)
{
	register struct vpmb *vp;
	register struct vpmbd *bdp;
	paddr_t	addr;

	vp = &vpmb[BDEV(dev)];
	switch(code) {
		case RRTNXBUF:
			vpmsave('X',dev,vp->vb_xbkmc,0);
			vp->vb_xbkmc--;
			if((vp->vb_state&WCLOSE) && (vp->vb_xbkmc == 0)) {
				wakeup((caddr_t)&vp->vb_xbkmc);
				return;
			}
			while(vp->vb_xbkmc < vp->vb_xmax && (bdp = vpmdeq(&vp->vb_xmtq))) {
				addr = ubmdata(bdp);
				kmcload(dev,XBUFINCMD,loword(addr),hiword(addr));
				vp->vb_xbkmc++;
			}
			(*vp->vb_rint)(dev,code,(struct vpmbd *)ubmrev(sel4,sel6));
			break;
		case RRTNRBUF:
			vpmsave('R',dev,vp->vb_rbkmc,0);
			(*vp->vb_rint)(dev,code,(struct vpmbd *)ubmrev(sel4,sel6));
			vp->vb_rbkmc--;
			while(vp->vb_rbkmc < vp->vb_rmax && (bdp = vpmdeq(&vp->vb_emptq))) {
				addr = ubmdata(bdp);
				kmcload(dev,RBUFINCMD,loword(addr),hiword(addr));
				vp->vb_rbkmc++;
			}
			break;
		case RTRACE:
			vpmsave('T',dev,sel4,sel6);
			break;
		case ERRTERM:
			vpmsave('E',dev,sel4,sel6);
			if((sel6&ERRMASK) == HALTRCVD)
				vpmclean(dev);
			else
				(*vp->vb_rint)(dev,code,sel6);
			break;
		case RTNOK:
			vp->vb_state |= VPMOK;
			kmcload(dev,OKCMD,NOARG,NOARG);
			break;
		case RTNSNAP:
			vpmsnap('S',dev,sel4,sel6);
			break;
		case RTNSRPT:
			vp->vb_rpt[0] = sel4&0377;
			vp->vb_rpt[1] = (sel4>>8)&0377;
			vp->vb_rpt[2] = sel6&0377;
			vp->vb_rpt[3] = (sel6>>8)&0377;
			vp->vb_state |= VPMRPTA;
			vpmsave('P',dev,sel4,sel6);
			break;
		case RTNERCNT:
			vpmsave('F',dev,sel4,sel6);
			vp->vb_state |= VPMECNT;
			wakeup((caddr_t)vp->vb_errs);
			break;
		case STARTUP:
			vp->vb_xmax = sel4&0377;
			vp->vb_rmax = (sel4>>8)&0377;
			if(sel6&INTROP0)
				vp->vb_state |= VPMOKCK;
			vpmsave('S',dev,sel4,sel6);
	}
}
vpmenq(bdp,clp)
struct vpmbd *bdp;
struct clist *clp;
{
	register char *p;
	register int n;

	if(bdp == 0)
		return(clp->c_cc/sizeof(struct vpmbd *));
	p = (char *)&bdp;
	for(n=sizeof(struct vpmbd *);--n>=0;)
		putc(*p++,clp);
	return(clp->c_cc/sizeof(struct vpmbd *));
}
struct vpmbd *
vpmdeq(clp)
struct clist *clp;
{
	struct vpmbd *bdp;
	register int n;
	register char *p;

	if(clp->c_cc == 0)
		return(0);
	p = (char *)&bdp;
	for(n=sizeof(struct vpmbd *);--n>=0;)
		*p++ = getc(clp);
	return(bdp);
}
vpmclean(dev)
{
	struct vpmb *vp;
	struct vpmbd *bdp;

	vp = &vpmb[BDEV(dev)];
	if((vp->vb_state&WCLOSE) == 0)
		return;
	vp->vb_state &= ~WCLOSE;
	while(bdp = vpmdeq(&vp->vb_xmtq))
		(*vp->vb_rint)(dev,RRTNEBUF,bdp);
	while(bdp = vpmdeq(&vp->vb_emptq))
		(*vp->vb_rint)(dev,RRTNEBUF,bdp);
	vpmsave('C',dev,vp->vb_state,vp->vb_xbkmc);
	vp->vb_xbkmc = 0;
	vp->vb_rbkmc = 0;
	vp->vb_state = 0;
}
vpmwake(dev)
{
	struct vpmb *vp;

	vp = &vpmb[BDEV(dev)];
	vp->vb_xbkmc = 0;
	wakeup((caddr_t)&vp->vb_xbkmc);
}
vpmcmd(dev,cmd)
char cmd[];
{
	short sel4,sel6;

	sel4 = ((short)cmd[1]<<8)|cmd[0];
	sel6 = ((short)cmd[3]<<8)|cmd[2];
	kmcload(dev,SCRIPTCMD,sel4,sel6);
}
char *
vpmrpt(dev)
{
	struct vpmb *vp;

	vp = &vpmb[BDEV(dev)];
	if(vp->vb_state&VPMRPTA) {
		vp->vb_state &= ~VPMRPTA;
		return(vp->vb_rpt);
	}
	return(0);
}
vpmok(dev)
{
	struct vpmb *vp;

	vp = &vpmb[BDEV(dev)];
	if((vp->vb_state&OPEN) == 0 || (vp->vb_state&VPMOKCK) == 0)
		return;
	if(vp->vb_state&VPMOK)
		vp->vb_state &= ~VPMOK;
	else{
		vpmsave('O',dev,vp->vb_state,0);
		(*vp->vb_rint)(dev,ERRTERM,NORESP);
	}
	timeout(vpmok,dev,5*HZ);
}
char *
vpmerrs(dev,n)
{
	struct vpmb *vp;
	paddr_t	addr;
 
	vp = &vpmb[BDEV(dev)];
	if(n <= 0 || n > 8)
		n = 8;
	vp->vb_state &= ~VPMECNT;
	addr = ubmdata(vp->vb_errs);
	kmcload(dev,GETECMD,loword(addr),(n<<8)|hiword(addr));
	spl5();
	while((vp->vb_state&VPMECNT) == 0)
		sleep((caddr_t)vp->vb_errs, VPMPRI);
	spl0();
	return(vp->vb_errs);
}
vpmsave(type,dev,word1,word2)
char type,dev;
short word1,word2;
{
	static int vpmseqn;
	register sps;
	struct {
		short	e_seqn;
		char	e_type;
		char	e_dev;
		short	e_word1;
		short	e_word2;
	} vpment;

	sps = spl5();
	if(vpmseqn >= 077777)
		vpmseqn = 0;
	vpment.e_seqn = ++vpmseqn;
	vpment.e_type = type;
	vpment.e_dev = dev;
	vpment.e_word1 = word1;
	vpment.e_word2 = word2;
	trsave(0,0,&vpment,sizeof(vpment));
	splx(sps);
}
vpmsnap(type,dev,word1,word2)
char type,dev;
short word1,word2;
{
	static int vpmseqn;
	register sps;
	struct {
		short	s_seqn;
		char	s_type;
		char	s_dev;
		short	s_word1;
		short	s_word2;
		long	s_lbolt;
	} vpmsnt;

	sps = spl5();
	if(vpmseqn >= 077777)
		vpmseqn = 0;
	vpmsnt.s_seqn = ++vpmseqn;
	vpmsnt.s_type = type;
	vpmsnt.s_dev = dev;
	vpmsnt.s_word1 = word1;
	vpmsnt.s_word2 = word2;
	vpmsnt.s_lbolt = lbolt;
	trsave(1,0,&vpmsnt,sizeof(vpmsnt));
	splx(sps);
}