File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / d / pits / tape.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


/*
 *********************
 *
 * Cypher tape driver
 *
 *********************/

#include "pte.h"
#include "cy.h"
#include "cyconf.h"

struct scp *SCP;	/* Pointer System configuration block */
struct scb scblk;	/* System conf. block */
struct ccb ccblk;	/* Channel control block */
struct tpb tpb;		/* Tape parameter block */
struct tpb tpb1;	/* Tape parameter block (spare) */
long cmd_done;		/* 1 : cmd completed without error */
			/* 2 : cmd error */
long CYattn;		/* Virtual address of Cypher I/O attention address */
long ntape;
extern long unused, Multi, Berr;
extern short erase, unit;

chk_tape()
{	register long r12;
	long oldvec;

	m_cy();			/* Map Tape master space */

	/* Set handler for tape master interrupt */
	asm("movab cyhdlr,r12");
	set_handler(CYVEC,&oldvec,r12);

	cy_reset();		/* Reset Tape master */
	return(ntape); 
}
tape()
{
	if (ntape == 0) {
		writes("\n\nNo Tape controller installed\n");
		return(0); }
	return(cy_setup());   /* Set up structures and initialize Tape master */
}
long tm_cnt;
/*	
	Routine to sent a command to Tape master
	return -1 if error
	return return count of TPB if sucessful
*/
sent_tm()
{	register long cntr, rtn_cnt;

	tm_cnt = 0;
	ccblk.gate = (char)GATE_CLOSED;		/* Close gate */
	cy_attn();				/* Execute command */
	cntr = RETRY;
	cmd_done = 0;
	if (Multi) return;
	while (!cmd_done) {		/* Wait for completion interrupt */
		DELAY(0x100000);
		if (--cntr == 0) {
			writes("\n...sent_tm no interrupt respond");
			return(-1);	/* Time out */
			}
		}
	if (cmd_done == 2) return(-1); 	/* Command has error */	
	return(tm_cnt);
}

/* 	Tape master completion interrupt handler
*/
tm_hdlr()
{
	if (chk_cstat())
		cmd_done = 2;	/* completion error */
	   else cmd_done = 1;	/* completion without error */
	tm_cnt = gt_bcnt();	/* Get return count from TPB */
	clr_tint();		/* Clear tape master interrupt */
}
/*	
	Routine to ACK on tape master completion interrupt
	Sent out a NOOP command without interrupt on completion
*/
clr_tint()
{
	while (g_open()==0)	/* Gate close */
		{ tm_init();
		error("\n...Received interrupt but gate closed.");
		}
	ccblk.gate = GATE_CLOSED;	
	ccblk.ccw = 0x9;		/* Clear tape master interrupt */
	set_g3(&tpb,NOOP,0,0,0);	/* No Interrupt on completion please */
	cy_attn();
	DELAY(0x1500);			/* wait for completion */
	while (g_open()==0)	/* Gate close */
		{ tm_init();
		error("\n...Cannot clear interrupt");
		return(0);
		}
	ccblk.ccw = 0x11;
	return(1);
}
/*	
	Check status of command previously issued
	If all are OK return 0
		else return Status byte.
*/
chk_cstat()
{
	register long *r12, cstat;
	r12 = (long *)&tpb.status[1];
	uncache(r12);
  	/* Cmd status without retry bit */
	cstat = (long)tpb.status[1];
	if (((cstat & 0x87) == 0x87) && (erase))
		{ writes("\nCy hard error 87 expected, tape is blank\n");
		  return(cstat); } 
	if ((cstat & 0xc0) != 0xc0)
		{ writes("\n...Cy hard error ");
		  writeh(cstat & 0xff); writec('\n');
		  return(cstat); } 
	return(0);
}
/*	
	Check status of drive after received command
	completion interrupt. If all are OK return 0
	else return Status byte.
*/
chk_dstat()
{	register long *r12, tstat;

	r12 = (long *)&tpb.status[0];
	uncache(r12);
	tstat = tpb.status[0];
	if ( (tstat & 0x48) != 0x48)
		{ writes("\n...drive error ");
		  writeh(tstat & 0xff);
		  return(tstat); }
	return(0);
}
/*
	Routine to get return_count field of TPB after
	receive command completion interrupt
*/
gt_bcnt()
{	register long *r12, tmp1, tmp2;

	r12 = (long *)&tpb.count;
	uncache(r12);
	tmp1 = (long)((tpb.count & (short)0xff)<<8);
	tmp2 = (long)((tpb.count & (short)0xff00)>>8);
	return(tmp1|tmp2);
}
/* 	
	Routine to issue a GO command to tape master
	also known as Channel attention interrupt
*/
cy_attn()
{	register long r12;

	r12 = CYattn;		/* R12 = Cypher attention address */
	asm("movob $0xff,(r12)");
}
/* 	
	Routine to reset Tape master controller 
*/
cy_reset()
{	register long r12;

	r12 = CYattn + 1;		/* R12 = Cypher attention address */
	asm("movob $0xff,(r12)");
	DELAY(100);
	ntape = 0;
	writes("\n\nProbing for Tape Master controller...");
	if(!Berr) { 
	    	writes("\nTape Master controller at address ");
		writeh(TBASE);
		ntape++; }
	writes("\n"); writed(ntape); writes(" Tape controller(s) found");
}
/*	
	Map channel attention address of Tape master 
*/
m_cy()
{	register long r12;
	long phys_pg, pte, old_pte, which1;

	/* physical page of Tape master in IO space */
	phys_pg = ((TBASE+IOBASE) >> PGSHIFT) & 0x3fffff;
	pte = phys_pg | PG_KW | PG_V | PG_NC;
	fix_pte(SBR,unused,&old_pte,pte);
	CYattn = (unused << PGSHIFT);	/* Virtual address of CY attn address */
	asm("mfpr $SLR,r12");
	r12++;
	asm("mtpr r12,$SLR");
	unused++;		/* Next unused PTE in system map */
}
/* 	
	Set up all structures for Tape master
	and initialize Tape master
*/
cy_setup()
{
	register long cntr;

	SCP = (struct scp *)SCP_ADR;	/* absolute - for setup */

	/* Initialize the system configuration pointer  */
	SCP->sysbus = 1;			/* system width = 16 bits. */
	set_pointer(&scblk.sysblk,(char *)SCP->pt_scb);

	/* Initialize the system configuration block. */
	scblk.sysblk = 0x3;		/* fixed value */
	scblk.nu2 = 0;			/* not used */
	set_pointer(&ccblk.ccw,(char *)scblk.pt_ccb);

	/* Initialize the channel control block. */
	ccblk.ccw = 0x11;		/* normal interrupts */
	set_pointer(&tpb,(char *)ccblk.pt_tpb);

	ccblk.gate = GATE_CLOSED;	
	cy_attn();		/* 1st attention : initialization Cypher */
	cntr = RETRY;
	while (ccblk.gate == GATE_CLOSED) {
		DELAY(0x400);			/* wait for completion */
		if (--cntr == 0) {
			writes("\n...Init : Cypher time out");
			return(0); }	/* Time out */
		}
	return(1);
}
 /*
 	Set a TAPEMASTER 20_bit 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 */
}
g_open()
{	register long *r12, cntr;

	r12 = (long *)&ccblk.gate;
	cntr = RETRY;
	while (ccblk.gate!=0) {
		uncache(r12);
		DELAY(0x500);			/* wait for completion */
		if (--cntr == 0) {
			writes("\n...g_open time out");
			return(0);
			}
		}
	return(1);
}
error(msg)
char *msg;
{
	writes(msg);
}
/* 	
	Set Tape Parameter Block
	Input :
	      cmd    = Opcode
	      bufsiz = Block size 
	      bufadr = System buffer address
	      int    = interrupt on completion or not
*/
set_g3(tpblk,cmd,bufsiz,bufadr,intr)
struct tpb *tpblk;
long cmd, bufsiz, intr;
char *bufadr;
{ 	char *cptr;

	tpblk->cmd = cmd;			/* Command */
	tpblk->control[1] = 0x80 | CW_100ips;	/* 16_bit system bus */
	tpblk->control[0] = ((unit << 2)|(intr << 5)); /* Drive,interrupt */
	tpblk->count = 0;			/* Return count = 0 */
	cptr = (char *)&tpblk->size;		/* Set buffer size */
	*cptr++ = (char)(bufsiz & 0xff);
	*cptr = (char)((bufsiz & 0xff00)>>8);	
	if(cmd == ERASE_F) 
		tpblk->rec_over = 0x0004;	/* Set record count, erase */
	else
		tpblk->rec_over = 0;		/* Set record count */
	/* Set system buffer address */
	set_pointer((long)(bufadr),(char *)tpblk->pt_data);
	tpblk->status[0] = tpblk->status[1] = 0;/* Clear ctlr & drive status */
}
/* 	
	*************************************
    	Routine to Read/Write Cypher tape 
    	return 0 if cannot complete operation
	*************************************
*/
long tape_op(cmd,buf_adr,buf_siz)
long cmd, buf_siz;
char *buf_adr;
{ 	char *cptr;
	register long cnt, stat, tmp1, tmp2;

	set_g3(&tpb,cmd,buf_siz,buf_adr,1);	/* Set up command block */
	while (g_open()==0) {		/* Gate closed !! */
		tm_init();		/* Init controller */
		writes("\n...tape_op : Can not open gate !!");
		return(0);
		} 
	return(sent_tm());
}

/*	
	Rewind tapemaster
*/
tm_rew()
{	char tstat;
	writes("\nTape rewinding");
	if (tape_op(REWD_TA,0,0) == -1)  return(0);
	tstat = tpb.status[0];
	if ( (tstat & 0x20) != 0x20) return(0);
	return(1);
}
/*	
	Erase 1024 records 
*/
tm_erase()
{
	writes("\nErasing 1024 records");
	if (tape_op(ERASE_F,0,0) == -1) return(0);
	return(1);
}	
/*	
	Routine to initialize tape master 
*/
tm_init()
{	register long cntr;

	cy_reset();
	if (!g_open()) return(0);
	ccblk.gate = GATE_CLOSED;	
	cy_attn();		/* 1st attention : initialization Cypher */
	cntr = RETRY;
	while (ccblk.gate == GATE_CLOSED) {
		DELAY(2000);			/* wait for completion */
		if (--cntr == 0) {
			writes("\n...Init : Cypher time out");
			return(0); }	/* Time out */
		}
	return(1);
}
cyhandler()
{	long dummy;

	asm(".align 2");
asm("cyhdlr:");
	asm("svpctx");
	tm_hdlr();
	asm("ldpctx");
	asm("rei");
	dummy = 0;
}


unix.superglobalmegacorp.com

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