xref: /original-bsd/sys/tahoe/stand/cy.c (revision d8754ee5)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Computer Consoles Inc.
7  *
8  * %sccs.include.proprietary.c%
9  *
10  *	@(#)cy.c	7.13 (Berkeley) 05/08/91
11  */
12 
13 /*
14  * Cypher tape driver. Stand alone version.
15  */
16 #include "../include/pte.h"
17 #include "../include/mtpr.h"
18 
19 #include "sys/param.h"
20 #include "sys/time.h"
21 
22 #include "stand/saio.h"
23 
24 #define CYERROR
25 #include "../vba/cyreg.h"
26 #include "../vba/vbaparam.h"
27 
28 /*
29  * NB: this driver assumes unit 0 throughout.
30  */
31 long	cystd[] = { 0xf4000, 0 };
32 #define	CYADDR(i)	(cystd[i] + (int)VBIOBASE)
33 
34 struct	cyscp *cyscp[] = { (struct cyscp *)0xc06, (struct cyscp *)0 };
35 #define	CYSCP(i)	(cyscp[i])
36 
37 struct	cyscp *SCP;
38 struct	cyscb scb;
39 struct	cyccb ccb;
40 struct	cytpb tpb;
41 struct	cytpb cycool;		/* tape parameter block to clear interrupts */
42 #ifdef notdef
43 int	cyblocksize = 1024;	/* foreign tape size as found in open routine */
44 #endif
45 int	cybufsize;		/* controller buffer size */
46 long	cyblock;		/* next block number for i/o */
47 
48 /*
49  * Reset the controller.
50  */
51 cyopen(io)
52 	register struct iob *io;
53 {
54 	register ctlradr = CYADDR(0);
55 	register int skip;
56 
57 	if ((u_int)io->i_adapt)
58 		return (EADAPT);
59 	if ((u_int)io->i_ctlr)
60 		return (ECTLR);
61 	SCP = CYSCP(0);				/* absolute - for setup */
62 	CY_RESET(ctlradr);			/* reset the controller */
63 	/*
64 	 * Initialize the system configuration pointer
65 	 */
66 	SCP->csp_buswidth = 1;			/* system width = 16 bits. */
67 	SCP->csp_unused = 0;
68 	/* initialize the pointer to the system configuration block */
69 	cyldmba(SCP->csp_scb, (caddr_t)&scb);
70 	/*
71 	 * Initialize the system configuration block.
72 	 */
73 	scb.csb_fixed = CSB_FIXED;		/* fixed value */
74 	/* initialize the pointer to the channel control block */
75 	cyldmba(scb.csb_ccb, (caddr_t)&ccb);
76 	/*
77 	 * Initialize the channel control block.
78 	 */
79 	ccb.cbcw = CBCW_IE;		/* normal interrupts */
80 	/* initialize the pointer to the tape parameter block */
81 	cyldmba(ccb.cbtpb, (caddr_t)&tpb);
82 	/*
83 	 * set the command to be CY_NOP.
84 	 */
85 	tpb.tpcmd = CY_NOP;
86 	/*
87 	 * TPB not used on first attention
88 	 */
89 	tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS;
90 	ccb.cbgate = GATE_CLOSED;
91 	CY_GO(ctlradr);			/* execute! */
92 	cywait(10*1000);
93 	/*
94 	 * set the command to be CY_CONFIGURE.
95 	 * NO interrupt on completion.
96 	 */
97 	tpb.tpcmd = CY_CONFIG;
98 	tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS;
99 	tpb.tpstatus = 0;
100 	ccb.cbgate = GATE_CLOSED;
101 	CY_GO(ctlradr);			/* execute! */
102 	cywait(10*1000);
103 	uncache(&tpb.tpstatus);
104 	if (tpb.tpstatus & CYS_ERR) {
105 		printf("Cypher initialization error!\n");
106 		cy_print_error(tpb.tpcmd, tpb.tpstatus);
107 		return (ENXIO);
108 	}
109 	uncache(&tpb.tpcount);
110 	cybufsize = tpb.tpcount;
111 	if (cycmd(io, CY_REW) == -1) {
112 		printf("cy%d: Rewind failed!\n", io->i_unit);
113 		return (ENXIO);
114 	}
115 	for (skip = io->i_part; skip--;)
116 		if (cycmd(io, CY_FSF) == -1) {
117 			printf("cy%d: seek failure!\n", io->i_unit);
118 			return (ENXIO);
119 		}
120 #ifdef notdef
121 #ifdef NOBLOCK
122 	if (io->i_flgs & F_READ) {
123 		cyblocksize = cycmd(io, CY_READFORN);
124 		if (cyblocksize == -1)
125 			_stop("Read foreign tape failed\n");
126 		cyblock++;		/* XXX force backspace record */
127 		if (cycmd(io, CY_SFORW) == -1)
128 			_stop("Backspace after read foreign failed\n");
129 	}
130 #endif
131 #endif
132 	return (0);
133 }
134 
135 cyclose(io)
136 	register struct iob *io;
137 {
138 
139 	if (io->i_flgs & F_WRITE) {	/* if writing, write file marks */
140 		cycmd(io, CY_WEOF);
141 		cycmd(io, CY_WEOF);
142 	}
143 	cycmd(io, CY_REW);
144 }
145 
146 cystrategy(io, func)
147 	register struct iob *io;
148 	register func;
149 {
150 	register count;
151 
152 #ifndef NOBLOCK
153 	if (func != CY_SFORW && func != CY_REW && io->i_bn != cyblock) {
154 		cycmd(io, CY_SFORW);
155 		tpb.tprec = 0;
156 	}
157 	if (func == F_READ || func == F_WRITE) {
158 		struct iob liob;
159 		register struct iob *lio = &liob;
160 
161 		liob = *io;
162 		while (lio->i_cc > 0) {
163 			if ((count = cycmd(lio, func)) == 0) {
164 				printf("cy%d: I/O error bn %d\n",
165 				    io->i_unit, io->i_bn);
166 				return (-1);
167 			}
168 			lio->i_cc -= count;
169 			lio->i_ma += count;
170 		}
171 		return (io->i_cc);
172 	}
173 #endif
174 	count = cycmd(io, func);
175 	if (count == -1)
176 		printf("cy%d: I/O error bn %d\n", io->i_unit, io->i_bn);
177 	return (count);
178 }
179 
180 cycmd(io, func)
181 	register struct iob *io;
182 	long func;
183 {
184 	register ctlradr = CYADDR(0);
185 	int timeout = 0;
186 	int err;
187 	short j;
188 
189 	cywait(9000); 			/* shouldn't be needed */
190 #define	PACKUNIT(unit)	(((unit&1)<<11)|((unit&2)<<9)|((unit&4)>>2))
191 	tpb.tpcontrol = CYCW_LOCK | CYCW_16BITS | PACKUNIT(io->i_unit);
192 	tpb.tpstatus = 0;
193 	tpb.tpcount = 0;
194 	cyldmba(ccb.cbtpb, (caddr_t)&tpb);
195 	tpb.tpcmd = func;
196 	switch (func) {
197 	case F_READ:
198 #ifdef notdef
199 		if (io->i_cc > cyblocksize)
200 			tpb.tpsize = htoms(cyblocksize);
201 		else
202 #endif
203 		tpb.tpsize = htoms(io->i_cc);
204 		cyldmba(tpb.tpdata, io->i_ma);
205 		tpb.tpcmd = CY_RCOM;
206 		cyblock++;
207 		break;
208 	case F_WRITE:
209 		tpb.tpcmd = CY_WCOM;
210 		tpb.tpsize = htoms(io->i_cc);
211 		cyldmba(tpb.tpdata, io->i_ma);
212 		cyblock++;
213 		break;
214 	case CY_SFORW:
215 		if ((j = io->i_bn - cyblock) < 0) {
216 			j = -j;
217 			tpb.tpcontrol |= CYCW_REV;
218 			cyblock -= j;
219 		} else
220 			cyblock += j;
221 		tpb.tprec = htoms(j);
222 		timeout = 60*5;
223 		break;
224 	case CY_FSF:
225 		tpb.tprec = htoms(1);
226 		/* fall thru... */
227 	case CY_REW:
228 		cyblock = 0;
229 		timeout = 60*5;
230 		break;
231 	}
232 	ccb.cbgate = GATE_CLOSED;
233 	CY_GO(ctlradr);			/* execute! */
234 	if (timeout == 0)
235 		timeout = 10;
236 	cywait(timeout*1000);
237 	/*
238 	 * First we clear the interrupt and close the gate.
239 	 */
240 	mtpr(PADC, 0);
241 	ccb.cbgate = GATE_CLOSED;
242 	cyldmba(ccb.cbtpb, (caddr_t)&cycool);
243 	cycool.tpcontrol = CYCW_LOCK;	/* No INTERRUPTS */
244 	CY_GO(ctlradr);
245 	cywait(20000);
246 	uncache(&tpb.tpstatus);
247 	if ((err = (tpb.tpstatus & CYS_ERR)) &&
248 	    err != CYER_FM && (err != CYER_STROBE || tpb.tpcmd != CY_RCOM)) {
249 		cy_print_error(tpb.tpcmd, tpb.tpstatus);
250 		io->i_error = EIO;
251 		return (-1);
252 	}
253 	uncache(&tpb.tpcount);
254 	return ((int)htoms(tpb.tpcount));
255 }
256 
257 cy_print_error(op, status)
258 	int op, status;
259 {
260 	register char *message;
261 
262 	if ((status & CYS_ERR) < NCYERROR)
263 		message = cyerror[status & CYS_ERR];
264 	else
265 		message = "unknown error";
266 	printf("cy0: cmd %x %s, status=%b.\n", op, message, status, CYS_BITS);
267 }
268 
269 cywait(timeout)
270 	register timeout;
271 {
272 	do {
273 		DELAY(1000);
274 		uncache(&ccb.cbgate);
275 	} while (ccb.cbgate != GATE_OPEN && --timeout > 0);
276 	if (timeout <= 0)
277 		_stop("cy: Transfer timeout");
278 }
279 
280 /*
281  * Load a 20 bit pointer into a Tapemaster pointer.
282  */
283 cyldmba(reg, value)
284 	register caddr_t reg;
285 	caddr_t value;
286 {
287 	register int v = (int)value;
288 
289 	*reg++ = v;
290 	*reg++ = v >> 8;
291 	*reg++ = 0;
292 	*reg = (v&0xf0000) >> 12;
293 }
294