xref: /csrg-svn/sys/vax/stand/tmscp.c (revision 49100)
127479Skjd 
2*49100Sbostic /*	@(#)tmscp.c	7.7 (Berkeley) 05/04/91 */
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 
4645803Sbostic #include "sys/param.h"
4733408Skarels 
4845803Sbostic #include "../include/pte.h"
4933408Skarels 
5045803Sbostic #include "stand/saio.h"
5127479Skjd #include "savax.h"
5227479Skjd 
5327479Skjd /*
5427479Skjd  * Parameters for the communications area
5527479Skjd  * (Only 1 cmd & 1 rsp packet)
5627479Skjd  */
5727479Skjd #define	NRSPL2	0
5827479Skjd #define	NCMDL2	0
5927479Skjd #define	NRSP	(1<<NRSPL2)
6027479Skjd #define	NCMD	(1<<NCMDL2)
6127479Skjd 
6245803Sbostic #include "../uba/tmscpreg.h"
6345803Sbostic #include "../uba/ubareg.h"
6427479Skjd #include "../vax/tmscp.h"
6527479Skjd 
6633646Sbostic #define	MAXCTLR		1		/* all addresses must be specified */
6733646Sbostic u_short tmscpstd[MAXCTLR] = { 0174500 };
6827479Skjd 
6927479Skjd struct iob	ctmscpbuf;
7027479Skjd 
7127479Skjd struct tmscpdevice *tmscpaddr = 0;
7227479Skjd 
7327479Skjd struct tmscp {
7427479Skjd 	struct tmscpca	tmscp_ca;
7527479Skjd 	struct mscp	tmscp_rsp;
7627479Skjd 	struct mscp	tmscp_cmd;
7733646Sbostic } tmscp;
7827479Skjd 
7927479Skjd struct tmscp *tmscp_ubaddr;		/* Unibus address of tmscp structure */
8027479Skjd 
8127479Skjd struct mscp *tmscpcmd();
8227479Skjd 
8327479Skjd int tmscp_offline = 1;		/* Flag to prevent multiple STCON */
8427479Skjd int tms_offline[4] = {1,1,1,1}; /* Flag to prevent multiple ONLIN */
8527479Skjd 
8627479Skjd /*
8727479Skjd  * Open a tmscp device. Initialize the controller and set the unit online.
8827479Skjd  */
tmscpopen(io)8927479Skjd tmscpopen(io)
9027479Skjd 	register struct iob *io;
9127479Skjd {
9227479Skjd 	register struct mscp *mp;
9327479Skjd 	int i;
9427479Skjd 
9533646Sbostic 	if ((u_int)io->i_ctlr >= MAXCTLR)
9633646Sbostic 		return (ECTLR);
9727479Skjd 	/*
9827479Skjd 	 * Have the tmscp controller characteristics already been set up
9927479Skjd 	 * (STCON)?
10027479Skjd 	 */
10133646Sbostic 	if (tmscp_offline) {
10227479Skjd 		if (tmscpaddr == 0)
10333646Sbostic 			tmscpaddr = (struct tmscpdevice *)ubamem(io->i_adapt, tmscpstd[0]);
10433646Sbostic 		if (tmscp_ubaddr == 0) {
10536514Smckusick 			ctmscpbuf = *io;
10627479Skjd 			ctmscpbuf.i_ma = (caddr_t)&tmscp;
10727479Skjd 			ctmscpbuf.i_cc = sizeof(tmscp);
10827479Skjd 			tmscp_ubaddr = (struct tmscp *)ubasetup(&ctmscpbuf, 2);
10933646Sbostic 		}
11027479Skjd 		/*
11127479Skjd 		 * Initialize the tmscp device and wait for the 4 steps
11227479Skjd 		 * to complete.
11327479Skjd 		 */
11427479Skjd 		tmscpaddr->tmscpip = 0;
11533646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0);
11627479Skjd 		tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8);
11727479Skjd 
11833646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0);
11927479Skjd #		define STEP1MASK 0174377
12027479Skjd #		define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
12127479Skjd 		if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
12227479Skjd 			printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
12327479Skjd 		tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase;
12427479Skjd 
12533646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0);
12627479Skjd #		define STEP2MASK 0174377
12727479Skjd #		define STEP2GOOD (TMSCP_STEP3)
12827479Skjd 		if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
12927479Skjd 			printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
13027479Skjd 		tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
13127479Skjd 
13233646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0);
13327479Skjd #		define STEP3MASK 0174000
13427479Skjd #		define STEP3GOOD TMSCP_STEP4
13527479Skjd 		if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
13627479Skjd 			printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
13727479Skjd 		tmscpaddr->tmscpsa = TMSCP_GO;
13827479Skjd 
13927479Skjd 		/*
14027479Skjd 		 * Init cmd & rsp area
14127479Skjd 		 */
14227479Skjd 		tmscp.tmscp_ca.ca_cmddsc[0] = (long)&tmscp_ubaddr->tmscp_cmd.mscp_cmdref;
14327479Skjd 		tmscp.tmscp_cmd.mscp_dscptr = tmscp.tmscp_ca.ca_cmddsc;
14427479Skjd 		tmscp.tmscp_cmd.mscp_header.tmscp_vcid = 1;	/* for tape */
14527479Skjd 
14627479Skjd 		tmscp.tmscp_ca.ca_rspdsc[0] = (long)&tmscp_ubaddr->tmscp_rsp.mscp_cmdref;
14727479Skjd 		tmscp.tmscp_rsp.mscp_dscptr = tmscp.tmscp_ca.ca_rspdsc;
14827479Skjd 		tmscp.tmscp_cmd.mscp_cntflgs = 0;
14933646Sbostic 		if (tmscpcmd(M_OP_STCON, 0) == 0) {
15033408Skarels 			printf("tms: open error, STCON\n");
15133408Skarels 			return (EIO);
15233646Sbostic 		}
15327479Skjd 		tmscp_offline = 0;
15433646Sbostic 	}
15527479Skjd 	tmscp.tmscp_cmd.mscp_unit = io->i_unit&03;
15627479Skjd 	/*
15727479Skjd 	 * Has this unit been issued an ONLIN?
15827479Skjd 	 */
15933646Sbostic 	if (tms_offline[tmscp.tmscp_cmd.mscp_unit]) {
16033646Sbostic 		if ((mp = tmscpcmd(M_OP_ONLIN, 0)) == 0) {
16133408Skarels 			_stop("tms: open error, ONLIN\n");
16233408Skarels 			return (EIO);
16333646Sbostic 		}
16427479Skjd 		tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0;
16533408Skarels 	}
16633646Sbostic 	/*
16733646Sbostic 	 * This makes no sense, but I could be wrong... KB
16833646Sbostic 	 *
16933646Sbostic 	 *	if ((u_int)io->i_part > 3)
17033646Sbostic 	 *		return (EPART);
17133646Sbostic 	 */
17233646Sbostic 	if (io->i_part) {
17327479Skjd 		/*
17427479Skjd 		 * Skip forward the appropriate number of files on the tape.
17527479Skjd 		 */
17633646Sbostic 		tmscp.tmscp_cmd.mscp_tmkcnt = io->i_part;
17733646Sbostic 		(void)tmscpcmd(M_OP_REPOS, 0);
17827479Skjd 		tmscp.tmscp_cmd.mscp_tmkcnt = 0;
17933646Sbostic 	}
18033408Skarels 	return (0);
18127479Skjd }
18227479Skjd 
18327479Skjd /*
18427479Skjd  * Close the device (rewind it to BOT)
18527479Skjd  */
tmscpclose(io)18627479Skjd tmscpclose(io)
18727479Skjd 	register struct iob *io;
18827479Skjd {
18933646Sbostic 	(void)tmscpcmd(M_OP_REPOS, M_MD_REWND);
19027479Skjd }
19127479Skjd 
19227479Skjd /*
19327479Skjd  * Set up tmscp command packet.  Cause the controller to poll to pick up
19427479Skjd  * the command.
19527479Skjd  */
19627479Skjd struct mscp *
tmscpcmd(op,mod)19727479Skjd tmscpcmd(op,mod)
19827479Skjd 	int op, mod;			/* opcode and modifier (usu 0) */
19927479Skjd {
20027479Skjd 	struct mscp *mp;		/* ptr to cmd packet */
20127479Skjd 	int i;				/* read into to init polling */
20227479Skjd 
20327479Skjd 	tmscp.tmscp_cmd.mscp_opcode = op;
20427479Skjd 	tmscp.tmscp_cmd.mscp_modifier = mod;
20527479Skjd 	tmscp.tmscp_cmd.mscp_header.tmscp_msglen = mscp_msglen;
20627479Skjd 	tmscp.tmscp_ca.ca_cmddsc[0] |= TMSCP_OWN;	/* | TMSCP_INT */
20727479Skjd 	tmscp.tmscp_rsp.mscp_header.tmscp_msglen = mscp_msglen;
20827479Skjd 	tmscp.tmscp_ca.ca_rspdsc[0] |= TMSCP_OWN;	/* | TMSCP_INT */
20927479Skjd 
21027479Skjd 	i = tmscpaddr->tmscpip;
21133646Sbostic 	for (;;) {
21233646Sbostic 		if (tmscpaddr->tmscpsa & TMSCP_ERR) {
21327479Skjd 			printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr->tmscpsa & 0xffff);
21427479Skjd 			return(0);
21533646Sbostic 		}
21627479Skjd 
21727479Skjd 		if (tmscp.tmscp_ca.ca_cmdint)
21827479Skjd 			tmscp.tmscp_ca.ca_cmdint = 0;
21927479Skjd 		/*
22027479Skjd 		 * This is to handle the case of devices not setting the
22127479Skjd 		 * interrupt field in the communications area. Some
22227479Skjd 		 * devices (early TU81's) only clear the ownership field
22327479Skjd 		 * in the Response Descriptor.
22433646Sbostic 		 *
22533646Sbostic 		 *
22633646Sbostic 		 *	if (tmscp.tmscp_ca.ca_rspint)
22733646Sbostic 		 *		break;
22827479Skjd 		 */
22927479Skjd 		if (!(tmscp.tmscp_ca.ca_rspdsc[0] & (TMSCP_OWN)))
23027479Skjd 			break;
23133646Sbostic 	}
23227479Skjd 	tmscp.tmscp_ca.ca_rspint = 0;
23327479Skjd 	mp = &tmscp.tmscp_rsp;
23427479Skjd 	if (mp->mscp_opcode != (op|M_OP_END) ||
23533646Sbostic 	   (mp->mscp_status&M_ST_MASK) != M_ST_SUCC) {
23633646Sbostic 		/*
23733646Sbostic 		 * Detect hitting tape mark.  This signifies the end of the
23827479Skjd 		 * tape mini-root file.  We don't want to return an error
23927479Skjd 		 * condition to the strategy routine.
24027479Skjd 		 */
24133646Sbostic 		if ((mp->mscp_status & M_ST_MASK) != M_ST_TAPEM)
24233646Sbostic 			return(0);
24333646Sbostic 	}
24427479Skjd 	return(mp);
24527479Skjd }
24627479Skjd 
24727479Skjd /*
24827479Skjd  * Set up to do reads and writes; call tmscpcmd to issue the cmd.
24927479Skjd  */
tmscpstrategy(io,func)25027479Skjd tmscpstrategy(io, func)
25127479Skjd 	register struct iob *io;
25227479Skjd 	int func;
25327479Skjd {
25427479Skjd 	register struct mscp *mp;
25527479Skjd 	int ubinfo;
25627479Skjd 
25727479Skjd 	ubinfo = ubasetup(io, 1);
25827479Skjd 	mp = &tmscp.tmscp_cmd;
25927479Skjd 	mp->mscp_lbn = io->i_bn;
26027479Skjd 	mp->mscp_unit = io->i_unit&03;
26127479Skjd 	mp->mscp_bytecnt = io->i_cc;
26227479Skjd 	mp->mscp_buffer = (ubinfo & 0x3fffff) | (((ubinfo>>28)&0xf)<<24);
263*49100Sbostic 	if ((mp = tmscpcmd(func == F_READ ? M_OP_READ : M_OP_WRITE, 0)) == 0) {
26427479Skjd 		ubafree(io, ubinfo);
26527479Skjd 		printf("tms: I/O error\n");
26627479Skjd 		return(-1);
26733646Sbostic 	}
26827479Skjd 	ubafree(io, ubinfo);
26927479Skjd 	/*
27027479Skjd 	 * Detect hitting tape mark so we do it gracefully and return a
27127479Skjd 	 * character count of 0 to signify end of copy.  Rewind the tape
27227479Skjd 	 * before returning.
27327479Skjd 	 */
27427479Skjd 	if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM)
27527479Skjd 		return(0);
27627479Skjd 	return(io->i_cc);
27727479Skjd }
278