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