+ register int drive;
+ int mbasr, as;
+
+ /*
+ * 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&MBS_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;
+
+ /*
+ * Disable interrupts from the massbus adapter
+ * for the duration of the operation of the massbus
+ * driver, so that spurious interrupts won't be generated.
+ */
+ mbp->mba_cr &= ~MBAIE;
+
+ /*
+ * 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 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;
+ iodone(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_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(as)) {
+ drive--; /* was 1 origin */
+ as &= ~(1 << drive);
+ mi = mhp->mh_mbip[drive];
+ if (mi == NULL)
+ continue;
+ /*
+ * If driver has a handler for non-data transfer
+ * interrupts, give it a chance to tell us that
+ * the operation needs to be redone
+ */
+ if (mi->mi_driver->md_ndint) {
+ mi->mi_tab.b_active = 0;
+ switch ((*mi->mi_driver->md_ndint)(mi)) {
+
+ case MBN_DONE:
+ /*
+ * Non-data transfer interrupt
+ * completed i/o request's processing.
+ */
+ mi->mi_tab.b_errcnt = 0;
+ bp = mi->mi_tab.b_actf;
+ mi->mi_tab.b_actf = bp->av_forw;
+ iodone(bp);
+ /* fall into... */
+ case MBN_RETRY:
+ if (mi->mi_tab.b_actf)
+ mbustart(mi);
+ break;
+
+ case MBN_SKIP:
+ /*
+ * Ignore (unsolicited interrupt, e.g.)
+ */
+ break;
+
+ case MBN_CONT:
+ /*
+ * Continue with unit active, e.g.
+ * between first and second rewind
+ * interrupts.
+ */
+ mi->mi_tab.b_active = 1;
+ break;
+
+ default:
+ panic("mbintr");
+ }
+ } else
+ 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);
+ mbp->mba_cr |= MBAIE;
+}
+
+/*
+ * Setup the mapping registers for a transfer.
+ */
+mbasetup(mi)
+ register struct mba_device *mi;