1 /* mba.c 4.6 81/02/15 */ 2 3 /* 4 * Massbus driver; arbitrates massbusses through device driver routines 5 * and provides common functions. 6 */ 7 int mbadebug = 0; 8 #define dprintf if (mbadebug) printf 9 10 #include "../h/param.h" 11 #include "../h/systm.h" 12 #include "../h/dk.h" 13 #include "../h/buf.h" 14 #include "../h/conf.h" 15 #include "../h/dir.h" 16 #include "../h/user.h" 17 #include "../h/proc.h" 18 #include "../h/map.h" 19 #include "../h/pte.h" 20 #include "../h/mba.h" 21 #include "../h/mtpr.h" 22 #include "../h/vm.h" 23 24 /* 25 * Start activity on a massbus device. 26 * We are given the device's mba_info structure and activate 27 * the device via the unit start routine. The unit start 28 * routine may indicate that it is finished (e.g. if the operation 29 * was a ``sense'' on a tape drive), that the (multi-ported) unit 30 * is busy (we will get an interrupt later), that it started the 31 * unit (e.g. for a non-data transfer operation), or that it has 32 * set up a data transfer operation and we should start the massbus adaptor. 33 */ 34 mbustart(mi) 35 register struct mba_info *mi; 36 { 37 register struct mba_drv *mdp; /* drive registers */ 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 41 dprintf("enter mbustart\n"); 42 loop: 43 /* 44 * Get the first thing to do off device queue. 45 */ 46 bp = mi->mi_tab.b_actf; 47 if (bp == NULL) 48 return; 49 mdp = mi->mi_drv; 50 /* 51 * Since we clear attentions on the drive when we are 52 * finished processing it, the fact that an attention 53 * status shows indicated confusion in the hardware or our logic. 54 */ 55 if (mdp->mbd_as & (1 << mi->mi_drive)) { 56 printf("mbustart: ata on for %d\n", mi->mi_drive); 57 mdp->mbd_as = 1 << mi->mi_drive; 58 } 59 /* 60 * Let the drivers unit start routine have at it 61 * and then process the request further, per its instructions. 62 */ 63 switch ((*mi->mi_driver->md_ustart)(mi)) { 64 65 case MBU_NEXT: /* request is complete (e.g. ``sense'') */ 66 dprintf("mbu_next\n"); 67 mi->mi_tab.b_active = 0; 68 mi->mi_tab.b_actf = bp->av_forw; 69 iodone(bp); 70 goto loop; 71 72 case MBU_DODATA: /* all ready to do data transfer */ 73 dprintf("mbu_dodata\n"); 74 /* 75 * Queue the device mba_info structure on the massbus 76 * mba_hd structure for processing as soon as the 77 * data path is available. 78 */ 79 mhp = mi->mi_hd; 80 mi->mi_forw = NULL; 81 if (mhp->mh_actf == NULL) 82 mhp->mh_actf = mi; 83 else 84 mhp->mh_actl->mi_forw = mi; 85 mhp->mh_actl = mi; 86 /* 87 * If data path is idle, start transfer now. 88 * In any case the device is ``active'' waiting for the 89 * data to transfer. 90 */ 91 if (mhp->mh_active == 0) 92 mbstart(mhp); 93 mi->mi_tab.b_active = 1; 94 return; 95 96 case MBU_STARTED: /* driver started a non-data transfer */ 97 dprintf("mbu_started\n"); 98 /* 99 * Mark device busy during non-data transfer 100 * and count this as a ``seek'' on the device. 101 */ 102 if (mi->mi_dk >= 0) 103 dk_seek[mi->mi_dk]++; 104 mi->mi_tab.b_active = 1; 105 return; 106 107 case MBU_BUSY: /* dual port drive busy */ 108 dprintf("mbu_busy\n"); 109 /* 110 * We mark the device structure so that when an 111 * interrupt occurs we will know to restart the unit. 112 */ 113 mi->mi_tab.b_flags |= B_BUSY; 114 return; 115 116 default: 117 panic("mbustart"); 118 } 119 } 120 121 /* 122 * Start an i/o operation on the massbus specified by the argument. 123 * We peel the first operation off its queue and insure that the drive 124 * is present and on-line. We then use the drivers start routine 125 * (if any) to prepare the drive, setup the massbus map for the transfer 126 * and start the transfer. 127 */ 128 mbstart(mhp) 129 register struct mba_hd *mhp; 130 { 131 register struct mba_info *mi; 132 struct buf *bp; 133 register struct mba_drv *daddr; 134 register struct mba_regs *mbp; 135 136 dprintf("mbstart\n"); 137 loop: 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 } 190 191 /* 192 * Take an interrupt off of massbus mbanum, 193 * and dispatch to drivers as appropriate. 194 */ 195 mbintr(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; 201 register struct buf *bp; 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; 233 } 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 } 284 doattn: 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 */ 305 random: 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 */ 355 mbasetup(mi) 356 register struct mba_info *mi; 357 { 358 register struct mba_regs *mbap = mi->mi_mba; 359 struct buf *bp = mi->mi_tab.b_actf; 360 register int i; 361 int npf; 362 unsigned v; 363 register struct pte *pte, *io; 364 int o; 365 int vaddr; 366 struct proc *rp; 367 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; 393 } 394 } 395 *(int *)io++ = 0; 396 return (vaddr); 397 } 398