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