xref: /original-bsd/sys/vax/mba/mba.c (revision 6c57d260)
1 /*	mba.c	4.20	81/05/09	*/
2 
3 #include "mba.h"
4 #if NMBA > 0
5 /*
6  * Massbus driver, arbitrates a massbus among attached devices.
7  */
8 #include "../h/param.h"
9 #include "../h/systm.h"
10 #include "../h/dk.h"
11 #include "../h/buf.h"
12 #include "../h/conf.h"
13 #include "../h/dir.h"
14 #include "../h/user.h"
15 #include "../h/proc.h"
16 #include "../h/map.h"
17 #include "../h/pte.h"
18 #include "../h/mbareg.h"
19 #include "../h/mbavar.h"
20 #include "../h/mtpr.h"
21 #include "../h/vm.h"
22 
23 char	mbsr_bits[] = MBSR_BITS;
24 /*
25  * Start activity on a massbus device.
26  * We are given the device's mba_device structure and activate
27  * the device via the unit start routine.  The unit start
28  * routine may indicate that it is finished (e.g. if the operation
29  * was a ``sense'' on a tape drive), that the (multi-ported) unit
30  * is busy (we will get an interrupt later), that it started the
31  * unit (e.g. for a non-data transfer operation), or that it has
32  * set up a data transfer operation and we should start the massbus adaptor.
33  */
34 mbustart(mi)
35 	register struct mba_device *mi;
36 {
37 	register struct buf *bp;	/* i/o operation at head of queue */
38 	register struct mba_hd *mhp;	/* header for mba device is on */
39 
40 loop:
41 	/*
42 	 * Get the first thing to do off device queue.
43 	 */
44 	bp = mi->mi_tab.b_actf;
45 	if (bp == NULL)
46 		return;
47 	/*
48 	 * Let the drivers unit start routine have at it
49 	 * and then process the request further, per its instructions.
50 	 */
51 	switch ((*mi->mi_driver->md_ustart)(mi)) {
52 
53 	case MBU_NEXT:		/* request is complete (e.g. ``sense'') */
54 		mi->mi_tab.b_active = 0;
55 		mi->mi_tab.b_errcnt = 0;
56 		mi->mi_tab.b_actf = bp->av_forw;
57 		iodone(bp);
58 		goto loop;
59 
60 	case MBU_DODATA:	/* all ready to do data transfer */
61 		/*
62 		 * Queue the device mba_device structure on the massbus
63 		 * mba_hd structure for processing as soon as the
64 		 * data path is available.
65 		 */
66 		mhp = mi->mi_hd;
67 		mi->mi_forw = NULL;
68 		if (mhp->mh_actf == NULL)
69 			mhp->mh_actf = mi;
70 		else
71 			mhp->mh_actl->mi_forw = mi;
72 		mhp->mh_actl = mi;
73 		/*
74 		 * If data path is idle, start transfer now.
75 		 * In any case the device is ``active'' waiting for the
76 		 * data to transfer.
77 		 */
78 		mi->mi_tab.b_active = 1;
79 		if (mhp->mh_active == 0)
80 			mbstart(mhp);
81 		return;
82 
83 	case MBU_STARTED:	/* driver started a non-data transfer */
84 		/*
85 		 * Mark device busy during non-data transfer
86 		 * and count this as a ``seek'' on the device.
87 		 */
88 		if (mi->mi_dk >= 0) {
89 			dk_seek[mi->mi_dk]++;
90 			dk_busy |= (1 << mi->mi_dk);
91 		}
92 		mi->mi_tab.b_active = 1;
93 		return;
94 
95 	case MBU_BUSY:		/* dual port drive busy */
96 		/*
97 		 * We mark the device structure so that when an
98 		 * interrupt occurs we will know to restart the unit.
99 		 */
100 		mi->mi_tab.b_flags |= B_BUSY;
101 		return;
102 
103 	default:
104 		panic("mbustart");
105 	}
106 }
107 
108 /*
109  * Start an i/o operation on the massbus specified by the argument.
110  * We peel the first operation off its queue and insure that the drive
111  * is present and on-line.  We then use the drivers start routine
112  * (if any) to prepare the drive, setup the massbus map for the transfer
113  * and start the transfer.
114  */
115 mbstart(mhp)
116 	register struct mba_hd *mhp;
117 {
118 	register struct mba_device *mi;
119 	struct buf *bp;
120 	register struct mba_regs *mbp;
121 	register int com;
122 
123 loop:
124 	/*
125 	 * Look for an operation at the front of the queue.
126 	 */
127 	if ((mi = mhp->mh_actf) == NULL) {
128 		return;
129 	}
130 	if ((bp = mi->mi_tab.b_actf) == NULL) {
131 		mhp->mh_actf = mi->mi_forw;
132 		goto loop;
133 	}
134 	/*
135 	 * If this device isn't present and on-line, then
136 	 * we screwed up, and can't really do the operation.
137 	 */
138 	if ((mi->mi_drv->mbd_ds & MBDS_DREADY) != MBDS_DREADY) {
139 		printf("%s%d: not ready\n", mi->mi_driver->md_dname,
140 		    dkunit(bp));
141 		mi->mi_tab.b_actf = bp->av_forw;
142 		mi->mi_tab.b_errcnt = 0;
143 		mi->mi_tab.b_active = 0;
144 		bp->b_flags |= B_ERROR;
145 		iodone(bp);
146 		goto loop;
147 	}
148 	/*
149 	 * We can do the operation; mark the massbus active
150 	 * and let the device start routine setup any necessary
151 	 * device state for the transfer (e.g. desired cylinder, etc
152 	 * on disks).
153 	 */
154 	mhp->mh_active = 1;
155 	if (mi->mi_driver->md_start) {
156 		if ((com = (*mi->mi_driver->md_start)(mi)) == 0)
157 			com = (bp->b_flags & B_READ) ?
158 			    MB_RCOM|MB_GO : MB_WCOM|MB_GO;
159 	} else
160 		com = (bp->b_flags & B_READ) ? MB_RCOM|MB_GO : MB_WCOM|MB_GO;
161 
162 	/*
163 	 * Setup the massbus control and map registers and start
164 	 * the transfer.
165 	 */
166 	mbp = mi->mi_mba;
167 	mbp->mba_sr = -1;	/* conservative */
168 	mbp->mba_var = mbasetup(mi);
169 	mbp->mba_bcr = -bp->b_bcount;
170 	mi->mi_drv->mbd_cs1 = com;
171 	if (mi->mi_dk >= 0) {
172 		dk_busy |= 1 << mi->mi_dk;
173 		dk_xfer[mi->mi_dk]++;
174 		dk_wds[mi->mi_dk] += bp->b_bcount >> 6;
175 	}
176 }
177 
178 /*
179  * Take an interrupt off of massbus mbanum,
180  * and dispatch to drivers as appropriate.
181  */
182 mbintr(mbanum)
183 	int mbanum;
184 {
185 	register struct mba_hd *mhp = &mba_hd[mbanum];
186 	register struct mba_regs *mbp = mhp->mh_mba;
187 	register struct mba_device *mi;
188 	register struct buf *bp;
189 	register int drive;
190 	int mbasr, as;
191 
192 	/*
193 	 * Read out the massbus status register
194 	 * and attention status register and clear
195 	 * the bits in same by writing them back.
196 	 */
197 	mbasr = mbp->mba_sr;
198 	mbp->mba_sr = mbasr;
199 #if VAX750
200 	if (mbasr&MBSR_CBHUNG) {
201 		printf("mba%d: control bus hung\n", mbanum);
202 		panic("cbhung");
203 	}
204 #endif
205 	/* note: the mbd_as register is shared between drives */
206 	as = mbp->mba_drv[0].mbd_as & 0xff;
207 	mbp->mba_drv[0].mbd_as = as;
208 
209 	/*
210 	 * If the mba was active, process the data transfer
211 	 * complete interrupt; otherwise just process units which
212 	 * are now finished.
213 	 */
214 	if (mhp->mh_active) {
215 		/*
216 		 * Clear attention status for drive whose data
217 		 * transfer related operation completed,
218 		 * and give the dtint driver
219 		 * routine a chance to say what is next.
220 		 */
221 		mi = mhp->mh_actf;
222 		as &= ~(1 << mi->mi_drive);
223 		dk_busy &= ~(1 << mi->mi_dk);
224 		bp = mi->mi_tab.b_actf;
225 		switch ((*mi->mi_driver->md_dtint)(mi, mbasr)) {
226 
227 		case MBD_DONE:		/* all done, for better or worse */
228 			/*
229 			 * Flush request from drive queue.
230 			 */
231 			mi->mi_tab.b_errcnt = 0;
232 			mi->mi_tab.b_actf = bp->av_forw;
233 			iodone(bp);
234 			/* fall into... */
235 		case MBD_RETRY:		/* attempt the operation again */
236 			/*
237 			 * Dequeue data transfer from massbus queue;
238 			 * if there is still a i/o request on the device
239 			 * queue then start the next operation on the device.
240 			 * (Common code for DONE and RETRY).
241 			 */
242 			mhp->mh_active = 0;
243 			mi->mi_tab.b_active = 0;
244 			mhp->mh_actf = mi->mi_forw;
245 			if (mi->mi_tab.b_actf)
246 				mbustart(mi);
247 			break;
248 
249 		case MBD_RESTARTED:	/* driver restarted op (ecc, e.g.)
250 			/*
251 			 * Note that mhp->mh_active is still on.
252 			 */
253 			break;
254 
255 		default:
256 			panic("mbintr");
257 		}
258 	}
259 	/*
260 	 * Service drives which require attention
261 	 * after non-data-transfer operations.
262 	 */
263 	while (drive = ffs(as)) {
264 		drive--;		/* was 1 origin */
265 		as &= ~(1 << drive);
266 		mi = mhp->mh_mbip[drive];
267 		if (mi == NULL)
268 			continue;
269 		/*
270 		 * If driver has a handler for non-data transfer
271 		 * interrupts, give it a chance to tell us what to do.
272 		 */
273 		if (mi->mi_driver->md_ndint) {
274 			mi->mi_tab.b_active = 0;
275 			switch ((*mi->mi_driver->md_ndint)(mi)) {
276 
277 			case MBN_DONE:		/* operation completed */
278 				mi->mi_tab.b_errcnt = 0;
279 				bp = mi->mi_tab.b_actf;
280 				mi->mi_tab.b_actf = bp->av_forw;
281 				iodone(bp);
282 				/* fall into common code */
283 			case MBN_RETRY:		/* operation continues */
284 				if (mi->mi_tab.b_actf)
285 					mbustart(mi);
286 				break;
287 			case MBN_SKIP:		/* ignore unsol. interrupt */
288 				break;
289 			default:
290 				panic("mbintr");
291 			}
292 		} else
293 			/*
294 			 * If there is no non-data transfer interrupt
295 			 * routine, then we should just
296 			 * restart the unit, leading to a mbstart() soon.
297 			 */
298 			mbustart(mi);
299 	}
300 	/*
301 	 * If there is an operation available and
302 	 * the massbus isn't active, get it going.
303 	 */
304 	if (mhp->mh_actf && !mhp->mh_active)
305 		mbstart(mhp);
306 	/* THHHHATS all folks... */
307 }
308 
309 /*
310  * Setup the mapping registers for a transfer.
311  */
312 mbasetup(mi)
313 	register struct mba_device *mi;
314 {
315 	register struct mba_regs *mbap = mi->mi_mba;
316 	struct buf *bp = mi->mi_tab.b_actf;
317 	register int i;
318 	int npf;
319 	unsigned v;
320 	register struct pte *pte, *io;
321 	int o;
322 	int vaddr;
323 	struct proc *rp;
324 
325 	io = mbap->mba_map;
326 	v = btop(bp->b_un.b_addr);
327 	o = (int)bp->b_un.b_addr & PGOFSET;
328 	npf = btoc(bp->b_bcount + o);
329 	rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;
330 	vaddr = o;
331 	if (bp->b_flags & B_UAREA) {
332 		for (i = 0; i < UPAGES; i++) {
333 			if (rp->p_addr[i].pg_pfnum == 0)
334 				panic("mba: zero upage");
335 			*(int *)io++ = rp->p_addr[i].pg_pfnum | PG_V;
336 		}
337 	} else if ((bp->b_flags & B_PHYS) == 0) {
338 		pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)];
339 		while (--npf >= 0)
340 			*(int *)io++ = pte++->pg_pfnum | PG_V;
341 	} else {
342 		if (bp->b_flags & B_PAGET)
343 			pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
344 		else
345 			pte = vtopte(rp, v);
346 		while (--npf >= 0) {
347 			if (pte->pg_pfnum == 0)
348 				panic("mba, zero entry");
349 			*(int *)io++ = pte++->pg_pfnum | PG_V;
350 		}
351 	}
352 	*(int *)io++ = 0;
353 	return (vaddr);
354 }
355 
356 /*
357  * Init and interrupt enable a massbus adapter.
358  */
359 mbainit(mp)
360 	struct mba_regs *mp;
361 {
362 
363 	mp->mba_cr = MBCR_INIT;
364 	mp->mba_cr = MBCR_IE;
365 }
366 #endif
367