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