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