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 */ 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 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 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 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 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 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 */ 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