install copy, drtest, pcs750.bin
[unix-history] / usr / src / sys / vax / stand / tmscp.c
/* @(#)tmscp.c 1.1 (Berkeley) %G% */
/****************************************************************
* *
* Licensed from Digital Equipment Corporation *
* Copyright (c) *
* Digital Equipment Corporation *
* Maynard, Massachusetts *
* 1985, 1986 *
* All rights reserved. *
* *
* The Information in this software is subject to change *
* without notice and should not be construed as a commitment *
* by Digital Equipment Corporation. Digital makes no *
* representations about the suitability of this software for *
* any purpose. It is supplied "As Is" without expressed or *
* implied warranty. *
* *
* If the Regents of the University of California or its *
* licensees modify the software in a manner creating *
* diriviative copyright rights, appropriate copyright *
* legends may be placed on the drivative work in addition *
* to that set forth above. *
***************************************************************/
/*
* tmscp.c - TMSCP (TK50/TU81) standalone driver
*/
# ifndef lint
static char *sccsid = "@(#)tmscp.c 1.5 (ULTRIX) 4/18/86";
# endif not lint
/* ------------------------------------------------------------------------
* Modification History: /sys/stand/tmscp.c
*
* 3-15-85 afd
* Don't ask for an interrupt when commands are issued and
* check ownership bit in the response descriptor to detect when a
* command is complete. Necessary due to the TU81's failure to set
* the response interrupt field in the communications area.
*
* ------------------------------------------------------------------------
*/
#include "../machine/pte.h"
#include "../h/param.h"
#include "../h/gnode.h"
#include "../h/devio.h"
#include "savax.h"
#include "saio.h"
/*
* Parameters for the communications area
* (Only 1 cmd & 1 rsp packet)
*/
#define NRSPL2 0
#define NCMDL2 0
#define NRSP (1<<NRSPL2)
#define NCMD (1<<NCMDL2)
#include "../vaxuba/tmscpreg.h"
#include "../vaxuba/ubareg.h"
#include "../vax/tmscp.h"
u_short tmscpstd[] = { 0174500 };
struct iob ctmscpbuf;
struct tmscpdevice *tmscpaddr = 0;
struct tmscp {
struct tmscpca tmscp_ca;
struct mscp tmscp_rsp;
struct mscp tmscp_cmd;
} tmscp;
struct tmscp *tmscp_ubaddr; /* Unibus address of tmscp structure */
struct mscp *tmscpcmd();
int tmscp_offline = 1; /* Flag to prevent multiple STCON */
int tms_offline[4] = {1,1,1,1}; /* Flag to prevent multiple ONLIN */
/*
* Open a tmscp device. Initialize the controller and set the unit online.
*/
tmscpopen(io)
register struct iob *io;
{
register struct mscp *mp;
int i;
/*
* Have the tmscp controller characteristics already been set up
* (STCON)?
*/
if (tmscp_offline)
{
if (tmscpaddr == 0)
tmscpaddr = (struct tmscpdevice *)ubamem(io->i_unit, tmscpstd[0]);
if (tmscp_ubaddr == 0)
{
ctmscpbuf.i_unit = io->i_unit;
ctmscpbuf.i_ma = (caddr_t)&tmscp;
ctmscpbuf.i_cc = sizeof(tmscp);
tmscp_ubaddr = (struct tmscp *)ubasetup(&ctmscpbuf, 2);
}
/*
* Initialize the tmscp device and wait for the 4 steps
* to complete.
*/
tmscpaddr->tmscpip = 0;
while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
;
tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8);
while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0)
;
# define STEP1MASK 0174377
# define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase;
while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0)
;
# define STEP2MASK 0174377
# define STEP2GOOD (TMSCP_STEP3)
if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0)
;
# define STEP3MASK 0174000
# define STEP3GOOD TMSCP_STEP4
if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
tmscpaddr->tmscpsa = TMSCP_GO;
/*
* Init cmd & rsp area
*/
tmscp.tmscp_ca.ca_cmddsc[0] = (long)&tmscp_ubaddr->tmscp_cmd.mscp_cmdref;
tmscp.tmscp_cmd.mscp_dscptr = tmscp.tmscp_ca.ca_cmddsc;
tmscp.tmscp_cmd.mscp_header.tmscp_vcid = 1; /* for tape */
tmscp.tmscp_ca.ca_rspdsc[0] = (long)&tmscp_ubaddr->tmscp_rsp.mscp_cmdref;
tmscp.tmscp_rsp.mscp_dscptr = tmscp.tmscp_ca.ca_rspdsc;
tmscp.tmscp_cmd.mscp_cntflgs = 0;
if (tmscpcmd(M_OP_STCON, 0) == 0)
{
_stop("tms: open error, STCON");
return;
}
tmscp_offline = 0;
}
tmscp.tmscp_cmd.mscp_unit = io->i_unit&03;
/*
* Has this unit been issued an ONLIN?
*/
if (tms_offline[tmscp.tmscp_cmd.mscp_unit])
{
if ((mp = tmscpcmd(M_OP_ONLIN, 0)) == 0)
{
_stop("tms: open error, ONLIN");
return;
}
tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0;
}
if (io->i_boff < 0 || io->i_boff > 3)
_stop("tms: bad offset");
else if (io->i_boff > 0)
/*
* Skip forward the appropriate number of files on the tape.
*/
{
tmscp.tmscp_cmd.mscp_tmkcnt = io->i_boff;
tmscpcmd(M_OP_REPOS, 0);
tmscp.tmscp_cmd.mscp_tmkcnt = 0;
}
}
/*
* Close the device (rewind it to BOT)
*/
tmscpclose(io)
register struct iob *io;
{
tmscpcmd(M_OP_REPOS, M_MD_REWND);
}
/*
* Set up tmscp command packet. Cause the controller to poll to pick up
* the command.
*/
struct mscp *
tmscpcmd(op,mod)
int op, mod; /* opcode and modifier (usu 0) */
{
struct mscp *mp; /* ptr to cmd packet */
int i; /* read into to init polling */
tmscp.tmscp_cmd.mscp_opcode = op;
tmscp.tmscp_cmd.mscp_modifier = mod;
tmscp.tmscp_cmd.mscp_header.tmscp_msglen = mscp_msglen;
tmscp.tmscp_ca.ca_cmddsc[0] |= TMSCP_OWN; /* | TMSCP_INT */
tmscp.tmscp_rsp.mscp_header.tmscp_msglen = mscp_msglen;
tmscp.tmscp_ca.ca_rspdsc[0] |= TMSCP_OWN; /* | TMSCP_INT */
i = tmscpaddr->tmscpip;
for (;;)
{
if (tmscpaddr->tmscpsa & TMSCP_ERR)
{
printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr->tmscpsa & 0xffff);
return(0);
}
if (tmscp.tmscp_ca.ca_cmdint)
tmscp.tmscp_ca.ca_cmdint = 0;
/*
* This is to handle the case of devices not setting the
* interrupt field in the communications area. Some
* devices (early TU81's) only clear the ownership field
* in the Response Descriptor.
*/
/*
if (tmscp.tmscp_ca.ca_rspint)
break;
*/
if (!(tmscp.tmscp_ca.ca_rspdsc[0] & (TMSCP_OWN)))
break;
}
tmscp.tmscp_ca.ca_rspint = 0;
mp = &tmscp.tmscp_rsp;
if (mp->mscp_opcode != (op|M_OP_END) ||
(mp->mscp_status&M_ST_MASK) != M_ST_SUCC)
{
/* Detect hitting tape mark. This signifies the end of the
* tape mini-root file. We don't want to return an error
* condition to the strategy routine.
*/
if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM)
return(mp);
return(0);
}
return(mp);
}
/*
* Set up to do reads and writes; call tmscpcmd to issue the cmd.
*/
tmscpstrategy(io, func)
register struct iob *io;
int func;
{
register struct mscp *mp;
int ubinfo;
ubinfo = ubasetup(io, 1);
mp = &tmscp.tmscp_cmd;
mp->mscp_lbn = io->i_bn;
mp->mscp_unit = io->i_unit&03;
mp->mscp_bytecnt = io->i_cc;
mp->mscp_buffer = (ubinfo & 0x3fffff) | (((ubinfo>>28)&0xf)<<24);
if ((mp = tmscpcmd(func == READ ? M_OP_READ : M_OP_WRITE, 0)) == 0)
{
ubafree(io, ubinfo);
printf("tms: I/O error\n");
return(-1);
}
ubafree(io, ubinfo);
/*
* Detect hitting tape mark so we do it gracefully and return a
* character count of 0 to signify end of copy. Rewind the tape
* before returning.
*/
if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM)
return(0);
return(io->i_cc);
}
/*ARGSUSED*/
tmscpioctl(io, cmd, arg)
struct iob *io;
int cmd;
caddr_t arg;
{
return (ECMD);
}