summaryrefslogtreecommitdiff
path: root/sys/arch/vax/mba/mba.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/vax/mba/mba.c')
-rw-r--r--sys/arch/vax/mba/mba.c343
1 files changed, 299 insertions, 44 deletions
diff --git a/sys/arch/vax/mba/mba.c b/sys/arch/vax/mba/mba.c
index 4b2d13f7864..01a40b19c06 100644
--- a/sys/arch/vax/mba/mba.c
+++ b/sys/arch/vax/mba/mba.c
@@ -1,7 +1,6 @@
-
-/* $NetBSD: mba.c,v 1.1 1995/02/13 00:44:02 ragge Exp $ */
+/* $NetBSD: mba.c,v 1.6 1996/04/08 18:38:59 ragge Exp $ */
/*
- * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
+ * Copyright (c) 1994, 1996 Ludd, University of Lule}, Sweden.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +13,8 @@
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
- * This product includes software developed at Ludd, University of Lule}.
+ * This product includes software developed at Ludd, University of
+ * Lule}, Sweden and its contributors.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
@@ -30,70 +30,325 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
- /* All bugs are subject to removal without further notice */
-
+/*
+ * Simple massbus drive routine.
+ * TODO:
+ * Autoconfig new devices 'on the fly'.
+ * More intelligent way to handle different interrupts.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
-/* mba.c - main mba routines, 930312/ragge */
+#include <machine/trap.h>
+#include <machine/scb.h>
+#include <machine/nexus.h>
+#include <machine/pte.h>
+#include <machine/pcb.h>
+#include <machine/sid.h>
-#include "mba.h"
-#include "nexus.h"
-#include "vax/mba/mbavar.h"
-#include "vax/mba/mbareg.h"
+#include <vax/mba/mbareg.h>
+#include <vax/mba/mbavar.h>
-struct mba_ctrl mba_ctrl[NMBA];
+struct mbaunit mbaunit[] = {
+ {MBADT_RP04, "rp04", MB_RP},
+ {MBADT_RP05, "rp05", MB_RP},
+ {MBADT_RP06, "rp06", MB_RP},
+ {MBADT_RP07, "rp07", MB_RP},
+ {MBADT_RM02, "rm02", MB_RP},
+ {MBADT_RM03, "rm03", MB_RP},
+ {MBADT_RM05, "rm05", MB_RP},
+ {MBADT_RM80, "rm80", MB_RP},
+ {0, 0, 0}
+};
-extern mba_0(), mba_1(), mba_2(), mba_3();
-int (*mbaintv[4])() = { mba_0, mba_1, mba_2, mba_3 };
-#if NMBA > 4
- Need to expand the table for more than 4 massbus adaptors
-#endif
+int mbamatch __P((struct device *, void *, void *));
+void mbaattach __P((struct device *, struct device *, void *));
+void mbaintr __P((int));
+int mbaprint __P((void *, char *));
+void mbaqueue __P((struct mba_device *));
+void mbastart __P((struct mba_softc *));
+void mbamapregs __P((struct mba_softc *));
+
+struct cfdriver mba_cd = {
+ NULL, "mba", DV_DULL
+};
+
+struct cfattach mba_ca = {
+ sizeof(struct mba_softc), mbamatch, mbaattach
+};
+
+/*
+ * Look if this is a massbuss adapter.
+ */
+int
+mbamatch(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct sbi_attach_args *sa = (struct sbi_attach_args *)aux;
+ struct cfdata *cf = match;
+
+ if ((cf->cf_loc[0] != sa->nexnum) && (cf->cf_loc[0] > -1 ))
+ return 0;
+
+ if (sa->type == NEX_MBA)
+ return 1;
-mbainterrupt(mba){
+ return 0;
+}
+
+/*
+ * Attach the found massbuss adapter. Setup its interrupt vectors,
+ * reset it and go searching for drives on it.
+ */
+void
+mbaattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct mba_softc *sc = (void *)self;
+ struct sbi_attach_args *sa = (struct sbi_attach_args *)aux;
+ volatile struct mba_regs *mbar = (struct mba_regs *)sa->nexaddr;
+ struct mba_attach_args ma;
+ extern struct ivec_dsp idsptch;
+ int i, j;
+
+ printf("\n");
+ /*
+ * Set up interrupt vectors for this MBA.
+ */
+ bcopy(&idsptch, &sc->sc_dsp, sizeof(struct ivec_dsp));
+ scb->scb_nexvec[0][sa->nexnum] = scb->scb_nexvec[1][sa->nexnum] =
+ scb->scb_nexvec[2][sa->nexnum] = scb->scb_nexvec[3][sa->nexnum] =
+ &sc->sc_dsp;
+ sc->sc_dsp.pushlarg = sc->sc_dev.dv_unit;
+ sc->sc_dsp.hoppaddr = mbaintr;
+
+ sc->sc_physnr = sa->nexnum - 8; /* MBA's have TR between 8 - 11... */
+#ifdef VAX750
+ if (cpunumber == VAX_750)
+ sc->sc_physnr += 4; /* ...but not on 11/750 */
+#endif
+ sc->sc_first = 0;
+ sc->sc_last = (void *)&sc->sc_first;
+ sc->sc_mbareg = (struct mba_regs *)mbar;
+ mbar->mba_cr = MBACR_INIT; /* Reset adapter */
+ mbar->mba_cr = MBACR_IE; /* Enable interrupts */
- if(mba_hd[mba].mh_mba->mba_sr&MBA_NED){
- printf("Adresserat icke existerande massbussenhet.\n");
- mba_hd[mba].mh_mba->mba_sr=MBA_NED+MBA_MCPE;
- return;
+ for (i = 0; i < MAXMBADEV; i++) {
+ sc->sc_state = SC_AUTOCONF;
+ if ((mbar->mba_md[i].md_ds & MBADS_DPR) == 0)
+ continue;
+ /* We have a drive, ok. */
+ ma.unit = i;
+ ma.type = mbar->mba_md[i].md_dt & 0777;
+ j = 0;
+ while (mbaunit[j++].nr)
+ if (mbaunit[j].nr == ma.type)
+ break;
+ ma.devtyp = mbaunit[j].devtyp;
+ ma.name = mbaunit[j].name;
+ config_found(&sc->sc_dev, (void *)&ma, mbaprint);
}
- printf("Interrupt fr}n massbussadapter %d\n",mba);
- printf("mba_hd[mba]->mba_sr: %x\n",mba_hd[mba].mh_mba->mba_sr);
}
/*
- * mbafind() set up interrupt vectors for each found mba and calls
- * config routines for hp disks, tu and mt tapes (currently only hp).
+ * We got an interrupt. Check type of interrupt and call the specific
+ * device interrupt handling routine.
*/
+void
+mbaintr(mba)
+ int mba;
+{
+ struct mba_softc *sc = mba_cd.cd_devs[mba];
+ volatile struct mba_regs *mr = sc->sc_mbareg;
+ struct mba_device *md;
+ struct buf *bp;
+ int itype, attn, anr;
+
+ itype = mr->mba_sr;
+ mr->mba_sr = itype; /* Write back to clear bits */
+
+ attn = mr->mba_md[0].md_as & 0xff;
+ mr->mba_md[0].md_as = attn;
+
+ if (sc->sc_state == SC_AUTOCONF)
+ return; /* During autoconfig */
+
+ md = sc->sc_first;
+ bp = md->md_q.b_actf;
+ /*
+ * A data-transfer interrupt. Current operation is finished,
+ * call that device's finish routine to see what to do next.
+ */
+ if (sc->sc_state == SC_ACTIVE) {
+
+ sc->sc_state = SC_IDLE;
+ switch ((*md->md_finish)(md, itype, &attn)) {
-mbafind(nexnum,nexaddr){
- struct mba_regs *mbr;
- struct mba_device *mi;
+ case XFER_FINISH:
+ /*
+ * Transfer is finished. Take buffer of drive
+ * queue, and take drive of adapter queue.
+ * If more to transfer, start the adapter again
+ * by calling mbastart().
+ */
+ md->md_q.b_actf = bp->b_actf;
+ sc->sc_first = md->md_back;
+ md->md_back = 0;
+ if (sc->sc_first == 0)
+ sc->sc_last = (void *)&sc->sc_first;
+
+ if (md->md_q.b_actf) {
+ sc->sc_last->md_back = md;
+ sc->sc_last = md;
+ }
+
+ bp->b_resid = 0;
+ biodone(bp);
+ if (sc->sc_first)
+ mbastart(sc);
+ break;
+
+ case XFER_RESTART:
+ /*
+ * Something went wrong with the transfer. Try again.
+ */
+ mbastart(sc);
+ break;
+ }
+ }
+
+ while (attn) {
+ anr = ffs(attn) - 1;
+ attn &= ~(1 << anr);
+ if (sc->sc_md[anr]->md_attn == 0)
+ panic("Should check for new MBA device %d", anr);
+ (*sc->sc_md[anr]->md_attn)(sc->sc_md[anr]);
+ }
+}
+
+int
+mbaprint(aux, mbaname)
+ void *aux;
+ char *mbaname;
+{
+ struct mba_attach_args *ma = aux;
+
+ if (mbaname) {
+ if (ma->name)
+ printf("%s", ma->name);
+ else
+ printf("device type %o", ma->type);
+ printf(" at %s", mbaname);
+ }
+ printf(" drive %d", ma->unit);
+ return (ma->name ? UNCONF : UNSUPP);
+}
- mba_ctrl[nmba].mba_regs= (struct mba_regs *)nexaddr;
- mbr=&(mba_ctrl[nmba].mba_regs);
/*
- * Set up interruptvectors and enable interrupt
+ * A device calls mbaqueue() when it wants to get on the adapter queue.
+ * Called at splbio(). If the adapter is inactive, start it.
*/
- nex_vec_num(14,nexnum)=nex_vec_num(15,nexnum)=
- nex_vec_num(16,nexnum)=nex_vec_num(17,nexnum)=
- (caddr_t)mbaintv[nmba];
- mbr->mba_cr=MBCR_INIT;
- mbr->mba_cr=MBCR_IE;
+void
+mbaqueue(md)
+ struct mba_device *md;
+{
+ struct mba_softc *sc = md->md_mba;
+ int i = (int)sc->sc_first;
+
+ sc->sc_last->md_back = md;
+ sc->sc_last = md;
+
+ if (i == 0)
+ mbastart(sc);
+}
+
/*
- * Loop thru all massbuss devices and check for existance
+ * Start activity on (idling) adapter. Calls mbamapregs() to setup
+ * for dma transfer, then the unit-specific start routine.
*/
+void
+mbastart(sc)
+ struct mba_softc *sc;
+{
+ struct mba_device *md = sc->sc_first;
+ volatile struct mba_regs *mr = sc->sc_mbareg;
+ struct buf *bp = md->md_q.b_actf;
+
+ mbamapregs(sc);
+
+ sc->sc_state = SC_ACTIVE;
+ mr->mba_var = ((u_int)bp->b_un.b_addr & PGOFSET);
+ mr->mba_bc = (~bp->b_bcount) + 1;
+ (*md->md_start)(md); /* machine-dependent start */
+}
- for(i=0;i<8;i++){
- if(!mbr->mba_drv[i].rmds&MBDS_DPR) continue;
/*
- * Device found; check if generated
+ * Setup map registers for a dma transfer.
+ * This routine could be synced with the other adapter map routines!
*/
- for(mi = mbdinit; mi->driver; mi++) {
- if(mi->alive) continue; /* Already config'd */
- }
+void
+mbamapregs(sc)
+ struct mba_softc *sc;
+{
+ struct mba_device *md = sc->sc_first;
+ volatile struct mba_regs *mr = sc->sc_mbareg;
+ struct buf *bp = md->md_q.b_actf;
+ struct pcb *pcb;
+ pt_entry_t *pte;
+ volatile pt_entry_t *io;
+ int pfnum, npf, o, i;
+ caddr_t addr;
+
+ o = (int)bp->b_un.b_addr & PGOFSET;
+ npf = btoc(bp->b_bcount + o) + 1;
+ addr = bp->b_un.b_addr;
+
+ /*
+ * Get a pointer to the pte pointing out the first virtual address.
+ * Use different ways in kernel and user space.
+ */
+ if ((bp->b_flags & B_PHYS) == 0) {
+ pte = kvtopte(addr);
+ } else {
+ pcb = bp->b_proc->p_vmspace->vm_pmap.pm_pcb;
+ pte = uvtopte(addr, pcb);
}
+ /*
+ * When we are doing DMA to user space, be sure that all pages
+ * we want to transfer to is mapped. WHY DO WE NEED THIS???
+ * SHOULDN'T THEY ALWAYS BE MAPPED WHEN DOING THIS???
+ */
+ for (i = 0; i < (npf - 1); i++) {
+ if ((pte + i)->pg_pfn == 0) {
+ int rv;
+ rv = vm_fault(&bp->b_proc->p_vmspace->vm_map,
+ (unsigned)addr + i * NBPG,
+ VM_PROT_READ|VM_PROT_WRITE, FALSE);
+ if (rv)
+ panic("MBA DMA to nonexistent page, %d", rv);
+ }
+ }
+ io = &mr->mba_map[0];
+ while (--npf > 0) {
+ pfnum = pte->pg_pfn;
+ if (pfnum == 0)
+ panic("mba zero entry");
+ pte++;
+ *(int *)io++ = pfnum | PG_V;
+ }
+ *(int *)io = 0;
}