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