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