File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / stand / cy.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

/*	cy.c	Tahoe version 	Mar 1983.	*/

/*
 * Cypher tape driver. Stand alone version.
 *
 */
#include "../h/param.h"
#include "../h/inode.h"
#include "../h/fs.h"
#include "../machine/pte.h"
#include "../machine/mtpr.h"
#include "../stand/saio.h"
#include "../stand/cyvar.h"

long	cystd[] = { 0xf4000, 0 };

struct scp	/* SYSTEM CONFIGURATION POINTER */
{
  char sysbus ;	/* width of system buss 0=8;1=16 */
  char nu1 ;
  char pt_scb[4] ;	/* pointer to ->SYSTEM CONFIGURATION BLOCK */
};

struct scp * SCP;	/* absolute address - jumpered on the controller */
			/* set to 0xC06 for Tahoe */

struct scb	/* SYSTEM CONFIGUREATION BLOCK */
{
  char sysblk[1] ;	/* 0x03 fixed value code */
  char nu2[1] ;
  char pt_ccb[4] ;	/* pointer to ->CHANNEL CONTROL BLOCK */
}scb;

struct ccb	/* CHANNEL CONTROL BLOCK */
{
  char ccw[1] ;		/* 0x11 normal; 0x09 clear non_vect interrupt */
  char gate[1] ;	/* This is "the" GATE */
  char pt_tpb[4] ;	/* pointer to ->TAPE OPERATION BLOCK or MOVE BLOCK */
}ccb;

struct tpb	/* TAPE OPERATIONS PARAMETER BLOCK */
{
  long cmd ;		/* COMMAND (input) */
  char control[2] ;	/* CONTROL (input) */
  short count ;		/* RETURN COUNT (output) */
  short size ;		/* BUFFER SIZE (input/output) */
  short rec_over ;	/* RECORDS/OVERRUN (input/output) */
  char pt_data[4] ;	/* pointer to ->SOURCE/DEST (input) */
  char status[2] ;	/* STATUS (output) */
  char pt_link[4] ;	/* pointer to ->INTERRUPT/PARAMETER BLOCK (input) */
} tpb;

struct tpb cycool	/* tape parameter block to clear interrupts */
= {
	0L,		/* command */
	0,0,		/* control */
	0,		/* count */
	0,		/* size */
	0,		/* rec_over */
	0,0,0,0,	/* pt_data */
	0,0,		/* status */
	0,0,0,0		/* pt_link */
} ;	
int cyblksiz = 1024;	/* foreign tape size as found in open routine */
long cyblock;		/* next block number for i/o */
/*
 * Reset the controller.
 */
cyopen(io)
	register struct iob *io;
{
	register ctlradr;

	ctlradr = cystd[0] + IOBASE;
	SCP = (struct scp *)0xc06;		/* absolute - for setup */
	TM_RESET(ctlradr,0xff);	/* reset the controller */
	/*
	 * Initialize the system configuration pointer
	 */
	SCP->sysbus = 1;			/* system width = 16 bits. */
	/* initialize the pointer to the system configuration block */
	set_pointer((long)&scb.sysblk[0],(char *)SCP->pt_scb);
	/*
	 * Initialize the system configuration block.
	 */
	scb.sysblk[0] = 0x3;		/* fixed value */
	/* initialize the pointer to the channel control block */
	set_pointer((long)&ccb.ccw[0],(char *)scb.pt_ccb);
	/*
	 * Initialize the channel control block.
	 */
	ccb.ccw[0] = 0x11;		/* normal interrupts */
	/* initialize the pointer to the tape parameter block */
	set_pointer((long)&tpb,(char *)ccb.pt_tpb);
	/*
	 * set the command to be NO_OP.
	 */
	tpb.cmd = NO_OP;
	tpb.control[0] = CW_BL;		/* TPB not used on first attention */
	tpb.control[1] = CW_16bits;
	ccb.gate[0] = GATE_CLOSED;	
	TM_ATTENTION(ctlradr, 0xff);	/* execute! */
	cywait(10*1000);
	/*
	 * set the command to be CONFIGURE.
	 */
	tpb.cmd = CONFIG;
	tpb.control[0] = CW_BL;		/* NO interrupt on completion */
	tpb.control[1] = CW_16bits;
	tpb.status[0] = tpb.status[1] = 0;
	ccb.gate[0] = GATE_CLOSED;	
	TM_ATTENTION(ctlradr, 0xff);	/* execute! */
	cywait(10*1000);
	uncache (&tpb.status[1]) ;
	if (tpb.status[1] & CS_ERm) {
	   printf("Cypher initialization error!\n");
	   cy_decode_error(tpb.status[1]&CS_ERm);
	   _stop("");
	}
	if(cycmd(io,REWD_TA) == -1)
		_stop("Rewind failed!\n");
	while(io->i_boff > 0) {
		if(cycmd(io,SPAC_FM) == -1)
			_stop("cy: seek failure!\n");
		io->i_boff--;
	}
#ifdef NOBLOCK
	if (io->i_flgs & F_READ) {
		if((cyblksiz = cycmd(io,READ_FO)) == -1)
			_stop("Read foriegn tape failed!\n");
		if(cycmd(io,REWD_TA) == -1)
			_stop("Rewind after read failed\n");
	}
#endif
}

/* if tape was open for writing write a file mark */
cyclose(io)
	register struct iob *io;
{
	if (io->i_flgs & F_WRITE) cycmd(io,WRITE_FMARK);
	cycmd(io,REWD_TA);
	cyblock = 0;
}

cystrategy(io,func)
	register struct iob *io;
	register long	func;
{

#ifndef NOBLOCK
	if ((func != SPACE) && (func != REWD_TA) && (io->i_bn != cyblock)) {
		cycmd(io,SPACE);
		tpb.rec_over = 0;
	}
	if(func==READ || func==WRITE) {
		struct iob liob;
		register struct iob *lio = &liob;
		register count;

		liob = *io;
		while(lio->i_cc > 0) {
			if((count = cycmd(lio, func)) == 0)
				return(-1);
			lio->i_cc -= count;
			lio->i_ma += count;
		}
		return(io->i_cc);
	}
#endif
	return(cycmd(io, func));
}

cycmd(io,func)
	register struct iob *io;
	long	func;
{
	register ctlradr;
	short j;

	ctlradr = cystd[0] + IOBASE;
	cywait(9000); 
	if (func == READ) func = READ_TA;
	else if (func == WRITE) func = WRIT_TA;
	else if (func == WRITE_FMARK) func = WRIT_FM;
	tpb.cmd = func;
	uncache(&ccb.gate[0]);
	while(ccb.gate[0] == GATE_CLOSED)
		uncache(&ccb.gate[0]);
	ccb.gate[0] = GATE_CLOSED;
	tpb.control[0] = CW_BL;
	tpb.control[1] = CW_16bits;
	tpb.status[0] = tpb.status[1] = 0;
	tpb.count = 0;
	set_pointer((long)&tpb,(char *)ccb.pt_tpb);
	switch (func) 
	{
	case READ_TA:
		if (io->i_cc > cyblksiz)
			tpb.size = TM_SHORT(cyblksiz);
		else tpb.size = TM_SHORT(io->i_cc);
		set_pointer((long)io->i_ma,(char *)tpb.pt_data);
		cyblock += 1;
		break;
	case WRIT_TA:
		tpb.size = TM_SHORT(io->i_cc);
		set_pointer((long)io->i_ma,(char *)tpb.pt_data);
		cyblock += 1;
		break;
	case SPACE:
		if ((j = io->i_bn - cyblock) < 0) {
			j = -j;
			tpb.control[1] |= CW_R;
			cyblock -= j;
		}
		else
			cyblock += j;
		tpb.rec_over = TM_SHORT(j);
		break;
	case REWD_TA:
		cyblock = 0;
		break;
	}
	TM_ATTENTION(ctlradr, 0xff);	/* execute! */
	if (func == REWD_TA || func == SPACE) {
		cywait(60*5*1000);
	}
	else cywait(10*1000);
	/*
	 * First we clear the interrupt and close the gate.
	 */
	mtpr (0, PADC);
	ccb.gate[0] = GATE_CLOSED;
	set_pointer((int)&cycool,(char *)ccb.pt_tpb);
	cycool.cmd = NO_OP;	/* no operation */
	cycool.control[0] = CW_BL;	/* No INTERRUPTS */
	cycool.control[1] = 0;
	TM_ATTENTION(ctlradr,0xff);	/* cool it ! */
	cywait(20000); 
	uncache (&tpb.status[1] ) ; 
	if (tpb.status[1] & CS_ERm) {
		cy_decode_error(tpb.status[1]&CS_ERm);
		return -1;
	}
	uncache (&tpb.count);
	return((long)TM_SHORT(tpb.count));
}
	


cyprint_error(message)
register char	*message;
{
	printf("cy0: %s.\n", message);
}

/*
*/

cy_decode_error(status)
register int	status;
{
	switch(status) {
	case ER_TO1:
	case ER_TO2:
	case ER_TO3:
	case ER_TO4:
	case ER_TO5:
		cyprint_error("Drive timed out during transfer");
		break;
	case ER_TO6:	
		cyprint_error("Non-existant system memory reference");
		break;
	case ER_DIAG:
	case ER_JUMP:
		cyprint_error("Controller micro diagnostics failed");
		break;
	case ER_HARD:
		cyprint_error("Unrecoverble media error");
		break;
	case ER_TOF:
		if (tpb.cmd == WRIT_TA)
			cyprint_error("Unsatisfactory media");
		break;
	case ER_FIFO:
		cyprint_error("Data transfer over run");
		break;
	case ER_TRN:
		cyprint_error("Drive is not ready");
		break;
	case ER_PRO:
		cyprint_error("Tape is write protected");
		break;
	case ER_PSUM:
		cyprint_error("Checksum error in controller proms");
		break;
	case ER_PARI:
		cyprint_error("Unrecoverable tape parity error");
		break;
	case ER_BLAN:
		cyprint_error("Blank tape found where data was expected");
		break;
	case ER_ER:
		cyprint_error("Unrecoverble hardware error");
	default:
		break;
	}
}


long 
cywait(timeout)
	long timeout;
{
	long dummy;

	uncache (&ccb.gate[0]) ;
	while (ccb.gate[0] != GATE_OPEN) {
		uncache (&ccb.gate[0]) ;
		DELAY(1000);
		if (--timeout == 0) {
			cyprint_error("Transfer timeout");
			_stop("");
		}
	}
}

/*
 *  Set a TAPEMASTER pointer (first parameter), into the
 *  4 bytes array pointed by the second parameter.
 */
set_pointer(pointer,dest)
long pointer;
char * dest;
{
	*dest++ = pointer & 0xff;		/* low byte - offset */
	*dest++ = (pointer >> 8) & 0xff;	/* high byte - offset */
	*dest++ = 0; 
	*dest   = (pointer & 0xf0000) >> 12;	/* base */
}

movow(word, destination)
long word, destination;
{
	asm("movow	6(fp),*8(fp);");
}

movob(byte, destination)
long byte, destination;
{
	asm("movob	7(fp),*8(fp);");
}

unix.superglobalmegacorp.com

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