diff options
Diffstat (limited to 'sys/arch/vax/mba/mba.c')
-rw-r--r-- | sys/arch/vax/mba/mba.c | 343 |
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; } |