1*6537Ssam /* mba.c 4.26 82/04/11 */ 228Sbill 32704Swnj #include "mba.h" 42704Swnj #if NMBA > 0 52383Swnj /* 63095Swnj * Massbus driver, arbitrates a massbus among attached devices. 72383Swnj */ 828Sbill #include "../h/param.h" 92383Swnj #include "../h/systm.h" 102383Swnj #include "../h/dk.h" 1128Sbill #include "../h/buf.h" 1228Sbill #include "../h/conf.h" 1328Sbill #include "../h/dir.h" 1428Sbill #include "../h/user.h" 1528Sbill #include "../h/proc.h" 162383Swnj #include "../h/map.h" 1728Sbill #include "../h/pte.h" 182981Swnj #include "../h/mbareg.h" 192981Swnj #include "../h/mbavar.h" 2028Sbill #include "../h/mtpr.h" 2128Sbill #include "../h/vm.h" 2228Sbill 233095Swnj char mbsr_bits[] = MBSR_BITS; 2428Sbill /* 252383Swnj * Start activity on a massbus device. 262981Swnj * We are given the device's mba_device structure and activate 272383Swnj * the device via the unit start routine. The unit start 282383Swnj * routine may indicate that it is finished (e.g. if the operation 292383Swnj * was a ``sense'' on a tape drive), that the (multi-ported) unit 302383Swnj * is busy (we will get an interrupt later), that it started the 312383Swnj * unit (e.g. for a non-data transfer operation), or that it has 322383Swnj * set up a data transfer operation and we should start the massbus adaptor. 3328Sbill */ 342383Swnj mbustart(mi) 352981Swnj register struct mba_device *mi; 362383Swnj { 372383Swnj register struct buf *bp; /* i/o operation at head of queue */ 382383Swnj register struct mba_hd *mhp; /* header for mba device is on */ 3928Sbill 402383Swnj loop: 412383Swnj /* 422383Swnj * Get the first thing to do off device queue. 432383Swnj */ 442383Swnj bp = mi->mi_tab.b_actf; 452383Swnj if (bp == NULL) 462383Swnj return; 472383Swnj /* 48*6537Ssam * Make sure the drive is still there before starting it up. 49*6537Ssam */ 50*6537Ssam if ((mi->mi_drv->mbd_dt & MBDT_TYPE) == 0) { 51*6537Ssam printf("%s%d: nonexistent\n", mi->mi_driver->md_dname, 52*6537Ssam dkunit(bp)); 53*6537Ssam mi->mi_alive = 0; 54*6537Ssam mi->mi_tab.b_actf = bp->av_forw; 55*6537Ssam mi->mi_tab.b_active = 0; 56*6537Ssam mi->mi_tab.b_errcnt = 0; 57*6537Ssam bp->b_flags |= B_ERROR; 58*6537Ssam iodone(bp); 59*6537Ssam goto loop; 60*6537Ssam } 61*6537Ssam /* 622383Swnj * Let the drivers unit start routine have at it 632383Swnj * and then process the request further, per its instructions. 642383Swnj */ 652383Swnj switch ((*mi->mi_driver->md_ustart)(mi)) { 662383Swnj 672383Swnj case MBU_NEXT: /* request is complete (e.g. ``sense'') */ 682383Swnj mi->mi_tab.b_active = 0; 692955Swnj mi->mi_tab.b_errcnt = 0; 702383Swnj mi->mi_tab.b_actf = bp->av_forw; 712383Swnj iodone(bp); 722383Swnj goto loop; 732383Swnj 742383Swnj case MBU_DODATA: /* all ready to do data transfer */ 752383Swnj /* 762981Swnj * Queue the device mba_device structure on the massbus 772383Swnj * mba_hd structure for processing as soon as the 782383Swnj * data path is available. 792383Swnj */ 802383Swnj mhp = mi->mi_hd; 812383Swnj mi->mi_forw = NULL; 822383Swnj if (mhp->mh_actf == NULL) 832383Swnj mhp->mh_actf = mi; 842383Swnj else 852383Swnj mhp->mh_actl->mi_forw = mi; 862383Swnj mhp->mh_actl = mi; 872383Swnj /* 882383Swnj * If data path is idle, start transfer now. 892383Swnj * In any case the device is ``active'' waiting for the 902383Swnj * data to transfer. 912383Swnj */ 922893Swnj mi->mi_tab.b_active = 1; 932383Swnj if (mhp->mh_active == 0) 942383Swnj mbstart(mhp); 952383Swnj return; 962383Swnj 972383Swnj case MBU_STARTED: /* driver started a non-data transfer */ 982383Swnj /* 992383Swnj * Mark device busy during non-data transfer 1002383Swnj * and count this as a ``seek'' on the device. 1012383Swnj */ 1023182Swnj if (mi->mi_dk >= 0) { 1032383Swnj dk_seek[mi->mi_dk]++; 1043182Swnj dk_busy |= (1 << mi->mi_dk); 1053182Swnj } 1062383Swnj mi->mi_tab.b_active = 1; 1072383Swnj return; 1082383Swnj 1092383Swnj case MBU_BUSY: /* dual port drive busy */ 1102383Swnj /* 1112383Swnj * We mark the device structure so that when an 1122383Swnj * interrupt occurs we will know to restart the unit. 1132383Swnj */ 1142383Swnj mi->mi_tab.b_flags |= B_BUSY; 1152383Swnj return; 1162383Swnj 1172383Swnj default: 1182383Swnj panic("mbustart"); 1192383Swnj } 1202403Skre } 1212383Swnj 1222383Swnj /* 1232383Swnj * Start an i/o operation on the massbus specified by the argument. 1242383Swnj * We peel the first operation off its queue and insure that the drive 1252383Swnj * is present and on-line. We then use the drivers start routine 1262383Swnj * (if any) to prepare the drive, setup the massbus map for the transfer 1272383Swnj * and start the transfer. 1282383Swnj */ 1292383Swnj mbstart(mhp) 1302383Swnj register struct mba_hd *mhp; 1312383Swnj { 1322981Swnj register struct mba_device *mi; 1332383Swnj struct buf *bp; 1342383Swnj register struct mba_regs *mbp; 1353708Sroot register int com; 1362383Swnj 1372383Swnj loop: 1382383Swnj /* 1392383Swnj * Look for an operation at the front of the queue. 1402383Swnj */ 1412955Swnj if ((mi = mhp->mh_actf) == NULL) { 1422383Swnj return; 1432955Swnj } 1442383Swnj if ((bp = mi->mi_tab.b_actf) == NULL) { 1452383Swnj mhp->mh_actf = mi->mi_forw; 1462383Swnj goto loop; 1472383Swnj } 1482383Swnj /* 1492383Swnj * If this device isn't present and on-line, then 1502383Swnj * we screwed up, and can't really do the operation. 1514757Swnj * Only check for non-tapes because tape drivers check 1524757Swnj * ONLINE themselves and because TU78 registers are 1534757Swnj * different. 1542383Swnj */ 155*6537Ssam if (((com = mi->mi_drv->mbd_dt) & MBDT_TAP) == 0) 1563095Swnj if ((mi->mi_drv->mbd_ds & MBDS_DREADY) != MBDS_DREADY) { 157*6537Ssam if ((com & MBDT_TYPE) == 0) { 158*6537Ssam mi->mi_alive = 0; 159*6537Ssam printf("%s%d: nonexistent\n", mi->mi_driver->md_dname, 160*6537Ssam dkunit(bp)); 161*6537Ssam } else 162*6537Ssam printf("%s%d: not ready\n", mi->mi_driver->md_dname, 163*6537Ssam dkunit(bp)); 1642383Swnj mi->mi_tab.b_actf = bp->av_forw; 1652893Swnj mi->mi_tab.b_errcnt = 0; 1662893Swnj mi->mi_tab.b_active = 0; 1672383Swnj bp->b_flags |= B_ERROR; 1682383Swnj iodone(bp); 1692383Swnj goto loop; 1702383Swnj } 1712383Swnj /* 1722383Swnj * We can do the operation; mark the massbus active 1732383Swnj * and let the device start routine setup any necessary 1742383Swnj * device state for the transfer (e.g. desired cylinder, etc 1752383Swnj * on disks). 1762383Swnj */ 1772383Swnj mhp->mh_active = 1; 1783708Sroot if (mi->mi_driver->md_start) { 1793708Sroot if ((com = (*mi->mi_driver->md_start)(mi)) == 0) 1803708Sroot com = (bp->b_flags & B_READ) ? 1813708Sroot MB_RCOM|MB_GO : MB_WCOM|MB_GO; 1823708Sroot } else 1833708Sroot com = (bp->b_flags & B_READ) ? MB_RCOM|MB_GO : MB_WCOM|MB_GO; 1842383Swnj 1852383Swnj /* 1862383Swnj * Setup the massbus control and map registers and start 1872383Swnj * the transfer. 1882383Swnj */ 1892383Swnj mbp = mi->mi_mba; 1902383Swnj mbp->mba_sr = -1; /* conservative */ 1912383Swnj mbp->mba_var = mbasetup(mi); 1922383Swnj mbp->mba_bcr = -bp->b_bcount; 1933708Sroot mi->mi_drv->mbd_cs1 = com; 1942383Swnj if (mi->mi_dk >= 0) { 1952383Swnj dk_busy |= 1 << mi->mi_dk; 1962383Swnj dk_xfer[mi->mi_dk]++; 1972383Swnj dk_wds[mi->mi_dk] += bp->b_bcount >> 6; 1982383Swnj } 1992383Swnj } 2002383Swnj 2012383Swnj /* 2022383Swnj * Take an interrupt off of massbus mbanum, 2032383Swnj * and dispatch to drivers as appropriate. 2042383Swnj */ 2052383Swnj mbintr(mbanum) 2062383Swnj int mbanum; 2072383Swnj { 2082383Swnj register struct mba_hd *mhp = &mba_hd[mbanum]; 2092383Swnj register struct mba_regs *mbp = mhp->mh_mba; 2102981Swnj register struct mba_device *mi; 211420Sbill register struct buf *bp; 2122383Swnj register int drive; 2132955Swnj int mbasr, as; 214*6537Ssam extern struct mba_device *mbaconfig(); 2152383Swnj 2162383Swnj /* 2172383Swnj * Read out the massbus status register 2182383Swnj * and attention status register and clear 2192383Swnj * the bits in same by writing them back. 2202383Swnj */ 2212955Swnj mbasr = mbp->mba_sr; 2222955Swnj mbp->mba_sr = mbasr; 2232884Swnj #if VAX750 2243095Swnj if (mbasr&MBSR_CBHUNG) { 2252930Swnj printf("mba%d: control bus hung\n", mbanum); 2262930Swnj panic("cbhung"); 2272930Swnj } 2282884Swnj #endif 2292383Swnj /* note: the mbd_as register is shared between drives */ 2302955Swnj as = mbp->mba_drv[0].mbd_as & 0xff; 2312383Swnj mbp->mba_drv[0].mbd_as = as; 2322383Swnj 2332383Swnj /* 2342383Swnj * If the mba was active, process the data transfer 2352383Swnj * complete interrupt; otherwise just process units which 2362383Swnj * are now finished. 2372383Swnj */ 2382383Swnj if (mhp->mh_active) { 2392383Swnj /* 2402383Swnj * Clear attention status for drive whose data 2413095Swnj * transfer related operation completed, 2423095Swnj * and give the dtint driver 2432383Swnj * routine a chance to say what is next. 2442383Swnj */ 2452383Swnj mi = mhp->mh_actf; 2462383Swnj as &= ~(1 << mi->mi_drive); 2472383Swnj dk_busy &= ~(1 << mi->mi_dk); 2482383Swnj bp = mi->mi_tab.b_actf; 2493095Swnj switch ((*mi->mi_driver->md_dtint)(mi, mbasr)) { 2502383Swnj 2512383Swnj case MBD_DONE: /* all done, for better or worse */ 2522383Swnj /* 2532383Swnj * Flush request from drive queue. 2542383Swnj */ 2552383Swnj mi->mi_tab.b_errcnt = 0; 2562383Swnj mi->mi_tab.b_actf = bp->av_forw; 2572383Swnj iodone(bp); 2582383Swnj /* fall into... */ 2592383Swnj case MBD_RETRY: /* attempt the operation again */ 2602383Swnj /* 2612383Swnj * Dequeue data transfer from massbus queue; 2622383Swnj * if there is still a i/o request on the device 2632383Swnj * queue then start the next operation on the device. 2642383Swnj * (Common code for DONE and RETRY). 2652383Swnj */ 2662383Swnj mhp->mh_active = 0; 2672383Swnj mi->mi_tab.b_active = 0; 2682383Swnj mhp->mh_actf = mi->mi_forw; 2692383Swnj if (mi->mi_tab.b_actf) 2702383Swnj mbustart(mi); 2712383Swnj break; 2722383Swnj 2732383Swnj case MBD_RESTARTED: /* driver restarted op (ecc, e.g.) 2742383Swnj /* 2752893Swnj * Note that mhp->mh_active is still on. 2762383Swnj */ 2772383Swnj break; 2782383Swnj 2792383Swnj default: 2802884Swnj panic("mbintr"); 2812383Swnj } 2822383Swnj } 2832383Swnj /* 2842383Swnj * Service drives which require attention 2852383Swnj * after non-data-transfer operations. 2862383Swnj */ 2872955Swnj while (drive = ffs(as)) { 2882955Swnj drive--; /* was 1 origin */ 2892955Swnj as &= ~(1 << drive); 2902981Swnj mi = mhp->mh_mbip[drive]; 291*6537Ssam if (mi == NULL || mi->mi_alive == 0) { 292*6537Ssam struct mba_device fnd; 293*6537Ssam struct mba_slave *ms; 294*6537Ssam struct mba_drv *mbd = &mhp->mh_mba->mba_drv[drive]; 295*6537Ssam int dt = mbd->mbd_dt & 0xffff; 296*6537Ssam 297*6537Ssam if (dt == 0 || dt == MBDT_MOH) 298*6537Ssam continue; 299*6537Ssam fnd.mi_mba = mhp->mh_mba; 300*6537Ssam fnd.mi_mbanum = mbanum; 301*6537Ssam fnd.mi_drive = drive; 302*6537Ssam if ((mi = mbaconfig(&fnd, dt)) == NULL) 303*6537Ssam continue; 304*6537Ssam if (dt & MBDT_TAP) { 305*6537Ssam for (ms = mbsinit; ms->ms_driver; ms++) 306*6537Ssam if (ms->ms_driver == mi->mi_driver && 307*6537Ssam ms->ms_alive == 0 && 308*6537Ssam (ms->ms_ctlr == mi->mi_unit || 309*6537Ssam ms->ms_ctlr == '?')) { 310*6537Ssam if ((*ms->ms_driver->md_slave)(mi, ms)) { 311*6537Ssam printf("%s%d at %s%d slave %d\n", 312*6537Ssam ms->ms_driver->md_sname, 313*6537Ssam ms->ms_unit, 314*6537Ssam mi->mi_driver->md_dname, 315*6537Ssam mi->mi_unit, 316*6537Ssam ms->ms_slave); 317*6537Ssam ms->ms_alive = 1; 318*6537Ssam ms->ms_ctlr = mi->mi_unit; 319*6537Ssam } 320*6537Ssam } 321*6537Ssam } 322*6537Ssam } 3232955Swnj /* 3242981Swnj * If driver has a handler for non-data transfer 3253095Swnj * interrupts, give it a chance to tell us what to do. 3262955Swnj */ 3272955Swnj if (mi->mi_driver->md_ndint) { 3282955Swnj switch ((*mi->mi_driver->md_ndint)(mi)) { 3292383Swnj 3303095Swnj case MBN_DONE: /* operation completed */ 331*6537Ssam mi->mi_tab.b_active = 0; 3322955Swnj mi->mi_tab.b_errcnt = 0; 3332981Swnj bp = mi->mi_tab.b_actf; 3342955Swnj mi->mi_tab.b_actf = bp->av_forw; 3352955Swnj iodone(bp); 3363095Swnj /* fall into common code */ 3373095Swnj case MBN_RETRY: /* operation continues */ 3382955Swnj if (mi->mi_tab.b_actf) 3392955Swnj mbustart(mi); 3402955Swnj break; 3413095Swnj case MBN_SKIP: /* ignore unsol. interrupt */ 3422981Swnj break; 3432955Swnj default: 3442955Swnj panic("mbintr"); 3452955Swnj } 3462955Swnj } else 3473095Swnj /* 3483095Swnj * If there is no non-data transfer interrupt 3493095Swnj * routine, then we should just 3503095Swnj * restart the unit, leading to a mbstart() soon. 3513095Swnj */ 3522955Swnj mbustart(mi); 3532955Swnj } 3542383Swnj /* 3552383Swnj * If there is an operation available and 3562383Swnj * the massbus isn't active, get it going. 3572383Swnj */ 3582383Swnj if (mhp->mh_actf && !mhp->mh_active) 3592383Swnj mbstart(mhp); 3603095Swnj /* THHHHATS all folks... */ 3612383Swnj } 3622383Swnj 3632383Swnj /* 3642383Swnj * Setup the mapping registers for a transfer. 3652383Swnj */ 3662383Swnj mbasetup(mi) 3672981Swnj register struct mba_device *mi; 36828Sbill { 3692383Swnj register struct mba_regs *mbap = mi->mi_mba; 3702383Swnj struct buf *bp = mi->mi_tab.b_actf; 3716381Swnj register int npf; 37228Sbill unsigned v; 37328Sbill register struct pte *pte, *io; 37428Sbill int o; 37528Sbill struct proc *rp; 37628Sbill 3771412Sbill v = btop(bp->b_un.b_addr); 3781412Sbill o = (int)bp->b_un.b_addr & PGOFSET; 3791412Sbill npf = btoc(bp->b_bcount + o); 3801412Sbill rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc; 3816381Swnj if ((bp->b_flags & B_PHYS) == 0) 3821412Sbill pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)]; 3836381Swnj else if (bp->b_flags & B_UAREA) 3846381Swnj pte = &rp->p_addr[v]; 3856381Swnj else if (bp->b_flags & B_PAGET) 3866381Swnj pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)]; 3876381Swnj else 3886381Swnj pte = vtopte(rp, v); 3896381Swnj io = mbap->mba_map; 3906381Swnj while (--npf >= 0) { 3916381Swnj if (pte->pg_pfnum == 0) 3926381Swnj panic("mba, zero entry"); 3936381Swnj *(int *)io++ = pte++->pg_pfnum | PG_V; 39428Sbill } 3951412Sbill *(int *)io++ = 0; 3966381Swnj return (o); 39728Sbill } 3982930Swnj 3996181Sroot #if notdef 4003095Swnj /* 4013095Swnj * Init and interrupt enable a massbus adapter. 4023095Swnj */ 4032930Swnj mbainit(mp) 4042930Swnj struct mba_regs *mp; 4052930Swnj { 4062930Swnj 4073095Swnj mp->mba_cr = MBCR_INIT; 4083095Swnj mp->mba_cr = MBCR_IE; 4092930Swnj } 4102704Swnj #endif 4114966Swnj #endif 412