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