File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / d / ioex / vioc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (6 years, 11 months ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
Power 6/32 Unix version 1.2b


#include "vioc.h"
#include "conf.h"
#include "const.h"
#include "pte.h"

#define  ON		0x80
#define  OFF		0
#define	 LOOPBK		0
#define	 ECHO		1

#define  MAXPORT	16
#define  MAXRLEN	50
#define  MAXSLEN	256
#define  HEAD		"\n\r\t** VIOC test **\n"
#define  PORT		"\rlogical port no "
#define  NL		writec('\n')

/*		Pointers to VIOC structures in I/O space 	*/
struct vblok *VP;			/* Pointer to commom buffer */
struct cmd_inp cblok;			/* VIOC command block (from HOST) */
struct cmd_res *rblok;			/* PTR to CMD respond blk (from VIOC) */

short *s_entry;
short cmdrsp[MAXRLEN];

long msg_on = 1;			/* Global flag to enable messages */
long cmd_id = 0;
long IObase;				/* Virtual Address of VIOC base */
long vioc_ack, vioc_rsp;
long log_p0 = 1;			/* Logical port no. of 1st terminal */
long log_pn = 0;			/* Logical port no. of last terminal */

char port_on[MAXPORT];

extern long savvec3, unused, clk_cnt, proc_no;

vioc()
{	register long ix;
	long v_reset(), v_init();

	m_vioc();				/* Set up map for IO space */
	init_vec();				/* Set up int. handlers */
	if (!v_reset()) return(0);		/* Reset VIOC */
	writes("\nVIOC controller is at "); writeh(VBASE); 
	if (!v_init()) return(0);		/* Initialize VIOC */
	return(1);
}

/*	Routine to map VIOC :
	VIOC space is map from 1st unused virtual page on
*/
m_vioc()
{	long phys_pg, pte, old_pte, which1;

	phys_pg = ((VBASE+IOBASE) >> PGSHIFT) & 0x3fffff;
				/* 1st physical page of VIOC in IO space */
	pte = phys_pg | PG_KW | PG_V | PG_NC;
	for (which1=unused; which1<(unused+VIOC_LEN); which1++) {
		fix_pte(SBR,which1,&old_pte,pte);
		pte++; }
	VP = (struct vblok *)(unused << PGSHIFT);
	IObase = (long)VP;		/* Base addr of common buffer */
	asm("mfpr $SLR,_savvec3");
	savvec3 += VIOC_LEN;
	asm("mtpr _savvec3,$SLR");
	unused = which1;		/* Next unused PTE in system map */
}


/*	Initialize Tahoe SCB vectors to handle VIOC interrupts
*/
init_vec()
{	long old_vec1, old_vec2, old_vec3;

	asm("movab ack_hdlr,_savvec3");
	set_handler(ACK_VIOC,&old_vec1,savvec3);  /* Set handler for VIOC ACK */
	asm("movab rsp_hdlr,_savvec3");
	set_handler(CMD_RESP,&old_vec2,savvec3);  /* Set handler for VIOC RSP */
	asm("movab unsol_hdlr,_savvec3");
	set_handler(UNS_VEC,&old_vec3,savvec3);  /* Set hdler for VIOC UNSOL */
}

/*	Routine to Reset VIOC	
	Poll for 10 sec. then check 
	    if (VIOC busy flag is clear) and (VIOC is ready)
*/
v_reset()
{	register long cnt, stat, r10;

	VP->v_vioc = V_BSY;		/* Set VIOC busy flag */
	VP->v_ident = (short)0;
	VP->v_hdwre = V_RESET;		/* Reset VIOC	*/
	cnt = 200;			/* Might need to be tuned ! */
	while (VP->v_ident==(short)0)	/* WATCH OUT WHEN DATA CACHE IS ON */
		{ DELAY(0x50000);
		  if (--cnt == 0) { writes("\nVIOC error, Time out on Reset !");
		  		return(0); }
		}

	cnt = 0x1ffffff;			/* Need to be TUNED */
	for (;cnt != 0;--cnt);		/* VIOC is executing its diagnostic */

	if ((VP->v_ident != (short)V_ALLOK) && 
		(VP->v_ident != (unsigned short)0x5555) )	{
		writes("\nVIOC error after Reset !");
		stat = ((long)VP->v_ident)  & 0xffff;
		writes("\nFault code : ");
		writeh(stat); writec('\n');
		return(0);
		}
	VP->v_ustat = VP->v_uqual = 0;	/* Clear UNSOL. BUFF */
	return(1);
}

/*	VIOC initialization routines : Sent LIDENT cmd
	(1) Define interrupt vectors
	(2) Set 1st, Last logical port no.
*/
v_init()
{	short *flycmd(), *rsp_blk, stat_wd;

	cblok.opcode = LIDENT;		/* Set opcode */
	cblok.byte[0] = ACK_VIOC;	/* Set interrupt vectors */
	cblok.byte[1] = CMD_RESP;
	cblok.byte[3] = UNS_VEC;
	cblok.byte[4] = 16;		/* Max no port to turn on */
	cblok.byte[5] = log_p0 = 1;	/* 1st port is logical no. 1 */
					/* Sent command to VIOC */
	log_pn = 0;
	rsp_blk = flycmd(&stat_wd);
	if ((stat_wd & 0x7f00) != 0x300) 	{
		writes("LIDENT error ");
		stat_wd = (stat_wd >> 8) & 0xff;
		writeh((long)stat_wd); NL;
		return(0);
		asm("halt");
		}
	log_pn = (long)(rsp_blk[6] & 0xff);	/* Last log. port no */
	rsp2v(rsp_blk);			/* Sent a cmd respond int. to VIOC */
	if (log_pn < log_p0) writes("0 port available.\n"); 
	   else  {
		set_port();
		writes("\nLast port no. ");
		writed(log_pn); writec('\n');
		}
	return(1);
}

/*	check out how many ports are on line 
*/
set_port()
{	long ix;

	/* Initialze ports */
	for(ix=1; ix<=log_pn; ix++)	{
		msg_on = 0;
		port_on[ix-1] = (char)1;	/* This port is on */
		if ( !v_initp(ix,NDBT,NSBT,BAUD,PARY))  {
			port_on[ix-1] = (char)0;	/* This port is off */
			writes("Port "); writeh(ix);
			writes(" is not on line\n");	
			}
		   else {
			init_buf(ix);		/* Init. input buffer */
			}
		msg_on = 1;
		}
}


/*	routine to inittialize input buffer for port X
	input : pno - logical port no. on VIOC
*/
init_buf(pno)
long pno;
{	struct vbuf *vb;
	register long ix;

	vb = &vi_buf[pno-1];
	vb->cnt = vb->nxt_c = vb->nxt_fill = 0;
	for(ix=0; ix<BUFLEN; ix++) vb->buf[ix] = 0;
}

/*	Routine to sent LPRARAX command to VIOC
	Also used to probe if a port is on line
	return 1 if port is on line else return 0
*/
v_initp(pno, ndbits, nsbits, baud, parity)
long pno, ndbits, nsbits, baud, parity;
{
	short *flycmd(), stat_wd, *rsp_blk;

	cblok.opcode = LPARAX;		/* Set opcode */
	cblok.byte[0] = 0;		/* not used */
	cblok.byte[1] = (char)pno;	/* Port no. */
	cblok.byte[2] = 0;		/* Enable port's transmitter */
	cblok.byte[3] = 0;
	cblok.byte[4] = (char)ndbits;	/* no. data bit */
	cblok.byte[5] = (char)nsbits;	/* no. stop bit */
	cblok.byte[6] = (char)baud;	/* Baud rate */
	cblok.byte[7] = (char)parity;	/* Parity */

	/* Sent command to VIOC */
	rsp_blk = flycmd(&stat_wd);
	rsp2v(rsp_blk);		/* Sent a cmd respond int. to VIOC */
	if (stat_wd)  {	/* CMD Respond error */
		if (msg_on) {
			writes("LPARAX error ");
			stat_wd = (stat_wd >> 8) & 0xff;
			writeh((long)stat_wd); NL; }
		return(0);
		}
	return(1);
}

/*	Routine to sent AUTO loop back/local echo
	command to VIOC;
	return 1 if port is on line else return 0
*/
v_autol(pno,on,op)
long pno,on, op;
{
	short *flycmd(), stat_wd, *rsp_blk;

	cblok.opcode = AUTOLP;		/* Set opcode */
	cblok.byte[0] = on | op;	/* enable/disable auto loopback/echo */
	cblok.byte[1] = pno;		/* port no */

	/* Sent command to VIOC */
	rsp_blk = flycmd(&stat_wd);
	rsp2v(rsp_blk);		/* Sent a cmd respond int. to VIOC */

	if (stat_wd)  {	/* CMD Respond error */
		if (msg_on) {
			writes("AUTOLP error ");
			stat_wd = (stat_wd >> 8) & 0xff;
			writeh((long)stat_wd); NL; }
		return(0);
		}
	return(1);
}

/*	Sent a command to VIOC. wait for respond and
	(1) return pointer to respond buffer
	(2) output paramter :
		stat = 1st word of respond buffer if error; 
		       0 if command sucessfully executed by VIOC
		
*/
short *flycmd(stat)
short *stat;
{	register long *r12;
	short *sent_cmd(), *rsp_blk, stat_wd;

	rsp_blk = sent_cmd(&cblok);	/* issue command to VIOC */
	if ( !rsp_blk ) { 	/* HOST issued invalid interrupt */
		stop();
		}
	stat_wd = (*rsp_blk) & 0xffff;
	if ( stat_wd & (V_ERR << 8) ) *stat = stat_wd;
		else *stat = 0;
	return(rsp_blk);
}




/*	Routine to sent a command to VIOC, Command buffer should be 
	filled by HOST before calling this routine :
	    Issue CMD INP INT to VIOC, Wait for VIOC to sent ACK INT
	    If VIOC ACK with INT ERR bit set print INT ERR code and return 0
		else wait for CMD RESP INT from VIOC
	Return pointer to Command Respond block.
*/
short *sent_cmd(cmdblk)
struct cmd_inp *cmdblk;
{
	register long cnt, *r11;
	register short *rsp_stat;
	short *sptr, *gt_rspadr(), ix;

	cnt = 0x100;
	while (v_busy())		/* Test VIOC Busy flag */
		{ DELAY(0x50000);
		  if (--cnt == 0) panic("\nSent_cmd time out\n");
		}
	if (!v_rdy4cmd()) 	/* VIOC not ready for new command */
		{ DELAY(0x50000);
		  if (--cnt == 0) panic("\nSent_cmd not ready\n");
		}
	set_cadr((long)cmdblk);		/* Set cmd address in commom buffer */
	VP->v_vcbsy = V_BSY;		/* Set CMD BUSY FLAG	*/
	v_int((char)V_CMDI);		/* Sent CMD INPUT INTERRUPT */

	for(vioc_ack=1;vioc_ack != 0;);	/* Wait for ACK */
	if (VP->v_vcid & V_ERR)
		{	/* Interrupt error */
		writes("\nCmd input Int. error ");
		writeh((long)(VP->v_vcid & 0x3)); NL;
		return(0);
		}
	cmd_id = (long)VP->v_vcid & 0xf;	/* Get command ID from VIOC */

	for(vioc_rsp=1;vioc_rsp != 0;);	/* Wait for CMD respond int. */
	rsp_stat =  gt_rspadr();	/* Get addr of Respond buffer */

	/* For debugging only : Read command respond buffer from VIOC */
	sptr = rsp_stat;
	for (ix=0; ix <MAXRLEN; ix++) cmdrsp[ix] = *sptr++;

	return(rsp_stat);
}

/*	This routine sent a command respond interrupt to VIOC
*/
rsp2v(rsp_blk)
short *rsp_blk;
{	register long cnt;

	cnt = 0x100;
	while (v_busy())		/* Test VIOC Busy flag */
		{ DELAY(0x50000);
		  if (--cnt == 0) panic("\nRsp2v time out\n");
		}
	*rsp_blk = 0;		 	/* Clear RESP. BUSY Flag */
	v_int((char)V_CMDRI);		/* Sent a cmd respond int. to VIOC */
}

/*	Routine to sent a string to port #pno
	Return a 1 if command executed else return 0
*/
pstr(pno,c)
long pno;
char *c;
{	register long *lptr, slen, phys_adr;
	char *cptr;
	short *rsp_blk, stat_wd , *flycnd();

	/* Count length of string */
	slen = 0;
	for (cptr=c; *cptr++ != NULL; slen++);

	/* Fill command buffer */
	cblok.opcode = (short)XMITDTA;	/* XMIT opcode */
	cblok.byte[0] = (char)pno;	/* Port no. */
	cblok.byte[1] = (char)slen;	/* Byte count */
	lptr = (long *)&cblok.byte[2];
	phys_adr = va2pa((long)c);	/* Convert VA of string to phys. addr */
	*lptr = (long)phys_adr;		/* Set address of buffer */	

	rsp_blk = flycmd(&stat_wd);	/* Sent command to VIOC */
	rsp2v(rsp_blk);			/* sent respond int. to VIOC */
	if (stat_wd)	{
		writes("XMITDTA error ");
		stat_wd = (stat_wd >> 8) & 0xff;
		writeh((long)stat_wd); NL;
		return(0);
		}
	return(1);
}


/*	Routine to put a char to port #pno
*/
pchar(pno,c)
long pno;
char c;
{
	char str[3];

	str[0] = c;
	if (c=='\n') {
		str[1] = '\r';
		str[2] = NULL;	}
	    else  str[1] = NULL;
	return(pstr(pno,str));
}


/* 	Routine return the address of CMD RESP. Buffer in 
	shared area
*/
short *gt_rspadr()
{
	return((short *)((long)VP + VP->v_rsp));
}


/*	Routine to sent an interrupt to VIOC	
	Input : Bit 0,1 of 'qual' indicate type of interrupt
*/
v_int(qual)
char qual;
{
	char vint;

	vint = (char)((V_BSY | qual) & 0xff);
	VP->v_vioc = vint;	/* Set busy flag, int. qualifier */
	VP->v_hdwre = V_INTR;	/* Interrupt VIOC */
}


/*	Routine to test if VIOC is ready to accept new command
	Return 1 if ready Else return 0
*/
v_rdy4cmd()
{	register long *r12;

	if (VP->v_vcbsy & V_BSY) {
		return(0);
		}
	   else return(1);
}


/*	Routine to test if VIOC busy, Return 1
	if not busy Else return 0
*/
v_busy()
{	register long *r12;

	if (VP->v_vioc & V_BSY) return(1);
	    else {
		return(0);
	    }
}


/*	Routine to set cmd address in commom buffer. 
	Command address has to be translated to physical
	address. 
	input : blkadr (virtual address)
*/
set_cadr(blkadr)
long blkadr;
{	register long word1, cmdadr;

	cmdadr = va2pa(blkadr);		/* VA to physical address */
	VP->v_vcp1 = (short)(cmdadr & 0xffff);
	word1 = (cmdadr >> 16) & 0xffff;
	VP->v_vcp0 = (short)word1;
}


/*	Routine translate virtual address to physical address
*/
va2pa(va)
long va;
{	register long *base, pte, pte_no, page_no, cmdadr;

	/* Translate virtual to physical address */
	asm("mfpr $SBR,r12");
	pte_no = (va >> PGSHIFT) & 0x3fffff; /* Virtual pgno of cmd addr */
	pte = base[pte_no];			 /* PTE for this page no */
	page_no = pte & 0x3fffff;
	cmdadr = (page_no << PGSHIFT) | (va & 0x3ff);
	return(cmdadr);
}

panic(msg)
char *msg;
{
	writes(msg);
	stop();
}

stop()
{
	asm("halt");
}



/* Handler of VIOC CMD RESP. INT */
rsp_handlr()
{
	asm(".align 2");
	asm(".globl rsp_hdlr");
asm("rsp_hdlr:");
	vioc_rsp = 0;			/* Clear Vioc_rsp flag */
	asm("rei");
}



/* Handler of VIOC ACK INT */
ack_handlr()
{
	asm(".align 2");
	asm(".globl ack_hdlr");
asm("ack_hdlr:");
	vioc_ack = 0;			/* Clear Vioc ack flag */
	asm("rei");
}

/*	Global variables used in Unsolicited int. handler */
long silo_no, no_char, cin, count;
char ascii;

/* 	Handler of VIOC UNSOLICITED interrupt : service on ISP
	(1) Dump silo contents
*/
unsol_handlr()
{
	asm(".align 2");
	asm(".globl unsol_hdlr");
asm("unsol_hdlr:");
	asm("svpctx");		/* Save context, also switch to ISP */
	dmp_silo();
	asm("ldpctx");		/* Restore context, switch to KSP */
	asm("rei");
}


dmp_silo()
{	register long rsp_qual, pno, error, rec_err;

	rec_err = 0;
	rsp_qual = VP->v_uqual & 0x7;
	switch (rsp_qual)	{
		case 1 : {
			writes("received data error\n");
			rec_err = 1;
			goto nomore; }
		case 2 : {	
			writes("VIOC process error\n");
			goto nomore; }
		case 3 : {	
			writes("data set change ");
			writeh(VP->v_uqual & 0x3f); NL;
			goto nomore; }
		case 4 : {	
			writes("secondary receive change");
			goto nomore; }
		case 5 : {	
			writes("undefined respond error code ");
			writeh(rsp_qual); NL;
			goto nomore; }
		}
	/* Data available */
	silo_no = (long)VP->v_usdata[0];
	for(;;)  {
		s_entry = (short *)(IObase+SILO_BASE + (silo_no * SILO_DEPTH));
		cin = (long)((*s_entry) & 0xff);  	/* Get char. count */
		if (cin==0) goto nomore;

		/* Print contents of 1 SILO */
		for(no_char=1; no_char<=cin; no_char++)
			{
			ascii = (char)((s_entry[no_char] & 0xff00) >> 8);
			if ( !(s_entry[no_char] & 0x00c0) )  {
				pno = s_entry[no_char] & 0x3f;

				/* Check for port no out of bound */
				if (!((pno>log_pn) || (pno<log_p0))) {
					fillc(pno,ascii);  }
				}
			   else {
				/* Data receive error : parity,frame,overrun */
				/*
				writes("data receive error ");
				error = (long)(s_entry[no_char] & 0xc0) >> 6;
				writeh(error & 0x3); NL;
				*/
				}
			}
		*s_entry = 0;  		/* Clear char. count */
		silo_no++;		/* Proceed to next silo */
	}
nomore:
	count = 200;
	while (v_busy())		/* Test VIOC Busy flag */
		{ DELAY(0x50000);
		  if (--count == 0) 
			panic("\nUNSOL hdlr : Time out on VIOC busy flag..\n");
		}
	VP->v_uqual = 0;		/* Reset UNSOL BUSY FLAG */
	v_int((char)V_URESP);		/* Sent ACK UNSOL interrupt to VIOC */
	return(0);
}


fillc(pno,c)
long pno;
char c;
{	struct vbuf *vb;

	vb = &vi_buf[pno-1];
	if (vb->cnt >= BUFLEN) {
		writes("\ninput overflow port ");
		writed(pno); NL;
		return(0); }
	vb->buf[vb->nxt_fill++] = c;
	vb->cnt++;
	if (vb->nxt_fill > BUFLEN) vb->nxt_fill = 0; 
}


char get1c(pno)
long pno;
{	struct vbuf *vb;
	char c;

	vb = &vi_buf[pno-1];
	if (vb->cnt == 0) return((char)0xff);
	c = vb->buf[vb->nxt_c++];
	vb->cnt--;
	if (vb->nxt_c > BUFLEN) vb->nxt_c = 0; 
	return(c);
}

unix.superglobalmegacorp.com

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