+ register int drive;
+ int mbasr, as;
+ extern struct mba_device *mbaconfig();
+
+ /*
+ * Read out the massbus status register
+ * and attention status register and clear
+ * the bits in same by writing them back.
+ */
+ mbasr = mbp->mba_sr;
+ mbp->mba_sr = mbasr;
+#if VAX750
+ if (mbasr&MBSR_CBHUNG) {
+ printf("mba%d: control bus hung\n", mbanum);
+ panic("cbhung");
+ }
+#endif
+ /* note: the mbd_as register is shared between drives */
+ as = mbp->mba_drv[0].mbd_as & 0xff;
+ mbp->mba_drv[0].mbd_as = as;
+
+ /*
+ * If the mba was active, process the data transfer
+ * complete interrupt; otherwise just process units which
+ * are now finished.
+ */
+ if (mhp->mh_active) {
+ /*
+ * Clear attention status for drive whose data
+ * transfer related operation completed,
+ * and give the dtint driver
+ * routine a chance to say what is next.
+ */
+ mi = mhp->mh_actf;
+ as &= ~(1 << mi->mi_drive);
+ dk_busy &= ~(1 << mi->mi_dk);
+ bp = mi->mi_tab.b_actf;
+ switch ((*mi->mi_driver->md_dtint)(mi, mbasr)) {
+
+ case MBD_DONE: /* all done, for better or worse */
+ /*
+ * Flush request from drive queue.
+ */
+ mi->mi_tab.b_errcnt = 0;
+ mi->mi_tab.b_actf = bp->av_forw;
+ biodone(bp);
+ /* fall into... */
+ case MBD_RETRY: /* attempt the operation again */
+ /*
+ * Dequeue data transfer from massbus queue;
+ * if there is still a i/o request on the device
+ * queue then start the next operation on the device.
+ * (Common code for DONE and RETRY).
+ */
+ mhp->mh_active = 0;
+ mi->mi_tab.b_active = 0;
+ mhp->mh_actf = mi->mi_forw;
+ if (mi->mi_tab.b_actf)
+ mbustart(mi);
+ break;
+
+ case MBD_REPOSITION: /* driver started repositioning */
+ /*
+ * Drive is repositioning, not doing data transfer.
+ * Free controller, but don't have to restart drive.
+ */
+ mhp->mh_active = 0;
+ mhp->mh_actf = mi->mi_forw;
+ break;
+
+ case MBD_RESTARTED: /* driver restarted op (ecc, e.g.) */
+ /*
+ * Note that mhp->mh_active is still on.
+ */
+ break;
+
+ default:
+ panic("mbintr");
+ }
+ }
+ /*
+ * Service drives which require attention
+ * after non-data-transfer operations.
+ */
+ while (drive = ffs((long)as)) {
+ drive--; /* was 1 origin */
+ as &= ~(1 << drive);
+ mi = mhp->mh_mbip[drive];
+ if (mi == NULL || mi->mi_alive == 0) {
+ struct mba_device fnd;
+ struct mba_drv *mbd = &mhp->mh_mba->mba_drv[drive];
+ int dt = mbd->mbd_dt & 0xffff;
+
+ if (dt == 0 || dt == MBDT_MOH)
+ continue;
+ fnd.mi_mba = mhp->mh_mba;
+ fnd.mi_mbanum = mbanum;
+ fnd.mi_drive = drive;
+ if ((mi = mbaconfig(&fnd, dt)) == NULL)
+ continue;
+ /*
+ * If a tape, poke the slave attach routines.
+ * Otherwise, could be a disk which we want
+ * to swap on, so make a pass over the swap
+ * configuration table in case the size of
+ * the swap area must be determined by drive type.
+ */
+ if (dt & MBDT_TAP)
+ mbaddtape(mi, drive);
+ else
+ swapconf();
+ }
+ /*
+ * If driver has a handler for non-data transfer
+ * interrupts, give it a chance to tell us what to do.
+ */
+ if (mi->mi_driver->md_ndint) {
+ switch ((*mi->mi_driver->md_ndint)(mi)) {
+
+ case MBN_DONE: /* operation completed */
+ mi->mi_tab.b_active = 0;
+ mi->mi_tab.b_errcnt = 0;
+ bp = mi->mi_tab.b_actf;
+ mi->mi_tab.b_actf = bp->av_forw;
+ biodone(bp);
+ /* fall into common code */
+ case MBN_RETRY: /* operation continues */
+ if (mi->mi_tab.b_actf)
+ mbustart(mi);
+ break;
+ case MBN_SKIP: /* ignore unsol. interrupt */
+ break;
+ default:
+ panic("mbintr");
+ }
+ } else
+ /*
+ * If there is no non-data transfer interrupt
+ * routine, then we should just
+ * restart the unit, leading to a mbstart() soon.
+ */
+ mbustart(mi);
+ }
+ /*
+ * If there is an operation available and
+ * the massbus isn't active, get it going.
+ */
+ if (mhp->mh_actf && !mhp->mh_active)
+ mbstart(mhp);
+ /* THHHHATS all folks... */
+}
+
+/*
+ * For autoconfig'ng tape drives on the fly.
+ */
+mbaddtape(mi, drive)
+ struct mba_device *mi;
+ int drive;
+{
+ register struct mba_slave *ms;
+
+ for (ms = mbsinit; ms->ms_driver; ms++)
+ if (ms->ms_driver == mi->mi_driver && ms->ms_alive == 0 &&
+ (ms->ms_ctlr == mi->mi_unit ||
+ ms->ms_ctlr == '?')) {
+ if ((*ms->ms_driver->md_slave)(mi, ms, drive)) {
+ printf("%s%d at %s%d slave %d\n",
+ ms->ms_driver->md_sname,
+ ms->ms_unit,
+ mi->mi_driver->md_dname,
+ mi->mi_unit,
+ ms->ms_slave);
+ ms->ms_alive = 1;
+ ms->ms_ctlr = mi->mi_unit;
+ }
+ }
+}
+
+/*
+ * Setup the mapping registers for a transfer.
+ */
+mbasetup(mi)
+ register struct mba_device *mi;