xref: /csrg-svn/sys/vax/mba/mba.c (revision 2383)
1*2383Swnj /*	mba.c	4.4	81/02/08	*/
228Sbill 
3*2383Swnj /*
4*2383Swnj  * Massbus driver; arbitrates massbusses through device driver routines
5*2383Swnj  * and provides common functions.
6*2383Swnj  */
7*2383Swnj int	mbadebug = 0;
8*2383Swnj #define	dprintf if (mbadebug) printf
9*2383Swnj 
1028Sbill #include "../h/param.h"
11*2383Swnj #include "../h/systm.h"
12*2383Swnj #include "../h/dk.h"
1328Sbill #include "../h/buf.h"
1428Sbill #include "../h/conf.h"
1528Sbill #include "../h/dir.h"
1628Sbill #include "../h/user.h"
1728Sbill #include "../h/proc.h"
18*2383Swnj #include "../h/map.h"
1928Sbill #include "../h/pte.h"
2028Sbill #include "../h/mba.h"
2128Sbill #include "../h/mtpr.h"
2228Sbill #include "../h/vm.h"
2328Sbill 
2428Sbill /*
25*2383Swnj  * Start activity on a massbus device.
26*2383Swnj  * We are given the device's mba_info structure and activate
27*2383Swnj  * the device via the unit start routine.  The unit start
28*2383Swnj  * routine may indicate that it is finished (e.g. if the operation
29*2383Swnj  * was a ``sense'' on a tape drive), that the (multi-ported) unit
30*2383Swnj  * is busy (we will get an interrupt later), that it started the
31*2383Swnj  * unit (e.g. for a non-data transfer operation), or that it has
32*2383Swnj  * set up a data transfer operation and we should start the massbus adaptor.
3328Sbill  */
34*2383Swnj mbustart(mi)
35*2383Swnj 	register struct mba_info *mi;
36*2383Swnj {
37*2383Swnj 	register struct mba_drv *mdp;	/* drive registers */
38*2383Swnj 	register struct buf *bp;	/* i/o operation at head of queue */
39*2383Swnj 	register struct mba_hd *mhp;	/* header for mba device is on */
4028Sbill 
41*2383Swnj 	dprintf("enter mbustart\n");
42*2383Swnj loop:
43*2383Swnj 	/*
44*2383Swnj 	 * Get the first thing to do off device queue.
45*2383Swnj 	 */
46*2383Swnj 	bp = mi->mi_tab.b_actf;
47*2383Swnj 	if (bp == NULL)
48*2383Swnj 		return;
49*2383Swnj 	mdp = mi->mi_drv;
50*2383Swnj 	/*
51*2383Swnj 	 * Since we clear attentions on the drive when we are
52*2383Swnj 	 * finished processing it, the fact that an attention
53*2383Swnj 	 * status shows indicated confusion in the hardware or our logic.
54*2383Swnj 	 */
55*2383Swnj 	if (mdp->mbd_as & (1 << mi->mi_drive)) {
56*2383Swnj 		printf("mbustart: ata on for %d\n", mi->mi_drive);
57*2383Swnj 		mdp->mbd_as = 1 << mi->mi_drive;
58*2383Swnj 	}
59*2383Swnj 	/*
60*2383Swnj 	 * Let the drivers unit start routine have at it
61*2383Swnj 	 * and then process the request further, per its instructions.
62*2383Swnj 	 */
63*2383Swnj 	switch ((*mi->mi_driver->md_ustart)(mi)) {
64*2383Swnj 
65*2383Swnj 	case MBU_NEXT:		/* request is complete (e.g. ``sense'') */
66*2383Swnj 		dprintf("mbu_next\n");
67*2383Swnj 		mi->mi_tab.b_active = 0;
68*2383Swnj 		mi->mi_tab.b_actf = bp->av_forw;
69*2383Swnj 		iodone(bp);
70*2383Swnj 		goto loop;
71*2383Swnj 
72*2383Swnj 	case MBU_DODATA:	/* all ready to do data transfer */
73*2383Swnj 		dprintf("mbu_dodata\n");
74*2383Swnj 		/*
75*2383Swnj 		 * Queue the device mba_info structure on the massbus
76*2383Swnj 		 * mba_hd structure for processing as soon as the
77*2383Swnj 		 * data path is available.
78*2383Swnj 		 */
79*2383Swnj 		mhp = mi->mi_hd;
80*2383Swnj 		mi->mi_forw = NULL;
81*2383Swnj 		if (mhp->mh_actf == NULL)
82*2383Swnj 			mhp->mh_actf = mi;
83*2383Swnj 		else
84*2383Swnj 			mhp->mh_actl->mi_forw = mi;
85*2383Swnj 		mhp->mh_actl = mi;
86*2383Swnj 		/*
87*2383Swnj 		 * If data path is idle, start transfer now.
88*2383Swnj 		 * In any case the device is ``active'' waiting for the
89*2383Swnj 		 * data to transfer.
90*2383Swnj 		 */
91*2383Swnj 		if (mhp->mh_active == 0)
92*2383Swnj 			mbstart(mhp);
93*2383Swnj 		mi->mi_tab.b_active = 1;
94*2383Swnj 		return;
95*2383Swnj 
96*2383Swnj 	case MBU_STARTED:	/* driver started a non-data transfer */
97*2383Swnj 		dprintf("mbu_started\n");
98*2383Swnj 		/*
99*2383Swnj 		 * Mark device busy during non-data transfer
100*2383Swnj 		 * and count this as a ``seek'' on the device.
101*2383Swnj 		 */
102*2383Swnj 		if (mi->mi_dk >= 0)
103*2383Swnj 			dk_seek[mi->mi_dk]++;
104*2383Swnj 		mi->mi_tab.b_active = 1;
105*2383Swnj 		return;
106*2383Swnj 
107*2383Swnj 	case MBU_BUSY:		/* dual port drive busy */
108*2383Swnj 		dprintf("mbu_busy\n");
109*2383Swnj 		/*
110*2383Swnj 		 * We mark the device structure so that when an
111*2383Swnj 		 * interrupt occurs we will know to restart the unit.
112*2383Swnj 		 */
113*2383Swnj 		mi->mi_tab.b_flags |= B_BUSY;
114*2383Swnj 		return;
115*2383Swnj 
116*2383Swnj 	default:
117*2383Swnj 		panic("mbustart");
118*2383Swnj 	}
119*2383Swnj #if VAX==780
120*2383Swnj 
121*2383Swnj /*
122*2383Swnj  * Start an i/o operation on the massbus specified by the argument.
123*2383Swnj  * We peel the first operation off its queue and insure that the drive
124*2383Swnj  * is present and on-line.  We then use the drivers start routine
125*2383Swnj  * (if any) to prepare the drive, setup the massbus map for the transfer
126*2383Swnj  * and start the transfer.
127*2383Swnj  */
128*2383Swnj mbstart(mhp)
129*2383Swnj 	register struct mba_hd *mhp;
130*2383Swnj {
131*2383Swnj 	register struct mba_info *mi;
132*2383Swnj 	struct buf *bp;
133*2383Swnj 	register struct mba_drv *daddr;
134*2383Swnj 	register struct mba_regs *mbp;
135*2383Swnj 
136*2383Swnj 	dprintf("mbstart\n");
137*2383Swnj loop:
138*2383Swnj 	/*
139*2383Swnj 	 * Look for an operation at the front of the queue.
140*2383Swnj 	 */
141*2383Swnj 	if ((mi = mhp->mh_actf) == NULL) {
142*2383Swnj 		dprintf("nothing to do\n");
143*2383Swnj 		return;
144*2383Swnj 	}
145*2383Swnj 	if ((bp = mi->mi_tab.b_actf) == NULL) {
146*2383Swnj 		dprintf("nothing on actf\n");
147*2383Swnj 		mhp->mh_actf = mi->mi_forw;
148*2383Swnj 		goto loop;
149*2383Swnj 	}
150*2383Swnj 	/*
151*2383Swnj 	 * If this device isn't present and on-line, then
152*2383Swnj 	 * we screwed up, and can't really do the operation.
153*2383Swnj 	 */
154*2383Swnj 	if ((mi->mi_drv->mbd_ds & (MBD_DPR|MBD_MOL)) != (MBD_DPR|MBD_MOL)) {
155*2383Swnj 		dprintf("not on line ds %x\n", mi->mi_drv->mbd_ds);
156*2383Swnj 		mi->mi_tab.b_actf = bp->av_forw;
157*2383Swnj 		bp->b_flags |= B_ERROR;
158*2383Swnj 		iodone(bp);
159*2383Swnj 		goto loop;
160*2383Swnj 	}
161*2383Swnj 	/*
162*2383Swnj 	 * We can do the operation; mark the massbus active
163*2383Swnj 	 * and let the device start routine setup any necessary
164*2383Swnj 	 * device state for the transfer (e.g. desired cylinder, etc
165*2383Swnj 	 * on disks).
166*2383Swnj 	 */
167*2383Swnj 	mhp->mh_active = 1;
168*2383Swnj 	if (mi->mi_driver->md_start) {
169*2383Swnj 		dprintf("md_start\n");
170*2383Swnj 		(*mi->mi_driver->md_start)(mi);
171*2383Swnj 	}
172*2383Swnj 
173*2383Swnj 	/*
174*2383Swnj 	 * Setup the massbus control and map registers and start
175*2383Swnj 	 * the transfer.
176*2383Swnj 	 */
177*2383Swnj 	dprintf("start mba\n");
178*2383Swnj 	mbp = mi->mi_mba;
179*2383Swnj 	mbp->mba_sr = -1;	/* conservative */
180*2383Swnj 	mbp->mba_var = mbasetup(mi);
181*2383Swnj 	mbp->mba_bcr = -bp->b_bcount;
182*2383Swnj 	mi->mi_drv->mbd_cs1 =
183*2383Swnj 	    (bp->b_flags & B_READ) ? MBD_RCOM|MBD_GO : MBD_WCOM|MBD_GO;
184*2383Swnj 	if (mi->mi_dk >= 0) {
185*2383Swnj 		dk_busy |= 1 << mi->mi_dk;
186*2383Swnj 		dk_xfer[mi->mi_dk]++;
187*2383Swnj 		dk_wds[mi->mi_dk] += bp->b_bcount >> 6;
188*2383Swnj 	}
189*2383Swnj }
190*2383Swnj 
191*2383Swnj /*
192*2383Swnj  * Take an interrupt off of massbus mbanum,
193*2383Swnj  * and dispatch to drivers as appropriate.
194*2383Swnj  */
195*2383Swnj mbintr(mbanum)
196*2383Swnj 	int mbanum;
197*2383Swnj {
198*2383Swnj 	register struct mba_hd *mhp = &mba_hd[mbanum];
199*2383Swnj 	register struct mba_regs *mbp = mhp->mh_mba;
200*2383Swnj 	register struct mba_info *mi;
201420Sbill 	register struct buf *bp;
202*2383Swnj 	register int drive;
203*2383Swnj 	int mbastat, as;
204*2383Swnj 
205*2383Swnj 	/*
206*2383Swnj 	 * Read out the massbus status register
207*2383Swnj 	 * and attention status register and clear
208*2383Swnj 	 * the bits in same by writing them back.
209*2383Swnj 	 */
210*2383Swnj 	mbastat = mbp->mba_sr;
211*2383Swnj 	mbp->mba_sr = mbastat;
212*2383Swnj 	/* note: the mbd_as register is shared between drives */
213*2383Swnj 	as = mbp->mba_drv[0].mbd_as;
214*2383Swnj 	mbp->mba_drv[0].mbd_as = as;
215*2383Swnj 	dprintf("mbintr mbastat %x as %x\n", mbastat, as);
216*2383Swnj 
217*2383Swnj 	/*
218*2383Swnj 	 * Disable interrupts from the massbus adapter
219*2383Swnj 	 * for the duration of the operation of the massbus
220*2383Swnj 	 * driver, so that spurious interrupts won't be generated.
221*2383Swnj 	 */
222*2383Swnj 	mbp->mba_cr &= ~MBAIE;
223*2383Swnj 
224*2383Swnj 	/*
225*2383Swnj 	 * If the mba was active, process the data transfer
226*2383Swnj 	 * complete interrupt; otherwise just process units which
227*2383Swnj 	 * are now finished.
228*2383Swnj 	 */
229*2383Swnj 	if (mhp->mh_active) {
230*2383Swnj 		if ((mbastat & MBS_DTCMP) == 0) {
231*2383Swnj 			printf("mbintr(%d),b_active,no DTCMP!\n", mbanum);
232*2383Swnj 			goto doattn;
233*2383Swnj #include "../h/buf.h"
234*2383Swnj 		/*
235*2383Swnj 		 * Clear attention status for drive whose data
236*2383Swnj 		 * transfer completed, and give the dtint driver
237*2383Swnj 		 * routine a chance to say what is next.
238*2383Swnj 		 */
239*2383Swnj 		mi = mhp->mh_actf;
240*2383Swnj 		as &= ~(1 << mi->mi_drive);
241*2383Swnj 		dk_busy &= ~(1 << mi->mi_dk);
242*2383Swnj 		bp = mi->mi_tab.b_actf;
243*2383Swnj 		switch((*mi->mi_driver->md_dtint)(mi, mbastat)) {
244*2383Swnj 
245*2383Swnj 		case MBD_DONE:		/* all done, for better or worse */
246*2383Swnj 			dprintf("mbd_done\n");
247*2383Swnj 			/*
248*2383Swnj 			 * Flush request from drive queue.
249*2383Swnj 			 */
250*2383Swnj 			mi->mi_tab.b_errcnt = 0;
251*2383Swnj 			mi->mi_tab.b_actf = bp->av_forw;
252*2383Swnj 			iodone(bp);
253*2383Swnj 			/* fall into... */
254*2383Swnj 		case MBD_RETRY:		/* attempt the operation again */
255*2383Swnj 			dprintf("mbd_retry\n");
256*2383Swnj 			/*
257*2383Swnj 			 * Dequeue data transfer from massbus queue;
258*2383Swnj 			 * if there is still a i/o request on the device
259*2383Swnj 			 * queue then start the next operation on the device.
260*2383Swnj 			 * (Common code for DONE and RETRY).
261*2383Swnj 			 */
262*2383Swnj 			mhp->mh_active = 0;
263*2383Swnj 			mi->mi_tab.b_active = 0;
264*2383Swnj 			mhp->mh_actf = mi->mi_forw;
265*2383Swnj 			if (mi->mi_tab.b_actf)
266*2383Swnj 				mbustart(mi);
267*2383Swnj 			break;
268*2383Swnj 
269*2383Swnj 		case MBD_RESTARTED:	/* driver restarted op (ecc, e.g.)
270*2383Swnj 			dprintf("mbd_restarted\n");
271*2383Swnj 			/*
272*2383Swnj 			 * Note that mp->b_active is still on.
273*2383Swnj 			 */
274*2383Swnj 			break;
275*2383Swnj 
276*2383Swnj 		default:
277*2383Swnj 			panic("mbaintr");
278*2383Swnj 		}
279*2383Swnj 	} else {
280*2383Swnj 		dprintf("!dtcmp\n");
281*2383Swnj 		if (mbastat & MBS_DTCMP)
282*2383Swnj 			printf("mbaintr,DTCMP,!b_active\n");
283*2383Swnj 	}
284*2383Swnj doattn:
285*2383Swnj 	/*
286*2383Swnj 	 * Service drives which require attention
287*2383Swnj 	 * after non-data-transfer operations.
288*2383Swnj 	 */
289*2383Swnj 	for (drive = 0; as && drive < 8; drive++)
290*2383Swnj 		if (as & (1 << drive)) {
291*2383Swnj 			dprintf("service as %d\n", drive);
292*2383Swnj 			as &= ~(1 << drive);
293*2383Swnj 			/*
294*2383Swnj 			 * Consistency check the implied attention,
295*2383Swnj 			 * to make sure the drive should have interrupted.
296*2383Swnj 			 */
297*2383Swnj 			mi = mhp->mh_mbip[drive];
298*2383Swnj 			if (mi == NULL)
299*2383Swnj 				goto random;		/* no such drive */
300*2383Swnj 			if (mi->mi_tab.b_active == 0 &&
301*2383Swnj 			    (mi->mi_tab.b_flags&B_BUSY) == 0)
302*2383Swnj 				goto random;		/* not active */
303*2383Swnj 			if ((bp = mi->mi_tab.b_actf) == NULL) {
304*2383Swnj 							/* nothing doing */
305*2383Swnj random:
306*2383Swnj 				printf("random mbaintr %d %d\n",mbanum,drive);
307*2383Swnj 				continue;
308*2383Swnj 			}
309*2383Swnj 			/*
310*2383Swnj 			 * If this interrupt wasn't a notification that
311*2383Swnj 			 * a dual ported drive is available, and if the
312*2383Swnj 			 * driver has a handler for non-data transfer
313*2383Swnj 			 * interrupts, give it a chance to tell us that
314*2383Swnj 			 * the operation needs to be redone
315*2383Swnj 			 */
316*2383Swnj 			if ((mi->mi_tab.b_flags&B_BUSY) == 0 &&
317*2383Swnj 			    mi->mi_driver->md_ndint) {
318*2383Swnj 				mi->mi_tab.b_active = 0;
319*2383Swnj 				switch((*mi->mi_driver->md_ndint)(mi)) {
320*2383Swnj 
321*2383Swnj 				case MBN_DONE:
322*2383Swnj 					dprintf("mbn_done\n");
323*2383Swnj 					/*
324*2383Swnj 					 * Non-data transfer interrupt
325*2383Swnj 					 * completed i/o request's processing.
326*2383Swnj 					 */
327*2383Swnj 					mi->mi_tab.b_errcnt = 0;
328*2383Swnj 					mi->mi_tab.b_actf = bp->av_forw;
329*2383Swnj 					iodone(bp);
330*2383Swnj 					/* fall into... */
331*2383Swnj 				case MBN_RETRY:
332*2383Swnj 					dprintf("mbn_retry\n");
333*2383Swnj 					if (mi->mi_tab.b_actf)
334*2383Swnj 						mbustart(mi);
335*2383Swnj 					break;
336*2383Swnj 
337*2383Swnj 				default:
338*2383Swnj 					panic("mbintr ndint");
339*2383Swnj 				}
340*2383Swnj 			} else
341*2383Swnj 				mbustart(mi);
342*2383Swnj 		}
343*2383Swnj 	/*
344*2383Swnj 	 * If there is an operation available and
345*2383Swnj 	 * the massbus isn't active, get it going.
346*2383Swnj 	 */
347*2383Swnj 	if (mhp->mh_actf && !mhp->mh_active)
348*2383Swnj 		mbstart(mhp);
349*2383Swnj 	mbp->mba_cr |= MBAIE;
350*2383Swnj }
351*2383Swnj 
352*2383Swnj /*
353*2383Swnj  * Setup the mapping registers for a transfer.
354*2383Swnj  */
355*2383Swnj mbasetup(mi)
356*2383Swnj 	register struct mba_info *mi;
35728Sbill {
358*2383Swnj 	register struct mba_regs *mbap = mi->mi_mba;
359*2383Swnj 	struct buf *bp = mi->mi_tab.b_actf;
36028Sbill 	register int i;
36128Sbill 	int npf;
36228Sbill 	unsigned v;
36328Sbill 	register struct pte *pte, *io;
36428Sbill 	int o;
36528Sbill 	int vaddr;
36628Sbill 	struct proc *rp;
36728Sbill 
3681412Sbill 	io = mbap->mba_map;
3691412Sbill 	v = btop(bp->b_un.b_addr);
3701412Sbill 	o = (int)bp->b_un.b_addr & PGOFSET;
3711412Sbill 	npf = btoc(bp->b_bcount + o);
3721412Sbill 	rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;
3731412Sbill 	vaddr = o;
3741412Sbill 	if (bp->b_flags & B_UAREA) {
3751412Sbill 		for (i = 0; i < UPAGES; i++) {
3761412Sbill 			if (rp->p_addr[i].pg_pfnum == 0)
3771412Sbill 				panic("mba: zero upage");
3781412Sbill 			*(int *)io++ = rp->p_addr[i].pg_pfnum | PG_V;
37928Sbill 		}
3801412Sbill 	} else if ((bp->b_flags & B_PHYS) == 0) {
3811412Sbill 		pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)];
3821412Sbill 		while (--npf >= 0)
3831412Sbill 			*(int *)io++ = pte++->pg_pfnum | PG_V;
3841412Sbill 	} else {
3851412Sbill 		if (bp->b_flags & B_PAGET)
3861412Sbill 			pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
3871412Sbill 		else
3881412Sbill 			pte = vtopte(rp, v);
3891412Sbill 		while (--npf >= 0) {
3901412Sbill 			if (pte->pg_pfnum == 0)
3911412Sbill 				panic("mba, zero entry");
3921412Sbill 			*(int *)io++ = pte++->pg_pfnum | PG_V;
3931412Sbill 		}
39428Sbill 	}
3951412Sbill 	*(int *)io++ = 0;
396*2383Swnj 	return (vaddr);
39728Sbill }
398