127479Skjd 2*33408Skarels /* @(#)tmscp.c 7.2 (Berkeley) 01/28/88 */ 327479Skjd 427479Skjd /**************************************************************** 527479Skjd * * 627479Skjd * Licensed from Digital Equipment Corporation * 727479Skjd * Copyright (c) * 827479Skjd * Digital Equipment Corporation * 927479Skjd * Maynard, Massachusetts * 1027479Skjd * 1985, 1986 * 1127479Skjd * All rights reserved. * 1227479Skjd * * 1327479Skjd * The Information in this software is subject to change * 1427479Skjd * without notice and should not be construed as a commitment * 1527479Skjd * by Digital Equipment Corporation. Digital makes no * 1627479Skjd * representations about the suitability of this software for * 1727479Skjd * any purpose. It is supplied "As Is" without expressed or * 1827479Skjd * implied warranty. * 1927479Skjd * * 2027479Skjd * If the Regents of the University of California or its * 2127479Skjd * licensees modify the software in a manner creating * 2227479Skjd * diriviative copyright rights, appropriate copyright * 2327479Skjd * legends may be placed on the drivative work in addition * 2427479Skjd * to that set forth above. * 2527479Skjd ***************************************************************/ 2627479Skjd /* 2727479Skjd * tmscp.c - TMSCP (TK50/TU81) standalone driver 2827479Skjd */ 2927479Skjd 3027479Skjd # ifndef lint 3127479Skjd static char *sccsid = "@(#)tmscp.c 1.5 (ULTRIX) 4/18/86"; 3227479Skjd # endif not lint 3327479Skjd 3427479Skjd /* ------------------------------------------------------------------------ 3527479Skjd * Modification History: /sys/stand/tmscp.c 3627479Skjd * 3727479Skjd * 3-15-85 afd 3827479Skjd * Don't ask for an interrupt when commands are issued and 3927479Skjd * check ownership bit in the response descriptor to detect when a 4027479Skjd * command is complete. Necessary due to the TU81's failure to set 4127479Skjd * the response interrupt field in the communications area. 4227479Skjd * 4327479Skjd * ------------------------------------------------------------------------ 4427479Skjd */ 4527479Skjd 4627479Skjd 47*33408Skarels #include "param.h" 48*33408Skarels #include "inode.h" 49*33408Skarels #include "fs.h" 50*33408Skarels 51*33408Skarels #include "../vax/pte.h" 52*33408Skarels 5327479Skjd #include "savax.h" 5427479Skjd #include "saio.h" 5527479Skjd 5627479Skjd /* 5727479Skjd * Parameters for the communications area 5827479Skjd * (Only 1 cmd & 1 rsp packet) 5927479Skjd */ 6027479Skjd #define NRSPL2 0 6127479Skjd #define NCMDL2 0 6227479Skjd #define NRSP (1<<NRSPL2) 6327479Skjd #define NCMD (1<<NCMDL2) 6427479Skjd 6527479Skjd #include "../vaxuba/tmscpreg.h" 6627479Skjd #include "../vaxuba/ubareg.h" 6727479Skjd #include "../vax/tmscp.h" 6827479Skjd 6927479Skjd u_short tmscpstd[] = { 0174500 }; 7027479Skjd 7127479Skjd struct iob ctmscpbuf; 7227479Skjd 7327479Skjd struct tmscpdevice *tmscpaddr = 0; 7427479Skjd 7527479Skjd struct tmscp { 7627479Skjd struct tmscpca tmscp_ca; 7727479Skjd struct mscp tmscp_rsp; 7827479Skjd struct mscp tmscp_cmd; 7927479Skjd } tmscp; 8027479Skjd 8127479Skjd struct tmscp *tmscp_ubaddr; /* Unibus address of tmscp structure */ 8227479Skjd 8327479Skjd struct mscp *tmscpcmd(); 8427479Skjd 8527479Skjd int tmscp_offline = 1; /* Flag to prevent multiple STCON */ 8627479Skjd int tms_offline[4] = {1,1,1,1}; /* Flag to prevent multiple ONLIN */ 8727479Skjd 8827479Skjd 8927479Skjd /* 9027479Skjd * Open a tmscp device. Initialize the controller and set the unit online. 9127479Skjd */ 9227479Skjd tmscpopen(io) 9327479Skjd register struct iob *io; 9427479Skjd { 9527479Skjd register struct mscp *mp; 9627479Skjd int i; 9727479Skjd 9827479Skjd /* 9927479Skjd * Have the tmscp controller characteristics already been set up 10027479Skjd * (STCON)? 10127479Skjd */ 10227479Skjd if (tmscp_offline) 10327479Skjd { 10427479Skjd if (tmscpaddr == 0) 10527479Skjd tmscpaddr = (struct tmscpdevice *)ubamem(io->i_unit, tmscpstd[0]); 10627479Skjd if (tmscp_ubaddr == 0) 10727479Skjd { 10827479Skjd ctmscpbuf.i_unit = io->i_unit; 10927479Skjd ctmscpbuf.i_ma = (caddr_t)&tmscp; 11027479Skjd ctmscpbuf.i_cc = sizeof(tmscp); 11127479Skjd tmscp_ubaddr = (struct tmscp *)ubasetup(&ctmscpbuf, 2); 11227479Skjd } 11327479Skjd /* 11427479Skjd * Initialize the tmscp device and wait for the 4 steps 11527479Skjd * to complete. 11627479Skjd */ 11727479Skjd tmscpaddr->tmscpip = 0; 11827479Skjd while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0) 11927479Skjd ; 12027479Skjd tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8); 12127479Skjd 12227479Skjd while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0) 12327479Skjd ; 12427479Skjd # define STEP1MASK 0174377 12527479Skjd # define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2) 12627479Skjd if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD) 12727479Skjd printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff); 12827479Skjd tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase; 12927479Skjd 13027479Skjd while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0) 13127479Skjd ; 13227479Skjd # define STEP2MASK 0174377 13327479Skjd # define STEP2GOOD (TMSCP_STEP3) 13427479Skjd if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD) 13527479Skjd printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff); 13627479Skjd tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16); 13727479Skjd 13827479Skjd while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0) 13927479Skjd ; 14027479Skjd # define STEP3MASK 0174000 14127479Skjd # define STEP3GOOD TMSCP_STEP4 14227479Skjd if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD) 14327479Skjd printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff); 14427479Skjd tmscpaddr->tmscpsa = TMSCP_GO; 14527479Skjd 14627479Skjd /* 14727479Skjd * Init cmd & rsp area 14827479Skjd */ 14927479Skjd tmscp.tmscp_ca.ca_cmddsc[0] = (long)&tmscp_ubaddr->tmscp_cmd.mscp_cmdref; 15027479Skjd tmscp.tmscp_cmd.mscp_dscptr = tmscp.tmscp_ca.ca_cmddsc; 15127479Skjd tmscp.tmscp_cmd.mscp_header.tmscp_vcid = 1; /* for tape */ 15227479Skjd 15327479Skjd tmscp.tmscp_ca.ca_rspdsc[0] = (long)&tmscp_ubaddr->tmscp_rsp.mscp_cmdref; 15427479Skjd tmscp.tmscp_rsp.mscp_dscptr = tmscp.tmscp_ca.ca_rspdsc; 15527479Skjd tmscp.tmscp_cmd.mscp_cntflgs = 0; 15627479Skjd if (tmscpcmd(M_OP_STCON, 0) == 0) 15727479Skjd { 158*33408Skarels printf("tms: open error, STCON\n"); 159*33408Skarels return (EIO); 16027479Skjd } 16127479Skjd tmscp_offline = 0; 16227479Skjd } 16327479Skjd tmscp.tmscp_cmd.mscp_unit = io->i_unit&03; 16427479Skjd /* 16527479Skjd * Has this unit been issued an ONLIN? 16627479Skjd */ 16727479Skjd if (tms_offline[tmscp.tmscp_cmd.mscp_unit]) 16827479Skjd { 16927479Skjd if ((mp = tmscpcmd(M_OP_ONLIN, 0)) == 0) 17027479Skjd { 171*33408Skarels _stop("tms: open error, ONLIN\n"); 172*33408Skarels return (EIO); 17327479Skjd } 17427479Skjd tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0; 17527479Skjd } 176*33408Skarels if (io->i_boff < 0 || io->i_boff > 3) { 177*33408Skarels printf("tms: bad offset\n"); 178*33408Skarels return (EUNIT); 179*33408Skarels } 18027479Skjd else if (io->i_boff > 0) 18127479Skjd /* 18227479Skjd * Skip forward the appropriate number of files on the tape. 18327479Skjd */ 18427479Skjd { 18527479Skjd tmscp.tmscp_cmd.mscp_tmkcnt = io->i_boff; 18627479Skjd tmscpcmd(M_OP_REPOS, 0); 18727479Skjd tmscp.tmscp_cmd.mscp_tmkcnt = 0; 18827479Skjd } 189*33408Skarels return (0); 19027479Skjd } 19127479Skjd 19227479Skjd 19327479Skjd /* 19427479Skjd * Close the device (rewind it to BOT) 19527479Skjd */ 19627479Skjd tmscpclose(io) 19727479Skjd register struct iob *io; 19827479Skjd { 19927479Skjd tmscpcmd(M_OP_REPOS, M_MD_REWND); 20027479Skjd } 20127479Skjd 20227479Skjd 20327479Skjd /* 20427479Skjd * Set up tmscp command packet. Cause the controller to poll to pick up 20527479Skjd * the command. 20627479Skjd */ 20727479Skjd struct mscp * 20827479Skjd tmscpcmd(op,mod) 20927479Skjd int op, mod; /* opcode and modifier (usu 0) */ 21027479Skjd { 21127479Skjd struct mscp *mp; /* ptr to cmd packet */ 21227479Skjd int i; /* read into to init polling */ 21327479Skjd 21427479Skjd tmscp.tmscp_cmd.mscp_opcode = op; 21527479Skjd tmscp.tmscp_cmd.mscp_modifier = mod; 21627479Skjd tmscp.tmscp_cmd.mscp_header.tmscp_msglen = mscp_msglen; 21727479Skjd tmscp.tmscp_ca.ca_cmddsc[0] |= TMSCP_OWN; /* | TMSCP_INT */ 21827479Skjd tmscp.tmscp_rsp.mscp_header.tmscp_msglen = mscp_msglen; 21927479Skjd tmscp.tmscp_ca.ca_rspdsc[0] |= TMSCP_OWN; /* | TMSCP_INT */ 22027479Skjd 22127479Skjd i = tmscpaddr->tmscpip; 22227479Skjd for (;;) 22327479Skjd { 22427479Skjd if (tmscpaddr->tmscpsa & TMSCP_ERR) 22527479Skjd { 22627479Skjd printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr->tmscpsa & 0xffff); 22727479Skjd return(0); 22827479Skjd } 22927479Skjd 23027479Skjd if (tmscp.tmscp_ca.ca_cmdint) 23127479Skjd tmscp.tmscp_ca.ca_cmdint = 0; 23227479Skjd /* 23327479Skjd * This is to handle the case of devices not setting the 23427479Skjd * interrupt field in the communications area. Some 23527479Skjd * devices (early TU81's) only clear the ownership field 23627479Skjd * in the Response Descriptor. 23727479Skjd */ 23827479Skjd /* 23927479Skjd if (tmscp.tmscp_ca.ca_rspint) 24027479Skjd break; 24127479Skjd */ 24227479Skjd if (!(tmscp.tmscp_ca.ca_rspdsc[0] & (TMSCP_OWN))) 24327479Skjd break; 24427479Skjd } 24527479Skjd tmscp.tmscp_ca.ca_rspint = 0; 24627479Skjd mp = &tmscp.tmscp_rsp; 24727479Skjd if (mp->mscp_opcode != (op|M_OP_END) || 24827479Skjd (mp->mscp_status&M_ST_MASK) != M_ST_SUCC) 24927479Skjd { 25027479Skjd /* Detect hitting tape mark. This signifies the end of the 25127479Skjd * tape mini-root file. We don't want to return an error 25227479Skjd * condition to the strategy routine. 25327479Skjd */ 25427479Skjd if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM) 25527479Skjd return(mp); 25627479Skjd return(0); 25727479Skjd } 25827479Skjd return(mp); 25927479Skjd } 26027479Skjd 26127479Skjd 26227479Skjd /* 26327479Skjd * Set up to do reads and writes; call tmscpcmd to issue the cmd. 26427479Skjd */ 26527479Skjd tmscpstrategy(io, func) 26627479Skjd register struct iob *io; 26727479Skjd int func; 26827479Skjd { 26927479Skjd register struct mscp *mp; 27027479Skjd int ubinfo; 27127479Skjd 27227479Skjd ubinfo = ubasetup(io, 1); 27327479Skjd mp = &tmscp.tmscp_cmd; 27427479Skjd mp->mscp_lbn = io->i_bn; 27527479Skjd mp->mscp_unit = io->i_unit&03; 27627479Skjd mp->mscp_bytecnt = io->i_cc; 27727479Skjd mp->mscp_buffer = (ubinfo & 0x3fffff) | (((ubinfo>>28)&0xf)<<24); 27827479Skjd if ((mp = tmscpcmd(func == READ ? M_OP_READ : M_OP_WRITE, 0)) == 0) 27927479Skjd { 28027479Skjd ubafree(io, ubinfo); 28127479Skjd printf("tms: I/O error\n"); 28227479Skjd return(-1); 28327479Skjd } 28427479Skjd ubafree(io, ubinfo); 28527479Skjd /* 28627479Skjd * Detect hitting tape mark so we do it gracefully and return a 28727479Skjd * character count of 0 to signify end of copy. Rewind the tape 28827479Skjd * before returning. 28927479Skjd */ 29027479Skjd if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM) 29127479Skjd return(0); 29227479Skjd return(io->i_cc); 29327479Skjd } 29427479Skjd 29527479Skjd /*ARGSUSED*/ 29627479Skjd tmscpioctl(io, cmd, arg) 29727479Skjd struct iob *io; 29827479Skjd int cmd; 29927479Skjd caddr_t arg; 30027479Skjd { 30127479Skjd return (ECMD); 30227479Skjd } 303