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 */
cyopen(io)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
cyclose(io)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
cystrategy(io,func)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
cycmd(io,func)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
cy_print_error(op,status)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
cywait(timeout)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 */
cyldmba(reg,value)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