1: /* @(#)tmscp.c 7.1.5 (2.11BSD GTE) 1998/1/30 */ 2: 3: /**************************************************************** 4: * Licensed from Digital Equipment Corporation * 5: * Copyright (c) * 6: * Digital Equipment Corporation * 7: * Maynard, Massachusetts * 8: * 1985, 1986 * 9: * All rights reserved. * 10: * * 11: * The Information in this software is subject to change * 12: * without notice and should not be construed as a commitment * 13: * by Digital Equipment Corporation. Digital makes no * 14: * representations about the suitability of this software for * 15: * any purpose. It is supplied "As Is" without expressed or * 16: * implied warranty. * 17: * * 18: * If the Regents of the University of California or its * 19: * licensees modify the software in a manner creating * 20: * deriviative copyright rights, appropriate copyright * 21: * legends may be placed on the drivative work in addition * 22: * to that set forth above. * 23: ***************************************************************/ 24: /* 25: * tmscp.c - TMSCP (TK50/TU81) standalone driver 26: */ 27: 28: /* static char *sccsid = "@(#)tmscp.c 1.5 (ULTRIX) 4/18/86"; */ 29: 30: /* ------------------------------------------------------------------------ 31: * Modification History: /sys/pdpstand/tmscp.c 32: * 33: * 5-30-95 sms - new iob structure. 34: * 4-20-91 sms - add multi controller and unit support (sms) 35: * 8-20-90 steven m. schultz (sms@wlv.iipo.gtegsc.com) 36: * Port from 4.3BSD to 2.11BSD 37: * 3-15-85 afd 38: * Don't ask for an interrupt when commands are issued and 39: * check ownership bit in the response descriptor to detect when a 40: * command is complete. Necessary due to the TU81's failure to set 41: * the response interrupt field in the communications area. 42: * 43: * ------------------------------------------------------------------------ 44: */ 45: 46: #include "../h/param.h" 47: #include "saio.h" 48: 49: /* 50: * Parameters for the communications area 51: * (Only 1 cmd & 1 rsp packet) 52: */ 53: #define NRSPL2 0 /* Define these before including */ 54: #define NCMDL2 0 /* tmscpreg.h and tmscp.h below */ 55: 56: #include "sys/buf.h" 57: #include "../pdpuba/tmscpreg.h" 58: #include "../pdp/tmscp.h" 59: 60: #define NTMS 2 61: 62: struct tmscpdevice *TMScsr[NTMS + 1] = 63: { 64: (struct tmscpdevice *)0174500, 65: (struct tmscpdevice *)0, 66: (struct tmscpdevice *)-1 67: }; 68: 69: struct tmscp tmscp[NTMS]; 70: 71: u_char tmsoffline[NTMS] = {1, 1}; /* Flag to prevent multiple STCON */ 72: u_char tms_offline[NTMS][4] = {{1,1,1,1}, 73: {1,1,1,1}}; /* Flag to prevent multiple ONLIN */ 74: static char opnmsg[] = "tms%d: step %d failed sa=0%o\n"; 75: 76: extern int tapemark; /* flag to indicate tapemark encountered 77: (see sys.c as to how it's used) */ 78: 79: /* 80: * Open a tmscp device. Initialize the controller and set the unit online. 81: */ 82: tmscpopen(io) 83: register struct iob *io; 84: { 85: register struct tmscpdevice *tmscpaddr; 86: int ctlr = io->i_ctlr; 87: int unit = io->i_unit, bae, lo16; 88: register struct tmscp *tms = &tmscp[ctlr]; 89: 90: if (genopen(NTMS, io) < 0) 91: return(-1); 92: io->i_flgs |= F_TAPE; 93: tmscpaddr = TMScsr[ctlr]; 94: 95: /* 96: * Have the tmscp controller characteristics already been set up 97: * (STCON)? 98: */ 99: if (tmsoffline[ctlr]) 100: { 101: /* 102: * Initialize the tmscp device and wait for the 4 steps 103: * to complete. 104: */ 105: tmscpaddr->tmscpip = 0; 106: while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0) 107: ; 108: tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8); 109: 110: while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0) 111: ; 112: #define STEP1MASK 0174377 113: #define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2) 114: iomapadr(&tms->tmscp_ca.ca_ringbase, &bae, &lo16); 115: if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD) 116: printf(opnmsg, ctlr, 1, tmscpaddr->tmscpsa); 117: tmscpaddr->tmscpsa = lo16; 118: 119: while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0) 120: ; 121: #define STEP2MASK 0174377 122: #define STEP2GOOD (TMSCP_STEP3) 123: if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD) 124: printf(opnmsg, ctlr, 2, tmscpaddr->tmscpsa); 125: tmscpaddr->tmscpsa = bae; 126: 127: while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0) 128: ; 129: #define STEP3MASK 0174000 130: #define STEP3GOOD TMSCP_STEP4 131: if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD) 132: printf(opnmsg, ctlr, 3, tmscpaddr->tmscpsa); 133: tmscpaddr->tmscpsa = TMSCP_GO; 134: if (tmscpcmd(io, M_OP_STCON, 0) == 0) 135: { 136: printf("%s STCON", devname(io)); 137: return(-1); 138: } 139: tmsoffline[ctlr] = 0; 140: } 141: tms->tmscp_cmd[0].mscp_unit = unit; 142: /* 143: * Has this unit been issued an ONLIN? 144: */ 145: if (tms_offline[ctlr][unit]) 146: { 147: if (tmscpcmd(io, M_OP_ONLIN, 0) == 0) 148: { 149: printf("%s ONLIN", devname(io)); 150: return(-1); 151: } 152: tms_offline[ctlr][unit] = 0; 153: } 154: tmscpclose(io); /* close just does a rewind */ 155: if (io->i_part > 0) 156: /* 157: * Skip forward the appropriate number of files on the tape. 158: */ 159: { 160: tms->tmscp_cmd[0].mscp_tmkcnt = io->i_part; 161: tms->tmscp_cmd[0].mscp_buffer_h = 0; 162: tms->tmscp_cmd[0].mscp_bytecnt = 0; 163: tmscpcmd(io, M_OP_REPOS, 0); 164: tms->tmscp_cmd[0].mscp_tmkcnt = 0; 165: } 166: return(0); 167: } 168: 169: /* 170: * Close the device (rewind it to BOT) 171: */ 172: tmscpclose(io) 173: register struct iob *io; 174: { 175: register struct tmscp *tms = &tmscp[io->i_ctlr]; 176: 177: tms->tmscp_cmd[0].mscp_buffer_l = 0; /* tmkcnt */ 178: tms->tmscp_cmd[0].mscp_buffer_h = 0; 179: tms->tmscp_cmd[0].mscp_bytecnt = 0; 180: tms->tmscp_cmd[0].mscp_unit = io->i_unit; 181: tmscpcmd(io, M_OP_REPOS, M_MD_REWND | M_MD_CLSEX); 182: } 183: 184: /* 185: * Set up tmscp command packet. Cause the controller to poll to pick up 186: * the command. 187: */ 188: tmscpcmd(io, op,mod) 189: struct iob *io; 190: int op, mod; /* opcode and modifier (usu 0) */ 191: { 192: int ctlr = io->i_ctlr; 193: register struct tmscp *tms = &tmscp[ctlr]; 194: register struct mscp *mp; /* ptr to cmd packet */ 195: int i; /* read into to init polling */ 196: int bae, lo16; 197: 198: /* 199: * Init cmd & rsp area 200: */ 201: iomapadr(&tms->tmscp_cmd[0].mscp_cmdref, &bae, &lo16); 202: tms->tmscp_ca.ca_cmddsc[0].lsh = lo16; 203: tms->tmscp_ca.ca_cmddsc[0].hsh = bae; 204: tms->tmscp_cmd[0].mscp_dscptr = (long *)tms->tmscp_ca.ca_cmddsc; 205: tms->tmscp_cmd[0].mscp_header.mscp_vcid = 1; /* for tape */ 206: 207: iomapadr(&tms->tmscp_rsp[0].mscp_cmdref, &bae, &lo16); 208: tms->tmscp_ca.ca_rspdsc[0].lsh = lo16; 209: tms->tmscp_ca.ca_rspdsc[0].hsh = bae; 210: tms->tmscp_rsp[0].mscp_dscptr = (long *)tms->tmscp_ca.ca_rspdsc; 211: tms->tmscp_cmd[0].mscp_cntflgs = 0; 212: 213: tms->tmscp_cmd[0].mscp_opcode = op; 214: tms->tmscp_cmd[0].mscp_modifier = mod; 215: tms->tmscp_cmd[0].mscp_header.mscp_msglen = sizeof (struct tmscp); 216: tms->tmscp_ca.ca_cmddsc[0].hsh |= TMSCP_OWN; /* | TMSCP_INT */ 217: tms->tmscp_rsp[0].mscp_header.mscp_msglen = sizeof (struct tmscp); 218: tms->tmscp_ca.ca_rspdsc[0].hsh |= TMSCP_OWN; /* | TMSCP_INT */ 219: tms->tmscp_cmd[0].mscp_zzz2 = 0; 220: 221: i = TMScsr[ctlr]->tmscpip; 222: for (;;) 223: { 224: if (TMScsr[ctlr]->tmscpsa & TMSCP_ERR) { 225: printf("%s Fatal err sa=%o\n", 226: devname(io), TMScsr[ctlr]->tmscpsa); 227: return(0); 228: } 229: 230: if (tms->tmscp_ca.ca_cmdint) 231: tms->tmscp_ca.ca_cmdint = 0; 232: /* 233: * This is to handle the case of devices not setting the 234: * interrupt field in the communications area. Some 235: * devices (early TU81's) only clear the ownership field 236: * in the Response Descriptor. 237: */ 238: /* 239: if (tms->tmscp_ca.ca_rspint) 240: break; 241: */ 242: if (!(tms->tmscp_ca.ca_rspdsc[0].hsh & TMSCP_OWN)) 243: break; 244: } 245: tms->tmscp_ca.ca_rspint = 0; 246: mp = &tms->tmscp_rsp[0]; 247: if (mp->mscp_opcode != (op|M_OP_END) || 248: (mp->mscp_status&M_ST_MASK) != M_ST_SUCC) { 249: /* Detect hitting tape mark. This signifies the end of the 250: * tape mini-root file. We don't want to return an error 251: * condition to the strategy routine. Set tapemark flag 252: * for sys.c 253: */ 254: if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM) { 255: tapemark = 1; 256: return(1); 257: } 258: printf("%s I/O err 0%o op=0%o mod=0%o\n", devname(io), 259: mp->mscp_status, op, mod); 260: return(0); 261: } 262: return(1); 263: } 264: 265: /* 266: * Set up to do reads and writes; call tmscpcmd to issue the cmd. 267: */ 268: tmscpstrategy(io, func) 269: register struct iob *io; 270: int func; 271: { 272: int ctlr = io->i_ctlr, unit = io->i_unit; 273: int bae, lo16; 274: register struct tmscp *tms = &tmscp[ctlr]; 275: register struct mscp *mp; 276: 277: mp = &tms->tmscp_cmd[0]; 278: mp->mscp_lbn_l = loint(io->i_bn); 279: mp->mscp_lbn_h = hiint(io->i_bn); 280: mp->mscp_unit = unit; 281: mp->mscp_bytecnt = io->i_cc; 282: iomapadr(io->i_ma, &bae, &lo16); 283: mp->mscp_buffer_l = lo16; 284: mp->mscp_buffer_h = bae; 285: if (tmscpcmd(io, func == READ ? M_OP_READ : M_OP_WRITE, 0) ==0) 286: return(-1); 287: /* 288: * Detect hitting tape mark so we do it gracefully and return a 289: * character count of 0 to signify end of copy. 290: */ 291: if (tapemark) 292: return(0); 293: return(io->i_cc); 294: } 295: 296: tmscpseek(io, space) 297: register struct iob *io; 298: int space; 299: { 300: register struct tmscp *tms = &tmscp[io->i_ctlr]; 301: int mod; 302: 303: if (space == 0) 304: return(0); 305: if (space < 0) 306: { 307: mod = M_MD_REVRS; 308: space = -space; 309: } 310: else 311: mod = 0; 312: tms->tmscp_cmd[0].mscp_buffer_l = 0; 313: tms->tmscp_cmd[0].mscp_buffer_h = 0; 314: tms->tmscp_cmd[0].mscp_unit = io->i_unit; 315: tms->tmscp_cmd[0].mscp_reccnt = space; 316: tmscpcmd(io, M_OP_REPOS, mod | M_MD_OBJCT); 317: return(0); 318: }