xref: /csrg-svn/sys/vax/stand/tmscp.c (revision 36514)
127479Skjd 
2*36514Smckusick /*	@(#)tmscp.c	7.4 (Berkeley) 01/06/89 */
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 
4633408Skarels #include "param.h"
4733408Skarels #include "inode.h"
4833408Skarels #include "fs.h"
4933408Skarels 
5033408Skarels #include "../vax/pte.h"
5133408Skarels 
5227479Skjd #include "savax.h"
5327479Skjd #include "saio.h"
5427479Skjd 
5527479Skjd /*
5627479Skjd  * Parameters for the communications area
5727479Skjd  * (Only 1 cmd & 1 rsp packet)
5827479Skjd  */
5927479Skjd #define	NRSPL2	0
6027479Skjd #define	NCMDL2	0
6127479Skjd #define	NRSP	(1<<NRSPL2)
6227479Skjd #define	NCMD	(1<<NCMDL2)
6327479Skjd 
6427479Skjd #include "../vaxuba/tmscpreg.h"
6527479Skjd #include "../vaxuba/ubareg.h"
6627479Skjd #include "../vax/tmscp.h"
6727479Skjd 
6833646Sbostic #define	MAXCTLR		1		/* all addresses must be specified */
6933646Sbostic u_short tmscpstd[MAXCTLR] = { 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;
7933646Sbostic } 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  * Open a tmscp device. Initialize the controller and set the unit online.
9027479Skjd  */
9127479Skjd tmscpopen(io)
9227479Skjd 	register struct iob *io;
9327479Skjd {
9427479Skjd 	register struct mscp *mp;
9527479Skjd 	int i;
9627479Skjd 
9733646Sbostic 	if ((u_int)io->i_ctlr >= MAXCTLR)
9833646Sbostic 		return (ECTLR);
9927479Skjd 	/*
10027479Skjd 	 * Have the tmscp controller characteristics already been set up
10127479Skjd 	 * (STCON)?
10227479Skjd 	 */
10333646Sbostic 	if (tmscp_offline) {
10427479Skjd 		if (tmscpaddr == 0)
10533646Sbostic 			tmscpaddr = (struct tmscpdevice *)ubamem(io->i_adapt, tmscpstd[0]);
10633646Sbostic 		if (tmscp_ubaddr == 0) {
107*36514Smckusick 			ctmscpbuf = *io;
10827479Skjd 			ctmscpbuf.i_ma = (caddr_t)&tmscp;
10927479Skjd 			ctmscpbuf.i_cc = sizeof(tmscp);
11027479Skjd 			tmscp_ubaddr = (struct tmscp *)ubasetup(&ctmscpbuf, 2);
11133646Sbostic 		}
11227479Skjd 		/*
11327479Skjd 		 * Initialize the tmscp device and wait for the 4 steps
11427479Skjd 		 * to complete.
11527479Skjd 		 */
11627479Skjd 		tmscpaddr->tmscpip = 0;
11733646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0);
11827479Skjd 		tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8);
11927479Skjd 
12033646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0);
12127479Skjd #		define STEP1MASK 0174377
12227479Skjd #		define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
12327479Skjd 		if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
12427479Skjd 			printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
12527479Skjd 		tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase;
12627479Skjd 
12733646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0);
12827479Skjd #		define STEP2MASK 0174377
12927479Skjd #		define STEP2GOOD (TMSCP_STEP3)
13027479Skjd 		if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
13127479Skjd 			printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
13227479Skjd 		tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
13327479Skjd 
13433646Sbostic 		while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0);
13527479Skjd #		define STEP3MASK 0174000
13627479Skjd #		define STEP3GOOD TMSCP_STEP4
13727479Skjd 		if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
13827479Skjd 			printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
13927479Skjd 		tmscpaddr->tmscpsa = TMSCP_GO;
14027479Skjd 
14127479Skjd 		/*
14227479Skjd 		 * Init cmd & rsp area
14327479Skjd 		 */
14427479Skjd 		tmscp.tmscp_ca.ca_cmddsc[0] = (long)&tmscp_ubaddr->tmscp_cmd.mscp_cmdref;
14527479Skjd 		tmscp.tmscp_cmd.mscp_dscptr = tmscp.tmscp_ca.ca_cmddsc;
14627479Skjd 		tmscp.tmscp_cmd.mscp_header.tmscp_vcid = 1;	/* for tape */
14727479Skjd 
14827479Skjd 		tmscp.tmscp_ca.ca_rspdsc[0] = (long)&tmscp_ubaddr->tmscp_rsp.mscp_cmdref;
14927479Skjd 		tmscp.tmscp_rsp.mscp_dscptr = tmscp.tmscp_ca.ca_rspdsc;
15027479Skjd 		tmscp.tmscp_cmd.mscp_cntflgs = 0;
15133646Sbostic 		if (tmscpcmd(M_OP_STCON, 0) == 0) {
15233408Skarels 			printf("tms: open error, STCON\n");
15333408Skarels 			return (EIO);
15433646Sbostic 		}
15527479Skjd 		tmscp_offline = 0;
15633646Sbostic 	}
15727479Skjd 	tmscp.tmscp_cmd.mscp_unit = io->i_unit&03;
15827479Skjd 	/*
15927479Skjd 	 * Has this unit been issued an ONLIN?
16027479Skjd 	 */
16133646Sbostic 	if (tms_offline[tmscp.tmscp_cmd.mscp_unit]) {
16233646Sbostic 		if ((mp = tmscpcmd(M_OP_ONLIN, 0)) == 0) {
16333408Skarels 			_stop("tms: open error, ONLIN\n");
16433408Skarels 			return (EIO);
16533646Sbostic 		}
16627479Skjd 		tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0;
16733408Skarels 	}
16833646Sbostic 	/*
16933646Sbostic 	 * This makes no sense, but I could be wrong... KB
17033646Sbostic 	 *
17133646Sbostic 	 *	if ((u_int)io->i_part > 3)
17233646Sbostic 	 *		return (EPART);
17333646Sbostic 	 */
17433646Sbostic 	if (io->i_part) {
17527479Skjd 		/*
17627479Skjd 		 * Skip forward the appropriate number of files on the tape.
17727479Skjd 		 */
17833646Sbostic 		tmscp.tmscp_cmd.mscp_tmkcnt = io->i_part;
17933646Sbostic 		(void)tmscpcmd(M_OP_REPOS, 0);
18027479Skjd 		tmscp.tmscp_cmd.mscp_tmkcnt = 0;
18133646Sbostic 	}
18233408Skarels 	return (0);
18327479Skjd }
18427479Skjd 
18527479Skjd /*
18627479Skjd  * Close the device (rewind it to BOT)
18727479Skjd  */
18827479Skjd tmscpclose(io)
18927479Skjd 	register struct iob *io;
19027479Skjd {
19133646Sbostic 	(void)tmscpcmd(M_OP_REPOS, M_MD_REWND);
19227479Skjd }
19327479Skjd 
19427479Skjd /*
19527479Skjd  * Set up tmscp command packet.  Cause the controller to poll to pick up
19627479Skjd  * the command.
19727479Skjd  */
19827479Skjd struct mscp *
19927479Skjd tmscpcmd(op,mod)
20027479Skjd 	int op, mod;			/* opcode and modifier (usu 0) */
20127479Skjd {
20227479Skjd 	struct mscp *mp;		/* ptr to cmd packet */
20327479Skjd 	int i;				/* read into to init polling */
20427479Skjd 
20527479Skjd 	tmscp.tmscp_cmd.mscp_opcode = op;
20627479Skjd 	tmscp.tmscp_cmd.mscp_modifier = mod;
20727479Skjd 	tmscp.tmscp_cmd.mscp_header.tmscp_msglen = mscp_msglen;
20827479Skjd 	tmscp.tmscp_ca.ca_cmddsc[0] |= TMSCP_OWN;	/* | TMSCP_INT */
20927479Skjd 	tmscp.tmscp_rsp.mscp_header.tmscp_msglen = mscp_msglen;
21027479Skjd 	tmscp.tmscp_ca.ca_rspdsc[0] |= TMSCP_OWN;	/* | TMSCP_INT */
21127479Skjd 
21227479Skjd 	i = tmscpaddr->tmscpip;
21333646Sbostic 	for (;;) {
21433646Sbostic 		if (tmscpaddr->tmscpsa & TMSCP_ERR) {
21527479Skjd 			printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr->tmscpsa & 0xffff);
21627479Skjd 			return(0);
21733646Sbostic 		}
21827479Skjd 
21927479Skjd 		if (tmscp.tmscp_ca.ca_cmdint)
22027479Skjd 			tmscp.tmscp_ca.ca_cmdint = 0;
22127479Skjd 		/*
22227479Skjd 		 * This is to handle the case of devices not setting the
22327479Skjd 		 * interrupt field in the communications area. Some
22427479Skjd 		 * devices (early TU81's) only clear the ownership field
22527479Skjd 		 * in the Response Descriptor.
22633646Sbostic 		 *
22733646Sbostic 		 *
22833646Sbostic 		 *	if (tmscp.tmscp_ca.ca_rspint)
22933646Sbostic 		 *		break;
23027479Skjd 		 */
23127479Skjd 		if (!(tmscp.tmscp_ca.ca_rspdsc[0] & (TMSCP_OWN)))
23227479Skjd 			break;
23333646Sbostic 	}
23427479Skjd 	tmscp.tmscp_ca.ca_rspint = 0;
23527479Skjd 	mp = &tmscp.tmscp_rsp;
23627479Skjd 	if (mp->mscp_opcode != (op|M_OP_END) ||
23733646Sbostic 	   (mp->mscp_status&M_ST_MASK) != M_ST_SUCC) {
23833646Sbostic 		/*
23933646Sbostic 		 * Detect hitting tape mark.  This signifies the end of the
24027479Skjd 		 * tape mini-root file.  We don't want to return an error
24127479Skjd 		 * condition to the strategy routine.
24227479Skjd 		 */
24333646Sbostic 		if ((mp->mscp_status & M_ST_MASK) != M_ST_TAPEM)
24433646Sbostic 			return(0);
24533646Sbostic 	}
24627479Skjd 	return(mp);
24727479Skjd }
24827479Skjd 
24927479Skjd /*
25027479Skjd  * Set up to do reads and writes; call tmscpcmd to issue the cmd.
25127479Skjd  */
25227479Skjd tmscpstrategy(io, func)
25327479Skjd 	register struct iob *io;
25427479Skjd 	int func;
25527479Skjd {
25627479Skjd 	register struct mscp *mp;
25727479Skjd 	int ubinfo;
25827479Skjd 
25927479Skjd 	ubinfo = ubasetup(io, 1);
26027479Skjd 	mp = &tmscp.tmscp_cmd;
26127479Skjd 	mp->mscp_lbn = io->i_bn;
26227479Skjd 	mp->mscp_unit = io->i_unit&03;
26327479Skjd 	mp->mscp_bytecnt = io->i_cc;
26427479Skjd 	mp->mscp_buffer = (ubinfo & 0x3fffff) | (((ubinfo>>28)&0xf)<<24);
26533646Sbostic 	if ((mp = tmscpcmd(func == READ ? M_OP_READ : M_OP_WRITE, 0)) == 0) {
26627479Skjd 		ubafree(io, ubinfo);
26727479Skjd 		printf("tms: I/O error\n");
26827479Skjd 		return(-1);
26933646Sbostic 	}
27027479Skjd 	ubafree(io, ubinfo);
27127479Skjd 	/*
27227479Skjd 	 * Detect hitting tape mark so we do it gracefully and return a
27327479Skjd 	 * character count of 0 to signify end of copy.  Rewind the tape
27427479Skjd 	 * before returning.
27527479Skjd 	 */
27627479Skjd 	if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM)
27727479Skjd 		return(0);
27827479Skjd 	return(io->i_cc);
27927479Skjd }
280