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