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