+ register int drive;
+ int mbastat, as;
+
+ /*
+ * Read out the massbus status register
+ * and attention status register and clear
+ * the bits in same by writing them back.
+ */
+ mbastat = mbp->mba_sr;
+ mbp->mba_sr = mbastat;
+ /* note: the mbd_as register is shared between drives */
+ as = mbp->mba_drv[0].mbd_as;
+ mbp->mba_drv[0].mbd_as = as;
+ dprintf("mbintr mbastat %x as %x\n", mbastat, 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) {
+ if ((mbastat & MBS_DTCMP) == 0) {
+ printf("mbintr(%d),b_active,no DTCMP!\n", mbanum);
+ goto doattn;
+#include "../h/buf.h"
+ /*
+ * 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, mbastat)) {
+
+ case MBD_DONE: /* all done, for better or worse */
+ dprintf("mbd_done\n");
+ /*
+ * 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 */
+ dprintf("mbd_retry\n");
+ /*
+ * 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.)
+ dprintf("mbd_restarted\n");
+ /*
+ * Note that mp->b_active is still on.
+ */
+ break;
+
+ default:
+ panic("mbaintr");
+ }
+ } else {
+ dprintf("!dtcmp\n");
+ if (mbastat & MBS_DTCMP)
+ printf("mbaintr,DTCMP,!b_active\n");
+ }
+doattn:
+ /*
+ * Service drives which require attention
+ * after non-data-transfer operations.
+ */
+ for (drive = 0; as && drive < 8; drive++)
+ if (as & (1 << drive)) {
+ dprintf("service as %d\n", drive);
+ as &= ~(1 << drive);
+ /*
+ * Consistency check the implied attention,
+ * to make sure the drive should have interrupted.
+ */
+ mi = mhp->mh_mbip[drive];
+ if (mi == NULL)
+ goto random; /* no such drive */
+ if (mi->mi_tab.b_active == 0 &&
+ (mi->mi_tab.b_flags&B_BUSY) == 0)
+ goto random; /* not active */
+ if ((bp = mi->mi_tab.b_actf) == NULL) {
+ /* nothing doing */
+random:
+ printf("random mbaintr %d %d\n",mbanum,drive);
+ continue;
+ }
+ /*
+ * If this interrupt wasn't a notification that
+ * a dual ported drive is available, and if the
+ * 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_tab.b_flags&B_BUSY) == 0 &&
+ mi->mi_driver->md_ndint) {
+ mi->mi_tab.b_active = 0;
+ switch((*mi->mi_driver->md_ndint)(mi)) {
+
+ case MBN_DONE:
+ dprintf("mbn_done\n");
+ /*
+ * Non-data transfer interrupt
+ * completed i/o request's processing.
+ */
+ mi->mi_tab.b_errcnt = 0;
+ mi->mi_tab.b_actf = bp->av_forw;
+ iodone(bp);
+ /* fall into... */
+ case MBN_RETRY:
+ dprintf("mbn_retry\n");
+ if (mi->mi_tab.b_actf)
+ mbustart(mi);
+ break;
+
+ default:
+ panic("mbintr ndint");
+ }
+ } 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_info *mi;