-/* mba.c 3.5 %G% */
+/* mba.c 4.16 81/03/07 */
+#include "mba.h"
+#if NMBA > 0
+/*
+ * Massbus driver; arbitrates massbus using device
+ * driver routines. This module provides common functions.
+ */
#include "../h/param.h"
+#include "../h/systm.h"
+#include "../h/dk.h"
#include "../h/buf.h"
#include "../h/conf.h"
-#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
-#include "../h/seg.h"
-#include "../h/pte.h"
#include "../h/map.h"
-#include "../h/mba.h"
+#include "../h/pte.h"
+#include "../h/mbareg.h"
+#include "../h/mbavar.h"
#include "../h/mtpr.h"
#include "../h/vm.h"
+char mbasr_bits[] = MBASR_BITS;
/*
- * startup routine for MBA controllers.
+ * Start activity on a massbus device.
+ * We are given the device's mba_device structure and activate
+ * the device via the unit start routine. The unit start
+ * routine may indicate that it is finished (e.g. if the operation
+ * was a ``sense'' on a tape drive), that the (multi-ported) unit
+ * is busy (we will get an interrupt later), that it started the
+ * unit (e.g. for a non-data transfer operation), or that it has
+ * set up a data transfer operation and we should start the massbus adaptor.
*/
-#define MBAWCOM 0x30
-#define MBARCOM 0x38
-#define GO 01
+mbustart(mi)
+ register struct mba_device *mi;
+{
+ register struct buf *bp; /* i/o operation at head of queue */
+ register struct mba_hd *mhp; /* header for mba device is on */
+
+loop:
+ /*
+ * Get the first thing to do off device queue.
+ */
+ bp = mi->mi_tab.b_actf;
+ if (bp == NULL)
+ return;
+ /*
+ * Let the drivers unit start routine have at it
+ * and then process the request further, per its instructions.
+ */
+ switch ((*mi->mi_driver->md_ustart)(mi)) {
-extern char buffers[NBUF][BSIZE];
+ case MBU_NEXT: /* request is complete (e.g. ``sense'') */
+ mi->mi_tab.b_active = 0;
+ mi->mi_tab.b_errcnt = 0;
+ mi->mi_tab.b_actf = bp->av_forw;
+ iodone(bp);
+ goto loop;
-mbastart(bp, adcr)
+ case MBU_DODATA: /* all ready to do data transfer */
+ /*
+ * Queue the device mba_device structure on the massbus
+ * mba_hd structure for processing as soon as the
+ * data path is available.
+ */
+ mhp = mi->mi_hd;
+ mi->mi_forw = NULL;
+ if (mhp->mh_actf == NULL)
+ mhp->mh_actf = mi;
+ else
+ mhp->mh_actl->mi_forw = mi;
+ mhp->mh_actl = mi;
+ /*
+ * If data path is idle, start transfer now.
+ * In any case the device is ``active'' waiting for the
+ * data to transfer.
+ */
+ mi->mi_tab.b_active = 1;
+ if (mhp->mh_active == 0)
+ mbstart(mhp);
+ return;
+
+ case MBU_STARTED: /* driver started a non-data transfer */
+ /*
+ * Mark device busy during non-data transfer
+ * and count this as a ``seek'' on the device.
+ */
+ if (mi->mi_dk >= 0)
+ dk_seek[mi->mi_dk]++;
+ mi->mi_tab.b_active = 1;
+ return;
+
+ case MBU_BUSY: /* dual port drive busy */
+ /*
+ * We mark the device structure so that when an
+ * interrupt occurs we will know to restart the unit.
+ */
+ mi->mi_tab.b_flags |= B_BUSY;
+ return;
+
+ default:
+ panic("mbustart");
+ }
+}
+
+/*
+ * Start an i/o operation on the massbus specified by the argument.
+ * We peel the first operation off its queue and insure that the drive
+ * is present and on-line. We then use the drivers start routine
+ * (if any) to prepare the drive, setup the massbus map for the transfer
+ * and start the transfer.
+ */
+mbstart(mhp)
+ register struct mba_hd *mhp;
+{
+ register struct mba_device *mi;
+ struct buf *bp;
+ register struct mba_regs *mbp;
+
+loop:
+ /*
+ * Look for an operation at the front of the queue.
+ */
+ if ((mi = mhp->mh_actf) == NULL) {
+ return;
+ }
+ if ((bp = mi->mi_tab.b_actf) == NULL) {
+ mhp->mh_actf = mi->mi_forw;
+ goto loop;
+ }
+ /*
+ * If this device isn't present and on-line, then
+ * we screwed up, and can't really do the operation.
+ */
+ if ((mi->mi_drv->mbd_ds & (MBD_DPR|MBD_MOL)) != (MBD_DPR|MBD_MOL)) {
+ printf("%s%d: not ready\n", mi->mi_driver->md_dname,
+ dkunit(bp));
+ mi->mi_tab.b_actf = bp->av_forw;
+ mi->mi_tab.b_errcnt = 0;
+ mi->mi_tab.b_active = 0;
+ bp->b_flags |= B_ERROR;
+ iodone(bp);
+ goto loop;
+ }
+ /*
+ * We can do the operation; mark the massbus active
+ * and let the device start routine setup any necessary
+ * device state for the transfer (e.g. desired cylinder, etc
+ * on disks).
+ */
+ mhp->mh_active = 1;
+ if (mi->mi_driver->md_start)
+ (*mi->mi_driver->md_start)(mi);
+
+ /*
+ * Setup the massbus control and map registers and start
+ * the transfer.
+ */
+ mbp = mi->mi_mba;
+ mbp->mba_sr = -1; /* conservative */
+ mbp->mba_var = mbasetup(mi);
+ mbp->mba_bcr = -bp->b_bcount;
+ mi->mi_drv->mbd_cs1 =
+ (bp->b_flags & B_READ) ? MBD_RCOM|MBD_GO : MBD_WCOM|MBD_GO;
+ if (mi->mi_dk >= 0) {
+ dk_busy |= 1 << mi->mi_dk;
+ dk_xfer[mi->mi_dk]++;
+ dk_wds[mi->mi_dk] += bp->b_bcount >> 6;
+ }
+}
+
+/*
+ * Take an interrupt off of massbus mbanum,
+ * and dispatch to drivers as appropriate.
+ */
+mbintr(mbanum)
+ int mbanum;
+{
+ register struct mba_hd *mhp = &mba_hd[mbanum];
+ register struct mba_regs *mbp = mhp->mh_mba;
+ register struct mba_device *mi;
register struct buf *bp;
- int *adcr;
+ 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;
{
+ register struct mba_regs *mbap = mi->mi_mba;
+ struct buf *bp = mi->mi_tab.b_actf;
register int i;
int npf;
unsigned v;
register struct pte *pte, *io;
int o;
int vaddr;
- register struct mba_regs *mbap;
struct proc *rp;
- mbap = mbainfo[mbanum[major(bp->b_dev)]].mi_loc;
- if ((bp->b_flags & B_PHYS) == 0)
- vaddr = (bp->b_un.b_addr - buffers[0]);
- else {
- io = &mbap->mba_map[128];
- v = btop(bp->b_un.b_addr);
- o = (int)bp->b_un.b_addr & PGOFSET;
- npf = btoc(bp->b_bcount + o);
- rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;
- vaddr = (128 << 9) | o;
- if (bp->b_flags & B_UAREA) {
- for (i = 0; i < UPAGES; i++) {
- if (rp->p_addr[i].pg_pfnum == 0)
- panic("mba: zero upage");
- *(int *)io++ = rp->p_addr[i].pg_pfnum | PG_V;
- }
- } else if ((bp->b_flags & B_PHYS) == 0) {
- v &= 0x1fffff; /* drop to physical addr */
- while (--npf >= 0)
- *(int *)io++ = v++ | PG_V;
- } else {
- if (bp->b_flags & B_PAGET)
- pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
- else
- pte = vtopte(rp, v);
- while (--npf >= 0) {
- if (pte->pg_pfnum == 0)
- panic("mba, zero entry");
- *(int *)io++ = pte++->pg_pfnum | PG_V;
- }
+ io = mbap->mba_map;
+ v = btop(bp->b_un.b_addr);
+ o = (int)bp->b_un.b_addr & PGOFSET;
+ npf = btoc(bp->b_bcount + o);
+ rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;
+ vaddr = o;
+ if (bp->b_flags & B_UAREA) {
+ for (i = 0; i < UPAGES; i++) {
+ if (rp->p_addr[i].pg_pfnum == 0)
+ panic("mba: zero upage");
+ *(int *)io++ = rp->p_addr[i].pg_pfnum | PG_V;
+ }
+ } else if ((bp->b_flags & B_PHYS) == 0) {
+ pte = &Sysmap[btop(((int)bp->b_un.b_addr)&0x7fffffff)];
+ while (--npf >= 0)
+ *(int *)io++ = pte++->pg_pfnum | PG_V;
+ } else {
+ if (bp->b_flags & B_PAGET)
+ pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
+ else
+ pte = vtopte(rp, v);
+ while (--npf >= 0) {
+ if (pte->pg_pfnum == 0)
+ panic("mba, zero entry");
+ *(int *)io++ = pte++->pg_pfnum | PG_V;
}
}
- mbap->mba_sr = -1; /* clear status (error) bits */
- mbap->mba_bcr = -bp->b_bcount;
- mbap->mba_var = vaddr;
- if (bp->b_flags & B_READ)
- *adcr = MBARCOM | GO;
- else
- *adcr = MBAWCOM | GO;
+ *(int *)io++ = 0;
+ return (vaddr);
}
-mbainit(mbanum)
- int mbanum;
+mbainit(mp)
+ struct mba_regs *mp;
{
- register struct pte *io, *b;
- register int i;
- register struct mba_info *mi;
- register struct mba_regs *mbap;
- unsigned v;
- mi = &mbainfo[mbanum];
- v = btop((int)mi->mi_phys);
- b = mi->mi_map;
- for (i = 0; i < 8192; i += NBPG) {
- *(int *)b++ = PG_V | PG_KW | v;
- mtpr(TBIS, ptob(v));
- v++;
- }
- mbap = mi->mi_loc;
- mbap->mba_cr = MBAINIT;
- mbap->mba_cr = MBAIE;
- io = mbap->mba_map;
- b = &Sysmap[btop(((int)buffers[0])&0x7fffffff)];
- for (i = NBUF * CLSIZE; i > 0; i--) {
- *(int *)io++ = PG_V | b->pg_pfnum;
- b++;
- }
- *(int *)io = 0;
- mbaact |= (1<<mbanum);
+ mp->mba_cr = MBAINIT;
+ mp->mba_cr = MBAIE;
}
+#endif