xref: /csrg-svn/sys/tahoe/stand/cy.c (revision 49431)
1*49431Sbostic /*-
2*49431Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*49431Sbostic  * All rights reserved.
4*49431Sbostic  *
5*49431Sbostic  * This code is derived from software contributed to Berkeley by
6*49431Sbostic  * Computer Consoles Inc.
7*49431Sbostic  *
8*49431Sbostic  * %sccs.include.proprietary.c%
9*49431Sbostic  *
10*49431Sbostic  *	@(#)cy.c	7.13 (Berkeley) 05/08/91
11*49431Sbostic  */
1225867Ssam 
1325867Ssam /*
1425867Ssam  * Cypher tape driver. Stand alone version.
1525867Ssam  */
1645796Sbostic #include "../include/pte.h"
1745796Sbostic #include "../include/mtpr.h"
1825867Ssam 
1943457Sroot #include "sys/param.h"
2043457Sroot #include "sys/time.h"
2125867Ssam 
2245796Sbostic #include "stand/saio.h"
2325867Ssam 
2430514Skarels #define CYERROR
2545796Sbostic #include "../vba/cyreg.h"
2645796Sbostic #include "../vba/vbaparam.h"
2725931Ssam 
2830514Skarels /*
2930514Skarels  * NB: this driver assumes unit 0 throughout.
3030514Skarels  */
3125867Ssam long	cystd[] = { 0xf4000, 0 };
3225931Ssam #define	CYADDR(i)	(cystd[i] + (int)VBIOBASE)
3325867Ssam 
3430514Skarels struct	cyscp *cyscp[] = { (struct cyscp *)0xc06, (struct cyscp *)0 };
3530514Skarels #define	CYSCP(i)	(cyscp[i])
3625867Ssam 
3730514Skarels struct	cyscp *SCP;
3830514Skarels struct	cyscb scb;
3930514Skarels struct	cyccb ccb;
4030514Skarels struct	cytpb tpb;
4130514Skarels struct	cytpb cycool;		/* tape parameter block to clear interrupts */
4230514Skarels #ifdef notdef
4330314Ssam int	cyblocksize = 1024;	/* foreign tape size as found in open routine */
4430514Skarels #endif
4530514Skarels int	cybufsize;		/* controller buffer size */
4630314Ssam long	cyblock;		/* next block number for i/o */
4730314Ssam 
4825867Ssam /*
4925867Ssam  * Reset the controller.
5025867Ssam  */
cyopen(io)5125867Ssam cyopen(io)
5225867Ssam 	register struct iob *io;
5325867Ssam {
5430314Ssam 	register ctlradr = CYADDR(0);
5534465Sbostic 	register int skip;
5625867Ssam 
5734465Sbostic 	if ((u_int)io->i_adapt)
5834465Sbostic 		return (EADAPT);
5934465Sbostic 	if ((u_int)io->i_ctlr)
6034465Sbostic 		return (ECTLR);
6130514Skarels 	SCP = CYSCP(0);				/* absolute - for setup */
6230514Skarels 	CY_RESET(ctlradr);			/* reset the controller */
6325867Ssam 	/*
6425867Ssam 	 * Initialize the system configuration pointer
6525867Ssam 	 */
6630514Skarels 	SCP->csp_buswidth = 1;			/* system width = 16 bits. */
6730514Skarels 	SCP->csp_unused = 0;
6825867Ssam 	/* initialize the pointer to the system configuration block */
6930514Skarels 	cyldmba(SCP->csp_scb, (caddr_t)&scb);
7025867Ssam 	/*
7125867Ssam 	 * Initialize the system configuration block.
7225867Ssam 	 */
7330514Skarels 	scb.csb_fixed = CSB_FIXED;		/* fixed value */
7425867Ssam 	/* initialize the pointer to the channel control block */
7530514Skarels 	cyldmba(scb.csb_ccb, (caddr_t)&ccb);
7625867Ssam 	/*
7725867Ssam 	 * Initialize the channel control block.
7825867Ssam 	 */
7930514Skarels 	ccb.cbcw = CBCW_IE;		/* normal interrupts */
8025867Ssam 	/* initialize the pointer to the tape parameter block */
8130514Skarels 	cyldmba(ccb.cbtpb, (caddr_t)&tpb);
8225867Ssam 	/*
8330514Skarels 	 * set the command to be CY_NOP.
8425867Ssam 	 */
8530514Skarels 	tpb.tpcmd = CY_NOP;
8630514Skarels 	/*
8730514Skarels 	 * TPB not used on first attention
8830514Skarels 	 */
8930514Skarels 	tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS;
9030514Skarels 	ccb.cbgate = GATE_CLOSED;
9130514Skarels 	CY_GO(ctlradr);			/* execute! */
9225867Ssam 	cywait(10*1000);
9325867Ssam 	/*
9430514Skarels 	 * set the command to be CY_CONFIGURE.
9530514Skarels 	 * NO interrupt on completion.
9625867Ssam 	 */
9730514Skarels 	tpb.tpcmd = CY_CONFIG;
9830514Skarels 	tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS;
9930514Skarels 	tpb.tpstatus = 0;
10030514Skarels 	ccb.cbgate = GATE_CLOSED;
10130514Skarels 	CY_GO(ctlradr);			/* execute! */
10225867Ssam 	cywait(10*1000);
10330514Skarels 	uncache(&tpb.tpstatus);
10430514Skarels 	if (tpb.tpstatus & CYS_ERR) {
10530314Ssam 		printf("Cypher initialization error!\n");
10630759Skarels 		cy_print_error(tpb.tpcmd, tpb.tpstatus);
10730854Skarels 		return (ENXIO);
10825867Ssam 	}
10930514Skarels 	uncache(&tpb.tpcount);
11030514Skarels 	cybufsize = tpb.tpcount;
11130854Skarels 	if (cycmd(io, CY_REW) == -1) {
11230854Skarels 		printf("cy%d: Rewind failed!\n", io->i_unit);
11330854Skarels 		return (ENXIO);
11430854Skarels 	}
11534465Sbostic 	for (skip = io->i_part; skip--;)
11630854Skarels 		if (cycmd(io, CY_FSF) == -1) {
11730854Skarels 			printf("cy%d: seek failure!\n", io->i_unit);
11830854Skarels 			return (ENXIO);
11930854Skarels 		}
12030514Skarels #ifdef notdef
12125867Ssam #ifdef NOBLOCK
12225867Ssam 	if (io->i_flgs & F_READ) {
12330514Skarels 		cyblocksize = cycmd(io, CY_READFORN);
12430314Ssam 		if (cyblocksize == -1)
12530314Ssam 			_stop("Read foreign tape failed\n");
12630314Ssam 		cyblock++;		/* XXX force backspace record */
12730514Skarels 		if (cycmd(io, CY_SFORW) == -1)
12830314Ssam 			_stop("Backspace after read foreign failed\n");
12925867Ssam 	}
13025867Ssam #endif
13130514Skarels #endif
13230854Skarels 	return (0);
13325867Ssam }
13425867Ssam 
cyclose(io)13525867Ssam cyclose(io)
13625867Ssam 	register struct iob *io;
13725867Ssam {
13830314Ssam 
13930514Skarels 	if (io->i_flgs & F_WRITE) {	/* if writing, write file marks */
14030514Skarels 		cycmd(io, CY_WEOF);
14130514Skarels 		cycmd(io, CY_WEOF);
14230514Skarels 	}
14330514Skarels 	cycmd(io, CY_REW);
14425867Ssam }
14525867Ssam 
cystrategy(io,func)14630314Ssam cystrategy(io, func)
14725867Ssam 	register struct iob *io;
14830314Ssam 	register func;
14925867Ssam {
15030759Skarels 	register count;
15125867Ssam 
15225867Ssam #ifndef NOBLOCK
15330514Skarels 	if (func != CY_SFORW && func != CY_REW && io->i_bn != cyblock) {
15430514Skarels 		cycmd(io, CY_SFORW);
15530514Skarels 		tpb.tprec = 0;
15625867Ssam 	}
15749096Sbostic 	if (func == F_READ || func == F_WRITE) {
15825867Ssam 		struct iob liob;
15925867Ssam 		register struct iob *lio = &liob;
16025867Ssam 
16125867Ssam 		liob = *io;
16230314Ssam 		while (lio->i_cc > 0) {
16330759Skarels 			if ((count = cycmd(lio, func)) == 0) {
16430759Skarels 				printf("cy%d: I/O error bn %d\n",
16530759Skarels 				    io->i_unit, io->i_bn);
16630314Ssam 				return (-1);
16730759Skarels 			}
16825867Ssam 			lio->i_cc -= count;
16925867Ssam 			lio->i_ma += count;
17025867Ssam 		}
17130314Ssam 		return (io->i_cc);
17225867Ssam 	}
17325867Ssam #endif
17430759Skarels 	count = cycmd(io, func);
17530759Skarels 	if (count == -1)
17630759Skarels 		printf("cy%d: I/O error bn %d\n", io->i_unit, io->i_bn);
17730759Skarels 	return (count);
17825867Ssam }
17925867Ssam 
cycmd(io,func)18030314Ssam cycmd(io, func)
18125867Ssam 	register struct iob *io;
18230314Ssam 	long func;
18325867Ssam {
18430314Ssam 	register ctlradr = CYADDR(0);
18530314Ssam 	int timeout = 0;
18630514Skarels 	int err;
18725867Ssam 	short j;
18825867Ssam 
18930514Skarels 	cywait(9000); 			/* shouldn't be needed */
19034465Sbostic #define	PACKUNIT(unit)	(((unit&1)<<11)|((unit&2)<<9)|((unit&4)>>2))
19134465Sbostic 	tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS | PACKUNIT(io->i_unit);
19230514Skarels 	tpb.tpstatus = 0;
19330514Skarels 	tpb.tpcount = 0;
19430514Skarels 	cyldmba(ccb.cbtpb, (caddr_t)&tpb);
19530514Skarels 	tpb.tpcmd = func;
19630314Ssam 	switch (func) {
19749096Sbostic 	case F_READ:
19830514Skarels #ifdef notdef
19930314Ssam 		if (io->i_cc > cyblocksize)
20030514Skarels 			tpb.tpsize = htoms(cyblocksize);
20130314Ssam 		else
20230514Skarels #endif
20330514Skarels 		tpb.tpsize = htoms(io->i_cc);
20430514Skarels 		cyldmba(tpb.tpdata, io->i_ma);
20530514Skarels 		tpb.tpcmd = CY_RCOM;
20630314Ssam 		cyblock++;
20725867Ssam 		break;
20849096Sbostic 	case F_WRITE:
20930514Skarels 		tpb.tpcmd = CY_WCOM;
21030514Skarels 		tpb.tpsize = htoms(io->i_cc);
21130514Skarels 		cyldmba(tpb.tpdata, io->i_ma);
21230314Ssam 		cyblock++;
21325867Ssam 		break;
21430514Skarels 	case CY_SFORW:
21525867Ssam 		if ((j = io->i_bn - cyblock) < 0) {
21625867Ssam 			j = -j;
21730514Skarels 			tpb.tpcontrol |= CYCW_REV;
21825867Ssam 			cyblock -= j;
21930314Ssam 		} else
22025867Ssam 			cyblock += j;
22130514Skarels 		tpb.tprec = htoms(j);
22230314Ssam 		timeout = 60*5;
22325867Ssam 		break;
22430514Skarels 	case CY_FSF:
22530514Skarels 		tpb.tprec = htoms(1);
22630314Ssam 		/* fall thru... */
22730514Skarels 	case CY_REW:
22825867Ssam 		cyblock = 0;
22930314Ssam 		timeout = 60*5;
23025867Ssam 		break;
23125867Ssam 	}
23230514Skarels 	ccb.cbgate = GATE_CLOSED;
23330514Skarels 	CY_GO(ctlradr);			/* execute! */
23430314Ssam 	if (timeout == 0)
23530314Ssam 		timeout = 10;
23630314Ssam 	cywait(timeout*1000);
23725867Ssam 	/*
23825867Ssam 	 * First we clear the interrupt and close the gate.
23925867Ssam 	 */
24025867Ssam 	mtpr(PADC, 0);
24130514Skarels 	ccb.cbgate = GATE_CLOSED;
24230514Skarels 	cyldmba(ccb.cbtpb, (caddr_t)&cycool);
24330514Skarels 	cycool.tpcontrol = CYCW_LOCK;	/* No INTERRUPTS */
24430514Skarels 	CY_GO(ctlradr);
24525867Ssam 	cywait(20000);
24630514Skarels 	uncache(&tpb.tpstatus);
24730759Skarels 	if ((err = (tpb.tpstatus & CYS_ERR)) &&
24830514Skarels 	    err != CYER_FM && (err != CYER_STROBE || tpb.tpcmd != CY_RCOM)) {
24930759Skarels 		cy_print_error(tpb.tpcmd, tpb.tpstatus);
25030314Ssam 		io->i_error = EIO;
25130314Ssam 		return (-1);
25225867Ssam 	}
25330514Skarels 	uncache(&tpb.tpcount);
25430514Skarels 	return ((int)htoms(tpb.tpcount));
25525867Ssam }
25634465Sbostic 
cy_print_error(op,status)25730759Skarels cy_print_error(op, status)
25830759Skarels 	int op, status;
25925867Ssam {
26030514Skarels 	register char *message;
26130314Ssam 
26230514Skarels 	if ((status & CYS_ERR) < NCYERROR)
26330514Skarels 		message = cyerror[status & CYS_ERR];
26430514Skarels 	else
26530514Skarels 		message = "unknown error";
26630759Skarels 	printf("cy0: cmd %x %s, status=%b.\n", op, message, status, CYS_BITS);
26725867Ssam }
26825867Ssam 
cywait(timeout)26925867Ssam cywait(timeout)
27030314Ssam 	register timeout;
27125867Ssam {
27230314Ssam 	do {
27325867Ssam 		DELAY(1000);
27430514Skarels 		uncache(&ccb.cbgate);
27530514Skarels 	} while (ccb.cbgate != GATE_OPEN && --timeout > 0);
27630314Ssam 	if (timeout <= 0)
27730314Ssam 		_stop("cy: Transfer timeout");
27825867Ssam }
27925867Ssam 
28025867Ssam /*
28130514Skarels  * Load a 20 bit pointer into a Tapemaster pointer.
28225867Ssam  */
cyldmba(reg,value)28330514Skarels cyldmba(reg, value)
28430514Skarels 	register caddr_t reg;
28530514Skarels 	caddr_t value;
28625867Ssam {
28730514Skarels 	register int v = (int)value;
28830314Ssam 
28930514Skarels 	*reg++ = v;
29030514Skarels 	*reg++ = v >> 8;
29130514Skarels 	*reg++ = 0;
29230514Skarels 	*reg = (v&0xf0000) >> 12;
29325867Ssam }
294