xref: /csrg-svn/sys/vax/stand/tmscp.c (revision 27479)
1*27479Skjd 
2*27479Skjd /*	@(#)tmscp.c	1.1 (Berkeley) 04/28/86 */
3*27479Skjd 
4*27479Skjd /****************************************************************
5*27479Skjd  *                                                              *
6*27479Skjd  *        Licensed from Digital Equipment Corporation           *
7*27479Skjd  *                       Copyright (c)                          *
8*27479Skjd  *               Digital Equipment Corporation                  *
9*27479Skjd  *                   Maynard, Massachusetts                     *
10*27479Skjd  *                         1985, 1986                           *
11*27479Skjd  *                    All rights reserved.                      *
12*27479Skjd  *                                                              *
13*27479Skjd  *        The Information in this software is subject to change *
14*27479Skjd  *   without notice and should not be construed as a commitment *
15*27479Skjd  *   by  Digital  Equipment  Corporation.   Digital   makes  no *
16*27479Skjd  *   representations about the suitability of this software for *
17*27479Skjd  *   any purpose.  It is supplied "As Is" without expressed  or *
18*27479Skjd  *   implied  warranty.                                         *
19*27479Skjd  *                                                              *
20*27479Skjd  *        If the Regents of the University of California or its *
21*27479Skjd  *   licensees modify the software in a manner creating         *
22*27479Skjd  *   diriviative copyright rights, appropriate copyright        *
23*27479Skjd  *   legends may be placed on  the drivative work in addition   *
24*27479Skjd  *   to that set forth above.                                   *
25*27479Skjd  ***************************************************************/
26*27479Skjd /*
27*27479Skjd  * tmscp.c - TMSCP (TK50/TU81) standalone driver
28*27479Skjd  */
29*27479Skjd 
30*27479Skjd # ifndef lint
31*27479Skjd static char *sccsid = "@(#)tmscp.c	1.5	(ULTRIX)	4/18/86";
32*27479Skjd # endif not lint
33*27479Skjd 
34*27479Skjd /* ------------------------------------------------------------------------
35*27479Skjd  * Modification History: /sys/stand/tmscp.c
36*27479Skjd  *
37*27479Skjd  * 3-15-85  afd
38*27479Skjd  *	Don't ask for an interrupt when commands are issued and
39*27479Skjd  *	check ownership bit in the response descriptor to detect when a
40*27479Skjd  *	command is complete.  Necessary due to the TU81's failure to set
41*27479Skjd  *	the response interrupt field in the communications area.
42*27479Skjd  *
43*27479Skjd  * ------------------------------------------------------------------------
44*27479Skjd  */
45*27479Skjd 
46*27479Skjd #include "../machine/pte.h"
47*27479Skjd 
48*27479Skjd #include "../h/param.h"
49*27479Skjd #include "../h/gnode.h"
50*27479Skjd #include "../h/devio.h"
51*27479Skjd 
52*27479Skjd #include "savax.h"
53*27479Skjd 
54*27479Skjd #include "saio.h"
55*27479Skjd 
56*27479Skjd /*
57*27479Skjd  * Parameters for the communications area
58*27479Skjd  * (Only 1 cmd & 1 rsp packet)
59*27479Skjd  */
60*27479Skjd #define	NRSPL2	0
61*27479Skjd #define	NCMDL2	0
62*27479Skjd #define	NRSP	(1<<NRSPL2)
63*27479Skjd #define	NCMD	(1<<NCMDL2)
64*27479Skjd 
65*27479Skjd #include "../vaxuba/tmscpreg.h"
66*27479Skjd #include "../vaxuba/ubareg.h"
67*27479Skjd #include "../vax/tmscp.h"
68*27479Skjd 
69*27479Skjd u_short tmscpstd[] = { 0174500 };
70*27479Skjd 
71*27479Skjd struct iob	ctmscpbuf;
72*27479Skjd 
73*27479Skjd struct tmscpdevice *tmscpaddr = 0;
74*27479Skjd 
75*27479Skjd struct tmscp {
76*27479Skjd 	struct tmscpca	tmscp_ca;
77*27479Skjd 	struct mscp	tmscp_rsp;
78*27479Skjd 	struct mscp	tmscp_cmd;
79*27479Skjd 	} tmscp;
80*27479Skjd 
81*27479Skjd struct tmscp *tmscp_ubaddr;		/* Unibus address of tmscp structure */
82*27479Skjd 
83*27479Skjd struct mscp *tmscpcmd();
84*27479Skjd 
85*27479Skjd int tmscp_offline = 1;		/* Flag to prevent multiple STCON */
86*27479Skjd int tms_offline[4] = {1,1,1,1}; /* Flag to prevent multiple ONLIN */
87*27479Skjd 
88*27479Skjd 
89*27479Skjd /*
90*27479Skjd  * Open a tmscp device. Initialize the controller and set the unit online.
91*27479Skjd  */
92*27479Skjd tmscpopen(io)
93*27479Skjd 	register struct iob *io;
94*27479Skjd {
95*27479Skjd 	register struct mscp *mp;
96*27479Skjd 	int i;
97*27479Skjd 
98*27479Skjd 	/*
99*27479Skjd 	 * Have the tmscp controller characteristics already been set up
100*27479Skjd 	 * (STCON)?
101*27479Skjd 	 */
102*27479Skjd 	if (tmscp_offline)
103*27479Skjd 		{
104*27479Skjd 		if (tmscpaddr == 0)
105*27479Skjd 			tmscpaddr = (struct tmscpdevice *)ubamem(io->i_unit, tmscpstd[0]);
106*27479Skjd 		if (tmscp_ubaddr == 0)
107*27479Skjd 			{
108*27479Skjd 			ctmscpbuf.i_unit = io->i_unit;
109*27479Skjd 			ctmscpbuf.i_ma = (caddr_t)&tmscp;
110*27479Skjd 			ctmscpbuf.i_cc = sizeof(tmscp);
111*27479Skjd 			tmscp_ubaddr = (struct tmscp *)ubasetup(&ctmscpbuf, 2);
112*27479Skjd 			}
113*27479Skjd 		/*
114*27479Skjd 		 * Initialize the tmscp device and wait for the 4 steps
115*27479Skjd 		 * to complete.
116*27479Skjd 		 */
117*27479Skjd 		tmscpaddr->tmscpip = 0;
118*27479Skjd 		while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
119*27479Skjd 			;
120*27479Skjd 		tmscpaddr->tmscpsa =TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8);
121*27479Skjd 
122*27479Skjd 		while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0)
123*27479Skjd 			;
124*27479Skjd #		define STEP1MASK 0174377
125*27479Skjd #		define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
126*27479Skjd 		if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
127*27479Skjd 			printf("tmscpopen: step 1 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
128*27479Skjd 		tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase;
129*27479Skjd 
130*27479Skjd 		while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0)
131*27479Skjd 			;
132*27479Skjd #		define STEP2MASK 0174377
133*27479Skjd #		define STEP2GOOD (TMSCP_STEP3)
134*27479Skjd 		if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
135*27479Skjd 			printf("tmscpopen: step 2 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
136*27479Skjd 		tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
137*27479Skjd 
138*27479Skjd 		while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0)
139*27479Skjd 			;
140*27479Skjd #		define STEP3MASK 0174000
141*27479Skjd #		define STEP3GOOD TMSCP_STEP4
142*27479Skjd 		if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
143*27479Skjd 			printf("tmscpopen: step 3 not successful sa=%o\n",tmscpaddr->tmscpsa&0xffff);
144*27479Skjd 		tmscpaddr->tmscpsa = TMSCP_GO;
145*27479Skjd 
146*27479Skjd 		/*
147*27479Skjd 		 * Init cmd & rsp area
148*27479Skjd 		 */
149*27479Skjd 		tmscp.tmscp_ca.ca_cmddsc[0] = (long)&tmscp_ubaddr->tmscp_cmd.mscp_cmdref;
150*27479Skjd 		tmscp.tmscp_cmd.mscp_dscptr = tmscp.tmscp_ca.ca_cmddsc;
151*27479Skjd 		tmscp.tmscp_cmd.mscp_header.tmscp_vcid = 1;	/* for tape */
152*27479Skjd 
153*27479Skjd 		tmscp.tmscp_ca.ca_rspdsc[0] = (long)&tmscp_ubaddr->tmscp_rsp.mscp_cmdref;
154*27479Skjd 		tmscp.tmscp_rsp.mscp_dscptr = tmscp.tmscp_ca.ca_rspdsc;
155*27479Skjd 		tmscp.tmscp_cmd.mscp_cntflgs = 0;
156*27479Skjd 		if (tmscpcmd(M_OP_STCON, 0) == 0)
157*27479Skjd 			{
158*27479Skjd 			_stop("tms: open error, STCON");
159*27479Skjd 			return;
160*27479Skjd 			}
161*27479Skjd 		tmscp_offline = 0;
162*27479Skjd 		}
163*27479Skjd 	tmscp.tmscp_cmd.mscp_unit = io->i_unit&03;
164*27479Skjd 	/*
165*27479Skjd 	 * Has this unit been issued an ONLIN?
166*27479Skjd 	 */
167*27479Skjd 	if (tms_offline[tmscp.tmscp_cmd.mscp_unit])
168*27479Skjd 		{
169*27479Skjd 		if ((mp = tmscpcmd(M_OP_ONLIN, 0)) == 0)
170*27479Skjd 			{
171*27479Skjd 			_stop("tms: open error, ONLIN");
172*27479Skjd 			return;
173*27479Skjd 			}
174*27479Skjd 		tms_offline[tmscp.tmscp_cmd.mscp_unit] = 0;
175*27479Skjd 		}
176*27479Skjd 	if (io->i_boff < 0 || io->i_boff > 3)
177*27479Skjd 		_stop("tms: bad offset");
178*27479Skjd 	else if (io->i_boff > 0)
179*27479Skjd 		/*
180*27479Skjd 		 * Skip forward the appropriate number of files on the tape.
181*27479Skjd 		 */
182*27479Skjd 		{
183*27479Skjd 		tmscp.tmscp_cmd.mscp_tmkcnt = io->i_boff;
184*27479Skjd 		tmscpcmd(M_OP_REPOS, 0);
185*27479Skjd 		tmscp.tmscp_cmd.mscp_tmkcnt = 0;
186*27479Skjd 		}
187*27479Skjd }
188*27479Skjd 
189*27479Skjd 
190*27479Skjd /*
191*27479Skjd  * Close the device (rewind it to BOT)
192*27479Skjd  */
193*27479Skjd tmscpclose(io)
194*27479Skjd 	register struct iob *io;
195*27479Skjd {
196*27479Skjd 	tmscpcmd(M_OP_REPOS, M_MD_REWND);
197*27479Skjd }
198*27479Skjd 
199*27479Skjd 
200*27479Skjd /*
201*27479Skjd  * Set up tmscp command packet.  Cause the controller to poll to pick up
202*27479Skjd  * the command.
203*27479Skjd  */
204*27479Skjd struct mscp *
205*27479Skjd tmscpcmd(op,mod)
206*27479Skjd 	int op, mod;			/* opcode and modifier (usu 0) */
207*27479Skjd {
208*27479Skjd 	struct mscp *mp;		/* ptr to cmd packet */
209*27479Skjd 	int i;				/* read into to init polling */
210*27479Skjd 
211*27479Skjd 	tmscp.tmscp_cmd.mscp_opcode = op;
212*27479Skjd 	tmscp.tmscp_cmd.mscp_modifier = mod;
213*27479Skjd 	tmscp.tmscp_cmd.mscp_header.tmscp_msglen = mscp_msglen;
214*27479Skjd 	tmscp.tmscp_ca.ca_cmddsc[0] |= TMSCP_OWN;	/* | TMSCP_INT */
215*27479Skjd 	tmscp.tmscp_rsp.mscp_header.tmscp_msglen = mscp_msglen;
216*27479Skjd 	tmscp.tmscp_ca.ca_rspdsc[0] |= TMSCP_OWN;	/* | TMSCP_INT */
217*27479Skjd 
218*27479Skjd 	i = tmscpaddr->tmscpip;
219*27479Skjd 	for (;;)
220*27479Skjd 		{
221*27479Skjd 		if (tmscpaddr->tmscpsa & TMSCP_ERR)
222*27479Skjd 			{
223*27479Skjd 			printf("tmscpcmd: Fatal error sa=%o\n", tmscpaddr->tmscpsa & 0xffff);
224*27479Skjd 			return(0);
225*27479Skjd 			}
226*27479Skjd 
227*27479Skjd 		if (tmscp.tmscp_ca.ca_cmdint)
228*27479Skjd 			tmscp.tmscp_ca.ca_cmdint = 0;
229*27479Skjd 		/*
230*27479Skjd 		 * This is to handle the case of devices not setting the
231*27479Skjd 		 * interrupt field in the communications area. Some
232*27479Skjd 		 * devices (early TU81's) only clear the ownership field
233*27479Skjd 		 * in the Response Descriptor.
234*27479Skjd 		 */
235*27479Skjd /*
236*27479Skjd 		if (tmscp.tmscp_ca.ca_rspint)
237*27479Skjd 			break;
238*27479Skjd */
239*27479Skjd 		if (!(tmscp.tmscp_ca.ca_rspdsc[0] & (TMSCP_OWN)))
240*27479Skjd 			break;
241*27479Skjd 		}
242*27479Skjd 	tmscp.tmscp_ca.ca_rspint = 0;
243*27479Skjd 	mp = &tmscp.tmscp_rsp;
244*27479Skjd 	if (mp->mscp_opcode != (op|M_OP_END) ||
245*27479Skjd 	   (mp->mscp_status&M_ST_MASK) != M_ST_SUCC)
246*27479Skjd 		{
247*27479Skjd 		/* Detect hitting tape mark.  This signifies the end of the
248*27479Skjd 		 * tape mini-root file.  We don't want to return an error
249*27479Skjd 		 * condition to the strategy routine.
250*27479Skjd 		 */
251*27479Skjd 		if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM)
252*27479Skjd 			return(mp);
253*27479Skjd 		return(0);
254*27479Skjd 		}
255*27479Skjd 	return(mp);
256*27479Skjd }
257*27479Skjd 
258*27479Skjd 
259*27479Skjd /*
260*27479Skjd  * Set up to do reads and writes; call tmscpcmd to issue the cmd.
261*27479Skjd  */
262*27479Skjd tmscpstrategy(io, func)
263*27479Skjd 	register struct iob *io;
264*27479Skjd 	int func;
265*27479Skjd {
266*27479Skjd 	register struct mscp *mp;
267*27479Skjd 	int ubinfo;
268*27479Skjd 
269*27479Skjd 	ubinfo = ubasetup(io, 1);
270*27479Skjd 	mp = &tmscp.tmscp_cmd;
271*27479Skjd 	mp->mscp_lbn = io->i_bn;
272*27479Skjd 	mp->mscp_unit = io->i_unit&03;
273*27479Skjd 	mp->mscp_bytecnt = io->i_cc;
274*27479Skjd 	mp->mscp_buffer = (ubinfo & 0x3fffff) | (((ubinfo>>28)&0xf)<<24);
275*27479Skjd 	if ((mp = tmscpcmd(func == READ ? M_OP_READ : M_OP_WRITE, 0)) == 0)
276*27479Skjd 		{
277*27479Skjd 		ubafree(io, ubinfo);
278*27479Skjd 		printf("tms: I/O error\n");
279*27479Skjd 		return(-1);
280*27479Skjd 		}
281*27479Skjd 	ubafree(io, ubinfo);
282*27479Skjd 	/*
283*27479Skjd 	 * Detect hitting tape mark so we do it gracefully and return a
284*27479Skjd 	 * character count of 0 to signify end of copy.  Rewind the tape
285*27479Skjd 	 * before returning.
286*27479Skjd 	 */
287*27479Skjd 	if ((mp->mscp_status & M_ST_MASK) == M_ST_TAPEM)
288*27479Skjd 		return(0);
289*27479Skjd 	return(io->i_cc);
290*27479Skjd }
291*27479Skjd 
292*27479Skjd /*ARGSUSED*/
293*27479Skjd tmscpioctl(io, cmd, arg)
294*27479Skjd 	struct iob *io;
295*27479Skjd 	int cmd;
296*27479Skjd 	caddr_t arg;
297*27479Skjd {
298*27479Skjd 	return (ECMD);
299*27479Skjd }
300