4.3BSD-Tahoe/usr/src/sys/vaxstand/tmscp.c

Compare this file to the similar file:
Show the results in this format:


/*	@(#)tmscp.c	7.3 (Berkeley) 3/4/88 */

/****************************************************************
 *                                                              *
 *        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 "param.h"
#include "inode.h"
#include "fs.h"

#include "../vax/pte.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"
 
#define	MAXCTLR		1		/* all addresses must be specified */
u_short tmscpstd[MAXCTLR] = { 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;
 
	if ((u_int)io->i_ctlr >= MAXCTLR)
		return (ECTLR);
	/*
	 * Have the tmscp controller characteristics already been set up
	 * (STCON)?
	 */
	if (tmscp_offline) {
		if (tmscpaddr == 0)
			tmscpaddr = (struct tmscpdevice *)ubamem(io->i_adapt, 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) {
			printf("tms: open error, STCON\n");
			return (EIO);
		}
		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\n");
			return (EIO);
		}
		tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0;
	}
	/*
	 * This makes no sense, but I could be wrong... KB
	 *
	 *	if ((u_int)io->i_part > 3)
	 *		return (EPART);
	 */
	if (io->i_part) {
		/*
		 * Skip forward the appropriate number of files on the tape.
		 */
		tmscp.tmscp_cmd.mscp_tmkcnt = io->i_part;
		(void)tmscpcmd(M_OP_REPOS, 0);
		tmscp.tmscp_cmd.mscp_tmkcnt = 0;
	}
	return (0);
}
 
/*
 * Close the device (rewind it to BOT)
 */
tmscpclose(io)
	register struct iob *io;
{
	(void)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(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);
}