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