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