File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / vba / vcc.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:30:09 2019 UTC (6 years, 11 months ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

#include "vx.h"
#if NVX > 0
/*
 *  VIOC driver
 */
#include "../h/param.h"
#include "../h/file.h"
#include "../h/ioctl.h"
#include "../h/tty.h"
#include "../h/errno.h"
#include "../h/time.h"
#include "../h/kernel.h"
#include "../vba/vioc.h"
#ifdef VXPERF
#include "../vba/scope.h"
#endif VXPERF

#define CMDquals 0
#define RSPquals 1
#define UNSquals 2

extern	struct vcx	vcx[];
extern	struct tty	vx_tty[];
struct	vcmds		v_cmds[NVIOCX];

extern char vxtype[];
extern char vxbbno;
extern char vxbopno[];

#if defined(NVSNA) | defined(NSD)
extern vbrall();
#else
vbrall() {};
#endif

/*
 *  Write a command out to the VIOC
 */
vcmd(n, cmdad)
register int n;
register caddr_t cmdad;		/* command address */
{
	register struct	vcmds *cp;
	register struct vcx *xp;
	int s;

	s = spl8();
	cp = &v_cmds[n];
	xp = &vcx[n];

	if (xp->v_state&V_RESETTING && cmdad != NULL) {
		/*
		 * When the vioc is resetting, don't process
		 * anything other than LIDENT commands.
		 */
		register struct vxcmd *cp = (struct vxcmd *)
				((char *)cmdad - sizeof(cp->c_fwd));
		if (cp->cmd != LIDENT) {
			vrelease(xp, cp);
			return(0);
		}
	}
	if (cmdad != (caddr_t) 0) {
		cp->cmdbuf[cp->v_fill] = cmdad;
		if (++cp->v_fill >= VC_CMDBUFL)
			cp->v_fill = 0;
		if (cp->v_fill == cp->v_empty) {
			vpanic("vc: CMD Q OVFLO");
			vxstreset(n);
			splx(s);
			return(0);
		}
		cp->v_cmdsem++;
	}
	if (cp->v_cmdsem && cp->v_curcnt < vcx[n].v_maxcmd) {
		cp->v_cmdsem--;
		cp->v_curcnt++;
		vinthandl(n, ((V_BSY | CMDquals) << 8) | V_INTR);
	}
	splx(s);
	return(1);
}

/*
 * VIOC acknowledge interrupt.  The VIOC has received the new
 * command.  If no errors, the new command becomes one of 16 (max)
 * current commands being executed.
 */
vackint(n)
register int n;		/* VIOC number */
{
	register struct	vblok	*vp;
	register struct	vcmds	*cp;
	register int s;

#ifdef VXPERF
	scope_out(5);
#endif VXPERF

	if (vxtype[n]) {	/* It is a BOP */
		vbrall(n);	/* Int. from BOP, port 0 */
		return;
	}

	s = spl8();
	vp = VBAS(n);
	cp = &v_cmds[n];
	if (vp->v_vcid&V_ERR) {
		register char *resp;
		register i;
		printf("INTR ERR type = %x VIOC = %x\n", vp->v_vcid&07, n);
		resp = (char *)vp + (vp->v_rspoff&0x7FFF);
		for (i = 0; i < 16; i++)
			printf("%x ", resp[i]&0xff);
		vpanic("\nvcc: vackint");
		vxstreset(n);
		splx(s);
		return;
	}
	if ((vp->v_hdwre&017) == CMDquals)  {
		cp->v_curcmd[vp->v_vcid&VCMDLEN-1] = cp->cmdbuf[cp->v_empty];
		if (++cp->v_empty >= VC_CMDBUFL)
			cp->v_empty = 0;
	}
	if (++cp->v_itrempt >= VC_IQLEN)
		cp->v_itrempt = 0;
	vintempt(n);
	splx(s);
	vcmd(n, 0);	/* queue next cmd, if any */
}

/*
 *  Command Response interrupt.  The Vioc has completed
 *  a command.  The command may now be returned to
 *  the appropriate device driver .
 */
vcmdrsp(n)
register int n;
{
	register struct	vblok *vp;
	register struct	vcmds *cp;
	register caddr_t cmd;
	register char *resp;
	register int k, s;

#ifdef VXPERF
	scope_out(6);
#endif VXPERF

	if (vxtype[n]) {	/* Its a BOP */
		printf("vcmdrsp: stray interrupt from BOP at VIOC%d...\n", n);
		return;
	}
	s = spl8();
	vp = VBAS(n);

	cp = &v_cmds[n];
	resp = (char *)vp;
	resp += vp->v_rspoff&0x7FFF;

	if (
#if VX_TESTING
	   (vx_test&VX_CMDRESP_DEBUG) == 0 &&
#endif
	   (k=resp[1])&V_UNBSY)  {
		k &= VCMDLEN-1;
		cmd = cp->v_curcmd[k];
		cp->v_curcmd[k] = (caddr_t)0;
		cp->v_curcnt--;
		k = *((short *)&resp[4]);	/* cmd operation code */
		if ((k&0xFF00) == LIDENT) {	/* want hiport number */
			for (k = 0; k < VRESPLEN; k++)
				cmd[k] = resp[k+4];
		}
		resp[1] = 0;
		vxxint(n, cmd);
	}
	else {
		vpanic("vc, cmdresp debug");
		vxstreset(n);
		splx(s);
		return;
	}

	vinthandl(n, ((V_BSY | RSPquals) << 8) | V_INTR);
	splx(s);

}

/*
 * Unsolicited interrupt.
 */
vunsol(n)
register int n;
{
	register struct	vblok *vp;
	register int s;

#ifdef VXPERF
	scope_out(1);
#endif VXPERF

	if (vxtype[n]) {	/* Its a BOP */
		printf("vunsol: stray interrupt from BOP at VIOC%d...\n", n);
		return;
	}
	s = spl8();
	vp = VBAS(n);
	if (vp == 0) {
		printf("vunsol: stray interrupt from VIOC%d...\n", n);
		splx(s);
		return;
	}

	if (
#if VX_TESTING
	    (vx_test&VX_UNSOL_INT_DEBUG) == 0 &&
#endif
	    vp->v_uqual&V_UNBSY) {
		if (vxrint(n))
			vinthandl(n, ((V_BSY | UNSquals) << 8) | V_INTR);
		splx(s);
	}
	else {
		vpanic("vc: UNSOL INT ERR");
		vxstreset(n);
		splx(s);
	}
}

/*
 * Enqueue an interrupt
 */
vinthandl(n, item)
register int n, item;
{
	register struct vcmds *cp;
	register int empflag = 0;

	cp = &v_cmds[n];
	if (cp->v_itrfill == cp->v_itrempt)
		empflag++;
	cp->v_itrqueu[cp->v_itrfill] = item;
	if (++cp->v_itrfill >= VC_IQLEN)
		cp->v_itrfill = 0;
	if (cp->v_itrfill == cp->v_itrempt) {
		vpanic("vc: INT Q OVFLO");
		vxstreset(n);
	} else if (empflag)
		vintempt(n);
}

vintempt(n)
register int n;
{
	register struct vcmds *cp;
	register struct vblok *vp;
	register short item, *intr;

	vp = VBAS(n);
	if (vp->v_vioc&V_BSY)
		return;
	cp = &v_cmds[n];
	if (cp->v_itrempt == cp->v_itrfill)
		return;
	item = cp->v_itrqueu[cp->v_itrempt];
	intr = (short *)&vp->v_vioc;
	switch ((item >> 8)&03) {
	case CMDquals:		/* command */
		{
		int phys;

		if (cp->v_empty == cp->v_fill || vp->v_vcbsy&V_BSY)
			break;
		phys = vtoph(0, cp->cmdbuf[cp->v_empty]); /* should be a sys address */
		vp->v_vcp[0] = ((short *)&phys)[0];
		vp->v_vcp[1] = ((short *)&phys)[1];
		vp->v_vcbsy = V_BSY;
		*intr = item;
		}
#ifdef VXPERF
	scope_out(4);
#endif VXPERF
		break;

	case RSPquals:		/* command response */
		*intr = item;
#ifdef VXPERF
	scope_out(7);
#endif VXPERF
		break;

	case UNSquals:		/* unsolicited interrupt */
		vp->v_uqual = 0;
		*intr = item;
#ifdef VXPERF
	scope_out(2);
#endif VXPERF
		break;
	}
}

struct viocdump viocdump;	/* contents of VIOC memory prior to reset */

/* start a reset on a vioc after error (hopefully) */
vxstreset(n)
register int n;
{
	register struct vcx *xp;
	register struct	vblok *vp;
	register struct vxcmd *cp;
	register short *src, *dst, *end;
	register int j;
	extern int vxinreset();
	int s;

	s = spl8();
	vp = VBAS(n);
	xp = &vcx[n];

#if VX_TESTING
	vx_test = 0;
#endif
	if (xp->v_state&V_RESETTING) {
		/*
		 * Avoid infinite recursion.
		 */
		splx(s);
		return;
	}

	/*
	 * Dump the VIOC memory -- important we do it as shorts.
	 */
	src = (short *)vp;
	dst = (short *)viocdump.vxcore;
	end = (short *)((char *)viocdump.vxcore + sizeof(viocdump.vxcore));
	while (dst < end)
		*dst++ = *src++;

	/*
	 * Note the time so we may correlate console messages
	 * with the vioc dump.
	 */
	viocdump.vxtime = time.tv_sec;
	viocdump.vxn = n;
	viocdump.vxmagic = VIOCDMAGIC;

	/*
	 * Zero out the vioc structures, mark the vioc as being
	 * reset, reinitialize the free command list, reset the vioc
	 * and start a timer to check on the progress of the reset.
	 */
	bzero(&v_cmds[n], sizeof(struct vcmds));
	bzero(xp, sizeof(struct vcx));

	/*
	 * Setting V_RESETTING prevents others from issuing
	 * commands while allowing currently queued commands to
	 * be passed to the VIOC.
	 */
	xp->v_state |= V_RESETTING;
	for (j = 0; j < NVCXBUFS; j++) {/* init all cmd buffers */
		cp = &xp->vx_lst[j];	/* index a buffer */
		cp->c_fwd = &xp->vx_lst[j+1];	/* point to next buf */
	}
	xp->vx_avail = &xp->vx_lst[0];	/* set idx to 1st free buf */
	cp->c_fwd = (struct vxcmd *)0;	/* mark last buf in free list */

	printf("resetting VIOC %x at %x .. ", n, viocdump.vxtime);

	vp->v_fault = 0;
	vp->v_vioc = V_BSY;
	vp->v_hdwre = V_RESET;		/* reset interrupt */

	timeout(vxinreset, (caddr_t)n, hz*5);
	splx(s);
	return;
}

/* continue processing a reset on a vioc after an error (hopefully) */
vxinreset(vioc)
caddr_t vioc;
{
	register struct vcx *xp;
	register struct	vblok *vp;
	register int n = (int)vioc;
	int s = spl8();

	vp = VBAS(n);
	xp = &vcx[n];

	/*
	 * See if the vioc has reset.
	 */
	if (vp->v_fault != VREADY) {
		printf("failed\n");
		splx(s);
		return;
	}

	/*
	 * Send a LIDENT to the vioc and mess with carrier flags
	 * on parallel printer ports.
	 */
	vxinit(n, 0);
	splx(s);
}

/*
 * Restore modem control, parameters and restart output.
 */
/* finish the reset on the vioc after an error (hopefully) */
vxfnreset(n, cp)
register int n;
register struct vxcmd *cp;
{
	register struct vcx *xp;
	register struct	vblok *vp;
	register struct tty *tp, *tp0;
	register int i;
	register int on;
	int s = spl8();

	vp = VBAS(n);
	xp = &vcx[n];

	xp->v_loport = cp->par[5];	/* save low port number */
	xp->v_hiport = cp->par[7];	/* VIOC knows high port numbr */
	vrelease(xp, cp);		/* done with this control block */
	xp->v_nbr = n;			/* assign VIOC-X board number */

	xp->v_state &= ~V_RESETTING;
	vp->v_vcid = 0;

	/*
	 * Wakeup up anyone waiting for the reset (LIDENT) to complete.
	 */
	wakeup((caddr_t)&xp->v_state);

	/*
	 * Restore modem information and control.
	 */
	tp0 = &vx_tty[n<<4];
	for (i = xp->v_loport; i <= xp->v_hiport; i++) {
		tp = tp0 + i;
		if ((tp->t_state&(TS_ISOPEN|TS_WOPEN)) == 0)
			/*
			 * Nobody cares about this line.
			 */
			continue;
		/*
		 * Reset modem signals and set parameters
		 */
		tp->t_state &= ~TS_CARR_ON;
		vcmodem(tp->t_dev, VMOD_ON);
		vxcparam(tp->t_dev, 0);

		/*
		 * If carrier has changed while we were resetting,
		 * take appropriate action.
		 */
		on = vp->v_dcd&1<<i;
		if (on && (tp->t_state&TS_CARR_ON) == 0)  {
			/*
			 * Carrier has come on.
			 */
			tp->t_state |= TS_CARR_ON;
			wakeup((caddr_t)&tp->t_canq);
		} else if (!on && tp->t_state&TS_CARR_ON) {
			/*
			 * Carrier has gone off.
			 */
			tp->t_state &= ~TS_CARR_ON;
			if (tp->t_state&TS_ISOPEN) {
				ttyflush(tp, FREAD|FWRITE);
				if (tp->t_state&TS_FLUSH)
					wakeup((caddr_t)&tp->t_state);
				if ((tp->t_flags&NOHANG)==0) {
					gsignal(tp->t_pgrp, SIGHUP);
					gsignal(tp->t_pgrp, SIGCONT);
				}
			}
		}

		/*
		 * If anyone is awaiting a transmission interrupt,
		 * wake them up.
		 */
		if (tp->t_state&TS_ASLEEP) {
			tp->t_state &= ~TS_ASLEEP;
			wakeup((caddr_t)&tp->t_outq);
		}

		/*
		 * Restart pending output.
		 */
		tp->t_state &= ~(TS_BUSY|TS_TIMEOUT);
		if (tp->t_state&(TS_ISOPEN|TS_WOPEN))
			vxstart(tp);
	}
	printf("done\n");
	splx(s);
}

vxreset(dev)
dev_t dev;
{
	vxstreset(minor(dev)>>4);	/* completes asynchronously */
}

vxfreset(n)
register int n;
{
	register struct vblok *vp;

	if (n < 0 || n > NVX || VBAS(n) == NULL)
		return(ENODEV);
	vcx[n].v_state &= ~V_RESETTING;
	vxstreset(n);
	return(0);		/* completes asynchronously */
}
#endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.