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