2.11BSD/sys/pdpstand/tmscp.c
/* @(#)tmscp.c 7.1.5 (2.11BSD GTE) 1998/1/30 */
/****************************************************************
* 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 *
* deriviative 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
*/
/* static char *sccsid = "@(#)tmscp.c 1.5 (ULTRIX) 4/18/86"; */
/* ------------------------------------------------------------------------
* Modification History: /sys/pdpstand/tmscp.c
*
* 5-30-95 sms - new iob structure.
* 4-20-91 sms - add multi controller and unit support (sms)
* 8-20-90 steven m. schultz (sms@wlv.iipo.gtegsc.com)
* Port from 4.3BSD to 2.11BSD
* 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 "../h/param.h"
#include "saio.h"
/*
* Parameters for the communications area
* (Only 1 cmd & 1 rsp packet)
*/
#define NRSPL2 0 /* Define these before including */
#define NCMDL2 0 /* tmscpreg.h and tmscp.h below */
#include "sys/buf.h"
#include "../pdpuba/tmscpreg.h"
#include "../pdp/tmscp.h"
#define NTMS 2
struct tmscpdevice *TMScsr[NTMS + 1] =
{
(struct tmscpdevice *)0174500,
(struct tmscpdevice *)0,
(struct tmscpdevice *)-1
};
struct tmscp tmscp[NTMS];
u_char tmsoffline[NTMS] = {1, 1}; /* Flag to prevent multiple STCON */
u_char tms_offline[NTMS][4] = {{1,1,1,1},
{1,1,1,1}}; /* Flag to prevent multiple ONLIN */
static char opnmsg[] = "tms%d: step %d failed sa=0%o\n";
extern int tapemark; /* flag to indicate tapemark encountered
(see sys.c as to how it's used) */
/*
* Open a tmscp device. Initialize the controller and set the unit online.
*/
tmscpopen(io)
register struct iob *io;
{
register struct tmscpdevice *tmscpaddr;
int ctlr = io->i_ctlr;
int unit = io->i_unit, bae, lo16;
register struct tmscp *tms = &tmscp[ctlr];
if (genopen(NTMS, io) < 0)
return(-1);
io->i_flgs |= F_TAPE;
tmscpaddr = TMScsr[ctlr];
/*
* Have the tmscp controller characteristics already been set up
* (STCON)?
*/
if (tmsoffline[ctlr])
{
/*
* 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)
iomapadr(&tms->tmscp_ca.ca_ringbase, &bae, &lo16);
if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
printf(opnmsg, ctlr, 1, tmscpaddr->tmscpsa);
tmscpaddr->tmscpsa = lo16;
while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0)
;
#define STEP2MASK 0174377
#define STEP2GOOD (TMSCP_STEP3)
if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
printf(opnmsg, ctlr, 2, tmscpaddr->tmscpsa);
tmscpaddr->tmscpsa = bae;
while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0)
;
#define STEP3MASK 0174000
#define STEP3GOOD TMSCP_STEP4
if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
printf(opnmsg, ctlr, 3, tmscpaddr->tmscpsa);
tmscpaddr->tmscpsa = TMSCP_GO;
if (tmscpcmd(io, M_OP_STCON, 0) == 0)
{
printf("%s STCON", devname(io));
return(-1);
}
tmsoffline[ctlr] = 0;
}
tms->tmscp_cmd[0].mscp_unit = unit;
/*
* Has this unit been issued an ONLIN?
*/
if (tms_offline[ctlr][unit])
{
if (tmscpcmd(io, M_OP_ONLIN, 0) == 0)
{
printf("%s ONLIN", devname(io));
return(-1);
}
tms_offline[ctlr][unit] = 0;
}
tmscpclose(io); /* close just does a rewind */
if (io->i_part > 0)
/*
* Skip forward the appropriate number of files on the tape.
*/
{
tms->tmscp_cmd[0].mscp_tmkcnt = io->i_part;
tms->tmscp_cmd[0].mscp_buffer_h = 0;
tms->tmscp_cmd[0].mscp_bytecnt = 0;
tmscpcmd(io, M_OP_REPOS, 0);
tms->tmscp_cmd[0].mscp_tmkcnt = 0;
}
return(0);
}
/*
* Close the device (rewind it to BOT)
*/
tmscpclose(io)
register struct iob *io;
{
register struct tmscp *tms = &tmscp[io->i_ctlr];
tms->tmscp_cmd[0].mscp_buffer_l = 0; /* tmkcnt */
tms->tmscp_cmd[0].mscp_buffer_h = 0;
tms->tmscp_cmd[0].mscp_bytecnt = 0;
tms->tmscp_cmd[0].mscp_unit = io->i_unit;
tmscpcmd(io, M_OP_REPOS, M_MD_REWND | M_MD_CLSEX);
}
/*
* Set up tmscp command packet. Cause the controller to poll to pick up
* the command.
*/
tmscpcmd(io, op,mod)
struct iob *io;
int op, mod; /* opcode and modifier (usu 0) */
{
int ctlr = io->i_ctlr;
register struct tmscp *tms = &tmscp[ctlr];
register struct mscp *mp; /* ptr to cmd packet */
int i; /* read into to init polling */
int bae, lo16;
/*
* Init cmd & rsp area
*/
iomapadr(&tms->tmscp_cmd[0].mscp_cmdref, &bae, &lo16);
tms->tmscp_ca.ca_cmddsc[0].lsh = lo16;
tms->tmscp_ca.ca_cmddsc[0].hsh = bae;
tms->tmscp_cmd[0].mscp_dscptr = (long *)tms->tmscp_ca.ca_cmddsc;
tms->tmscp_cmd[0].mscp_header.mscp_vcid = 1; /* for tape */
iomapadr(&tms->tmscp_rsp[0].mscp_cmdref, &bae, &lo16);
tms->tmscp_ca.ca_rspdsc[0].lsh = lo16;
tms->tmscp_ca.ca_rspdsc[0].hsh = bae;
tms->tmscp_rsp[0].mscp_dscptr = (long *)tms->tmscp_ca.ca_rspdsc;
tms->tmscp_cmd[0].mscp_cntflgs = 0;
tms->tmscp_cmd[0].mscp_opcode = op;
tms->tmscp_cmd[0].mscp_modifier = mod;
tms->tmscp_cmd[0].mscp_header.mscp_msglen = sizeof (struct tmscp);
tms->tmscp_ca.ca_cmddsc[0].hsh |= TMSCP_OWN; /* | TMSCP_INT */
tms->tmscp_rsp[0].mscp_header.mscp_msglen = sizeof (struct tmscp);
tms->tmscp_ca.ca_rspdsc[0].hsh |= TMSCP_OWN; /* | TMSCP_INT */
tms->tmscp_cmd[0].mscp_zzz2 = 0;
i = TMScsr[ctlr]->tmscpip;
for (;;)
{
if (TMScsr[ctlr]->tmscpsa & TMSCP_ERR) {
printf("%s Fatal err sa=%o\n",
devname(io), TMScsr[ctlr]->tmscpsa);
return(0);
}
if (tms->tmscp_ca.ca_cmdint)
tms->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 (tms->tmscp_ca.ca_rspint)
break;
*/
if (!(tms->tmscp_ca.ca_rspdsc[0].hsh & TMSCP_OWN))
break;
}
tms->tmscp_ca.ca_rspint = 0;
mp = &tms->tmscp_rsp[0];
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. Set tapemark flag
* for sys.c
*/
if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM) {
tapemark = 1;
return(1);
}
printf("%s I/O err 0%o op=0%o mod=0%o\n", devname(io),
mp->mscp_status, op, mod);
return(0);
}
return(1);
}
/*
* Set up to do reads and writes; call tmscpcmd to issue the cmd.
*/
tmscpstrategy(io, func)
register struct iob *io;
int func;
{
int ctlr = io->i_ctlr, unit = io->i_unit;
int bae, lo16;
register struct tmscp *tms = &tmscp[ctlr];
register struct mscp *mp;
mp = &tms->tmscp_cmd[0];
mp->mscp_lbn_l = loint(io->i_bn);
mp->mscp_lbn_h = hiint(io->i_bn);
mp->mscp_unit = unit;
mp->mscp_bytecnt = io->i_cc;
iomapadr(io->i_ma, &bae, &lo16);
mp->mscp_buffer_l = lo16;
mp->mscp_buffer_h = bae;
if (tmscpcmd(io, func == READ ? M_OP_READ : M_OP_WRITE, 0) ==0)
return(-1);
/*
* Detect hitting tape mark so we do it gracefully and return a
* character count of 0 to signify end of copy.
*/
if (tapemark)
return(0);
return(io->i_cc);
}
tmscpseek(io, space)
register struct iob *io;
int space;
{
register struct tmscp *tms = &tmscp[io->i_ctlr];
int mod;
if (space == 0)
return(0);
if (space < 0)
{
mod = M_MD_REVRS;
space = -space;
}
else
mod = 0;
tms->tmscp_cmd[0].mscp_buffer_l = 0;
tms->tmscp_cmd[0].mscp_buffer_h = 0;
tms->tmscp_cmd[0].mscp_unit = io->i_unit;
tms->tmscp_cmd[0].mscp_reccnt = space;
tmscpcmd(io, M_OP_REPOS, mod | M_MD_OBJCT);
return(0);
}