Commit | Line | Data |
---|---|---|
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 | 24 | char 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 | 35 | mbustart(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 |
41 | loop: |
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 | */ | |
114 | mbstart(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 |
121 | loop: |
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 | */ | |
177 | mbintr(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 | */ | |
327 | mbasetup(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 | |
371 | mbainit(mp) | |
372 | struct mba_regs *mp; | |
373 | { | |
374 | ||
375 | mp->mba_cr = MBAINIT; | |
376 | mp->mba_cr = MBAIE; | |
377 | } | |
443c8066 | 378 | #endif |