xref: /original-bsd/sys/vax/uba/tmscp.c (revision e718b3e3)
1a05d0f95Sbostic /*-
2*e718b3e3Sbostic  * Copyright (c) 1991
3*e718b3e3Sbostic  *	The Regents of the University of California.  All rights reserved.
4*e718b3e3Sbostic  * (c) UNIX System Laboratories, Inc.
5*e718b3e3Sbostic  * All or some portions of this file are derived from material licensed
6*e718b3e3Sbostic  * to the University of California by American Telephone and Telegraph
7*e718b3e3Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8*e718b3e3Sbostic  * the permission of UNIX System Laboratories, Inc.
9a05d0f95Sbostic  *
10a05d0f95Sbostic  * %sccs.include.redist.c%
11a05d0f95Sbostic  *
12*e718b3e3Sbostic  *	@(#)tmscp.c	7.17 (Berkeley) 01/21/94
13a05d0f95Sbostic  */
14bc5e3c50Skarels 
15a05d0f95Sbostic /*
16a05d0f95Sbostic  * sccsid = "@(#)tmscp.c	1.24	(ULTRIX)	1/21/86";
17a05d0f95Sbostic  */
18bc5e3c50Skarels 
19bc5e3c50Skarels /************************************************************************
20bc5e3c50Skarels  *									*
2125ab8d95Skjd  *        Licensed from Digital Equipment Corporation 			*
2225ab8d95Skjd  *                       Copyright (c) 					*
2325ab8d95Skjd  *               Digital Equipment Corporation				*
2425ab8d95Skjd  *                   Maynard, Massachusetts 				*
2525ab8d95Skjd  *                         1985, 1986 					*
2625ab8d95Skjd  *                    All rights reserved. 				*
27bc5e3c50Skarels  *									*
2825ab8d95Skjd  *        The Information in this software is subject to change 	*
2925ab8d95Skjd  *   without notice and should not be construed as a commitment 	*
3025ab8d95Skjd  *   by  Digital  Equipment  Corporation.   Digital   makes  no 	*
3125ab8d95Skjd  *   representations about the suitability of this software for 	*
3225ab8d95Skjd  *   any purpose.  It is supplied "As Is" without expressed  or 	*
3325ab8d95Skjd  *   implied  warranty. 						*
34bc5e3c50Skarels  *									*
3525ab8d95Skjd  *        If the Regents of the University of California or its 	*
3625ab8d95Skjd  *   licensees modify the software in a manner creating  		*
3725ab8d95Skjd  *   diriviative copyright rights, appropriate copyright  		*
3825ab8d95Skjd  *   legends may be placed on  the drivative work in addition  		*
3925ab8d95Skjd  *   to that set forth above. 						*
40bc5e3c50Skarels  *									*
41bc5e3c50Skarels  ************************************************************************
42bc5e3c50Skarels  *
43bc5e3c50Skarels  * tmscp.c - TMSCP (TK50/TU81) tape device driver
44bc5e3c50Skarels  *
45bc5e3c50Skarels  * Modification History:
46bc5e3c50Skarels  *
47bc5e3c50Skarels  * 06-Jan-86 - afd
48bc5e3c50Skarels  *	Changed the probe routine to use DELAY (not TODR).  This now
49bc5e3c50Skarels  *	works for MicroVAXen as well.  This eliminates the busy-wait
50bc5e3c50Skarels  *	for MicroVAXen so a dead TK50 controller will not hang autoconf.
51bc5e3c50Skarels  *
52bc5e3c50Skarels  * 06-Dec-85 - afd
53bc5e3c50Skarels  *	Fixed a bug in density selection.  The "set unit characteristics"
54bc5e3c50Skarels  *	command to select density, was clearing the "unit flags" field
55bc5e3c50Skarels  *	where the CACHE bit was for TU81-E.  Now the unit's "format" and
56bc5e3c50Skarels  *	"unitflgs" are saved in tms_info struct.  And are used on STUNT
57bc5e3c50Skarels  *	commands.
58bc5e3c50Skarels  *
59bc5e3c50Skarels  * 19-Oct-85 - afd
60bc5e3c50Skarels  *	Added support to the open routine to allow drives to be opened
61bc5e3c50Skarels  *	for low density (800 or 1600 bpi) use.  When the slave routine
62bc5e3c50Skarels  *	initiates a "get-unit-char" cmd, the format menu for the unit
63bc5e3c50Skarels  *	is saved in the tms_info structure. The format menu is used in the
64bc5e3c50Skarels  *	start routine to select the proper low density.
65bc5e3c50Skarels  *
66bc5e3c50Skarels  * 02-Oct-85 - afd
67bc5e3c50Skarels  *	When a tmscp-type controller is initializing, it is possible for
68bc5e3c50Skarels  *	the sa reg to become 0 between states.  Thus the init code in
69bc5e3c50Skarels  *	the interrupt routine had to be modified to reflect this.
70bc5e3c50Skarels  *
71bc5e3c50Skarels  * 21-Sep-85 - afd
72bc5e3c50Skarels  *	The TK50 declares a serious exception when a tape mark is encountered.
73bc5e3c50Skarels  *	This causes problems to dd (& other UN*X utilities).  So a flag
74bc5e3c50Skarels  *	is set in the rsp() routine when a tape mark is encountered.  If
75bc5e3c50Skarels  *	this flag is set, the start() routine appends the Clear Serious
76bc5e3c50Skarels  *	Exception modifier to the next command.
77bc5e3c50Skarels  *
78bc5e3c50Skarels  * 03-Sep-85 -- jaw
79bc5e3c50Skarels  *	messed up previous edit..
80bc5e3c50Skarels  *
81bc5e3c50Skarels  * 29-Aug-85 - jaw
82bc5e3c50Skarels  *	fixed bugs in 8200 and 750 buffered datapath handling.
83bc5e3c50Skarels  *
84bc5e3c50Skarels  * 06-Aug-85 - afd
85bc5e3c50Skarels  *   1. When repositioning records or files, the count of items skipped
86bc5e3c50Skarels  *	does NOT HAVE to be returned by controllers (& the TU81 doesn't).
87bc5e3c50Skarels  *	So tmscprsp() had to be modified to stop reporting
88bc5e3c50Skarels  *	residual count errors on reposition commands.
89bc5e3c50Skarels  *
90bc5e3c50Skarels  *   2. Fixed bug in the open routine which allowed multiple opens.
91bc5e3c50Skarels  *
92bc5e3c50Skarels  * 18-Jul-85 - afd
93bc5e3c50Skarels  *   1. Need to return status when mt status (or corresponding ioctl) is done.
94bc5e3c50Skarels  *	Save resid, flags, endcode & status in tmscprsp() routine (except on
95bc5e3c50Skarels  *	clear serious exception no-op).  Return these fields when status
96bc5e3c50Skarels  *	ioctl is done (in tmscpcommand()).  How they are returned:
97bc5e3c50Skarels  *		mt_resid = resid
98bc5e3c50Skarels  *		mt_dsreg = flags|endcode
99bc5e3c50Skarels  *		mt_erreg = status
100bc5e3c50Skarels  *
101bc5e3c50Skarels  *   2. Added latent support for enabling/disabling caching.  This is
102bc5e3c50Skarels  *	handled along with all other ioctl commands.
103bc5e3c50Skarels  *
104bc5e3c50Skarels  *   3. Need to issue a no-op on unrecognized ioctl in tmscpstart(), since
105bc5e3c50Skarels  *	we have already commited to issuing a command at that point.
106bc5e3c50Skarels  *
107bc5e3c50Skarels  *   4. In tmscprsp() routine if encode is 0200 (invalid command issued);
108bc5e3c50Skarels  *	We need to: Unlink the buffer from the I/O wait queue,
109bc5e3c50Skarels  *	and signal iodone, so the higher level command can exit!
110bc5e3c50Skarels  *	Just as if it were a valid command.
111bc5e3c50Skarels  *
112bc5e3c50Skarels  * 11-jul-85 -- jaw
113bc5e3c50Skarels  *	fix bua/bda map registers.
114bc5e3c50Skarels  *
115bc5e3c50Skarels  * 19-Jun-85 -- jaw
116bc5e3c50Skarels  *	VAX8200 name change.
117bc5e3c50Skarels  *
118bc5e3c50Skarels  * 06-Jun-85 - jaw
119bc5e3c50Skarels  *	fixes for 8200.
120bc5e3c50Skarels  *
121bc5e3c50Skarels  * 9-Apr-85 - afd
122bc5e3c50Skarels  *	Added timeout code to the probe routine, so if the controller
123bc5e3c50Skarels  *	fails to init in 10 seconds we return failed status.
124bc5e3c50Skarels  *
125bc5e3c50Skarels  * 13-Mar-85 -jaw
126bc5e3c50Skarels  *	Changes for support of the VAX8200 were merged in.
127bc5e3c50Skarels  *
128bc5e3c50Skarels  * 27-Feb-85 -tresvik
129bc5e3c50Skarels  *	Changes for support of the VAX8600 were merged in.
130bc5e3c50Skarels  *
131bc5e3c50Skarels  */
132bc5e3c50Skarels 
133bc5e3c50Skarels #include "tms.h"
1341625a9a8Skarels #if NTMSCP > 0
135bc5e3c50Skarels 
136598a0063Sbostic #include "sys/param.h"
137598a0063Sbostic #include "sys/systm.h"
138598a0063Sbostic #include "sys/buf.h"
139598a0063Sbostic #include "sys/conf.h"
140598a0063Sbostic #include "sys/errno.h"
141598a0063Sbostic #include "sys/file.h"
142598a0063Sbostic #include "sys/map.h"
143598a0063Sbostic #include "sys/vm.h"
144598a0063Sbostic #include "sys/ioctl.h"
145598a0063Sbostic #include "sys/syslog.h"
146598a0063Sbostic #include "sys/mtio.h"
147598a0063Sbostic #include "sys/cmap.h"
148598a0063Sbostic #include "sys/uio.h"
149598a0063Sbostic #include "sys/tprintf.h"
1501625a9a8Skarels 
151598a0063Sbostic #include "../include/pte.h"
152598a0063Sbostic #include "../include/cpu.h"
153598a0063Sbostic #include "../include/mtpr.h"
1541625a9a8Skarels #include "ubareg.h"
1551625a9a8Skarels #include "ubavar.h"
1561625a9a8Skarels 
1571625a9a8Skarels #define TENSEC	(1000)
1581625a9a8Skarels #define	TMS_PRI	LOG_INFO
1591625a9a8Skarels 
1601625a9a8Skarels #define NRSPL2  3               /* log2 number of response packets */
1611625a9a8Skarels #define NCMDL2  3               /* log2 number of command packets */
1621625a9a8Skarels #define NRSP    (1<<NRSPL2)
1631625a9a8Skarels #define NCMD    (1<<NCMDL2)
1641625a9a8Skarels 
1651625a9a8Skarels #include "tmscpreg.h"
1661625a9a8Skarels #include "../vax/tmscp.h"
1671625a9a8Skarels 
1681625a9a8Skarels /* Software state per controller */
1691625a9a8Skarels 
1701625a9a8Skarels struct tmscp_softc {
1711625a9a8Skarels 	short   sc_state;       /* state of controller */
1721625a9a8Skarels 	short   sc_mapped;      /* Unibus map allocated for tmscp struct? */
1731625a9a8Skarels 	int     sc_ubainfo;     /* Unibus mapping info */
1741625a9a8Skarels 	struct	tmscp *sc_tmscp;   /* Unibus address of tmscp struct */
1751625a9a8Skarels 	int     sc_ivec;        /* interrupt vector address */
1761625a9a8Skarels 	short   sc_credits;     /* transfer credits */
1771625a9a8Skarels 	short   sc_lastcmd;     /* pointer into command ring */
1781625a9a8Skarels 	short   sc_lastrsp;     /* pointer into response ring */
179ee3b0629Skarels 	short   sc_ipl;		/* interrupt priority (Q-bus) */
1801625a9a8Skarels } tmscp_softc[NTMSCP];
1811625a9a8Skarels 
1821625a9a8Skarels struct tmscp {
1831625a9a8Skarels 	struct tmscpca	tmscp_ca;         /* communications area */
1841625a9a8Skarels 	struct mscp	tmscp_rsp[NRSP];  /* response packets */
1851625a9a8Skarels 	struct mscp	tmscp_cmd[NCMD];  /* command packets */
1861625a9a8Skarels } tmscp[NTMSCP];
1871625a9a8Skarels 
1881625a9a8Skarels /*
1891625a9a8Skarels  * Per drive-unit info
1901625a9a8Skarels  */
1911625a9a8Skarels struct tms_info {
1921625a9a8Skarels 	daddr_t		tms_dsize;	/* Max user size from online pkt */
1931625a9a8Skarels 	unsigned	tms_type;	/* Drive type int field  */
1941625a9a8Skarels 	int		tms_resid;	/* residual from last xfer */
1951625a9a8Skarels 	u_char		tms_endcode;	/* last command endcode */
1961625a9a8Skarels 	u_char		tms_flags;	/* last command end flags */
1971625a9a8Skarels 	unsigned	tms_status;	/* Command status from last command */
1981625a9a8Skarels 	char		tms_openf;	/* lock against multiple opens */
1991625a9a8Skarels 	char		tms_lastiow;	/* last op was a write */
2001625a9a8Skarels 	char		tms_serex;	/* set when serious exception occurs */
2011625a9a8Skarels 	char		tms_clserex;	/* set when serex being cleared by no-op */
2021625a9a8Skarels 	short		tms_fmtmenu;	/* the unit's format (density) menu */
2031625a9a8Skarels 	short		tms_unitflgs;	/* unit flag parameters */
2041625a9a8Skarels 	short		tms_format;	/* the unit's current format (density) */
2055d073b51Smarc 	tpr_t 		tms_tpr;	/* tprintf handle */
2061625a9a8Skarels } tms_info[NTMS];
2071625a9a8Skarels struct uba_ctlr *tmscpminfo[NTMSCP];
2081625a9a8Skarels struct uba_device *tmsdinfo[NTMS];
2091625a9a8Skarels /*
2101625a9a8Skarels  * ifdef other tmscp devices here if they allow more than 1 unit/controller
2111625a9a8Skarels  */
2121625a9a8Skarels struct uba_device *tmscpip[NTMSCP][1];
2131625a9a8Skarels struct buf ctmscpbuf[NTMSCP];		/* internal cmd buffer (for ioctls) */
2141625a9a8Skarels struct buf tmsutab[NTMS];		/* Drive queue */
2151625a9a8Skarels struct buf tmscpwtab[NTMSCP];		/* I/O wait queue, per controller */
2161625a9a8Skarels int    tmscpmicro[NTMSCP];		/* to store microcode level */
2171625a9a8Skarels short  utoctlr[NTMS];			/* Slave unit to controller mapping */
2181625a9a8Skarels 					/* filled in by the slave routine */
219bc5e3c50Skarels 
220bc5e3c50Skarels /* Bits in minor device */
221bc5e3c50Skarels #define	TMSUNIT(dev)	(minor(dev)&03)
222bc5e3c50Skarels #define	T_NOREWIND	04
223bc5e3c50Skarels #define	T_HIDENSITY	010
224bc5e3c50Skarels 
225bc5e3c50Skarels /* Slave unit to controller mapping */
226bc5e3c50Skarels #define TMSCPCTLR(dev)	(utoctlr[TMSUNIT(dev)])
227bc5e3c50Skarels 
228bc5e3c50Skarels /*
229bc5e3c50Skarels  * Internal (ioctl) command codes (these must also be declared in the
230bc5e3c50Skarels  * tmscpioctl routine).  These correspond to ioctls in mtio.h
231bc5e3c50Skarels  */
232bc5e3c50Skarels #define TMS_WRITM	0		/* write tape mark */
233bc5e3c50Skarels #define TMS_FSF		1		/* forward space file */
234bc5e3c50Skarels #define TMS_BSF		2		/* backward space file */
235bc5e3c50Skarels #define TMS_FSR		3		/* forward space record */
236bc5e3c50Skarels #define TMS_BSR		4		/* backward space record */
237bc5e3c50Skarels #define TMS_REW		5		/* rewind tape */
238bc5e3c50Skarels #define TMS_OFFL	6		/* rewind tape & mark unit offline */
239bc5e3c50Skarels #define TMS_SENSE	7		/* noop - do a get unit status */
240bc5e3c50Skarels #define TMS_CACHE	8		/* enable cache */
241bc5e3c50Skarels #define TMS_NOCACHE	9		/* disable cache */
242bc5e3c50Skarels /* These go last: after all real mt cmds, just bump the numbers up */
243bc5e3c50Skarels #define TMS_CSE		10		/* clear serious exception */
244bc5e3c50Skarels #define TMS_LOWDENSITY	11		/* set unit to low density */
245bc5e3c50Skarels #define TMS_HIDENSITY	12		/* set unit to high density */
246bc5e3c50Skarels 
247bc5e3c50Skarels /*
248bc5e3c50Skarels  * Controller states
249bc5e3c50Skarels  */
250bc5e3c50Skarels #define S_IDLE  0               /* hasn't been initialized */
251bc5e3c50Skarels #define S_STEP1 1               /* doing step 1 init */
252bc5e3c50Skarels #define S_STEP2 2               /* doing step 2 init */
253bc5e3c50Skarels #define S_STEP3 3               /* doing step 3 init */
254bc5e3c50Skarels #define S_SCHAR 4               /* doing "set controller characteristics" */
255bc5e3c50Skarels #define S_RUN   5               /* running */
256bc5e3c50Skarels 
257bc5e3c50Skarels int     tmscperror = 0;		/* causes hex dump of packets */
258bc5e3c50Skarels int	tmscp_cp_wait = 0;	/* Something to wait on for command */
259bc5e3c50Skarels 				/* packets and or credits. */
260bc5e3c50Skarels int	wakeup();
261bc5e3c50Skarels extern	int	hz;		/* Should find the right include */
262bc5e3c50Skarels 
263bc5e3c50Skarels #ifdef	DEBUG
264bc5e3c50Skarels #define printd if (tmscpdebug) printf
265bc5e3c50Skarels int tmscpdebug = 1;
266bc5e3c50Skarels #define	printd10 if(tmscpdebug >= 10) printf
267bc5e3c50Skarels #endif
268bc5e3c50Skarels 
269bc5e3c50Skarels int     tmscpprobe(), tmscpslave(), tmscpattach(), tmscpintr();
270bc5e3c50Skarels struct  mscp *tmscpgetcp();
271bc5e3c50Skarels 
272bc5e3c50Skarels #define DRVNAME "tms"
273bc5e3c50Skarels #define CTRLNAME "tmscp"
274bc5e3c50Skarels 
275bc5e3c50Skarels u_short tmscpstd[] = { 0174500, 0 };
276bc5e3c50Skarels struct  uba_driver tmscpdriver =
277bc5e3c50Skarels { tmscpprobe, tmscpslave, tmscpattach, 0, tmscpstd, DRVNAME, tmsdinfo, CTRLNAME
278bc5e3c50Skarels , tmscpminfo, 0};
279bc5e3c50Skarels 
280bc5e3c50Skarels #define b_qsize         b_resid         /* queue size per drive, in tmsutab */
281bc5e3c50Skarels #define b_ubinfo        b_resid         /* Unibus mapping info, per buffer */
282bc5e3c50Skarels 
283bc5e3c50Skarels 
284bc5e3c50Skarels /*************************************************************************/
285bc5e3c50Skarels 
286bc5e3c50Skarels #define DELAYTEN 1000
287bc5e3c50Skarels 
288c0a6ca24Smckusick /*
289c0a6ca24Smckusick  * Unfortunately qbgetpri can't be used because the TK50 doesn't flip the
290c0a6ca24Smckusick  * TMSCP_STEP2 flag in the tmscpsa register until after the pending interrupt
291c0a6ca24Smckusick  * has been acknowledged by the cpu. If you are at spl6(), the TMSCP_STEP2
292c0a6ca24Smckusick  * flag never gets set and you return (0).
293c0a6ca24Smckusick  */
tmscpprobe(reg,ctlr)294bc5e3c50Skarels tmscpprobe(reg, ctlr)
295bc5e3c50Skarels 	caddr_t reg;		/* address of the IP register */
2961625a9a8Skarels 	int ctlr;		/* index of controller in the tmscp_softc array */
297bc5e3c50Skarels {
298bc5e3c50Skarels 	register int br, cvec;	/* MUST be 1st (r11 & r10): IPL and intr vec */
299bc5e3c50Skarels 	register struct tmscp_softc *sc = &tmscp_softc[ctlr];
300bc5e3c50Skarels 				/* ptr to software controller structure */
3011625a9a8Skarels 	struct tmscpdevice *tmscpaddr; /* ptr to tmscpdevice struct (IP & SA) */
302c0a6ca24Smckusick 	int count;		/* for probe delay time out */
303bc5e3c50Skarels 
304bc5e3c50Skarels #	ifdef lint
305bc5e3c50Skarels 	br = 0; cvec = br; br = cvec; reg = reg;
306bc5e3c50Skarels 	tmscpreset(0); tmscpintr(0);
307bc5e3c50Skarels #	endif
308bc5e3c50Skarels 
309bc5e3c50Skarels 	tmscpaddr = (struct tmscpdevice *) reg;
310bc5e3c50Skarels 	/*
311bc5e3c50Skarels 	 * Set host-settable interrupt vector.
3121625a9a8Skarels 	 * Assign 0 to the ip register to start the tmscp-device initialization.
313bc5e3c50Skarels 	 * The device is not really initialized at this point, this is just to
314bc5e3c50Skarels 	 * find out if the device exists.
315bc5e3c50Skarels 	 */
316bc5e3c50Skarels 	sc->sc_ivec = (uba_hd[numuba].uh_lastiv -= 4);
317bc5e3c50Skarels 	tmscpaddr->tmscpip = 0;
318bc5e3c50Skarels 
319bc5e3c50Skarels 	count=0;
320bc5e3c50Skarels 	while(count < DELAYTEN)
321bc5e3c50Skarels 		{	/* wait for at most 10 secs */
322bc5e3c50Skarels 		if((tmscpaddr->tmscpsa & TMSCP_STEP1) != 0)
323bc5e3c50Skarels 			break;
324bc5e3c50Skarels 		DELAY(10000);
325bc5e3c50Skarels 		count=count+1;
326bc5e3c50Skarels 		}
327c0a6ca24Smckusick 	if (count == DELAYTEN)
328bc5e3c50Skarels 		return(0);
329bc5e3c50Skarels 
3301625a9a8Skarels 	tmscpaddr->tmscpsa = TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
331bc5e3c50Skarels 
332bc5e3c50Skarels 	count=0;
333bc5e3c50Skarels 	while(count < DELAYTEN)
334bc5e3c50Skarels 		{
335bc5e3c50Skarels 		if((tmscpaddr->tmscpsa & TMSCP_STEP2) != 0)
336bc5e3c50Skarels 			break;
337bc5e3c50Skarels 		DELAY(10000);
338bc5e3c50Skarels 		count = count+1;
339bc5e3c50Skarels 		}
340c0a6ca24Smckusick 	if (count == DELAYTEN)
341bc5e3c50Skarels 		return(0);
342bc5e3c50Skarels 
343ef1739d4Stef #ifdef QBA
344c0a6ca24Smckusick 	sc->sc_ipl = br = 0x15;
345b2029b16Skarels #endif
346bc5e3c50Skarels 	return(sizeof (struct tmscpdevice));
347bc5e3c50Skarels }
348bc5e3c50Skarels 
349bc5e3c50Skarels /*
350bc5e3c50Skarels  * Try to find a slave (a drive) on the controller.
351bc5e3c50Skarels  * If the controller is not in the run state, call init to initialize it.
352bc5e3c50Skarels  */
353bc5e3c50Skarels tmscpslave (ui, reg)
354bc5e3c50Skarels 	struct uba_device *ui;	/* ptr to the uba device structure */
355bc5e3c50Skarels 	caddr_t reg;		/* addr of the device controller */
356bc5e3c50Skarels {
357bc5e3c50Skarels 	register struct uba_ctlr *um = tmscpminfo[ui->ui_ctlr];
358bc5e3c50Skarels 	register struct tmscp_softc *sc = &tmscp_softc[ui->ui_ctlr];
3591625a9a8Skarels 	register struct tms_info *tms = &tms_info[ui->ui_unit];
360bc5e3c50Skarels 	struct   tmscpdevice *tmscpaddr;	/* ptr to IP & SA */
361bc5e3c50Skarels 	struct   mscp *mp;
362bc5e3c50Skarels 	int	 i;			/* Something to write into to start */
363bc5e3c50Skarels 					/* the tmscp polling */
364bc5e3c50Skarels 
365bc5e3c50Skarels #	ifdef lint
3664c8aebccSkarels 	reg = reg;
367bc5e3c50Skarels #	endif
368bc5e3c50Skarels 	tmscpaddr = (struct tmscpdevice *)um->um_addr;
369bc5e3c50Skarels 	/*
370bc5e3c50Skarels 	 * If its not in the run state, start the initialization process
371bc5e3c50Skarels 	 * (tmscpintr will complete it);  if the initialization doesn't start;
372bc5e3c50Skarels 	 * then return.
373bc5e3c50Skarels 	 */
374bc5e3c50Skarels 	if(sc->sc_state != S_RUN)
375bc5e3c50Skarels 		{
376bc5e3c50Skarels #		ifdef DEBUG
377bc5e3c50Skarels 		printd("tmscpslave: ctlr not running: calling init \n");
378bc5e3c50Skarels #		endif
379bc5e3c50Skarels 		if(!tmscpinit(ui->ui_ctlr))
380bc5e3c50Skarels 	    		return(0);
381bc5e3c50Skarels 		}
382bc5e3c50Skarels 	/*
383bc5e3c50Skarels 	 * Wait for the controller to come into the run state or go idle.
384bc5e3c50Skarels 	 * If it goes idle return.
385bc5e3c50Skarels 	 */
386bc5e3c50Skarels #	ifdef DEBUG
387bc5e3c50Skarels 	i=1;
388bc5e3c50Skarels #	endif
389bc5e3c50Skarels 	while(sc->sc_state != S_RUN && sc->sc_state != S_IDLE)
390bc5e3c50Skarels #		ifdef DEBUG
391bc5e3c50Skarels 		if (tmscpaddr->tmscpsa & TMSCP_ERR && i)
392bc5e3c50Skarels 	    		{
3931625a9a8Skarels 	    		printd("tmscp-device: fatal error (%o)\n", tmscpaddr->tmscpsa&0xffff);
394bc5e3c50Skarels 	    		i=0;
395bc5e3c50Skarels 	   		 }
396bc5e3c50Skarels #		endif
397bc5e3c50Skarels 		;	/* wait */
398bc5e3c50Skarels 	if(sc->sc_state == S_IDLE)
399bc5e3c50Skarels 		{	/* The tmscp device failed to initialize */
400bc5e3c50Skarels 		printf("tmscp controller failed to init\n");
401bc5e3c50Skarels 		return(0);
402bc5e3c50Skarels 		}
403bc5e3c50Skarels 	/* The controller is up so see if the drive is there */
404bc5e3c50Skarels 	if(0 == (mp = tmscpgetcp(um)))
405bc5e3c50Skarels 		{
406bc5e3c50Skarels 		printf("tmscp can't get command packet\n");
407bc5e3c50Skarels 		return(0);
408bc5e3c50Skarels 		}
409bc5e3c50Skarels 	/* Need to determine the drive type for generic driver */
4101625a9a8Skarels 	mp->mscp_opcode = M_OP_GTUNT;	/* This should give us the device type */
411bc5e3c50Skarels 	mp->mscp_unit = ui->ui_slave;
412bc5e3c50Skarels 	mp->mscp_cmdref = (long) ui->ui_slave;
4131625a9a8Skarels 	tms->tms_status = 0;	/* set to zero */
414bc5e3c50Skarels 	tmscpip[ui->ui_ctlr][ui->ui_slave] = ui;
4151625a9a8Skarels 	*((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;/* maybe we should poll*/
416bc5e3c50Skarels 	i = tmscpaddr->tmscpip;
4174c8aebccSkarels #ifdef lint
4184c8aebccSkarels 	i = i;
4194c8aebccSkarels #endif
4201625a9a8Skarels 	while(!tms->tms_status)
421bc5e3c50Skarels 		;				/* Wait for some status */
422bc5e3c50Skarels #	ifdef DEBUG
4231625a9a8Skarels 	printd("tmscpslave: status = %o\n",tms->tms_status & M_ST_MASK);
424bc5e3c50Skarels #	endif
425bc5e3c50Skarels 	tmscpip[ui->ui_ctlr][ui->ui_slave] = 0;
4261625a9a8Skarels 	if(!tms->tms_type)			/* packet from a GTUNT */
427bc5e3c50Skarels 		return(0);			/* Failed No such drive */
428bc5e3c50Skarels 	else
429bc5e3c50Skarels 		return(1);			/* Got it and it is there */
430bc5e3c50Skarels }
431bc5e3c50Skarels 
432bc5e3c50Skarels 
433bc5e3c50Skarels /*
434bc5e3c50Skarels  * Set ui flags to zero to show device is not online & set tmscpip.
435bc5e3c50Skarels  * Unit to Controller mapping is set up here.
436bc5e3c50Skarels  * Open routine will issue the online command, later.
437bc5e3c50Skarels  */
tmscpattach(ui)438bc5e3c50Skarels tmscpattach (ui)
439bc5e3c50Skarels 	register struct uba_device *ui;		/* ptr to unibus dev struct */
440bc5e3c50Skarels {
441bc5e3c50Skarels 
442bc5e3c50Skarels 	ui->ui_flags = 0;
443bc5e3c50Skarels 	tmscpip[ui->ui_ctlr][ui->ui_slave] = ui;
444bc5e3c50Skarels #	ifdef DEBUG
445bc5e3c50Skarels 	/*
446bc5e3c50Skarels 	 * Check to see if the drive is available.
447bc5e3c50Skarels 	 * If not then just print debug.
448bc5e3c50Skarels 	 */
449bc5e3c50Skarels 	if(tms_info[ui->ui_unit].tms_status != M_ST_AVLBL)
450bc5e3c50Skarels 		printd("tmscpattach: unavailable \n");
451bc5e3c50Skarels #	endif
452bc5e3c50Skarels 	utoctlr[ui->ui_unit] = ui->ui_ctlr;
453bc5e3c50Skarels }
454bc5e3c50Skarels 
455bc5e3c50Skarels 
456bc5e3c50Skarels /*
457bc5e3c50Skarels  * TMSCP interrupt routine.
458bc5e3c50Skarels  */
tmscpintr(d)459bc5e3c50Skarels tmscpintr (d)
460bc5e3c50Skarels 	int d;		/* index to the controller */
461bc5e3c50Skarels {
462bc5e3c50Skarels 	register struct uba_ctlr *um = tmscpminfo[d];
4631625a9a8Skarels 	register struct tmscpdevice *tmscpaddr = (struct tmscpdevice *)um->um_addr;
464bc5e3c50Skarels 	struct buf *bp;
465bc5e3c50Skarels 	register int i;
466bc5e3c50Skarels 	register struct tmscp_softc *sc = &tmscp_softc[d];
467bc5e3c50Skarels 	register struct tmscp *tm = &tmscp[d];
468bc5e3c50Skarels 	struct tmscp *ttm;
469bc5e3c50Skarels 	struct mscp *mp;
470bc5e3c50Skarels 
471bc5e3c50Skarels #	ifdef DEBUG
4721625a9a8Skarels 	printd10("tmscpintr: state %d, tmscpsa %o\n", sc->sc_state, tmscpaddr->tmscpsa);
473bc5e3c50Skarels #	endif
474bc5e3c50Skarels 
475ee3b0629Skarels #ifdef QBA
476ee3b0629Skarels 	splx(sc->sc_ipl);
477ee3b0629Skarels #endif
478bc5e3c50Skarels 	/*
479bc5e3c50Skarels 	 * How the interrupt is handled depends on the state of the controller.
480bc5e3c50Skarels 	 */
481bc5e3c50Skarels 	switch (sc->sc_state) {
482bc5e3c50Skarels 
483bc5e3c50Skarels 	case S_IDLE:
484bc5e3c50Skarels 		printf("tmscp%d: random interrupt ignored\n", d);
485bc5e3c50Skarels 		return;
486bc5e3c50Skarels 
487bc5e3c50Skarels 	/* Controller was in step 1 last, see if its gone to step 2 */
488bc5e3c50Skarels 	case S_STEP1:
489bc5e3c50Skarels #		define STEP1MASK 0174377
490bc5e3c50Skarels #		define STEP1GOOD (TMSCP_STEP2|TMSCP_IE|(NCMDL2<<3)|NRSPL2)
491bc5e3c50Skarels 		for (i = 0; i < 150; i++)
492bc5e3c50Skarels 			{
493bc5e3c50Skarels 			if ((tmscpaddr->tmscpsa&STEP1MASK) != STEP1GOOD)
494bc5e3c50Skarels 				{ /* still in step 1 (wait 1/100 sec) */
495bc5e3c50Skarels 				DELAY(10000);
496bc5e3c50Skarels #				ifdef DEBUG
497bc5e3c50Skarels 				printd("still in step 1, delaying\n");
498bc5e3c50Skarels #				endif DEBUG
499bc5e3c50Skarels 				}
500bc5e3c50Skarels 			else
501bc5e3c50Skarels 				break;
502bc5e3c50Skarels 			}
503bc5e3c50Skarels 		if (i > 149)
504bc5e3c50Skarels 			{
505bc5e3c50Skarels 			sc->sc_state = S_IDLE;
5061625a9a8Skarels 			printf("failed to initialize, in step1: sa 0x%x", tmscpaddr->tmscpsa);
507bc5e3c50Skarels 			wakeup((caddr_t)um);
508bc5e3c50Skarels 			return;
509bc5e3c50Skarels 			}
510bc5e3c50Skarels 		tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)
511bc5e3c50Skarels 			| ((cpu == VAX_780 || cpu == VAX_8600) ? TMSCP_PI : 0);
512bc5e3c50Skarels 		sc->sc_state = S_STEP2;
513bc5e3c50Skarels 		return;
514bc5e3c50Skarels 
515bc5e3c50Skarels 	/* Controller was in step 2 last, see if its gone to step 3 */
516bc5e3c50Skarels 	case S_STEP2:
517bc5e3c50Skarels #		define STEP2MASK 0174377
518bc5e3c50Skarels #		define STEP2GOOD (TMSCP_STEP3|TMSCP_IE|(sc->sc_ivec/4))
519bc5e3c50Skarels 		for (i = 0; i < 150; i++)
520bc5e3c50Skarels 			{
521bc5e3c50Skarels 			if ((tmscpaddr->tmscpsa&STEP2MASK) != STEP2GOOD)
522bc5e3c50Skarels 				{ /* still in step 2 (wait 1/100 sec) */
523bc5e3c50Skarels 				DELAY(10000);
524bc5e3c50Skarels #				ifdef DEBUG
525bc5e3c50Skarels 				printd("still in step 2, delaying\n");
526bc5e3c50Skarels #				endif DEBUG
527bc5e3c50Skarels 				}
528bc5e3c50Skarels 			else
529bc5e3c50Skarels 				break;
530bc5e3c50Skarels 			}
531bc5e3c50Skarels 		if (i > 149)
532bc5e3c50Skarels 			{
533bc5e3c50Skarels 			sc->sc_state = S_IDLE;
5341625a9a8Skarels 			printf("failed to initialize, in step2: sa 0x%x", tmscpaddr->tmscpsa);
535bc5e3c50Skarels 			wakeup((caddr_t)um);
536bc5e3c50Skarels 			return;
537bc5e3c50Skarels 			}
5381625a9a8Skarels 		tmscpaddr->tmscpsa = ((int)&sc->sc_tmscp->tmscp_ca.ca_ringbase)>>16;
539bc5e3c50Skarels 		sc->sc_state = S_STEP3;
540bc5e3c50Skarels 		return;
541bc5e3c50Skarels 
542bc5e3c50Skarels 	/* Controller was in step 3 last, see if its gone to step 4 */
543bc5e3c50Skarels 	case S_STEP3:
544bc5e3c50Skarels #		define STEP3MASK 0174000
545bc5e3c50Skarels #		define STEP3GOOD TMSCP_STEP4
546bc5e3c50Skarels 		for (i = 0; i < 150; i++)
547bc5e3c50Skarels 			{
548bc5e3c50Skarels 			if ((tmscpaddr->tmscpsa&STEP3MASK) != STEP3GOOD)
549bc5e3c50Skarels 				{ /* still in step 3 (wait 1/100 sec) */
550bc5e3c50Skarels 				DELAY(10000);
551bc5e3c50Skarels #				ifdef DEBUG
552bc5e3c50Skarels 				printd("still in step 3, delaying\n");
553bc5e3c50Skarels #				endif DEBUG
554bc5e3c50Skarels 				}
555bc5e3c50Skarels 			else
556bc5e3c50Skarels 				break;
557bc5e3c50Skarels 			}
558bc5e3c50Skarels 		if (i > 149)
559bc5e3c50Skarels 			{
560bc5e3c50Skarels 			sc->sc_state = S_IDLE;
5611625a9a8Skarels 			printf("failed to initialize, in step3: sa 0x%x", tmscpaddr->tmscpsa);
562bc5e3c50Skarels 			wakeup((caddr_t)um);
563bc5e3c50Skarels 			return;
564bc5e3c50Skarels 			}
565bc5e3c50Skarels 		/*
566bc5e3c50Skarels 		 * Get microcode version and model number of controller;
567bc5e3c50Skarels 		 * Signal initialization complete (_GO) (to the controller);
568bc5e3c50Skarels 		 *    ask for Last Fail response if tmscperror is set;
569bc5e3c50Skarels 		 * Set state to "set controller characteristics".
570bc5e3c50Skarels 		 */
571bc5e3c50Skarels 		tmscpmicro[d] = tmscpaddr->tmscpsa;
572bc5e3c50Skarels 		tmscpaddr->tmscpsa = TMSCP_GO | (tmscperror? TMSCP_LF : 0);
573bc5e3c50Skarels 		sc->sc_state = S_SCHAR;
574bc5e3c50Skarels #		ifdef DEBUG
575bc5e3c50Skarels 		printd("tmscpintr: completed state %d \n", sc->sc_state);
576bc5e3c50Skarels 		printd("tmscp%d Version %d model %d\n",d,tmscpmicro[d]&0xF,
577bc5e3c50Skarels 			(tmscpmicro[d]>>4) & 0xF);
578bc5e3c50Skarels #		endif
579bc5e3c50Skarels 
580bc5e3c50Skarels 	    /*
581bc5e3c50Skarels 	     * Initialize the data structures (response and command queues).
582bc5e3c50Skarels 	     */
583bc5e3c50Skarels 	    ttm = sc->sc_tmscp;
584bc5e3c50Skarels 	    for (i = 0; i < NRSP; i++)
585bc5e3c50Skarels 		    {
586bc5e3c50Skarels 		    tm->tmscp_ca.ca_rspdsc[i] = TMSCP_OWN | TMSCP_INT |
5871625a9a8Skarels 			   (long)&ttm->tmscp_rsp[i].mscp_cmdref;
588bc5e3c50Skarels 		    tm->tmscp_rsp[i].mscp_dscptr = &tm->tmscp_ca.ca_rspdsc[i];
589bc5e3c50Skarels 		    tm->tmscp_rsp[i].mscp_header.tmscp_msglen = mscp_msglen;
590bc5e3c50Skarels 		    }
591bc5e3c50Skarels 	    for (i = 0; i < NCMD; i++)
592bc5e3c50Skarels 		    {
593bc5e3c50Skarels 		    tm->tmscp_ca.ca_cmddsc[i] = TMSCP_INT |
594bc5e3c50Skarels 					(long)&ttm->tmscp_cmd[i].mscp_cmdref;
595bc5e3c50Skarels 		    tm->tmscp_cmd[i].mscp_dscptr = &tm->tmscp_ca.ca_cmddsc[i];
596bc5e3c50Skarels 		    tm->tmscp_cmd[i].mscp_header.tmscp_msglen = mscp_msglen;
597bc5e3c50Skarels 		    tm->tmscp_cmd[i].mscp_header.tmscp_vcid = 1;
598bc5e3c50Skarels 		    }
599bc5e3c50Skarels 	    bp = &tmscpwtab[d];
600bc5e3c50Skarels 	    bp->av_forw = bp->av_back = bp;
601bc5e3c50Skarels 	    sc->sc_lastcmd = 1;
602bc5e3c50Skarels 	    sc->sc_lastrsp = 0;
603bc5e3c50Skarels 	    mp = &tmscp[um->um_ctlr].tmscp_cmd[0];
604bc5e3c50Skarels 	    mp->mscp_unit = mp->mscp_modifier = 0;
605bc5e3c50Skarels 	    mp->mscp_flags = 0;
606bc5e3c50Skarels 	    mp->mscp_version = 0;
607bc5e3c50Skarels 	    mp->mscp_cntflgs = M_CF_ATTN|M_CF_MISC|M_CF_THIS;
608bc5e3c50Skarels 	    /*
609bc5e3c50Skarels 	     * A host time out value of 0 means that the controller will not
610bc5e3c50Skarels 	     * time out.  This is ok for the TK50.
611bc5e3c50Skarels 	     */
612bc5e3c50Skarels 	    mp->mscp_hsttmo = 0;
613bc5e3c50Skarels 	    mp->mscp_time.val[0] = 0;
614bc5e3c50Skarels 	    mp->mscp_time.val[1] = 0;
615bc5e3c50Skarels 	    mp->mscp_cntdep = 0;
616bc5e3c50Skarels 	    mp->mscp_opcode = M_OP_STCON;
617bc5e3c50Skarels 	    *((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
618bc5e3c50Skarels 	    i = tmscpaddr->tmscpip;      /* initiate polling */
619bc5e3c50Skarels 	    return;
620bc5e3c50Skarels 
621bc5e3c50Skarels 	case S_SCHAR:
622bc5e3c50Skarels 	case S_RUN:
623bc5e3c50Skarels 		break;
624bc5e3c50Skarels 
625bc5e3c50Skarels 	default:
6261625a9a8Skarels 	    printf("tmscp%d: interrupt in unknown state %d ignored\n",d,sc->sc_state);
627bc5e3c50Skarels 	    return;
628bc5e3c50Skarels 	}	/* end switch */
629bc5e3c50Skarels 
630bc5e3c50Skarels 	/*
631bc5e3c50Skarels 	 * The controller state is S_SCHAR or S_RUN
632bc5e3c50Skarels 	 */
633bc5e3c50Skarels 
634bc5e3c50Skarels 	/*
635bc5e3c50Skarels 	 * If the error bit is set in the SA register then print an error
636bc5e3c50Skarels 	 * message and reinitialize the controller.
637bc5e3c50Skarels 	 */
638bc5e3c50Skarels 	if (tmscpaddr->tmscpsa&TMSCP_ERR)
639bc5e3c50Skarels 		{
6401625a9a8Skarels 		printf("tmscp%d: fatal error (%o)\n", d, tmscpaddr->tmscpsa&0xffff);
641bc5e3c50Skarels 		tmscpaddr->tmscpip = 0;
642bc5e3c50Skarels 		wakeup((caddr_t)um);
643bc5e3c50Skarels 		}
644bc5e3c50Skarels 	/*
645bc5e3c50Skarels 	 * Check for a buffer purge request. (Won't happen w/ TK50 on Q22 bus)
646bc5e3c50Skarels 	 */
647bc5e3c50Skarels 	if (tm->tmscp_ca.ca_bdp)
648bc5e3c50Skarels 		{
649a073ccb3Skarels 		UBAPURGE(um->um_hd->uh_uba, tm->tmscp_ca.ca_bdp);
650bc5e3c50Skarels 		tm->tmscp_ca.ca_bdp = 0;
651bc5e3c50Skarels 		tmscpaddr->tmscpsa = 0;      /* signal purge complete */
652bc5e3c50Skarels 		}
653bc5e3c50Skarels 
654bc5e3c50Skarels 	/*
655bc5e3c50Skarels 	 * Check for response ring transition.
656bc5e3c50Skarels 	 */
657bc5e3c50Skarels 	if (tm->tmscp_ca.ca_rspint)
658bc5e3c50Skarels 		{
659bc5e3c50Skarels 		tm->tmscp_ca.ca_rspint = 0;
660bc5e3c50Skarels 		for (i = sc->sc_lastrsp;; i++)
661bc5e3c50Skarels 			{
662bc5e3c50Skarels 			i %= NRSP;
663bc5e3c50Skarels 			if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN)
664bc5e3c50Skarels 			    break;
665bc5e3c50Skarels 			tmscprsp(um, tm, sc, i);
666bc5e3c50Skarels 			tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN;
667bc5e3c50Skarels 			}
668bc5e3c50Skarels 		sc->sc_lastrsp = i;
669bc5e3c50Skarels 		}
670bc5e3c50Skarels 
671bc5e3c50Skarels 	/*
672bc5e3c50Skarels 	 * Check for command ring transition.
673bc5e3c50Skarels 	 */
674bc5e3c50Skarels 	if (tm->tmscp_ca.ca_cmdint)
675bc5e3c50Skarels 		{
676bc5e3c50Skarels #		ifdef DEBUG
677bc5e3c50Skarels 		printd("tmscpintr: command ring transition\n");
678bc5e3c50Skarels #		endif
679bc5e3c50Skarels 		tm->tmscp_ca.ca_cmdint = 0;
680bc5e3c50Skarels 		}
681bc5e3c50Skarels     	if(tmscp_cp_wait)
682a073ccb3Skarels 		wakeup((caddr_t)&tmscp_cp_wait);
683bc5e3c50Skarels     	(void) tmscpstart(um);
684bc5e3c50Skarels }
685bc5e3c50Skarels 
686bc5e3c50Skarels 
687bc5e3c50Skarels /*
688bc5e3c50Skarels  * Open a tmscp device and set the unit online.  If the controller is not
689bc5e3c50Skarels  * in the run state, call init to initialize the tmscp controller first.
690bc5e3c50Skarels  */
691bc5e3c50Skarels 
6924c8aebccSkarels /* ARGSUSED */
tmscpopen(dev,flag)693bc5e3c50Skarels tmscpopen(dev, flag)
694bc5e3c50Skarels 	dev_t dev;
695bc5e3c50Skarels 	int flag;
696bc5e3c50Skarels {
697bc5e3c50Skarels 	register int unit;
698bc5e3c50Skarels 	register struct uba_device *ui;
699bc5e3c50Skarels 	register struct tmscp_softc *sc;
7001625a9a8Skarels 	register struct tms_info *tms;
701bc5e3c50Skarels 	register struct mscp *mp;
702bc5e3c50Skarels 	register struct uba_ctlr *um;
703bc5e3c50Skarels 	struct tmscpdevice *tmscpaddr;
704bc5e3c50Skarels 	int s,i;
705bc5e3c50Skarels 
706bc5e3c50Skarels 	unit = TMSUNIT(dev);
707bc5e3c50Skarels #	ifdef DEBUG
708bc5e3c50Skarels 	printd("tmscpopen unit %d\n",unit);
709bc5e3c50Skarels 	if(tmscpdebug)DELAY(10000);
710bc5e3c50Skarels #	endif
7111625a9a8Skarels 	if (unit >= NTMS || (ui = tmsdinfo[unit]) == 0 || ui->ui_alive == 0)
712bc5e3c50Skarels 		return (ENXIO);
7131625a9a8Skarels 	tms = &tms_info[ui->ui_unit];
7141625a9a8Skarels 	if (tms->tms_openf)
7151625a9a8Skarels 		return (EBUSY);
716bc5e3c50Skarels 	sc = &tmscp_softc[ui->ui_ctlr];
7171625a9a8Skarels 	tms->tms_openf = 1;
7185d073b51Smarc 	tms->tms_tpr = tprintf_open();
719bc5e3c50Skarels 	s = spl5();
720bc5e3c50Skarels 	if (sc->sc_state != S_RUN)
721bc5e3c50Skarels 		{
722bc5e3c50Skarels 		if (sc->sc_state == S_IDLE)
723bc5e3c50Skarels 			if(!tmscpinit(ui->ui_ctlr))
724bc5e3c50Skarels 				{
725bc5e3c50Skarels 				printf("tmscp controller failed to init\n");
726bc5e3c50Skarels 				(void) splx(s);
727edb110f3Skarels 				tms->tms_openf = 0;
728bc5e3c50Skarels 				return(ENXIO);
729bc5e3c50Skarels 				}
730bc5e3c50Skarels 		/*
731bc5e3c50Skarels 		 * Wait for initialization to complete
732bc5e3c50Skarels 		 */
733bc5e3c50Skarels 		timeout(wakeup,(caddr_t)ui->ui_mi,11*hz);	/* to be sure*/
734bc5e3c50Skarels 		sleep((caddr_t)ui->ui_mi, 0);
735bc5e3c50Skarels 		if (sc->sc_state != S_RUN)
736bc5e3c50Skarels 			{
737bc5e3c50Skarels 			(void) splx(s);
7381625a9a8Skarels 			tms->tms_openf = 0;
739bc5e3c50Skarels 			return (EIO);
740bc5e3c50Skarels 			}
741bc5e3c50Skarels 		}
742bc5e3c50Skarels 	/*
743bc5e3c50Skarels 	 * Check to see if the device is really there.
744bc5e3c50Skarels 	 * this code was taken from Fred Canters 11 driver
745bc5e3c50Skarels 	 */
746bc5e3c50Skarels 	um = ui->ui_mi;
747bc5e3c50Skarels 	tmscpaddr = (struct tmscpdevice *) um->um_addr;
748bc5e3c50Skarels 	(void) splx(s);
749bc5e3c50Skarels 	if(ui->ui_flags == 0)
750bc5e3c50Skarels 		{
751bc5e3c50Skarels 		s = spl5();
752bc5e3c50Skarels 		while(0 ==(mp = tmscpgetcp(um)))
753bc5e3c50Skarels 			{
754bc5e3c50Skarels 			tmscp_cp_wait++;
755a073ccb3Skarels 			sleep((caddr_t)&tmscp_cp_wait,PSWP+1);
756bc5e3c50Skarels 			tmscp_cp_wait--;
757bc5e3c50Skarels 			}
758bc5e3c50Skarels 		(void) splx(s);
759bc5e3c50Skarels 		mp->mscp_opcode = M_OP_ONLIN;
760bc5e3c50Skarels 		mp->mscp_unit = ui->ui_slave;
7611625a9a8Skarels 		mp->mscp_cmdref = (long) & tms->tms_type;
762bc5e3c50Skarels 					    /* need to sleep on something */
763bc5e3c50Skarels #		ifdef DEBUG
764bc5e3c50Skarels 		printd("tmscpopen: bring unit %d online\n",ui->ui_unit);
765bc5e3c50Skarels #		endif
766bc5e3c50Skarels 		*((long *) mp->mscp_dscptr ) |= TMSCP_OWN | TMSCP_INT;
767bc5e3c50Skarels 		i = tmscpaddr->tmscpip;
7684c8aebccSkarels #ifdef lint
7694c8aebccSkarels 		i = i;
7704c8aebccSkarels #endif
771bc5e3c50Skarels 		/*
772bc5e3c50Skarels 		 * To make sure we wake up, timeout in 240 seconds.
773bc5e3c50Skarels 		 * Wakeup in tmscprsp routine.
774bc5e3c50Skarels 		 * 240 seconds (4 minutes) is necessary since a rewind
775bc5e3c50Skarels 		 * can take a few minutes.
776bc5e3c50Skarels 		 */
777bc5e3c50Skarels 		timeout(wakeup,(caddr_t) mp->mscp_cmdref,240 * hz);
778bc5e3c50Skarels 		sleep((caddr_t) mp->mscp_cmdref,PSWP+1);
779bc5e3c50Skarels 		}
7801625a9a8Skarels 	if(ui->ui_flags == 0) {
7811625a9a8Skarels 		tms->tms_openf = 0;
782bc5e3c50Skarels 		return(ENXIO);  /* Didn't go online */
7831625a9a8Skarels 	}
7841625a9a8Skarels 	tms->tms_lastiow = 0;
785bc5e3c50Skarels 	/*
786bc5e3c50Skarels 	 * If the high density device is not specified, set unit to low
787bc5e3c50Skarels 	 * density.  This is done as an "internal" ioctl command so
788bc5e3c50Skarels 	 * that the command setup and response handling
789bc5e3c50Skarels 	 * is done thru "regular" command routines.
790bc5e3c50Skarels 	 */
791bc5e3c50Skarels 	if ((minor(dev) & T_HIDENSITY) == 0)
792bc5e3c50Skarels 		tmscpcommand(dev, TMS_LOWDENSITY, 1);
793bc5e3c50Skarels 	else
794bc5e3c50Skarels 		tmscpcommand(dev, TMS_HIDENSITY, 1);
795bc5e3c50Skarels 	return (0);
796bc5e3c50Skarels }
797bc5e3c50Skarels 
798bc5e3c50Skarels 
799bc5e3c50Skarels /*
800bc5e3c50Skarels  * Close tape device.
801bc5e3c50Skarels  *
802bc5e3c50Skarels  * If tape was open for writing or last operation was
803bc5e3c50Skarels  * a write, then write two EOF's and backspace over the last one.
804bc5e3c50Skarels  * Unless this is a non-rewinding special file, rewind the tape.
805bc5e3c50Skarels  *
806bc5e3c50Skarels  * NOTE:
807bc5e3c50Skarels  *	We want to be sure that any serious exception is cleared on the
808bc5e3c50Skarels  *	close. A Clear Serious Exception (CSE) modifier is always done on
809bc5e3c50Skarels  *	the rewind command.  For the non-rewind case we check to see if the
810bc5e3c50Skarels  *	"serex" field is set in the softc struct; if it is then issue a noop
811bc5e3c50Skarels  *	command with the CSE modifier.
812bc5e3c50Skarels  * Make the tape available to others, by clearing openf flag.
813bc5e3c50Skarels  */
tmscpclose(dev,flag)814bc5e3c50Skarels tmscpclose(dev, flag)
815bc5e3c50Skarels 	register dev_t dev;
816bc5e3c50Skarels 	register flag;
817bc5e3c50Skarels {
8181625a9a8Skarels 	register struct tms_info *tms;
819bc5e3c50Skarels 	register struct uba_device *ui;
820bc5e3c50Skarels 
821bc5e3c50Skarels 	ui = tmsdinfo[TMSUNIT(dev)];
822bc5e3c50Skarels #	ifdef DEBUG
823bc5e3c50Skarels 	printd("tmscpclose: ctlr =  %d\n",TMSCPCTLR(dev));
824bc5e3c50Skarels 	printd("tmscpclose: unit = %d\n",TMSUNIT(dev));
825bc5e3c50Skarels 	if(tmscpdebug)DELAY(10000);
826bc5e3c50Skarels #	endif
8271625a9a8Skarels 	tms = &tms_info[ui->ui_unit];
8281625a9a8Skarels 	if (flag == FWRITE || (flag&FWRITE) && tms->tms_lastiow)
829bc5e3c50Skarels 		{
830bc5e3c50Skarels 		/*	   device, command, count */
831bc5e3c50Skarels 		tmscpcommand (dev, TMS_WRITM, 1);
832bc5e3c50Skarels 		tmscpcommand (dev, TMS_WRITM, 1);
833bc5e3c50Skarels 		tmscpcommand (dev, TMS_BSR, 1);
834bc5e3c50Skarels 		}
835bc5e3c50Skarels 	if ((minor(dev)&T_NOREWIND) == 0)
836bc5e3c50Skarels 		/*
837bc5e3c50Skarels 		 * Don't hang waiting for rewind complete.
838bc5e3c50Skarels 		 */
839bc5e3c50Skarels 		tmscpcommand(dev, TMS_REW, 0);
840bc5e3c50Skarels 	else
8411625a9a8Skarels 		if (tms->tms_serex)
842bc5e3c50Skarels 			{
843bc5e3c50Skarels #			ifdef DEBUG
844bc5e3c50Skarels 			printd("tmscpclose: clearing serex\n");
845bc5e3c50Skarels 			if(tmscpdebug)DELAY(10000);
846bc5e3c50Skarels #			endif
847bc5e3c50Skarels 			tmscpcommand(dev, TMS_CSE, 1);
848bc5e3c50Skarels 			}
8495d073b51Smarc 	tprintf_close(tms->tms_tpr);
8501625a9a8Skarels 	tms->tms_openf = 0;
851a8460117Smarc 	return (0);
852bc5e3c50Skarels }
853bc5e3c50Skarels 
854bc5e3c50Skarels 
855bc5e3c50Skarels /*
856bc5e3c50Skarels  * Execute a command on the tape drive a specified number of times.
857bc5e3c50Skarels  * This routine sets up a buffer and calls the strategy routine which
858bc5e3c50Skarels  * links the buffer onto the drive's buffer queue.
859bc5e3c50Skarels  * The start routine will take care of creating a tmscp command packet
860bc5e3c50Skarels  * with the command.  The start routine is called by the strategy or the
861bc5e3c50Skarels  * interrupt routine.
862bc5e3c50Skarels  */
863bc5e3c50Skarels 
tmscpcommand(dev,com,count)864bc5e3c50Skarels tmscpcommand (dev, com, count)
865bc5e3c50Skarels 	register dev_t dev;
866bc5e3c50Skarels 	int com, count;
867bc5e3c50Skarels {
868bc5e3c50Skarels 	register struct uba_device *ui;
869bc5e3c50Skarels 	register struct buf *bp;
870bc5e3c50Skarels 	register int s;
871bc5e3c50Skarels 	int unit = TMSUNIT(dev);
872bc5e3c50Skarels 
873bc5e3c50Skarels 	ui = tmsdinfo[unit];
874bc5e3c50Skarels 	bp = &ctmscpbuf[ui->ui_ctlr];
875bc5e3c50Skarels 
876bc5e3c50Skarels 	s = spl5();
877bc5e3c50Skarels 	while (bp->b_flags&B_BUSY)
878bc5e3c50Skarels 		{
879bc5e3c50Skarels 		/*
880bc5e3c50Skarels 		 * This special check is because B_BUSY never
881bc5e3c50Skarels 		 * gets cleared in the non-waiting rewind case.
882bc5e3c50Skarels 		 */
883bc5e3c50Skarels 		if (bp->b_bcount == 0 && (bp->b_flags&B_DONE))
884bc5e3c50Skarels 			break;
885bc5e3c50Skarels 		bp->b_flags |= B_WANTED;
886bc5e3c50Skarels 		sleep((caddr_t)bp, PRIBIO);
887bc5e3c50Skarels 		}
888bc5e3c50Skarels 	bp->b_flags = B_BUSY|B_READ;
889bc5e3c50Skarels 	splx(s);
890bc5e3c50Skarels 	/*
891bc5e3c50Skarels 	 * Load the buffer.  The b_count field gets used to hold the command
892bc5e3c50Skarels 	 * count.  the b_resid field gets used to hold the command mneumonic.
893bc5e3c50Skarels 	 * These 2 fields are "known" to be "safe" to use for this purpose.
894bc5e3c50Skarels 	 * (Most other drivers also use these fields in this way.)
895bc5e3c50Skarels 	 */
896bc5e3c50Skarels 	bp->b_dev = dev;
897bc5e3c50Skarels 	bp->b_bcount = count;
898bc5e3c50Skarels 	bp->b_resid = com;
899bc5e3c50Skarels 	bp->b_blkno = 0;
900bc5e3c50Skarels 	tmscpstrategy(bp);
901bc5e3c50Skarels 	/*
902bc5e3c50Skarels 	 * In case of rewind from close, don't wait.
903bc5e3c50Skarels 	 * This is the only case where count can be 0.
904bc5e3c50Skarels 	 */
905bc5e3c50Skarels 	if (count == 0)
906bc5e3c50Skarels 		return;
907bc5e3c50Skarels 	iowait(bp);
908bc5e3c50Skarels 	if (bp->b_flags&B_WANTED)
909bc5e3c50Skarels 		wakeup((caddr_t)bp);
910bc5e3c50Skarels 	bp->b_flags &= B_ERROR;
911bc5e3c50Skarels }
912bc5e3c50Skarels 
913bc5e3c50Skarels /*
914bc5e3c50Skarels  * Find an unused command packet
915bc5e3c50Skarels  */
916bc5e3c50Skarels struct mscp *
tmscpgetcp(um)917bc5e3c50Skarels tmscpgetcp(um)
918bc5e3c50Skarels 	struct uba_ctlr *um;
919bc5e3c50Skarels {
920bc5e3c50Skarels 	register struct mscp *mp;
921bc5e3c50Skarels 	register struct tmscpca *cp;
922bc5e3c50Skarels 	register struct tmscp_softc *sc;
923bc5e3c50Skarels 	register int i;
924bc5e3c50Skarels 	int	s;
925bc5e3c50Skarels 
926bc5e3c50Skarels 	s = spl5();
927bc5e3c50Skarels 	cp = &tmscp[um->um_ctlr].tmscp_ca;
928bc5e3c50Skarels 	sc = &tmscp_softc[um->um_ctlr];
929bc5e3c50Skarels 	/*
930bc5e3c50Skarels 	 * If no credits, can't issue any commands
931bc5e3c50Skarels 	 * until some outstanding commands complete.
932bc5e3c50Skarels 	 */
933bc5e3c50Skarels 	i = sc->sc_lastcmd;
934bc5e3c50Skarels #  	ifdef DEBUG
935bc5e3c50Skarels 	printd10("tmscpgetcp: %d credits remain\n", sc->sc_credits);
936bc5e3c50Skarels #	endif
937bc5e3c50Skarels 	if(((cp->ca_cmddsc[i]&(TMSCP_OWN|TMSCP_INT))==TMSCP_INT) &&
938bc5e3c50Skarels 	  (sc->sc_credits >= 2))
939bc5e3c50Skarels 		{
940bc5e3c50Skarels 		sc->sc_credits--;       /* This commits to issuing a command */
941bc5e3c50Skarels 		cp->ca_cmddsc[i] &= ~TMSCP_INT;
942bc5e3c50Skarels 		mp = &tmscp[um->um_ctlr].tmscp_cmd[i];
943bc5e3c50Skarels 		mp->mscp_unit = mp->mscp_modifier = 0;
944bc5e3c50Skarels 		mp->mscp_opcode = mp->mscp_flags = 0;
945bc5e3c50Skarels 		mp->mscp_bytecnt = mp->mscp_buffer = 0;
946bc5e3c50Skarels 		sc->sc_lastcmd = (i + 1) % NCMD;
947bc5e3c50Skarels 		(void) splx(s);
948bc5e3c50Skarels 		return(mp);
949bc5e3c50Skarels 		}
950bc5e3c50Skarels 	(void) splx(s);
951bc5e3c50Skarels 	return(NULL);
952bc5e3c50Skarels }
953bc5e3c50Skarels 
954bc5e3c50Skarels 
955bc5e3c50Skarels /*
956bc5e3c50Skarels  * Initialize a TMSCP device.  Set up UBA mapping registers,
957bc5e3c50Skarels  * initialize data structures, and start hardware
958bc5e3c50Skarels  * initialization sequence.
959bc5e3c50Skarels  */
tmscpinit(d)960bc5e3c50Skarels tmscpinit (d)
961bc5e3c50Skarels 	int d;			/* index to the controller */
962bc5e3c50Skarels {
963bc5e3c50Skarels 	register struct tmscp_softc *sc;
9641625a9a8Skarels 	register struct tmscp *t;  /* communications area; cmd & resp packets */
965bc5e3c50Skarels 	struct tmscpdevice *tmscpaddr;
966bc5e3c50Skarels 	struct uba_ctlr *um;
967bc5e3c50Skarels 
968bc5e3c50Skarels 	sc = &tmscp_softc[d];
969bc5e3c50Skarels 	um = tmscpminfo[d];
970bc5e3c50Skarels 	um->um_tab.b_active++;
971bc5e3c50Skarels 	t = &tmscp[d];
972bc5e3c50Skarels 	tmscpaddr = (struct tmscpdevice *)um->um_addr;
973bc5e3c50Skarels 	if (sc->sc_mapped == 0)
974bc5e3c50Skarels 		{
975bc5e3c50Skarels 		/*
976bc5e3c50Skarels 		 * Map the communications area and command
977bc5e3c50Skarels 		 * and response packets into Unibus address
978bc5e3c50Skarels 		 * space.
979bc5e3c50Skarels 		 */
9801625a9a8Skarels 		sc->sc_ubainfo = uballoc(um->um_ubanum, (caddr_t)t, sizeof (struct tmscp), 0);
981ee3b0629Skarels 		sc->sc_tmscp = (struct tmscp *)(UBAI_ADDR(sc->sc_ubainfo));
982bc5e3c50Skarels 		sc->sc_mapped = 1;
983bc5e3c50Skarels 		}
984bc5e3c50Skarels 
985bc5e3c50Skarels 	/*
986bc5e3c50Skarels 	 * Start the hardware initialization sequence.
987bc5e3c50Skarels 	 */
988bc5e3c50Skarels 	tmscpaddr->tmscpip = 0;              /* start initialization */
989bc5e3c50Skarels 
990bc5e3c50Skarels 	while((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
991bc5e3c50Skarels 		{
992bc5e3c50Skarels #		ifdef DEBUG
993bc5e3c50Skarels 		printd("tmscpinit: tmscpsa = 0%o\n",tmscpaddr->tmscpsa);
994bc5e3c50Skarels 		DELAY(100000);
995bc5e3c50Skarels #		endif
996bc5e3c50Skarels 		if(tmscpaddr->tmscpsa & TMSCP_ERR)
997bc5e3c50Skarels 			return(0);	/* CHECK */
998bc5e3c50Skarels 		}
9991625a9a8Skarels 	tmscpaddr->tmscpsa=TMSCP_ERR|(NCMDL2<<11)|(NRSPL2<<8)|TMSCP_IE|(sc->sc_ivec/4);
1000bc5e3c50Skarels 	/*
1001bc5e3c50Skarels 	 * Initialization continues in the interrupt routine.
1002bc5e3c50Skarels 	 */
1003bc5e3c50Skarels 	sc->sc_state = S_STEP1;
1004bc5e3c50Skarels 	sc->sc_credits = 0;
1005bc5e3c50Skarels 	return(1);
1006bc5e3c50Skarels }
1007bc5e3c50Skarels 
1008bc5e3c50Skarels 
1009bc5e3c50Skarels /*
1010bc5e3c50Skarels  * Start I/O operation
1011bc5e3c50Skarels  * This code is convoluted.  The majority of it was copied from the uda driver.
1012bc5e3c50Skarels  */
1013bc5e3c50Skarels 
tmscpstart(um)1014bc5e3c50Skarels tmscpstart(um)
1015bc5e3c50Skarels 	register struct uba_ctlr *um;
1016bc5e3c50Skarels {
1017bc5e3c50Skarels 	register struct buf *bp, *dp;
1018bc5e3c50Skarels 	register struct mscp *mp;
1019bc5e3c50Skarels 	register struct tmscp_softc *sc;
10201625a9a8Skarels 	register struct tms_info *tms;
1021bc5e3c50Skarels 	register struct uba_device *ui;
1022bc5e3c50Skarels 	struct   tmscpdevice *tmscpaddr;
1023bc5e3c50Skarels 	struct   tmscp *tm = &tmscp[um->um_ctlr];
1024bc5e3c50Skarels 	int i,tempi;
1025bc5e3c50Skarels 	char ioctl;		/* flag: set true if its an IOCTL command */
1026bc5e3c50Skarels 
1027bc5e3c50Skarels 	sc = &tmscp_softc[um->um_ctlr];
1028bc5e3c50Skarels 
1029bc5e3c50Skarels     for(;;)
1030bc5e3c50Skarels 	{
1031bc5e3c50Skarels 	if ((dp = um->um_tab.b_actf) == NULL)
1032bc5e3c50Skarels 		{
1033bc5e3c50Skarels 		/*
1034bc5e3c50Skarels 		 * Release unneeded UBA resources and return
1035bc5e3c50Skarels 		 * (drive was inactive)
1036bc5e3c50Skarels 		 */
1037bc5e3c50Skarels 		um->um_tab.b_active = 0;
1038bc5e3c50Skarels 		break;
1039bc5e3c50Skarels 		}
1040bc5e3c50Skarels 	if ((bp = dp->b_actf) == NULL)
1041bc5e3c50Skarels 		{
1042bc5e3c50Skarels 		/*
1043bc5e3c50Skarels 		 * No more requests for this drive, remove
1044bc5e3c50Skarels 		 * from controller queue and look at next drive.
1045bc5e3c50Skarels 		 * We know we're at the head of the controller queue.
1046bc5e3c50Skarels 		 */
1047bc5e3c50Skarels 		dp->b_active = 0;
1048bc5e3c50Skarels 		um->um_tab.b_actf = dp->b_forw;
1049bc5e3c50Skarels 		continue;		/* Need to check for loop */
1050bc5e3c50Skarels 		}
1051bc5e3c50Skarels 	um->um_tab.b_active++;
1052bc5e3c50Skarels 	tmscpaddr = (struct tmscpdevice *)um->um_addr;
10531625a9a8Skarels 	ui = tmsdinfo[(TMSUNIT(bp->b_dev))];
10541625a9a8Skarels 	tms = &tms_info[ui->ui_unit];
1055bc5e3c50Skarels 	if ((tmscpaddr->tmscpsa&TMSCP_ERR) || sc->sc_state != S_RUN)
1056bc5e3c50Skarels 		{
10575d073b51Smarc 		tprintf(tms->tms_tpr,
10581625a9a8Skarels 		    "tms%d: hard error bn%d\n",
10591625a9a8Skarels 		    minor(bp->b_dev)&03, bp->b_blkno);
10601625a9a8Skarels 		log(TMS_PRI, "tmscp%d: sa 0%o, state %d\n",um->um_ctlr,
1061bc5e3c50Skarels 				tmscpaddr->tmscpsa&0xffff, sc->sc_state);
1062a073ccb3Skarels 		(void)tmscpinit(um->um_ctlr);
1063bc5e3c50Skarels 		/* SHOULD REQUEUE OUTSTANDING REQUESTS, LIKE TMSCPRESET */
1064bc5e3c50Skarels 		break;
1065bc5e3c50Skarels 		}
1066bc5e3c50Skarels 	/*
1067bc5e3c50Skarels 	 * Default is that last command was NOT a write command;
1068bc5e3c50Skarels 	 * if a write command is done it will be detected in tmscprsp.
1069bc5e3c50Skarels 	 */
10701625a9a8Skarels 	tms->tms_lastiow = 0;
1071bc5e3c50Skarels 	if (ui->ui_flags == 0)
1072bc5e3c50Skarels 		{        /* not online */
1073bc5e3c50Skarels 		if ((mp = tmscpgetcp(um)) == NULL)
1074bc5e3c50Skarels 			break;
1075bc5e3c50Skarels 		mp->mscp_opcode = M_OP_ONLIN;
1076bc5e3c50Skarels 		mp->mscp_unit = ui->ui_slave;
1077bc5e3c50Skarels 		dp->b_active = 2;
1078bc5e3c50Skarels 		um->um_tab.b_actf = dp->b_forw; /* remove from controller q */
1079bc5e3c50Skarels 		*((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
1080bc5e3c50Skarels 		if (tmscpaddr->tmscpsa&TMSCP_ERR)
1081bc5e3c50Skarels 			printf("tmscp%d fatal error (0%o)\n",um->um_ctlr,
1082bc5e3c50Skarels 					tmscpaddr->tmscpsa&0xffff);
1083bc5e3c50Skarels 		i = tmscpaddr->tmscpip;
1084bc5e3c50Skarels 		continue;
1085bc5e3c50Skarels 		}
1086bc5e3c50Skarels 	switch (cpu) {
1087bc5e3c50Skarels 
1088bc5e3c50Skarels 	case VAX_8600:
1089bc5e3c50Skarels 	case VAX_780:
1090bc5e3c50Skarels 		i = UBA_NEEDBDP|UBA_CANTWAIT;
1091bc5e3c50Skarels 		break;
1092bc5e3c50Skarels 	case VAX_750:
1093bc5e3c50Skarels 		i = um->um_ubinfo|UBA_HAVEBDP|UBA_CANTWAIT;
1094bc5e3c50Skarels 		break;
1095bc5e3c50Skarels 	case VAX_730:
10968243dc3aSmckusick 	case VAX_630:
1097bc5e3c50Skarels 		i = UBA_CANTWAIT;
1098bc5e3c50Skarels 		break;
1099bc5e3c50Skarels 	}   /* end switch (cpu) */
1100bc5e3c50Skarels 	/*
11011625a9a8Skarels 	 * If command is an ioctl command then set the ioctl flag for later use.
1102bc5e3c50Skarels 	 * If not (i.e. it is a read or write) then attempt
1103bc5e3c50Skarels 	 * to set up a buffer pointer.
1104bc5e3c50Skarels 	 */
1105bc5e3c50Skarels 	ioctl = 0;
1106bc5e3c50Skarels 	if (bp == &ctmscpbuf[um->um_ctlr])
1107bc5e3c50Skarels 		ioctl = 1;
1108bc5e3c50Skarels 	else
1109bc5e3c50Skarels 		if ((i = ubasetup(um->um_ubanum, bp, i)) == 0)
1110bc5e3c50Skarels 			{
1111bc5e3c50Skarels 			if(dp->b_qsize != 0)
1112bc5e3c50Skarels 				break; /* When a command completes and */
11131625a9a8Skarels 				     /* frees a bdp tmscpstart will be called */
1114bc5e3c50Skarels 			if ((mp = tmscpgetcp(um)) == NULL)
1115bc5e3c50Skarels 				break;
1116bc5e3c50Skarels #			ifdef DEBUG
11171625a9a8Skarels 			printd("tmscpstart: GTUNT %d ubasetup = %d\n",ui->ui_unit, i);
1118bc5e3c50Skarels 			if(tmscpdebug)DELAY(10000);
1119bc5e3c50Skarels #			endif
1120bc5e3c50Skarels 			mp->mscp_opcode = M_OP_GTUNT;
1121bc5e3c50Skarels 			mp->mscp_unit = ui->ui_slave;
1122bc5e3c50Skarels 			*((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
1123bc5e3c50Skarels 			if (tmscpaddr->tmscpsa&TMSCP_ERR)
11241625a9a8Skarels 				printf("tmscp%d: fatal error (0%o)\n",um->um_ctlr,
1125bc5e3c50Skarels 					    tmscpaddr->tmscpsa&0xffff);
1126bc5e3c50Skarels 			i = tmscpaddr->tmscpip;	/* initiate polling */
1127bc5e3c50Skarels 			break;
1128bc5e3c50Skarels 			}
11291625a9a8Skarels #	if defined(VAX750)
11301625a9a8Skarels 	if (cpu == VAX_750)
1131bc5e3c50Skarels 		tempi = i & 0xfffffff;			/* mask off bdp */
1132bc5e3c50Skarels 	else
1133bc5e3c50Skarels #	endif
1134bc5e3c50Skarels 		tempi = i;
1135bc5e3c50Skarels 	if ((mp = tmscpgetcp(um)) == NULL)
1136bc5e3c50Skarels 		{
1137bc5e3c50Skarels 		if (!ioctl)		/* only need to release if NOT ioctl */
1138bc5e3c50Skarels 			ubarelse(um->um_ubanum,&tempi);
1139bc5e3c50Skarels 		break;
1140bc5e3c50Skarels 		}
1141bc5e3c50Skarels 	mp->mscp_cmdref = (long)bp;		/* pointer to get back */
1142bc5e3c50Skarels 	mp->mscp_unit = ui->ui_slave;
1143bc5e3c50Skarels 	/*
1144bc5e3c50Skarels 	 * If its an ioctl-type command then set up the appropriate
1145bc5e3c50Skarels 	 * tmscp command;  by doing a switch on the "b_resid" field where
1146bc5e3c50Skarels 	 * the command mneumonic is stored.
1147bc5e3c50Skarels 	 */
1148bc5e3c50Skarels 	if (ioctl)
1149bc5e3c50Skarels 		{
1150bc5e3c50Skarels #		ifdef DEBUG
1151bc5e3c50Skarels 		printd("tmscpstart: doing ioctl cmd %d\n", bp->b_resid);
1152bc5e3c50Skarels #		endif
1153bc5e3c50Skarels 		/*
1154bc5e3c50Skarels 		 * The reccnt and tmkcnt fields are set to zero by the getcp
1155bc5e3c50Skarels 		 * routine (as bytecnt and buffer fields).  Thus reccnt and
1156bc5e3c50Skarels 		 * tmkcnt are only modified here if they need to be set to
1157bc5e3c50Skarels 		 * a non-zero value.
1158bc5e3c50Skarels 		 */
11594c8aebccSkarels 		switch ((int)bp->b_resid) {
1160bc5e3c50Skarels 
1161bc5e3c50Skarels 		case TMS_WRITM:
1162bc5e3c50Skarels 			mp->mscp_opcode = M_OP_WRITM;
1163bc5e3c50Skarels 			break;
1164bc5e3c50Skarels 		case TMS_FSF:
1165bc5e3c50Skarels 			mp->mscp_opcode = M_OP_REPOS;
1166bc5e3c50Skarels 			mp->mscp_tmkcnt = bp->b_bcount;
1167bc5e3c50Skarels 			break;
1168bc5e3c50Skarels 		case TMS_BSF:
1169bc5e3c50Skarels 			mp->mscp_opcode = M_OP_REPOS;
1170bc5e3c50Skarels 			mp->mscp_modifier = M_MD_REVRS;
1171bc5e3c50Skarels 			mp->mscp_tmkcnt = bp->b_bcount;
1172bc5e3c50Skarels 			break;
1173bc5e3c50Skarels 		case TMS_FSR:
1174bc5e3c50Skarels 			mp->mscp_opcode = M_OP_REPOS;
1175bc5e3c50Skarels 			mp->mscp_modifier = M_MD_OBJCT;
1176bc5e3c50Skarels 			mp->mscp_reccnt = bp->b_bcount;
1177bc5e3c50Skarels 			break;
1178bc5e3c50Skarels 		case TMS_BSR:
1179bc5e3c50Skarels 			mp->mscp_opcode = M_OP_REPOS;
1180bc5e3c50Skarels 			mp->mscp_modifier = M_MD_REVRS | M_MD_OBJCT;
1181bc5e3c50Skarels 			mp->mscp_reccnt = bp->b_bcount;
1182bc5e3c50Skarels 			break;
1183bc5e3c50Skarels 		/*
1184bc5e3c50Skarels 		 * Clear serious exception is done for Rewind & Available cmds
1185bc5e3c50Skarels 		 */
1186bc5e3c50Skarels 		case TMS_REW:
1187bc5e3c50Skarels 			mp->mscp_opcode = M_OP_REPOS;
1188bc5e3c50Skarels 			mp->mscp_modifier = M_MD_REWND | M_MD_CLSEX;
1189bc5e3c50Skarels 			if (bp->b_bcount == 0)
1190bc5e3c50Skarels 				mp->mscp_modifier |= M_MD_IMMED;
11911625a9a8Skarels 			tms->tms_serex = 0;
1192bc5e3c50Skarels 			break;
1193bc5e3c50Skarels 		case TMS_OFFL:
1194bc5e3c50Skarels 			mp->mscp_opcode = M_OP_AVAIL;
1195bc5e3c50Skarels 			mp->mscp_modifier = M_MD_UNLOD | M_MD_CLSEX;
11961625a9a8Skarels 			tms->tms_serex = 0;
1197bc5e3c50Skarels 			break;
1198bc5e3c50Skarels 		case TMS_SENSE:
1199bc5e3c50Skarels 			mp->mscp_opcode = M_OP_GTUNT;
1200bc5e3c50Skarels 			break;
1201bc5e3c50Skarels 		case TMS_CACHE:
1202bc5e3c50Skarels 			mp->mscp_opcode = M_OP_STUNT;
12031625a9a8Skarels 			tms->tms_unitflgs |= M_UF_WBKNV;
12041625a9a8Skarels 			mp->mscp_unitflgs = tms->tms_unitflgs;
12051625a9a8Skarels 			mp->mscp_format = tms->tms_format;
1206bc5e3c50Skarels 			/* default device dependant parameters */
1207bc5e3c50Skarels 			mp->mscp_mediaid = 0;
1208bc5e3c50Skarels 			break;
1209bc5e3c50Skarels 		case TMS_NOCACHE:
1210bc5e3c50Skarels 			mp->mscp_opcode = M_OP_STUNT;
12111625a9a8Skarels 			tms->tms_unitflgs &= ~(M_UF_WBKNV);
12121625a9a8Skarels 			mp->mscp_unitflgs = tms->tms_unitflgs;
12131625a9a8Skarels 			mp->mscp_format = tms->tms_format;
1214bc5e3c50Skarels 			/* default device dependant parameters */
1215bc5e3c50Skarels 			mp->mscp_mediaid = 0;
1216bc5e3c50Skarels 			break;
1217bc5e3c50Skarels 		case TMS_CSE:
1218bc5e3c50Skarels 			/*
1219bc5e3c50Skarels 			 * This is a no-op command. It performs a
1220bc5e3c50Skarels 			 * clear serious exception only.  (Done on a
1221bc5e3c50Skarels 			 * non-rewinding close after a serious exception.)
1222bc5e3c50Skarels 			 */
1223bc5e3c50Skarels 			mp->mscp_opcode = M_OP_REPOS;
1224bc5e3c50Skarels 			mp->mscp_modifier = M_MD_CLSEX;
12251625a9a8Skarels 			tms->tms_serex = 0;
12261625a9a8Skarels 			tms->tms_clserex = 1;
1227bc5e3c50Skarels 			break;
1228bc5e3c50Skarels 		case TMS_LOWDENSITY:
1229bc5e3c50Skarels 			/*
1230bc5e3c50Skarels 			 * Set the unit to low density
1231bc5e3c50Skarels 			 */
1232bc5e3c50Skarels 			mp->mscp_opcode = M_OP_STUNT;
12331625a9a8Skarels 			mp->mscp_unitflgs = tms->tms_unitflgs;
12341625a9a8Skarels 			mp->mscp_mediaid = 0;	/* default device dependant parameters */
12351625a9a8Skarels 			if ((tms->tms_fmtmenu & M_TF_800) != 0)
1236bc5e3c50Skarels 				mp->mscp_format = M_TF_800;
1237bc5e3c50Skarels 			else
12381625a9a8Skarels 				mp->mscp_format = M_TF_PE & tms->tms_fmtmenu;
12391625a9a8Skarels 			tms->tms_format = mp->mscp_format;
1240bc5e3c50Skarels 			break;
1241bc5e3c50Skarels 		case TMS_HIDENSITY:
1242bc5e3c50Skarels 			/*
1243bc5e3c50Skarels 			 * Set the unit to high density (format == 0)
1244bc5e3c50Skarels 			 */
1245bc5e3c50Skarels 			mp->mscp_opcode = M_OP_STUNT;
12461625a9a8Skarels 			mp->mscp_unitflgs = tms->tms_unitflgs;
12471625a9a8Skarels 			mp->mscp_mediaid = 0;	/* default device dependant parameters */
1248bc5e3c50Skarels 			mp->mscp_format = 0;
12491625a9a8Skarels 			tms->tms_format = 0;
1250bc5e3c50Skarels 			break;
1251bc5e3c50Skarels 		default:
1252bc5e3c50Skarels 			printf("Bad ioctl on tms unit %d\n", ui->ui_unit);
1253bc5e3c50Skarels 			/* Need a no-op. Reposition no amount */
1254bc5e3c50Skarels 			mp->mscp_opcode = M_OP_REPOS;
1255bc5e3c50Skarels 			break;
1256bc5e3c50Skarels 		}   /* end switch (bp->b_resid) */
1257bc5e3c50Skarels 		}
1258bc5e3c50Skarels 	else    /* Its a read/write command (not an ioctl) */
1259bc5e3c50Skarels 		{
1260bc5e3c50Skarels 		mp->mscp_opcode = bp->b_flags&B_READ ? M_OP_READ : M_OP_WRITE;
1261bc5e3c50Skarels 		mp->mscp_bytecnt = bp->b_bcount;
1262ee3b0629Skarels 		mp->mscp_buffer = UBAI_ADDR(i) | (UBAI_BDP(i) << 24);
1263bc5e3c50Skarels 
1264bc5e3c50Skarels 		bp->b_ubinfo = tempi;			/* save mapping info */
1265bc5e3c50Skarels 		}
12661625a9a8Skarels 	if (tms->tms_serex == 2)			/* if tape mark read */
1267bc5e3c50Skarels 		{
12681625a9a8Skarels 		mp->mscp_modifier |= M_MD_CLSEX;	/*  clear serious exc */
12691625a9a8Skarels 		tms->tms_serex = 0;
1270bc5e3c50Skarels 		}
1271bc5e3c50Skarels 	*((long *)mp->mscp_dscptr) |= TMSCP_OWN|TMSCP_INT;
1272bc5e3c50Skarels #	ifdef DEBUG
12731625a9a8Skarels 	printd("tmscpstart: opcode 0%o mod %o unit %d cnt %d\n",mp->mscp_opcode,mp->mscp_modifier,mp->mscp_unit,mp->mscp_bytecnt);
1274bc5e3c50Skarels 	if(tmscpdebug)DELAY(100000);
1275bc5e3c50Skarels #	endif
1276bc5e3c50Skarels 	i = tmscpaddr->tmscpip;              /* initiate polling */
1277bc5e3c50Skarels 	dp->b_qsize++;
1278bc5e3c50Skarels 	/*
1279bc5e3c50Skarels 	 * Move drive to the end of the controller queue
1280bc5e3c50Skarels 	 */
1281bc5e3c50Skarels 	if (dp->b_forw != NULL)
1282bc5e3c50Skarels 		{
1283bc5e3c50Skarels 		um->um_tab.b_actf = dp->b_forw;
1284bc5e3c50Skarels 		um->um_tab.b_actl->b_forw = dp;
1285bc5e3c50Skarels 		um->um_tab.b_actl = dp;
1286bc5e3c50Skarels 		dp->b_forw = NULL;
1287bc5e3c50Skarels 		}
1288bc5e3c50Skarels 	/*
1289bc5e3c50Skarels 	 * Move buffer to I/O wait queue
1290bc5e3c50Skarels 	 */
1291bc5e3c50Skarels 	dp->b_actf = bp->av_forw;
1292bc5e3c50Skarels 	dp = &tmscpwtab[um->um_ctlr];
1293bc5e3c50Skarels 	bp->av_forw = dp;
1294bc5e3c50Skarels 	bp->av_back = dp->av_back;
1295bc5e3c50Skarels 	dp->av_back->av_forw = bp;
1296bc5e3c50Skarels 	dp->av_back = bp;
1297bc5e3c50Skarels 	if (tmscpaddr->tmscpsa&TMSCP_ERR)
1298bc5e3c50Skarels 		{
12991625a9a8Skarels 		printf("tmscp%d: fatal error (0%o)\n", um->um_ctlr, tmscpaddr->tmscpsa&0xffff);
1300a073ccb3Skarels 		(void)tmscpinit(um->um_ctlr);
1301bc5e3c50Skarels 		break;
1302bc5e3c50Skarels 		}
1303bc5e3c50Skarels     }   /* end for */
1304bc5e3c50Skarels     /*
1305bc5e3c50Skarels      * Check for response ring transitions lost in the
1306bc5e3c50Skarels      * Race condition
1307bc5e3c50Skarels      */
1308bc5e3c50Skarels     for (i = sc->sc_lastrsp;; i++)
1309bc5e3c50Skarels 	    {
1310bc5e3c50Skarels 	    i %= NRSP;
1311bc5e3c50Skarels 	    if (tm->tmscp_ca.ca_rspdsc[i]&TMSCP_OWN)
1312bc5e3c50Skarels 		    break;
1313bc5e3c50Skarels 	    tmscprsp(um, tm, sc, i);
1314bc5e3c50Skarels 	    tm->tmscp_ca.ca_rspdsc[i] |= TMSCP_OWN;
1315bc5e3c50Skarels 	    }
1316bc5e3c50Skarels     sc->sc_lastrsp = i;
1317bc5e3c50Skarels }
1318bc5e3c50Skarels 
1319bc5e3c50Skarels 
1320bc5e3c50Skarels /*
1321bc5e3c50Skarels  * Process a response packet
1322bc5e3c50Skarels  */
tmscprsp(um,tm,sc,i)1323bc5e3c50Skarels tmscprsp(um, tm, sc, i)
1324bc5e3c50Skarels 	register struct uba_ctlr *um;
1325bc5e3c50Skarels 	register struct tmscp *tm;
1326bc5e3c50Skarels 	register struct tmscp_softc *sc;
1327bc5e3c50Skarels 	int i;
1328bc5e3c50Skarels {
1329bc5e3c50Skarels 	register struct mscp *mp;
13301625a9a8Skarels 	register struct tms_info *tms;
1331bc5e3c50Skarels 	struct uba_device *ui;
13324c8aebccSkarels 	struct buf *dp, *bp;
1333bc5e3c50Skarels 	int st;
1334bc5e3c50Skarels 
1335bc5e3c50Skarels 	mp = &tm->tmscp_rsp[i];
1336bc5e3c50Skarels 	mp->mscp_header.tmscp_msglen = mscp_msglen;
13371625a9a8Skarels 	sc->sc_credits += mp->mscp_header.tmscp_credits & 0xf;  /* low 4 bits */
1338bc5e3c50Skarels 	if ((mp->mscp_header.tmscp_credits & 0xf0) > 0x10)	/* Check */
1339bc5e3c50Skarels 		return;
1340bc5e3c50Skarels #	ifdef DEBUG
13411625a9a8Skarels 	printd("tmscprsp, opcode 0%o status 0%o\n",mp->mscp_opcode,mp->mscp_status&M_ST_MASK);
1342bc5e3c50Skarels #	endif
1343bc5e3c50Skarels 	/*
1344bc5e3c50Skarels 	 * If it's an error log message (datagram),
1345bc5e3c50Skarels 	 * pass it on for more extensive processing.
1346bc5e3c50Skarels 	 */
1347bc5e3c50Skarels 	if ((mp->mscp_header.tmscp_credits & 0xf0) == 0x10)
1348bc5e3c50Skarels 		{	/* check */
1349bc5e3c50Skarels 		tmserror(um, (struct mslg *)mp);
1350bc5e3c50Skarels 		return;
1351bc5e3c50Skarels 		}
1352bc5e3c50Skarels 	st = mp->mscp_status&M_ST_MASK;
1353bc5e3c50Skarels 	/*
1354bc5e3c50Skarels 	 * The controller interrupts as drive 0.
1355bc5e3c50Skarels 	 * This means that you must check for controller interrupts
1356bc5e3c50Skarels 	 * before you check to see if there is a drive 0.
1357bc5e3c50Skarels 	 */
1358bc5e3c50Skarels 	if((M_OP_STCON|M_OP_END) == mp->mscp_opcode)
1359bc5e3c50Skarels 		{
1360bc5e3c50Skarels 		if (st == M_ST_SUCC)
1361bc5e3c50Skarels 			{
1362bc5e3c50Skarels #		  	ifdef DEBUG
13631625a9a8Skarels 			printd("ctlr has %d credits\n", mp->mscp_header.tmscp_credits & 0xf);
1364bc5e3c50Skarels 			printd("ctlr timeout = %d\n", mp->mscp_cnttmo);
1365bc5e3c50Skarels #			endif
1366bc5e3c50Skarels 			sc->sc_state = S_RUN;
1367bc5e3c50Skarels 			}
1368bc5e3c50Skarels 		else
1369bc5e3c50Skarels 			sc->sc_state = S_IDLE;
1370bc5e3c50Skarels 		um->um_tab.b_active = 0;
1371bc5e3c50Skarels 		wakeup((caddr_t)um);
1372bc5e3c50Skarels 		return;
1373bc5e3c50Skarels 		}
13741625a9a8Skarels 	if (mp->mscp_unit >= NTMS)
1375bc5e3c50Skarels 		return;
1376bc5e3c50Skarels 	if ((ui = tmscpip[um->um_ctlr][mp->mscp_unit]) == 0)
1377bc5e3c50Skarels 		return;
13781625a9a8Skarels 	tms = &tms_info[ui->ui_unit];
1379bc5e3c50Skarels 	/*
1380bc5e3c50Skarels 	 * Save endcode, endflags, and status for mtioctl get unit status.
1381bc5e3c50Skarels 	 * NOTE: Don't do this on Clear serious exception (reposition no-op);
1382bc5e3c50Skarels 	 *    which is done on close since this would
1383bc5e3c50Skarels 	 *    overwrite the real status we want.
1384bc5e3c50Skarels 	 */
13851625a9a8Skarels 	if (tms->tms_clserex != 1)
1386bc5e3c50Skarels 		{
13871625a9a8Skarels 		tms->tms_endcode = mp->mscp_opcode;
13881625a9a8Skarels 		tms->tms_flags = mp->mscp_flags;
13891625a9a8Skarels 		tms->tms_status = st;
1390bc5e3c50Skarels 		}
13911625a9a8Skarels 	else tms->tms_clserex = 0;
1392bc5e3c50Skarels 
1393bc5e3c50Skarels 	switch (mp->mscp_opcode) {
1394bc5e3c50Skarels 	case M_OP_ONLIN|M_OP_END:
13951625a9a8Skarels 		tms->tms_type = mp->mscp_mediaid;
1396bc5e3c50Skarels 		dp = &tmsutab[ui->ui_unit];
1397bc5e3c50Skarels 		if (st == M_ST_SUCC)
1398bc5e3c50Skarels 			{
1399bc5e3c50Skarels 			/*
1400bc5e3c50Skarels 			 * Link the drive onto the controller queue
1401bc5e3c50Skarels 			 */
1402bc5e3c50Skarels 			dp->b_forw = NULL;
1403bc5e3c50Skarels 			if (um->um_tab.b_actf == NULL)
1404bc5e3c50Skarels 				um->um_tab.b_actf = dp;
1405bc5e3c50Skarels 			else
1406bc5e3c50Skarels 				um->um_tab.b_actl->b_forw = dp;
1407bc5e3c50Skarels 			um->um_tab.b_actl = dp;
1408bc5e3c50Skarels 			ui->ui_flags = 1;       /* mark it online */
14091625a9a8Skarels 			tms->tms_dsize=(daddr_t)mp->mscp_maxwrt;
1410bc5e3c50Skarels #			ifdef DEBUG
1411bc5e3c50Skarels 			printd("tmscprsp: unit %d online\n", mp->mscp_unit);
1412bc5e3c50Skarels #			endif
1413bc5e3c50Skarels 			/*
1414bc5e3c50Skarels 			 * This define decodes the Media type identifier
1415bc5e3c50Skarels 			 */
14161625a9a8Skarels #	        	define F_to_C(x,i)     ( ((x)->mscp_mediaid) >> (i*5+7) & 0x1f ? ( ( (((x)->mscp_mediaid) >>( i*5 + 7)) & 0x1f) + 'A' - 1): ' ')
1417bc5e3c50Skarels #			ifdef DEBUG
1418bc5e3c50Skarels 			printd("tmscprsp: unit %d online %x %c%c %c%c%c%d\n"
1419bc5e3c50Skarels 				,mp->mscp_unit, mp->mscp_mediaid ,F_to_C(mp,4)
1420bc5e3c50Skarels 				,F_to_C(mp,3), F_to_C(mp,2)
14211625a9a8Skarels 				,F_to_C(mp,1), F_to_C(mp,0), mp->mscp_mediaid & 0x7f);
1422bc5e3c50Skarels #			endif
1423bc5e3c50Skarels 			dp->b_active = 1;
1424bc5e3c50Skarels 			}	/* end if st == M_ST_SUCC */
1425bc5e3c50Skarels 		else
1426bc5e3c50Skarels 			{
14274c8aebccSkarels 			if (bp = dp->b_actf)
14285d073b51Smarc 				tprintf(tms->tms_tpr,
14291625a9a8Skarels 				    "tms%d: hard error bn%d: OFFLINE\n",
14301625a9a8Skarels 				    minor(bp->b_dev)&03, bp->b_blkno);
1431bc5e3c50Skarels 			else
14325d073b51Smarc 				tprintf(tms->tms_tpr,
14331625a9a8Skarels 				    "tms%d: hard error: OFFLINE\n",
14344c8aebccSkarels 				    ui->ui_unit);
1435bc5e3c50Skarels 			while (bp = dp->b_actf)
1436bc5e3c50Skarels 				{
1437bc5e3c50Skarels 				dp->b_actf = bp->av_forw;
1438bc5e3c50Skarels 				bp->b_flags |= B_ERROR;
1439bc5e3c50Skarels 				iodone(bp);
1440bc5e3c50Skarels 				}
1441bc5e3c50Skarels 			}
1442bc5e3c50Skarels 		if(mp->mscp_cmdref!=NULL)
1443bc5e3c50Skarels 			/* Seems to get lost sometimes in uda */
1444a073ccb3Skarels 			wakeup((caddr_t)mp->mscp_cmdref);
1445bc5e3c50Skarels 		break;
1446bc5e3c50Skarels 	/*
1447bc5e3c50Skarels 	 * The AVAILABLE ATTENTION message occurs when the
1448bc5e3c50Skarels 	 * unit becomes available after loading,
1449bc5e3c50Skarels 	 * marking the unit offline (ui_flags = 0) will force an
1450bc5e3c50Skarels 	 * online command prior to using the unit.
1451bc5e3c50Skarels 	 */
1452bc5e3c50Skarels 	case M_OP_AVATN:
1453bc5e3c50Skarels 		ui->ui_flags = 0;
14541625a9a8Skarels 		tms->tms_type = mp->mscp_mediaid;
1455bc5e3c50Skarels 		break;
1456bc5e3c50Skarels 	case M_OP_END:
1457bc5e3c50Skarels 		/*
1458bc5e3c50Skarels 		 * An endcode without an opcode (0200) is an invalid command.
1459bc5e3c50Skarels 		 * The mscp specification states that this would be a protocol
1460bc5e3c50Skarels 		 * type error, such as illegal opcodes. The mscp spec. also
1461bc5e3c50Skarels 		 * states that parameter error type of invalid commands should
14621625a9a8Skarels 		 * return the normal end message for the command. This does not appear
14631625a9a8Skarels 		 * to be the case. An invalid logical block number returned an endcode
1464bc5e3c50Skarels 		 * of 0200 instead of the 0241 (read) that was expected.
1465bc5e3c50Skarels 		 */
1466bc5e3c50Skarels 
1467bc5e3c50Skarels 		printf("tmscp%d: invalid cmd, endcode = %o, status=%o\n",
1468bc5e3c50Skarels 			um->um_ctlr, mp->mscp_opcode, st);
1469bc5e3c50Skarels 		bp = (struct buf *)mp->mscp_cmdref;
1470bc5e3c50Skarels 		/*
1471bc5e3c50Skarels 		 * Unlink buffer from I/O wait queue.
1472bc5e3c50Skarels 		 * And signal iodone, so the higher level command can exit!
1473bc5e3c50Skarels 		 *
1474bc5e3c50Skarels 		 */
1475bc5e3c50Skarels 		bp->av_back->av_forw = bp->av_forw;
1476bc5e3c50Skarels 		bp->av_forw->av_back = bp->av_back;
1477bc5e3c50Skarels 		dp = &tmsutab[ui->ui_unit];
1478bc5e3c50Skarels 		dp->b_qsize--;
1479bc5e3c50Skarels 		iodone(bp);
1480bc5e3c50Skarels 		break;
1481bc5e3c50Skarels 	case M_OP_WRITE|M_OP_END:
1482bc5e3c50Skarels 		/* mark the last io op as a write */
14831625a9a8Skarels 		tms->tms_lastiow = 1;
1484bc5e3c50Skarels 	case M_OP_READ|M_OP_END:
1485bc5e3c50Skarels 	case M_OP_WRITM|M_OP_END:
1486bc5e3c50Skarels 	case M_OP_REPOS|M_OP_END:
1487bc5e3c50Skarels 	case M_OP_STUNT|M_OP_END:
1488bc5e3c50Skarels 	/*
1489bc5e3c50Skarels 	 * The AVAILABLE message occurs when the mt ioctl "rewoffl" is
1490bc5e3c50Skarels 	 * issued.  For the ioctl, "rewoffl", a tmscp AVAILABLE command is
1491bc5e3c50Skarels 	 * done with the UNLOAD modifier.  This performs a rewind, followed
1492bc5e3c50Skarels 	 * by marking the unit offline.  So mark the unit offline
1493bc5e3c50Skarels 	 * software wise as well (ui_flags = 0 and
14941625a9a8Skarels 	 * tms->tms_openf = 0).
1495bc5e3c50Skarels 	 */
1496bc5e3c50Skarels 	case M_OP_AVAIL|M_OP_END:
1497bc5e3c50Skarels #		ifdef DEBUG
1498bc5e3c50Skarels 		printd("tmscprsp: position = %d\n", mp->mscp_lbn);
1499bc5e3c50Skarels #		endif
1500bc5e3c50Skarels 		bp = (struct buf *)mp->mscp_cmdref;
1501bc5e3c50Skarels 		/*
15021625a9a8Skarels 		 * Only need to release buffer if the command was read or write.
1503bc5e3c50Skarels 		 * No ubasetup was done in "tmscpstart" if it was an ioctl cmd.
1504bc5e3c50Skarels 		 */
1505bc5e3c50Skarels 		if (mp->mscp_opcode == (M_OP_READ|M_OP_END) ||
1506bc5e3c50Skarels 		    mp->mscp_opcode == (M_OP_WRITE|M_OP_END))
1507bc5e3c50Skarels 			ubarelse(um->um_ubanum, (int *)&bp->b_ubinfo);
1508bc5e3c50Skarels 		/*
1509bc5e3c50Skarels 		 * Unlink buffer from I/O wait queue.
1510bc5e3c50Skarels 		 */
1511bc5e3c50Skarels 		bp->av_back->av_forw = bp->av_forw;
1512bc5e3c50Skarels 		bp->av_forw->av_back = bp->av_back;
15131625a9a8Skarels #		if defined(VAX750)
15141625a9a8Skarels 		if (cpu == VAX_750) {
15151625a9a8Skarels 		    if ((tmscpwtab[um->um_ctlr].av_forw == &tmscpwtab[um->um_ctlr]) &&
1516bc5e3c50Skarels 					(um->um_ubinfo != 0)) {
1517bc5e3c50Skarels 			ubarelse(um->um_ubanum, &um->um_ubinfo);
1518bc5e3c50Skarels 		    }
1519bc5e3c50Skarels 		    else {
1520bc5e3c50Skarels 			if (mp->mscp_opcode == (M_OP_READ|M_OP_END) ||
1521bc5e3c50Skarels 		    	    mp->mscp_opcode == (M_OP_WRITE|M_OP_END))
15221625a9a8Skarels 				UBAPURGE(uba_hd[um->um_ubanum].uh_uba,(um->um_ubinfo >>28) & 0x0f);
1523bc5e3c50Skarels 		    }
1524bc5e3c50Skarels 		}
1525bc5e3c50Skarels #		endif
1526bc5e3c50Skarels 		dp = &tmsutab[ui->ui_unit];
1527bc5e3c50Skarels 		dp->b_qsize--;
1528bc5e3c50Skarels 		if (st == M_ST_OFFLN || st == M_ST_AVLBL)
1529bc5e3c50Skarels 			{
1530bc5e3c50Skarels 			ui->ui_flags = 0;       /* mark unit offline */
15311625a9a8Skarels 			tms->tms_openf = 0;
15321625a9a8Skarels 			tms->tms_type = mp->mscp_mediaid;
1533bc5e3c50Skarels 			/*
1534bc5e3c50Skarels 			 * Link the buffer onto the front of the drive queue
1535bc5e3c50Skarels 			 */
1536bc5e3c50Skarels 			if ((bp->av_forw = dp->b_actf) == 0)
1537bc5e3c50Skarels 				dp->b_actl = bp;
1538bc5e3c50Skarels 			dp->b_actf = bp;
1539bc5e3c50Skarels 			/*
1540bc5e3c50Skarels 			 * Link the drive onto the controller queue
1541bc5e3c50Skarels 			 */
1542bc5e3c50Skarels 			if (dp->b_active == 0)
1543bc5e3c50Skarels 				{
1544bc5e3c50Skarels 				dp->b_forw = NULL;
1545bc5e3c50Skarels 				if (um->um_tab.b_actf == NULL)
1546bc5e3c50Skarels 					um->um_tab.b_actf = dp;
1547bc5e3c50Skarels 				else
1548bc5e3c50Skarels 					um->um_tab.b_actl->b_forw = dp;
1549bc5e3c50Skarels 				um->um_tab.b_actl = dp;
1550bc5e3c50Skarels 				dp->b_active = 1;
1551bc5e3c50Skarels 				}
15521625a9a8Skarels #			if defined(VAX750)
15531625a9a8Skarels 			if (cpu == VAX_750 && um->um_ubinfo == 0)
15541625a9a8Skarels 				um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP);
1555bc5e3c50Skarels #			endif
1556bc5e3c50Skarels 			return;
1557bc5e3c50Skarels 			}
1558bc5e3c50Skarels 		if (st != M_ST_SUCC)
1559bc5e3c50Skarels 			{
1560bc5e3c50Skarels 			if (mp->mscp_flags & M_EF_SEREX)
15611625a9a8Skarels 				tms->tms_serex = 1;
1562bc5e3c50Skarels 			if (st != M_ST_TAPEM)
1563bc5e3c50Skarels 				{
15645d073b51Smarc 				tprintf(tms->tms_tpr,
15651625a9a8Skarels 				    "tms%d: hard error bn%d\n",
15661625a9a8Skarels 				    minor(bp->b_dev)&03, bp->b_blkno);
15671625a9a8Skarels 				errinfo(st);		/* produces more info */
1568bc5e3c50Skarels #				ifdef DEBUG
15691625a9a8Skarels 				printd("tmscprsp: error; status sub-code = 0%o, flags = 0%o\n",
15701625a9a8Skarels 					(mp->mscp_status & 177740)>>5, mp->mscp_flags);
1571bc5e3c50Skarels #				endif
1572bc5e3c50Skarels 				bp->b_flags |= B_ERROR;
1573bc5e3c50Skarels 				}
1574bc5e3c50Skarels 			else
1575bc5e3c50Skarels 				/* Hit a tape mark - Set serex flag to
1576bc5e3c50Skarels 				 * a special value so we can clear the
1577bc5e3c50Skarels 				 * serious exception on the next command.
1578bc5e3c50Skarels 				 */
15791625a9a8Skarels 				tms->tms_serex = 2;
1580bc5e3c50Skarels 			}
1581bc5e3c50Skarels 		/*
1582bc5e3c50Skarels 		 * The tmscp spec states that controllers do not have to
1583bc5e3c50Skarels 		 * report the number of records or files skipped.  So on
1584bc5e3c50Skarels 		 * reposition commands we go strictly by cmd status.
1585bc5e3c50Skarels 		 */
1586bc5e3c50Skarels 		if (mp->mscp_opcode != (M_OP_REPOS|M_OP_END))
1587bc5e3c50Skarels 			bp->b_resid = bp->b_bcount - mp->mscp_bytecnt;
1588bc5e3c50Skarels 		else
1589bc5e3c50Skarels 			bp->b_resid = 0;
15901625a9a8Skarels 		tms->tms_resid = bp->b_resid;
1591bc5e3c50Skarels 		iodone(bp);
1592bc5e3c50Skarels 		break;
1593bc5e3c50Skarels 
1594bc5e3c50Skarels 	case M_OP_GTUNT|M_OP_END:
1595bc5e3c50Skarels #		ifdef DEBUG
1596bc5e3c50Skarels 		printd("tmscprsp: GTUNT end packet status = 0%o\n",st);
15971625a9a8Skarels 		printd("tmscprsp: unit %d mediaid %x %c%c %c%c%c%d %x %x t=%d\n"
1598bc5e3c50Skarels 		    ,mp->mscp_unit, mp->mscp_mediaid
1599bc5e3c50Skarels 		    ,F_to_C(mp,4),F_to_C(mp,3),F_to_C(mp,2)
1600bc5e3c50Skarels 		    ,F_to_C(mp,1),F_to_C(mp,0)
1601bc5e3c50Skarels 		    ,mp->mscp_mediaid & 0x7f
1602bc5e3c50Skarels 		    ,mp->mscp_unitid.val[0]
1603bc5e3c50Skarels 		    ,mp->mscp_unitid.val[1]
1604bc5e3c50Skarels 		    ,mp->mscp_format);
1605bc5e3c50Skarels #		endif
16061625a9a8Skarels 		tms->tms_type = mp->mscp_mediaid;
16071625a9a8Skarels 		tms->tms_fmtmenu = mp->mscp_fmtmenu;
16081625a9a8Skarels 		tms->tms_unitflgs = mp->mscp_unitflgs;
1609bc5e3c50Skarels 		break;
1610bc5e3c50Skarels 
1611bc5e3c50Skarels 	default:
1612bc5e3c50Skarels 		printf("tmscp unknown packet\n");
1613bc5e3c50Skarels 		tmserror(um, (struct mslg *)mp);
1614bc5e3c50Skarels 	}	/* end switch mp->mscp_opcode */
1615bc5e3c50Skarels }
1616bc5e3c50Skarels 
1617bc5e3c50Skarels 
1618bc5e3c50Skarels /*
1619bc5e3c50Skarels  * Give a meaningful error when the mscp_status field returns an error code.
1620bc5e3c50Skarels  */
1621bc5e3c50Skarels 
errinfo(st)1622bc5e3c50Skarels errinfo(st)
1623bc5e3c50Skarels 	int st;			/* the status code */
1624bc5e3c50Skarels {
1625bc5e3c50Skarels 	switch(st) {
1626bc5e3c50Skarels 	case M_ST_ICMD:
1627bc5e3c50Skarels 		printf("invalid command\n");
1628bc5e3c50Skarels 		break;
1629bc5e3c50Skarels 	case M_ST_ABRTD:
1630bc5e3c50Skarels 		printf("command aborted\n");
1631bc5e3c50Skarels 		break;
1632bc5e3c50Skarels 	case M_ST_OFFLN:
1633bc5e3c50Skarels 		printf("unit offline\n");
1634bc5e3c50Skarels 		break;
1635bc5e3c50Skarels 	case M_ST_WRTPR:
1636bc5e3c50Skarels 		printf("unit write protected\n");
1637bc5e3c50Skarels 		break;
1638bc5e3c50Skarels 	case M_ST_COMP:
1639bc5e3c50Skarels 		printf("compare error\n");
1640bc5e3c50Skarels 		break;
1641bc5e3c50Skarels 	case M_ST_DATA:
1642bc5e3c50Skarels 		printf("data error\n");
1643bc5e3c50Skarels 		break;
1644bc5e3c50Skarels 	case M_ST_HSTBF:
1645bc5e3c50Skarels 		printf("host buffer access error\n");
1646bc5e3c50Skarels 		break;
1647bc5e3c50Skarels 	case M_ST_CNTLR:
1648bc5e3c50Skarels 		printf("controller error\n");
1649bc5e3c50Skarels 		break;
1650bc5e3c50Skarels 	case M_ST_DRIVE:
1651bc5e3c50Skarels 		printf("drive error\n");
1652bc5e3c50Skarels 		break;
1653bc5e3c50Skarels 	case M_ST_FMTER:
1654bc5e3c50Skarels 		printf("formatter error\n");
1655bc5e3c50Skarels 		break;
1656bc5e3c50Skarels 	case M_ST_BOT:
1657bc5e3c50Skarels 		printf("BOT encountered\n");
1658bc5e3c50Skarels 		break;
1659bc5e3c50Skarels 	case M_ST_TAPEM:
1660bc5e3c50Skarels 		printf("tape mark encountered\n");
1661bc5e3c50Skarels 		break;
1662bc5e3c50Skarels 	case M_ST_RDTRN:
1663bc5e3c50Skarels 		printf("record data truncated\n");
1664bc5e3c50Skarels 		break;
1665bc5e3c50Skarels 	case M_ST_PLOST:
1666bc5e3c50Skarels 		printf("position lost\n");
1667bc5e3c50Skarels 		break;
1668bc5e3c50Skarels 	case M_ST_SEX:
1669bc5e3c50Skarels 		printf("serious exception\n");
1670bc5e3c50Skarels 		break;
1671bc5e3c50Skarels 	case M_ST_LED:
1672bc5e3c50Skarels 		printf("LEOT detected\n");
1673bc5e3c50Skarels 		break;
1674bc5e3c50Skarels 	}
1675bc5e3c50Skarels }
1676bc5e3c50Skarels 
1677bc5e3c50Skarels 
1678bc5e3c50Skarels /*
1679bc5e3c50Skarels  * Manage buffers and perform block mode read and write operations.
1680bc5e3c50Skarels  */
1681bc5e3c50Skarels 
tmscpstrategy(bp)1682bc5e3c50Skarels tmscpstrategy (bp)
1683bc5e3c50Skarels 	register struct buf *bp;
1684bc5e3c50Skarels {
1685bc5e3c50Skarels 	register struct uba_device *ui;
1686bc5e3c50Skarels 	register struct uba_ctlr *um;
1687bc5e3c50Skarels 	register struct buf *dp;
1688bc5e3c50Skarels 	register int unit = TMSUNIT(bp->b_dev);
1689bc5e3c50Skarels 	int s;
1690bc5e3c50Skarels 
16911625a9a8Skarels 	if (unit >= NTMS)
1692bc5e3c50Skarels 		{
1693bc5e3c50Skarels #		ifdef DEBUG
1694bc5e3c50Skarels 		printd ("tmscpstrategy: bad unit # %d\n",unit);
1695bc5e3c50Skarels #		endif
1696bc5e3c50Skarels 		bp->b_flags |= B_ERROR;
1697bc5e3c50Skarels 		iodone(bp);
1698bc5e3c50Skarels 		return;
1699bc5e3c50Skarels 		}
1700bc5e3c50Skarels 	ui = tmsdinfo[unit];
1701bc5e3c50Skarels 	um = ui->ui_mi;
1702bc5e3c50Skarels 	if (ui == 0 || ui->ui_alive == 0)
1703bc5e3c50Skarels 		{
1704bc5e3c50Skarels 		bp->b_flags |= B_ERROR;
1705bc5e3c50Skarels 		iodone(bp);
1706bc5e3c50Skarels 		return;
1707bc5e3c50Skarels 		}
1708bc5e3c50Skarels 	s = spl5();
1709bc5e3c50Skarels 	/*
1710bc5e3c50Skarels 	 * Link the buffer onto the drive queue
1711bc5e3c50Skarels 	 */
1712bc5e3c50Skarels 	dp = &tmsutab[ui->ui_unit];
1713bc5e3c50Skarels 	if (dp->b_actf == 0)
1714bc5e3c50Skarels 		dp->b_actf = bp;
1715bc5e3c50Skarels 	else
1716bc5e3c50Skarels 		dp->b_actl->av_forw = bp;
1717bc5e3c50Skarels 	dp->b_actl = bp;
1718bc5e3c50Skarels 	bp->av_forw = 0;
1719bc5e3c50Skarels 	/*
1720bc5e3c50Skarels 	 * Link the drive onto the controller queue
1721bc5e3c50Skarels 	 */
1722bc5e3c50Skarels 	if (dp->b_active == 0)
1723bc5e3c50Skarels 		{
1724bc5e3c50Skarels 		dp->b_forw = NULL;
1725bc5e3c50Skarels 		if (um->um_tab.b_actf == NULL)
1726bc5e3c50Skarels 			um->um_tab.b_actf = dp;
1727bc5e3c50Skarels 		else
1728bc5e3c50Skarels 			um->um_tab.b_actl->b_forw = dp;
1729bc5e3c50Skarels 		um->um_tab.b_actl = dp;
1730bc5e3c50Skarels 		dp->b_active = 1;
1731bc5e3c50Skarels 		}
1732bc5e3c50Skarels 	/*
1733bc5e3c50Skarels 	 * If the controller is not active, start it.
1734bc5e3c50Skarels 	 */
1735bc5e3c50Skarels 	if (um->um_tab.b_active == 0)
1736bc5e3c50Skarels 		{
17371625a9a8Skarels #		if defined(VAX750)
17381625a9a8Skarels 		if (cpu == VAX_750
17391625a9a8Skarels 				 && tmscpwtab[um->um_ctlr].av_forw == &tmscpwtab[um->um_ctlr])
1740bc5e3c50Skarels 			{
1741bc5e3c50Skarels 			if (um->um_ubinfo != 0)
17421625a9a8Skarels 				log(TMS_PRI, "tmscpstrategy: ubinfo 0x%x\n",
17431625a9a8Skarels 				    um->um_ubinfo);
1744bc5e3c50Skarels 			else
17451625a9a8Skarels 				um->um_ubinfo = uballoc(um->um_ubanum, (caddr_t)0, 0, UBA_NEEDBDP);
1746bc5e3c50Skarels 			}
1747bc5e3c50Skarels #		endif
1748bc5e3c50Skarels #		ifdef DEBUG
17491625a9a8Skarels 		printd10("tmscpstrategy: Controller not active, starting it\n");
1750bc5e3c50Skarels #		endif
1751bc5e3c50Skarels 		(void) tmscpstart(um);
1752bc5e3c50Skarels 		}
1753bc5e3c50Skarels 	splx(s);
1754bc5e3c50Skarels 	return;
1755bc5e3c50Skarels }
1756bc5e3c50Skarels 
1757bc5e3c50Skarels #define DBSIZE 32
1758bc5e3c50Skarels 
1759bc5e3c50Skarels #define ca_Rspdsc       ca_rspdsc[0]
1760bc5e3c50Skarels #define ca_Cmddsc       ca_rspdsc[1]
1761bc5e3c50Skarels #define tmscp_Rsp       tmscp_rsp[0]
1762bc5e3c50Skarels #define tmscp_Cmd       tmscp_cmd[0]
1763bc5e3c50Skarels 
1764bc5e3c50Skarels struct  tmscp     tmscpd[NTMSCP];
1765bc5e3c50Skarels 
tmscpdump(dev)1766bc5e3c50Skarels tmscpdump(dev)
1767bc5e3c50Skarels 	dev_t dev;
1768bc5e3c50Skarels {
1769bc5e3c50Skarels 	struct tmscpdevice *tmscpaddr;
1770bc5e3c50Skarels 	struct tmscp *tmscp_ubaddr;
1771bc5e3c50Skarels 	char *start;
1772bc5e3c50Skarels 	int num, blk, unit;
1773bc5e3c50Skarels 	register struct uba_regs *uba;
1774bc5e3c50Skarels 	register struct uba_device *ui;
1775bc5e3c50Skarels 	register struct tmscp *tmscpp;
1776bc5e3c50Skarels 	register struct pte *io;
1777bc5e3c50Skarels 	register int i;
1778bc5e3c50Skarels 
1779bc5e3c50Skarels 	unit = minor(dev) & 03;
17801625a9a8Skarels 	if (unit >= NTMS)
1781bc5e3c50Skarels 		return (ENXIO);
1782bc5e3c50Skarels #	define phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
1783bc5e3c50Skarels 	ui = phys(struct uba_device *, tmsdinfo[unit]);
1784bc5e3c50Skarels 	if (ui->ui_alive == 0)
1785bc5e3c50Skarels 		return (ENXIO);
1786bc5e3c50Skarels 	uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
1787bc5e3c50Skarels 	ubainit(uba);
1788bc5e3c50Skarels 	tmscpaddr = (struct tmscpdevice *)ui->ui_physaddr;
1789bc5e3c50Skarels 	DELAY(2000000);
1790bc5e3c50Skarels 	tmscpp = phys(struct tmscp *, &tmscpd[ui->ui_ctlr]);
1791bc5e3c50Skarels 
1792bc5e3c50Skarels 	num = btoc(sizeof(struct tmscp)) + 1;
1793bc5e3c50Skarels 	io = &uba->uba_map[NUBMREG-num];
1794bc5e3c50Skarels 	for(i = 0; i<num; i++)
1795bc5e3c50Skarels 		*(int *)io++ = UBAMR_MRV|(btop(tmscpp)+i);
17961625a9a8Skarels 	tmscp_ubaddr = (struct tmscp *)(((int)tmscpp & PGOFSET)|((NUBMREG-num)<<9));
1797bc5e3c50Skarels 
1798bc5e3c50Skarels 	tmscpaddr->tmscpip = 0;
1799bc5e3c50Skarels 	while ((tmscpaddr->tmscpsa & TMSCP_STEP1) == 0)
1800bc5e3c50Skarels 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
1801bc5e3c50Skarels 	tmscpaddr->tmscpsa = TMSCP_ERR;
1802bc5e3c50Skarels 	while ((tmscpaddr->tmscpsa & TMSCP_STEP2) == 0)
1803bc5e3c50Skarels 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
1804bc5e3c50Skarels 	tmscpaddr->tmscpsa = (short)&tmscp_ubaddr->tmscp_ca.ca_ringbase;
1805bc5e3c50Skarels 	while ((tmscpaddr->tmscpsa & TMSCP_STEP3) == 0)
1806bc5e3c50Skarels 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
18071625a9a8Skarels 	tmscpaddr->tmscpsa = (short)(((int)&tmscp_ubaddr->tmscp_ca.ca_ringbase) >> 16);
1808bc5e3c50Skarels 	while ((tmscpaddr->tmscpsa & TMSCP_STEP4) == 0)
1809bc5e3c50Skarels 		if(tmscpaddr->tmscpsa & TMSCP_ERR) return(EFAULT);
1810bc5e3c50Skarels 	tmscpaddr->tmscpsa = TMSCP_GO;
18111625a9a8Skarels 	tmscpp->tmscp_ca.ca_Rspdsc = (long)&tmscp_ubaddr->tmscp_Rsp.mscp_cmdref;
18121625a9a8Skarels 	tmscpp->tmscp_ca.ca_Cmddsc = (long)&tmscp_ubaddr->tmscp_Cmd.mscp_cmdref;
1813bc5e3c50Skarels 	tmscpp->tmscp_Cmd.mscp_header.tmscp_vcid = 1;	/* for tape */
1814bc5e3c50Skarels 	tmscpp->tmscp_Cmd.mscp_cntflgs = 0;
1815bc5e3c50Skarels 	tmscpp->tmscp_Cmd.mscp_version = 0;
1816bc5e3c50Skarels 	if (tmscpcmd(M_OP_STCON, tmscpp, tmscpaddr) == 0) {
1817bc5e3c50Skarels 		return(EFAULT);
1818bc5e3c50Skarels 	}
1819bc5e3c50Skarels 	tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave;
1820bc5e3c50Skarels 	if (tmscpcmd(M_OP_ONLIN, tmscpp, tmscpaddr) == 0) {
1821bc5e3c50Skarels 		return(EFAULT);
1822bc5e3c50Skarels 	}
1823bc5e3c50Skarels 
1824bc5e3c50Skarels 	num = maxfree;
1825bc5e3c50Skarels 	start = 0;
1826bc5e3c50Skarels 	while (num > 0)
1827bc5e3c50Skarels 		{
1828bc5e3c50Skarels 		blk = num > DBSIZE ? DBSIZE : num;
1829bc5e3c50Skarels 		io = uba->uba_map;
1830bc5e3c50Skarels 		for (i = 0; i < blk; i++)
1831bc5e3c50Skarels 			*(int *)io++ = (btop(start)+i) | UBAMR_MRV;
1832bc5e3c50Skarels 		*(int *)io = 0;
1833bc5e3c50Skarels 		tmscpp->tmscp_Cmd.mscp_lbn = btop(start);
1834bc5e3c50Skarels 		tmscpp->tmscp_Cmd.mscp_unit = ui->ui_slave;
1835bc5e3c50Skarels 		tmscpp->tmscp_Cmd.mscp_bytecnt = blk*NBPG;
1836bc5e3c50Skarels #		ifdef	MVAX
1837bc5e3c50Skarels 		if( cpu == MVAX_I )
1838bc5e3c50Skarels 			tmscpp->tmscp_Cmd.mscp_buffer = (long) start;
1839bc5e3c50Skarels 		else
1840bc5e3c50Skarels #		endif 	MVAX
1841bc5e3c50Skarels 			tmscpp->tmscp_Cmd.mscp_buffer = 0;
1842bc5e3c50Skarels 		if (tmscpcmd(M_OP_WRITE, tmscpp, tmscpaddr) == 0)
1843bc5e3c50Skarels 			return(EIO);
1844bc5e3c50Skarels 		start += blk*NBPG;
1845bc5e3c50Skarels 		num -= blk;
1846bc5e3c50Skarels 		}
1847bc5e3c50Skarels 	return (0);
1848bc5e3c50Skarels }
1849bc5e3c50Skarels 
1850bc5e3c50Skarels 
1851bc5e3c50Skarels /*
1852bc5e3c50Skarels  * Perform a standalone tmscp command.  This routine is only used by tmscpdump.
1853bc5e3c50Skarels  */
1854bc5e3c50Skarels 
tmscpcmd(op,tmscpp,tmscpaddr)1855bc5e3c50Skarels tmscpcmd(op, tmscpp, tmscpaddr)
1856bc5e3c50Skarels 	int op;
1857bc5e3c50Skarels 	register struct tmscp *tmscpp;
1858bc5e3c50Skarels 	struct tmscpdevice *tmscpaddr;
1859bc5e3c50Skarels {
1860bc5e3c50Skarels 	int i;
1861bc5e3c50Skarels 
1862bc5e3c50Skarels 
1863bc5e3c50Skarels 	tmscpp->tmscp_Cmd.mscp_opcode = op;
1864bc5e3c50Skarels 	tmscpp->tmscp_Rsp.mscp_header.tmscp_msglen = mscp_msglen;
1865bc5e3c50Skarels 	tmscpp->tmscp_Cmd.mscp_header.tmscp_msglen = mscp_msglen;
1866bc5e3c50Skarels 	tmscpp->tmscp_ca.ca_Rspdsc |= TMSCP_OWN|TMSCP_INT;
1867bc5e3c50Skarels 	tmscpp->tmscp_ca.ca_Cmddsc |= TMSCP_OWN|TMSCP_INT;
1868bc5e3c50Skarels 	if (tmscpaddr->tmscpsa&TMSCP_ERR)
1869bc5e3c50Skarels 		printf("tmscp fatal error (0%o)\n", tmscpaddr->tmscpsa&0xffff);
1870bc5e3c50Skarels 	i = tmscpaddr->tmscpip;
18714c8aebccSkarels #ifdef lint
18724c8aebccSkarels 	i = i;
18734c8aebccSkarels #endif
1874bc5e3c50Skarels 	for (;;)
1875bc5e3c50Skarels 		{
1876bc5e3c50Skarels 		if (tmscpp->tmscp_ca.ca_cmdint)
1877bc5e3c50Skarels 			tmscpp->tmscp_ca.ca_cmdint = 0;
1878bc5e3c50Skarels 		if (tmscpp->tmscp_ca.ca_rspint)
1879bc5e3c50Skarels 			break;
1880bc5e3c50Skarels 		}
1881bc5e3c50Skarels 	tmscpp->tmscp_ca.ca_rspint = 0;
1882bc5e3c50Skarels 	if (tmscpp->tmscp_Rsp.mscp_opcode != (op|M_OP_END) ||
1883bc5e3c50Skarels 	    (tmscpp->tmscp_Rsp.mscp_status&M_ST_MASK) != M_ST_SUCC)
1884bc5e3c50Skarels 		{
1885bc5e3c50Skarels 		printf("error: com %d opc 0x%x stat 0x%x\ndump ", op,
18861625a9a8Skarels 			tmscpp->tmscp_Rsp.mscp_opcode, tmscpp->tmscp_Rsp.mscp_status);
1887bc5e3c50Skarels 		return(0);
1888bc5e3c50Skarels 		}
1889bc5e3c50Skarels 	return(1);
1890bc5e3c50Skarels }
1891bc5e3c50Skarels 
1892bc5e3c50Skarels /*
1893bc5e3c50Skarels  * Catch ioctl commands, and call the "command" routine to do them.
1894bc5e3c50Skarels  */
1895bc5e3c50Skarels 
18964c8aebccSkarels /* ARGSUSED */
tmscpioctl(dev,cmd,data,flag)1897bc5e3c50Skarels tmscpioctl(dev, cmd, data, flag)
1898bc5e3c50Skarels 	dev_t dev;
1899bc5e3c50Skarels 	int cmd;
1900bc5e3c50Skarels 	caddr_t data;
1901bc5e3c50Skarels 	int flag;
1902bc5e3c50Skarels {
1903bc5e3c50Skarels 	register struct buf *bp = &ctmscpbuf[TMSCPCTLR(dev)];
1904bc5e3c50Skarels 	register callcount;	/* number of times to call cmd routine */
1905bc5e3c50Skarels 	register struct uba_device *ui;
19061625a9a8Skarels 	register struct tms_info *tms;
1907bc5e3c50Skarels 	int fcount;		/* number of files (or records) to space */
19081ba79fc0Ssklower 	int error = 0;
19094c8aebccSkarels 	register struct mtop *mtop;	/* mag tape cmd op to perform */
19104c8aebccSkarels 	register struct mtget *mtget;	/* mag tape struct to get info in */
1911bc5e3c50Skarels 
1912bc5e3c50Skarels 	/* we depend of the values and order of the TMS ioctl codes here */
1913bc5e3c50Skarels 	static tmsops[] =
1914bc5e3c50Skarels 	 {TMS_WRITM,TMS_FSF,TMS_BSF,TMS_FSR,TMS_BSR,TMS_REW,TMS_OFFL,TMS_SENSE,
1915bc5e3c50Skarels 	  TMS_CACHE,TMS_NOCACHE};
1916bc5e3c50Skarels 
1917bc5e3c50Skarels 	switch (cmd) {
1918bc5e3c50Skarels 	case MTIOCTOP:	/* tape operation */
1919bc5e3c50Skarels 		mtop = (struct mtop *)data;
1920bc5e3c50Skarels 		switch (mtop->mt_op) {
1921bc5e3c50Skarels 
1922bc5e3c50Skarels 		case MTWEOF:
1923bc5e3c50Skarels 			callcount = mtop->mt_count;
1924bc5e3c50Skarels 			fcount = 1;
1925bc5e3c50Skarels 			break;
1926bc5e3c50Skarels 		case MTFSF: case MTBSF:
1927bc5e3c50Skarels 		case MTFSR: case MTBSR:
1928bc5e3c50Skarels 			callcount = 1;
1929bc5e3c50Skarels 			fcount = mtop->mt_count;
1930bc5e3c50Skarels 			break;
1931bc5e3c50Skarels 		case MTREW: case MTOFFL: case MTNOP:
1932bc5e3c50Skarels 		case MTCACHE: case MTNOCACHE:
1933bc5e3c50Skarels 			callcount = 1;
1934bc5e3c50Skarels 			fcount = 1;		/* wait for this rewind */
1935bc5e3c50Skarels 			break;
1936bc5e3c50Skarels 		default:
1937bc5e3c50Skarels 			return (ENXIO);
1938bc5e3c50Skarels 		}	/* end switch mtop->mt_op */
1939bc5e3c50Skarels 
1940bc5e3c50Skarels 		if (callcount <= 0 || fcount <= 0)
1941bc5e3c50Skarels 			return (EINVAL);
1942bc5e3c50Skarels 		while (--callcount >= 0)
1943bc5e3c50Skarels 			{
1944bc5e3c50Skarels 			tmscpcommand(dev, tmsops[mtop->mt_op], fcount);
1945bc5e3c50Skarels 			if ((mtop->mt_op == MTFSR || mtop->mt_op == MTBSR) &&
1946bc5e3c50Skarels 			    bp->b_resid)
1947bc5e3c50Skarels 				return (EIO);
1948bc5e3c50Skarels 			if (bp->b_flags & B_ERROR)	/* like hitting BOT */
1949bc5e3c50Skarels 				break;
1950bc5e3c50Skarels 			}
19511ba79fc0Ssklower 		if (bp->b_flags&B_ERROR)
19521ba79fc0Ssklower 			if ((error = bp->b_error)==0)
19531ba79fc0Ssklower 				return (EIO);
19541ba79fc0Ssklower 		return (error);
1955bc5e3c50Skarels 
1956bc5e3c50Skarels 	case MTIOCGET:
1957bc5e3c50Skarels 		/*
1958bc5e3c50Skarels 		 * Return status info associated with the particular UNIT.
1959bc5e3c50Skarels 		 */
1960bc5e3c50Skarels 		ui = tmsdinfo[TMSUNIT(dev)];
19611625a9a8Skarels 		tms = &tms_info[ui->ui_unit];
1962bc5e3c50Skarels 		mtget = (struct mtget *)data;
1963bc5e3c50Skarels 		mtget->mt_type = MT_ISTMSCP;
19641625a9a8Skarels 		mtget->mt_dsreg = tms->tms_flags << 8;
19651625a9a8Skarels 		mtget->mt_dsreg |= tms->tms_endcode;
19661625a9a8Skarels 		mtget->mt_erreg = tms->tms_status;
19671625a9a8Skarels 		mtget->mt_resid = tms->tms_resid;
1968bc5e3c50Skarels 		break;
1969bc5e3c50Skarels 
1970bc5e3c50Skarels 	default:
1971bc5e3c50Skarels 		return (ENXIO);
1972bc5e3c50Skarels 	}
1973bc5e3c50Skarels 	return (0);
1974bc5e3c50Skarels }
1975bc5e3c50Skarels 
1976bc5e3c50Skarels 
1977bc5e3c50Skarels /*
1978bc5e3c50Skarels  * Reset (for raw mode use only).
1979bc5e3c50Skarels  */
1980bc5e3c50Skarels 
tmscpreset(uban)1981bc5e3c50Skarels tmscpreset (uban)
1982bc5e3c50Skarels 	int uban;
1983bc5e3c50Skarels {
1984bc5e3c50Skarels 	register struct uba_ctlr *um;
1985bc5e3c50Skarels 	register struct uba_device *ui;
1986bc5e3c50Skarels 	register struct buf *bp, *dp;
1987bc5e3c50Skarels 	register int unit;
1988bc5e3c50Skarels 	struct buf *nbp;
1989bc5e3c50Skarels 	int d;
1990bc5e3c50Skarels 
1991bc5e3c50Skarels 	for (d = 0; d < NTMSCP; d++)
1992bc5e3c50Skarels 		{
1993bc5e3c50Skarels 		if ((um = tmscpminfo[d]) == 0 || um->um_ubanum != uban ||
1994bc5e3c50Skarels 		    um->um_alive == 0)
1995bc5e3c50Skarels 			continue;
1996bc5e3c50Skarels 		printf(" tmscp%d", d);
1997bc5e3c50Skarels 		um->um_tab.b_active = 0;
1998bc5e3c50Skarels 		um->um_tab.b_actf = um->um_tab.b_actl = 0;
1999bc5e3c50Skarels 		tmscp_softc[d].sc_state = S_IDLE;
2000bc5e3c50Skarels 		tmscp_softc[d].sc_mapped = 0;
20011625a9a8Skarels 		for (unit = 0; unit < NTMS; unit++)
2002bc5e3c50Skarels 			{
2003bc5e3c50Skarels 			if ((ui = tmsdinfo[unit]) == 0)
2004bc5e3c50Skarels 				continue;
2005bc5e3c50Skarels 			if (ui->ui_alive == 0 || ui->ui_mi != um)
2006bc5e3c50Skarels 				continue;
2007bc5e3c50Skarels 			tmsutab[unit].b_active = 0;
2008bc5e3c50Skarels 			tmsutab[unit].b_qsize = 0;
2009bc5e3c50Skarels 			}
2010bc5e3c50Skarels 		for (bp = tmscpwtab[d].av_forw; bp != &tmscpwtab[d]; bp = nbp)
2011bc5e3c50Skarels 			{
2012bc5e3c50Skarels 			nbp = bp->av_forw;
2013bc5e3c50Skarels 			bp->b_ubinfo = 0;
2014bc5e3c50Skarels 			/*
2015bc5e3c50Skarels 			 * Link the buffer onto the drive queue
2016bc5e3c50Skarels 			 */
2017bc5e3c50Skarels 			dp = &tmsutab[TMSUNIT(bp->b_dev)];
2018bc5e3c50Skarels 			if (dp->b_actf == 0)
2019bc5e3c50Skarels 				dp->b_actf = bp;
2020bc5e3c50Skarels 			else
2021bc5e3c50Skarels 				dp->b_actl->av_forw = bp;
2022bc5e3c50Skarels 			dp->b_actl = bp;
2023bc5e3c50Skarels 			bp->av_forw = 0;
2024bc5e3c50Skarels 			/*
2025bc5e3c50Skarels 			 * Link the drive onto the controller queue
2026bc5e3c50Skarels 			 */
2027bc5e3c50Skarels 			if (dp->b_active == 0)
2028bc5e3c50Skarels 				{
2029bc5e3c50Skarels 				dp->b_forw = NULL;
2030bc5e3c50Skarels 				if (um->um_tab.b_actf == NULL)
2031bc5e3c50Skarels 					um->um_tab.b_actf = dp;
2032bc5e3c50Skarels 				else
2033bc5e3c50Skarels 					um->um_tab.b_actl->b_forw = dp;
2034bc5e3c50Skarels 				um->um_tab.b_actl = dp;
2035bc5e3c50Skarels 				dp->b_active = 1;
2036bc5e3c50Skarels 				}
2037bc5e3c50Skarels 			}
2038a073ccb3Skarels 		(void)tmscpinit(d);
2039bc5e3c50Skarels 		}
2040bc5e3c50Skarels }
2041bc5e3c50Skarels 
2042bc5e3c50Skarels 
2043bc5e3c50Skarels /*
2044bc5e3c50Skarels  * Process an error log message
2045bc5e3c50Skarels  *
2046bc5e3c50Skarels  * Only minimal decoding is done, only "useful"
2047bc5e3c50Skarels  * information is printed.  Eventually should
2048bc5e3c50Skarels  * send message to an error logger.
2049bc5e3c50Skarels  */
2050bc5e3c50Skarels 
tmserror(um,mp)2051bc5e3c50Skarels tmserror(um, mp)
2052bc5e3c50Skarels 	register struct uba_ctlr *um;
2053bc5e3c50Skarels 	register struct mslg *mp;
2054bc5e3c50Skarels {
2055bc5e3c50Skarels 	register i;
2056bc5e3c50Skarels 
2057bc5e3c50Skarels #	ifdef DEBUG
2058bc5e3c50Skarels 	printd("tmserror:\n");
2059bc5e3c50Skarels #	endif
2060bc5e3c50Skarels 	if(!(mp->mslg_flags & (M_LF_SUCC | M_LF_CONT)))
20611625a9a8Skarels 		log(TMS_PRI, "tmscp%d: %s error, ", um->um_ctlr,
2062bc5e3c50Skarels 		mp->mslg_flags & ( M_LF_SUCC | M_LF_CONT ) ? "soft" : "hard");
2063bc5e3c50Skarels 
2064bc5e3c50Skarels 	switch (mp->mslg_format) {
2065bc5e3c50Skarels 
2066bc5e3c50Skarels 	case M_FM_CNTERR:
20671625a9a8Skarels 		log(TMS_PRI, "controller error, event 0%o\n", mp->mslg_event);
2068bc5e3c50Skarels 		break;
2069bc5e3c50Skarels 	case M_FM_BUSADDR:
20701625a9a8Skarels 		log(TMS_PRI, "host memory access error, event 0%o, addr 0%o\n",
2071bc5e3c50Skarels 			mp->mslg_event, mp->mslg_busaddr);
2072bc5e3c50Skarels 		break;
2073bc5e3c50Skarels 	case M_FM_TAPETRN:
20741625a9a8Skarels 		log(TMS_PRI, "tape transfer error, unit %d, grp 0x%x, event 0%o\n",
2075bc5e3c50Skarels 			mp->mslg_unit, mp->mslg_group, mp->mslg_event);
2076bc5e3c50Skarels 		break;
2077bc5e3c50Skarels 	case M_FM_STIERR:
20781625a9a8Skarels 		log(TMS_PRI, "STI error, unit %d, event 0%o\n",
2079bc5e3c50Skarels 			mp->mslg_unit, mp->mslg_event);
20801625a9a8Skarels #ifdef notdef
20811625a9a8Skarels 		/* too painful to do with log() */
2082bc5e3c50Skarels 		for(i = 0; i < 62;i++)
2083bc5e3c50Skarels 			mprintf("\t0x%x",mp->mslg_stiunsucc[i] & 0xff);
2084bc5e3c50Skarels 		mprintf("\n");
20851625a9a8Skarels #endif
2086bc5e3c50Skarels 		break;
2087bc5e3c50Skarels 	case M_FM_STIDEL:
20881625a9a8Skarels 		log(TMS_PRI, "STI Drive Error Log, unit %d, event 0%o\n",
2089bc5e3c50Skarels 			mp->mslg_unit, mp->mslg_event);
2090bc5e3c50Skarels 		break;
2091bc5e3c50Skarels 	case M_FM_STIFEL:
20921625a9a8Skarels 		log(TMS_PRI, "STI Formatter Error Log, unit %d, event 0%o\n",
2093bc5e3c50Skarels 			mp->mslg_unit, mp->mslg_event);
2094bc5e3c50Skarels 		break;
2095bc5e3c50Skarels 	default:
20961625a9a8Skarels 		log(TMS_PRI, "unknown error, unit %d, format 0%o, event 0%o\n",
2097bc5e3c50Skarels 			mp->mslg_unit, mp->mslg_format, mp->mslg_event);
2098bc5e3c50Skarels 	}
2099bc5e3c50Skarels 
2100bc5e3c50Skarels 	if (tmscperror)
2101bc5e3c50Skarels 		{
2102bc5e3c50Skarels 		register long *p = (long *)mp;
2103bc5e3c50Skarels 
2104bc5e3c50Skarels 		for (i = 0; i < mp->mslg_header.tmscp_msglen; i += sizeof(*p))
2105bc5e3c50Skarels 			printf("%x ", *p++);
2106bc5e3c50Skarels 		printf("\n");
2107bc5e3c50Skarels 		}
2108bc5e3c50Skarels }
2109bc5e3c50Skarels #endif
2110