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