diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/vax/vsa/ncr.c | 1394 | ||||
-rw-r--r-- | sys/arch/vax/vsa/vsbus.c | 755 |
2 files changed, 517 insertions, 1632 deletions
diff --git a/sys/arch/vax/vsa/ncr.c b/sys/arch/vax/vsa/ncr.c index 242e658561c..075c37f9648 100644 --- a/sys/arch/vax/vsa/ncr.c +++ b/sys/arch/vax/vsa/ncr.c @@ -1,16 +1,12 @@ -/* $OpenBSD: ncr.c,v 1.4 1999/01/11 05:12:09 millert Exp $ */ -/* $NetBSD: ncr.c,v 1.8 1997/02/26 22:29:12 gwr Exp $ */ +/* $NetBSD: ncr.c,v 1.26 2000/03/25 15:27:57 tsutsui Exp $ */ -/* #define DEBUG /* */ -/* #define TRACE /* */ -/* #define POLL_MODE /* */ -#define USE_VMAPBUF - -/* - * Copyright (c) 1995 David Jones, Gordon W. Ross - * Copyright (c) 1994 Adam Glass +/*- + * Copyright (c) 1996 The NetBSD Foundation, Inc. * All rights reserved. * + * This code is derived from software contributed to The NetBSD Foundation + * by Adam Glass, David Jones, Gordon W. Ross, and Jens A. Nilsson. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -19,608 +15,252 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. The name of the authors may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * 4. All advertising materials mentioning features or use of this software + * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by - * Adam Glass, David Jones, and Gordon Ross + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ /* - * This file contains only the machine-dependent parts of the - * Sun3 SCSI driver. (Autoconfig stuff and DMA functions.) - * The machine-independent parts are in ncr5380sbc.c - * - * Supported hardware includes: - * Sun SCSI-3 on OBIO (Sun3/50,Sun3/60) - * Sun SCSI-3 on VME (Sun3/160,Sun3/260) - * - * Could be made to support the Sun3/E if someone wanted to. - * - * Note: Both supported variants of the Sun SCSI-3 adapter have - * some really unusual "features" for this driver to deal with, - * generally related to the DMA engine. The OBIO variant will - * ignore any attempt to write the FIFO count register while the - * SCSI bus is in DATA_IN or DATA_OUT phase. This is dealt with - * by setting the FIFO count early in COMMAND or MSG_IN phase. + * This file contains the machine-dependent parts of the NCR-5380 + * controller. The machine-independent parts are in ncr5380sbc.c. * - * The VME variant has a bit to enable or disable the DMA engine, - * but that bit also gates the interrupt line from the NCR5380! - * Therefore, in order to get any interrupt from the 5380, (i.e. - * for reselect) one must clear the DMA engine transfer count and - * then enable DMA. This has the further complication that you - * CAN NOT touch the NCR5380 while the DMA enable bit is set, so - * we have to turn DMA back off before we even look at the 5380. + * Note: Only PIO transfers for now which implicates very bad + * performance. DMA support will come soon. * - * What wonderfully whacky hardware this is! + * Jens A. Nilsson. * - * Credits, history: - * - * David Jones wrote the initial version of this module, which - * included support for the VME adapter only. (no reselection). - * - * Gordon Ross added support for the OBIO adapter, and re-worked - * both the VME and OBIO code to support disconnect/reselect. - * (Required figuring out the hardware "features" noted above.) - * - * The autoconfiguration boilerplate came from Adam Glass. - * - * VS2000: + * Credits: + * + * This code is based on arch/sun3/dev/si* + * Written by David Jones, Gordon Ross, and Adam Glass. */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/errno.h> #include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/file.h> -#include <sys/stat.h> -#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/device.h> #include <sys/buf.h> +#include <sys/disk.h> #include <sys/proc.h> #include <sys/user.h> -#include <sys/map.h> -#include <sys/device.h> -#include <sys/dkstat.h> -#include <sys/disklabel.h> -#include <sys/disk.h> -#include <sys/syslog.h> -/* #include <sys/errno.h> */ +#include <vm/vm.h> +#include <vm/vm_kern.h> #include <scsi/scsi_all.h> #include <scsi/scsi_debug.h> #include <scsi/scsiconf.h> - -#include <machine/uvax.h> -#include <machine/ka410.h> -#include <machine/ka43.h> -#include <machine/vsbus.h> /* struct confargs */ +#include <scsi/sdvar.h> #include <dev/ic/ncr5380reg.h> #include <dev/ic/ncr5380var.h> -#define trace(x) -#define debug(x) +#include <machine/cpu.h> +#include <machine/vsbus.h> +#include <machine/bus.h> +#include <machine/sid.h> +#include <machine/scb.h> -#ifndef NCR5380_CSRBITS -#define NCR5380_CSRBITS \ - "\020\010DEND\007DREQ\006PERR\005IREQ\004MTCH\003DCON\002ATN\001ACK" -#endif +#define MIN_DMA_LEN 128 -#ifndef NCR5380_BUSCSRBITS -#define NCR5380_BUSCSRBITS \ - "\020\010RST\007BSY\006REQ\005MSG\004C/D\003I/O\002SEL\001DBP" -#endif - -#include "ncr.h" - -#ifdef DDB -#define integrate -#else -#define integrate static -#endif - -/* - * Transfers smaller than this are done using PIO - * (on assumption they're not worth DMA overhead) - */ -#define MIN_DMA_LEN 128 - -/* - * Transfers lager than 65535 bytes need to be split-up. - * (Some of the FIFO logic has only 16 bits counters.) - * Make the size an integer multiple of the page size - * to avoid buf/cluster remap problems. (paranoid?) - * - * bertram: VS2000 has an DMA-area which is 16KB, thus - * have a maximum DMA-size of 16KB... - */ -#ifdef DMA_SHARED -#define MAX_DMA_LEN 0x2000 /* (8 * 1024) */ -#define DMA_ADDR_HBYTE 0x20 -#define DMA_ADDR_LBYTE 0x00 -#else -#define MAX_DMA_LEN 0x4000 /* (16 * 1024) */ -#define DMA_ADDR_HBYTE 0x00 -#define DMA_ADDR_LBYTE 0x00 -#endif - -#ifdef DEBUG -int si_debug = 3; -static int si_link_flags = 0 /* | SDEV_DB2 */ ; -#endif - -/* - * This structure is used to keep track of mappedpwd DMA requests. - * Note: combined the UDC command block with this structure, so - * the array of these has to be in DVMA space. - */ struct si_dma_handle { - int dh_flags; -#define SIDH_BUSY 1 /* This DH is in use */ -#define SIDH_OUT 2 /* DMA does data out (write) */ -#define SIDH_PHYS 4 -#define SIDH_DONE 8 - u_char * dh_addr; /* KVA of start of buffer */ - int dh_maplen; /* Length of KVA mapping. */ - u_char * dh_dvma; /* VA of buffer in DVMA space */ - int dh_xlen; + int dh_flags; +#define SIDH_BUSY 1 +#define SIDH_OUT 2 + caddr_t dh_addr; + int dh_len; + struct proc *dh_proc; }; -/* - * The first structure member has to be the ncr5380_softc - * so we can just cast to go back and fourth between them. - */ struct si_softc { - struct ncr5380_softc ncr_sc; - volatile struct si_regs *sc_regs; /* do we really need this? */ - - struct si_dma_handle *sc_dma; - struct confargs *sc_cfargs; - - int sc_xflags; /* ka410/ka43: resid, sizeof(areg) */ - - char *sc_dbase; - int sc_dsize; - - volatile char *sc_dareg; - volatile short *sc_dcreg; - volatile char *sc_ddreg; - volatile int sc_dflags; - -#define VSDMA_LOCKED 0x80 /* */ -#define VSDMA_WANTED 0x40 /* */ -#define VSDMA_IWANTED 0x20 -#define VSDMA_BLOCKED 0x10 -#define VSDMA_DMABUSY 0x08 /* DMA in progress */ -#define VSDMA_REGBUSY 0x04 /* accessing registers */ -#define VSDMA_WRBUF 0x02 /* writing to bounce-buffer */ -#define VSDMA_RDBUF 0x01 /* reading from bounce-buffer */ - -#define VSDMA_STATUS 0xF0 -#define VSDMA_LCKTYPE 0x0F - -#ifdef POLL_MODE - volatile u_char *intreq; - volatile u_char *intclr; - volatile u_char *intmsk; - volatile int intbit; -#endif + struct ncr5380_softc ncr_sc; + caddr_t ncr_addr; + int ncr_off; + int ncr_dmaaddr; + int ncr_dmacount; + int ncr_dmadir; + + /* Pointers to bus_space */ + bus_space_tag_t sc_regt; + bus_space_handle_t sc_regh; + + struct si_dma_handle ncr_dma[SCI_OPENINGS]; }; -extern int cold; /* enable polling while cold-flag set */ - -/* Options. Interesting values are: 1,3,7 */ -int si_options = 3; /* bertram: 3 or 7 ??? */ -#define SI_ENABLE_DMA 1 /* Use DMA (maybe polled) */ -#define SI_DMA_INTR 2 /* DMA completion interrupts */ -#define SI_DO_RESELECT 4 /* Allow disconnect/reselect */ - -#define DMA_DIR_IN 1 -#define DMA_DIR_OUT 0 - -/* How long to wait for DMA before declaring an error. */ -int si_dma_intr_timo = 500; /* ticks (sec. X 100) */ - -integrate char si_name[] = "ncr"; -integrate int si_match(); -integrate void si_attach(); -integrate int si_intr __P((void *)); - -integrate void si_minphys __P((struct buf *bp)); -integrate void si_reset_adapter __P((struct ncr5380_softc *sc)); - -void si_dma_alloc __P((struct ncr5380_softc *)); -void si_dma_free __P((struct ncr5380_softc *)); -void si_dma_poll __P((struct ncr5380_softc *)); - -void si_intr_on __P((struct ncr5380_softc *)); -void si_intr_off __P((struct ncr5380_softc *)); - -int si_dmaLockBus __P((struct ncr5380_softc *, int)); -int si_dmaToggleLock __P((struct ncr5380_softc *, int, int)); -int si_dmaReleaseBus __P((struct ncr5380_softc *, int)); - -void si_dma_setup __P((struct ncr5380_softc *)); -void si_dma_start __P((struct ncr5380_softc *)); -void si_dma_eop __P((struct ncr5380_softc *)); -void si_dma_stop __P((struct ncr5380_softc *)); - -static struct scsi_adapter si_ops = { - ncr5380_scsi_cmd, /* scsi_cmd() */ - si_minphys, /* scsi_minphys() */ - NULL, /* open_target_lu() */ - NULL, /* close_target_lu() */ +static int si_match __P((struct device *, void *, void *)); +static void si_attach __P((struct device *, struct device *, void *)); +static void si_minphys __P((struct buf *)); + +static void si_dma_alloc __P((struct ncr5380_softc *)); +static void si_dma_free __P((struct ncr5380_softc *)); +static void si_dma_setup __P((struct ncr5380_softc *)); +static void si_dma_start __P((struct ncr5380_softc *)); +static void si_dma_poll __P((struct ncr5380_softc *)); +static void si_dma_eop __P((struct ncr5380_softc *)); +static void si_dma_stop __P((struct ncr5380_softc *)); + +#define NCR5380_READ(sc, reg) bus_space_read_1(sc->sc_regt, \ + 0, sc->ncr_sc.reg) +#define NCR5380_WRITE(sc, reg, val) bus_space_write_1(sc->sc_regt, \ + 0, sc->ncr_sc.reg, val) + +struct scsi_adapter si_ops = { + ncr5380_scsi_cmd, /* scsi_cmd() */ + si_minphys, /* scsi_minphys() */ + NULL, /* open_target_lu() */ + NULL, /* close_target_lu() */ }; -/* This is copied from julian's bt driver */ -/* "so we have a default dev struct for our link struct." */ -static struct scsi_device si_dev = { - NULL, /* Use default error handler. */ - NULL, /* Use default start handler. */ - NULL, /* Use default async handler. */ - NULL, /* Use default "done" routine. */ +struct scsi_device si_dev = { + NULL, /* use default error handler */ + NULL, /* no start function */ + NULL, /* no async handler */ + NULL /* use default done routine */ }; - -struct cfdriver ncr_cd = { - NULL, si_name, DV_DULL -}; struct cfattach ncr_ca = { - sizeof(struct si_softc), si_match, si_attach, + sizeof(struct si_softc), si_match, si_attach }; -void -dk_establish(p,q) - struct disk *p; - struct device *q; -{ -#if 0 - printf ("faking dk_establish()...\n"); -#endif -} - - -integrate int -si_match(parent, match, aux) - struct device *parent; - void *match, *aux; -{ - struct cfdata *cf = match; - struct confargs *ca = aux; - - trace(("ncr_match(0x%x, %d, %s)\n", parent, cf->cf_unit, ca->ca_name)); - - if (strcmp(ca->ca_name, "ncr") && - strcmp(ca->ca_name, "ncr5380") && - strcmp(ca->ca_name, "NCR5380")) - return (0); +struct cfdriver ncr_cd = { + NULL, "ncr", DV_DULL +}; - /* - * we just define it being there ... - */ - return (1); -} +extern struct cfdriver sd_cd; -integrate void -si_set_portid(pid,port) - int pid; - int port; +static int +si_match(parent, cf, aux) + struct device *parent; + void *cf; + void *aux; { - struct { - u_long :2; - u_long id0:3; - u_long id1:3; - u_long :26; - } *p; - -#ifdef DEBUG - int *ip; - ip = (void*)uvax_phys2virt(KA410_SCSIPORT); - p = (void*)uvax_phys2virt(KA410_SCSIPORT); - printf("scsi-id: (%x/%d) %d / %d\n", *ip, *ip, p->id0, p->id1); -#endif - - p = (void*)uvax_phys2virt(KA410_SCSIPORT); - switch (port) { - case 0: - p->id0 = pid; - printf(": scsi-id %d\n", p->id0); - break; - case 1: - p->id1 = pid; - printf(": scsi-id %d\n", p->id1); - break; - default: - printf("invalid port-number %d\n", port); - } + struct vsbus_attach_args *va = aux; + volatile char *si_csr = (char *) va->va_addr; + + if (vax_boardtype == VAX_BTYP_49) + return 0; + /* This is the way Linux autoprobes the interrupt MK-990321 */ + si_csr[12] = 0; + si_csr[16] = 0x80; + si_csr[0] = 0x80; + si_csr[4] = 5; /* 0xcf */ + DELAY(100000); + return 1; } -integrate void +static void si_attach(parent, self, aux) struct device *parent, *self; void *aux; { + struct vsbus_attach_args *va = aux; + struct vsbus_softc *vsc = (struct vsbus_softc *)parent; struct si_softc *sc = (struct si_softc *) self; - struct ncr5380_softc *ncr_sc = (struct ncr5380_softc *)sc; - volatile struct si_regs *regs; - struct confargs *ca = aux; - int i; - int *ip = aux;; + struct ncr5380_softc *ncr_sc = &sc->ncr_sc; - trace (("ncr_attach(0x%x, 0x%x, %s)\n", parent, self, ca->ca_name)); - - /* - * - */ -#ifdef POLL_MODE - sc->intreq = (void*)uvax_phys2virt(KA410_INTREQ); - sc->intmsk = (void*)uvax_phys2virt(KA410_INTMSK); - sc->intclr = (void*)uvax_phys2virt(KA410_INTCLR); - sc->intbit = ca->ca_intbit; -#endif - - sc->sc_cfargs = ca; /* needed for interrupt-setup */ - - regs = (void*)uvax_phys2virt(ca->ca_ioaddr); - - sc->sc_dareg = (void*)uvax_phys2virt(ca->ca_dareg); - sc->sc_dcreg = (void*)uvax_phys2virt(ca->ca_dcreg); - sc->sc_ddreg = (void*)uvax_phys2virt(ca->ca_ddreg); - sc->sc_dbase = (void*)uvax_phys2virt(ca->ca_dbase); - sc->sc_dsize = ca->ca_dsize; - sc->sc_dflags = 4; /* XXX */ - sc->sc_xflags = ca->ca_dflag; /* should/will be renamed */ - /* - * Fill in the prototype scsi_link. - */ -#ifndef __OpenBSD__ - ncr_sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE; -#endif - ncr_sc->sc_link.adapter_softc = sc; - ncr_sc->sc_link.adapter_target = ca->ca_idval; - ncr_sc->sc_link.adapter = &si_ops; - ncr_sc->sc_link.device = &si_dev; + printf("\n"); - si_set_portid(ca->ca_idval, ncr_sc->sc_dev.dv_unit); + /* enable interrupts on vsbus too */ + scb_vecalloc(va->va_cvec, (void (*)(void *)) ncr5380_intr, sc, SCB_ISTACK); + vsc->sc_mask |= 1 << (va->va_maskno-1); /* - * Initialize fields used by the MI code + * DMA area mapin. + * On VS3100, split the 128K block between the two devices. + * On VS2000, don't care for now. */ - ncr_sc->sci_r0 = (void*)®s->sci.sci_r0; - ncr_sc->sci_r1 = (void*)®s->sci.sci_r1; - ncr_sc->sci_r2 = (void*)®s->sci.sci_r2; - ncr_sc->sci_r3 = (void*)®s->sci.sci_r3; - ncr_sc->sci_r4 = (void*)®s->sci.sci_r4; - ncr_sc->sci_r5 = (void*)®s->sci.sci_r5; - ncr_sc->sci_r6 = (void*)®s->sci.sci_r6; - ncr_sc->sci_r7 = (void*)®s->sci.sci_r7; +#define DMASIZE (64*1024) + if (vax_boardtype != VAX_BTYP_410) { + if (va->va_paddr & 0x100) /* Magic */ + sc->ncr_off = DMASIZE; + sc->ncr_addr = (caddr_t)uvm_km_valloc(kernel_map, DMASIZE); + + ioaccess((vaddr_t)sc->ncr_addr, + 0x202d0000 + sc->ncr_off, DMASIZE/VAX_NBPG); - /* - * MD function pointers used by the MI code. - */ + /* + * MD function pointers used by the MI code. + */ + ncr_sc->sc_dma_alloc = si_dma_alloc; + ncr_sc->sc_dma_free = si_dma_free; + ncr_sc->sc_dma_setup = si_dma_setup; + ncr_sc->sc_dma_start = si_dma_start; + ncr_sc->sc_dma_poll = si_dma_poll; + ncr_sc->sc_dma_eop = si_dma_eop; + ncr_sc->sc_dma_stop = si_dma_stop; + + /* DMA control register offsets */ + sc->ncr_dmaaddr = 32; /* DMA address in buffer, longword */ + sc->ncr_dmacount = 64; /* DMA count register */ + sc->ncr_dmadir = 68; /* Direction of DMA transfer */ + } ncr_sc->sc_pio_out = ncr5380_pio_out; ncr_sc->sc_pio_in = ncr5380_pio_in; - ncr_sc->sc_dma_alloc = si_dma_alloc; - ncr_sc->sc_dma_free = si_dma_free; - ncr_sc->sc_dma_poll = si_dma_poll; /* si_dma_poll not used! */ - ncr_sc->sc_intr_on = si_intr_on; /* vsbus_unlockDMA; */ - ncr_sc->sc_intr_off = si_intr_off; /* vsbus_lockDMA; */ - - ncr_sc->sc_dma_setup = NULL; /* si_dma_setup not used! */ - ncr_sc->sc_dma_start = si_dma_start; - ncr_sc->sc_dma_eop = NULL; - ncr_sc->sc_dma_stop = si_dma_stop; - ncr_sc->sc_flags = 0; -#ifndef __OpenBSD__ - if ((si_options & SI_DO_RESELECT) == 0) - ncr_sc->sc_no_disconnect = 0xff; -#endif - if ((si_options & SI_DMA_INTR) == 0) - ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; ncr_sc->sc_min_dma_len = MIN_DMA_LEN; /* - * Initialize fields used only here in the MD code. + * Initialize fields used by the MI code. */ - i = SCI_OPENINGS * sizeof(struct si_dma_handle); - sc->sc_dma = (struct si_dma_handle *) malloc(i); - if (sc->sc_dma == NULL) - panic("si: dvma_malloc failed"); - for (i = 0; i < SCI_OPENINGS; i++) - sc->sc_dma[i].dh_flags = 0; - - sc->sc_regs = regs; - -#ifdef DEBUG - if (si_debug) - printf("si: Set TheSoftC=%x TheRegs=%x\n", sc, regs); - ncr_sc->sc_link.flags |= si_link_flags; -#endif +/* sc->sc_regt = Unused on VAX */ + sc->sc_regh = vax_map_physmem(va->va_paddr, 1); + + /* Register offsets */ + ncr_sc->sci_r0 = (void *)sc->sc_regh; + ncr_sc->sci_r1 = (void *)sc->sc_regh+4; + ncr_sc->sci_r2 = (void *)sc->sc_regh+8; + ncr_sc->sci_r3 = (void *)sc->sc_regh+12; + ncr_sc->sci_r4 = (void *)sc->sc_regh+16; + ncr_sc->sci_r5 = (void *)sc->sc_regh+20; + ncr_sc->sci_r6 = (void *)sc->sc_regh+24; + ncr_sc->sci_r7 = (void *)sc->sc_regh+28; + + ncr_sc->sc_no_disconnect = 0xff; + + ncr_sc->sc_link.adapter_softc = sc; + ncr_sc->sc_link.adapter_target = 7; + ncr_sc->sc_link.adapter = &si_ops; + ncr_sc->sc_link.device = &si_dev; /* - * Initialize si board itself. + * Initialize si board itself. */ - si_reset_adapter(ncr_sc); ncr5380_init(ncr_sc); ncr5380_reset_scsibus(ncr_sc); - config_found(self, &(ncr_sc->sc_link), scsiprint); - - /* - * Now ready for interrupts. - */ - vsbus_intr_register(sc->sc_cfargs, si_intr, (void *)sc); - vsbus_intr_enable(sc->sc_cfargs); + config_found(&(ncr_sc->sc_dev), &(ncr_sc->sc_link), scsiprint); } -integrate void -si_minphys(struct buf *bp) -{ - debug(("minphys: blkno=%d, bcount=%d, data=0x%x, flags=%x\n", - bp->b_blkno, bp->b_bcount, bp->b_data, bp->b_flags)); - - if (bp->b_bcount > MAX_DMA_LEN) { -#ifdef DEBUG - if (si_debug) { - printf("si_minphys len = 0x%x.\n", bp->b_bcount); -#ifdef DDB - Debugger(); -#endif - } -#endif - bp->b_bcount = MAX_DMA_LEN; - } - return (minphys(bp)); -} - - -#define CSR_WANT (SI_CSR_SBC_IP | SI_CSR_DMA_IP | \ - SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR ) - -static int si_intrCount = 0; -static int lastCSR = 0; - -integrate int -si_intr(arg) - void *arg; -{ - struct ncr5380_softc *ncr_sc = arg; - struct si_softc *sc = arg; - int count, claimed; - - count = ++si_intrCount; - trace(("%s: si-intr(%d).....\n", ncr_sc->sc_dev.dv_xname, count)); - -#ifdef DEBUG - /* - * Each DMA interrupt is followed by one spurious(?) interrupt. - * if (ncr_sc->sc_state & NCR_WORKING == 0) we know, that the - * interrupt was not claimed by the higher-level routine, so that - * it might be save to ignore these... - */ - if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { - printf("spurious(%d): %x, %d, status=%b\n", count, - sc->sc_dflags, ncr_sc->sc_ncmds, - *ncr_sc->sci_csr, NCR5380_CSRBITS); - } -#endif - /* - * If there was a DMA operation in progress, now it's no longer - * active, since whatever caused the interrupt also interrupted - * the DMA operation. Thus accessing the registers now doesn't - * harm anything which is not yet broken... - */ - debug(("si_intr(status: %x, dma-count: %d)\n", - *ncr_sc->sci_csr, *sc->sc_dcreg)); - - /* - * First check for DMA errors / incomplete transfers - * If operation was read/data-in, the copy data from buffer - */ - if (ncr_sc->sc_state & NCR_DOINGDMA) { - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - int resid, ntrans; - - resid = *sc->sc_dcreg; - if (resid == 1 && sc->sc_xflags) { - debug(("correcting resid...\n")); - resid = 0; - } - ntrans = dh->dh_xlen + resid; - if (resid == 0) { - if ((dh->dh_flags & SIDH_OUT) == 0) { - si_dmaToggleLock(ncr_sc, - VSDMA_DMABUSY, VSDMA_RDBUF); - bcopy(sc->sc_dbase, dh->dh_dvma, ntrans); - si_dmaToggleLock(ncr_sc, - VSDMA_RDBUF, VSDMA_DMABUSY); - dh->dh_flags |= SIDH_DONE; - } - } - else { -#ifdef DEBUG - int csr = *ncr_sc->sci_csr; - printf("DMA incomplete (%d/%d) status = %b\n", - ntrans, resid, csr, NCR5380_CSRBITS); - if(csr != lastCSR) { - int k = (csr & ~lastCSR) | (~csr & lastCSR); - debug(("Changed status bits: %b\n", - k, NCR5380_CSRBITS)); - lastCSR = csr & 0xFF; - } -#endif - printf("DMA incomplete: ntrans=%d/%d, lock=%x\n", - ntrans, dh->dh_xlen, sc->sc_dflags); - ncr_sc->sc_state |= NCR_ABORTING; - } - - if ((sc->sc_dflags & VSDMA_BLOCKED) == 0) { - printf("not blocked during DMA.\n"); - } - sc->sc_dflags &= ~VSDMA_BLOCKED; - si_dmaReleaseBus(ncr_sc, VSDMA_DMABUSY); - } - if ((sc->sc_dflags & VSDMA_BLOCKED) != 0) { - printf("blocked while not doing DMA.\n"); - sc->sc_dflags &= ~VSDMA_BLOCKED; - } - - /* - * Now, whatever it was, let the ncr5380sbc routine handle it... - */ - claimed = ncr5380_intr(ncr_sc); -#ifdef DEBUG - if (!claimed) { - printf("si_intr: spurious from SBC\n"); - if (si_debug & 4) { - Debugger(); /* XXX */ - } - } -#endif - trace(("%s: si-intr(%d) done, claimed=%d\n", - ncr_sc->sc_dev.dv_xname, count, claimed)); - return (claimed); -} - - -integrate void -si_reset_adapter(struct ncr5380_softc *ncr_sc) +/* + * Adjust the max transfer size. The DMA buffer is only 16k on VS2000. + */ +static void +si_minphys(bp) + struct buf *bp; { - struct si_softc *sc = (struct si_softc *)ncr_sc; - volatile struct si_regs *si = sc->sc_regs; - -#ifdef DEBUG - if (si_debug) { - printf("si_reset_adapter\n"); - } -#endif - SCI_CLR_INTR(ncr_sc); + if ((vax_boardtype == VAX_BTYP_410) && (bp->b_bcount > (16*1024))) + bp->b_bcount = (16*1024); + else if (bp->b_bcount > MAXPHYS) + bp->b_bcount = MAXPHYS; } - -/***************************************************************** - * Common functions for DMA - ****************************************************************/ - -/* - * Allocate a DMA handle and put it in sc->sc_dma. Prepare - * for DMA transfer. On the Sun3, this means mapping the buffer - * into DVMA space. dvma_mapin() flushes the cache for us. - */ void si_dma_alloc(ncr_sc) struct ncr5380_softc *ncr_sc; @@ -628,418 +268,70 @@ si_dma_alloc(ncr_sc) struct si_softc *sc = (struct si_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct scsi_xfer *xs = sr->sr_xs; - struct buf *bp = sr->sr_xs->bp; struct si_dma_handle *dh; - int i, xlen; - u_long addr; + int xlen, i; - trace (("si_dma_alloc()\n")); - -#ifdef DIAGNOSTIC +#ifdef DIAGNOSTIC if (sr->sr_dma_hand != NULL) panic("si_dma_alloc: already have DMA handle"); #endif - addr = (u_long) ncr_sc->sc_dataptr; - debug(("addr=%x, dataptr=%x\n", addr, ncr_sc->sc_dataptr)); + /* Polled transfers shouldn't allocate a DMA handle. */ + if (sr->sr_flags & SR_IMMED) + return; + xlen = ncr_sc->sc_datalen; /* Make sure our caller checked sc_min_dma_len. */ if (xlen < MIN_DMA_LEN) - panic("si_dma_alloc: xlen=0x%x", xlen); + panic("si_dma_alloc: len=0x%x\n", xlen); /* - * Never attempt single transfers of more than 63k, because - * our count register may be only 16 bits (an OBIO adapter). - * This should never happen since already bounded by minphys(). - * XXX - Should just segment these... + * Find free PDMA handle. Guaranteed to find one since we + * have as many PDMA handles as the driver has processes. + * (instances?) */ - if (xlen > MAX_DMA_LEN) { -#ifdef DEBUG - printf("si_dma_alloc: excessive xlen=0x%x\n", xlen); - Debugger(); -#endif - ncr_sc->sc_datalen = xlen = MAX_DMA_LEN; - } - - /* Find free DMA handle. Guaranteed to find one since we have - as many DMA handles as the driver has processes. */ - for (i = 0; i < SCI_OPENINGS; i++) { - if ((sc->sc_dma[i].dh_flags & SIDH_BUSY) == 0) + for (i = 0; i < SCI_OPENINGS; i++) { + if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0) goto found; } - panic("si: no free DMA handles."); + panic("sbc: no free PDMA handles"); found: - - dh = &sc->sc_dma[i]; + dh = &sc->ncr_dma[i]; dh->dh_flags = SIDH_BUSY; - dh->dh_addr = (u_char*) addr; - dh->dh_maplen = xlen; - dh->dh_xlen = xlen; - dh->dh_dvma = 0; + dh->dh_addr = ncr_sc->sc_dataptr; + dh->dh_len = xlen; + dh->dh_proc = xs->bp->b_proc; - /* Copy the "write" flag for convenience. */ + /* Remember dest buffer parameters */ if (xs->flags & SCSI_DATA_OUT) dh->dh_flags |= SIDH_OUT; -#if 1 - /* - * If the buffer has the flag B_PHYS, the the address specified - * in the buffer is a user-space address and we need to remap - * this address into kernel space so that using this buffer - * within the interrupt routine will work. - * If it's already a kernel space address, we need to make sure - * that all pages are in-core. the mapin() routine takes care - * of that. - */ - if (bp && (bp->b_flags & B_PHYS)) - dh->dh_flags |= SIDH_PHYS; -#endif - - if (!bp) { - printf("ncr.c: struct buf *bp is null-pointer.\n"); - dh->dh_flags = 0; - return; - } - if (bp->b_bcount < 0 || bp->b_bcount > MAX_DMA_LEN) { - printf("ncr.c: invalid bcount %d (0x%x)\n", - bp->b_bcount, bp->b_bcount); - dh->dh_flags = 0; - return; - } - dh->dh_dvma = bp->b_data; -#if 0 - /* - * mapping of user-space addresses is no longer neccessary, now - * that the vmapbuf/vunmapbuf routines exist. Now the higher-level - * driver already cares for the mapping! - */ - if (bp->b_flags & B_PHYS) { - xdebug(("not mapping in... %x/%x %x\n", bp->b_saveaddr, - bp->b_data, bp->b_bcount)); -#ifdef USE_VMAPBUF - dh->dh_addr = bp->b_data; - dh->dh_maplen = bp->b_bcount; - vmapbuf(bp, bp->b_bcount); - dh->dh_dvma = bp->b_data; -#else - dh->dh_dvma = (u_char*)vsdma_mapin(bp); -#endif - xdebug(("addr %x, maplen %d, dvma %x, bcount %d, dir %s\n", - dh->dh_addr, dh->dh_maplen, dh->dh_dvma, bp->b_bcount, - (dh->dh_flags & SIDH_OUT ? "OUT" : "IN"))); - } -#endif - /* success */ sr->sr_dma_hand = dh; - - return; } - void si_dma_free(ncr_sc) struct ncr5380_softc *ncr_sc; { - struct si_softc *sc = (struct si_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; - struct scsi_xfer *xs = sr->sr_xs; - struct buf *bp = sr->sr_xs->bp; struct si_dma_handle *dh = sr->sr_dma_hand; - trace (("si_dma_free()\n")); - -#ifdef DIAGNOSTIC - if (dh == NULL) - panic("si_dma_free: no DMA handle"); -#endif - - if (ncr_sc->sc_state & NCR_DOINGDMA) - panic("si_dma_free: free while in progress"); - - if (dh->dh_flags & SIDH_BUSY) { -#if 0 - debug(("bp->b_flags=0x%x\n", bp->b_flags)); - if (bp->b_flags & B_PHYS) { -#ifdef USE_VMAPBUF - printf("not unmapping(%x/%x %x/%x %d/%d)...\n", - dh->dh_addr, dh->dh_dvma, - bp->b_saveaddr, bp->b_data, - bp->b_bcount, dh->dh_maplen); - /* vunmapbuf(bp, dh->dh_maplen); */ - printf("done.\n"); -#endif - dh->dh_dvma = 0; - } -#endif + if (dh->dh_flags & SIDH_BUSY) dh->dh_flags = 0; - } - sr->sr_dma_hand = NULL; -} - - -/* - * REGBUSY and DMABUSY won't collide since the higher-level driver - * issues intr_on/intr_off before/after doing DMA. The only problem - * is to handle RDBUF/WRBUF wrt REGBUSY/DMABUSY - * - * There might be race-conditions, but for now we don't care for them... - */ -int -si_dmaLockBus(ncr_sc, lt) - struct ncr5380_softc *ncr_sc; - int lt; /* Lock-Type */ -{ - struct si_softc *sc = (void*)ncr_sc; - int timeout = 200; /* wait .2 seconds max. */ - - trace(("si_dmaLockBus(%x), cold: %d, current: %x\n", - lt, cold, sc->sc_dflags)); - -#ifdef POLL_MODE - if (cold) - return (0); -#endif - - if ((ncr_sc->sc_current != NULL) && (lt == VSDMA_REGBUSY)) { - printf("trying to use regs while sc_current is set.\n"); - printf("lt=%x, fl=%x, cur=%x\n", - lt, sc->sc_dflags, ncr_sc->sc_current); - } - if ((ncr_sc->sc_current == NULL) && (lt != VSDMA_REGBUSY)) { - printf("trying to use/prepare DMA without current.\n"); - printf("lt=%x, fl=%x, cur=%x\n", - lt, sc->sc_dflags, ncr_sc->sc_current); - } - - if ((sc->sc_dflags & VSDMA_LOCKED) == 0) { - struct si_softc *sc = (struct si_softc *)ncr_sc; - sc->sc_dflags |= VSDMA_WANTED; - vsbus_lockDMA(sc->sc_cfargs); - sc->sc_dflags = VSDMA_LOCKED | lt; - return (0); - } - -#if 1 - while ((sc->sc_dflags & VSDMA_LCKTYPE) != lt) { - debug(("busy wait(1)...\n")); - if (--timeout == 0) { - printf("timeout in busy-wait(%x %x)\n", - lt, sc->sc_dflags); - sc->sc_dflags &= ~VSDMA_LCKTYPE; - break; - } - delay(1000); - } - debug(("busy wait(1) done.\n")); - sc->sc_dflags |= lt; - -#else - if ((sc->sc_dflags & VSDMA_LCKTYPE) != lt) { - switch (lt) { - - case VSDMA_RDBUF: - /* sc->sc_dflags |= VSDMA_IWANTED; */ - debug(("busy wait(1)...\n")); - while (sc->sc_dflags & - (VSDMA_WRBUF | VSDMA_DMABUSY)) { - if (--timeout == 0) { - printf("timeout in busy-wait(1)\n"); - sc->sc_dflags &= ~VSDMA_WRBUF; - sc->sc_dflags &= ~VSDMA_DMABUSY; - } - delay(1000); - } - /* sc->sc_dflags &= ~VSDMA_IWANTED; */ - debug(("busy wait(1) done.\n")); - sc->sc_dflags |= lt; - break; - - case VSDMA_WRBUF: - /* sc->sc_dflags |= VSDMA_IWANTED; */ - debug(("busy wait(2)...\n")); - while (sc->sc_dflags & - (VSDMA_RDBUF | VSDMA_DMABUSY)) { - if (--timeout == 0) { - printf("timeout in busy-wait(2)\n"); - sc->sc_dflags &= ~VSDMA_RDBUF; - sc->sc_dflags &= ~VSDMA_DMABUSY; - } - delay(1000); - } - /* sc->sc_dflags &= ~VSDMA_IWANTED; */ - debug(("busy wait(2) done.\n")); - sc->sc_dflags |= lt; - break; - - case VSDMA_DMABUSY: - /* sc->sc_dflags |= VSDMA_IWANTED; */ - debug(("busy wait(3)...\n")); - while (sc->sc_dflags & - (VSDMA_RDBUF | VSDMA_WRBUF)) { - if (--timeout == 0) { - printf("timeout in busy-wait(3)\n"); - sc->sc_dflags &= ~VSDMA_RDBUF; - sc->sc_dflags &= ~VSDMA_WRBUF; - } - delay(1000); - } - /* sc->sc_dflags &= ~VSDMA_IWANTED; */ - debug(("busy wait(3) done.\n")); - sc->sc_dflags |= lt; - break; - - case VSDMA_REGBUSY: - /* sc->sc_dflags |= VSDMA_IWANTED; */ - debug(("busy wait(4)...\n")); - while (sc->sc_dflags & - (VSDMA_RDBUF | VSDMA_WRBUF | VSDMA_DMABUSY)) { - if (--timeout == 0) { - printf("timeout in busy-wait(4)\n"); - sc->sc_dflags &= ~VSDMA_RDBUF; - sc->sc_dflags &= ~VSDMA_WRBUF; - sc->sc_dflags &= ~VSDMA_DMABUSY; - } - delay(1000); - } - /* sc->sc_dflags &= ~VSDMA_IWANTED; */ - debug(("busy wait(4) done.\n")); - sc->sc_dflags |= lt; - break; - - default: - printf("illegal lockType %x in si_dmaLockBus()\n"); - } - } else - printf("already locked. (%x/%x)\n", lt, sc->sc_dflags); -#endif - if (sc->sc_dflags & lt) /* successfully locked for this type */ - return (0); - - printf("spurious %x in si_dmaLockBus(%x)\n", lt, sc->sc_dflags); -} - -/* - * the lock of this type is no longer needed. If all (internal) locks are - * released, release the DMA bus. - */ -int -si_dmaReleaseBus(ncr_sc, lt) - struct ncr5380_softc *ncr_sc; - int lt; /* Lock-Type */ -{ - struct si_softc *sc = (void*)ncr_sc; - - trace(("si_dmaReleaseBus(%x), cold: %d, current: %x\n", - lt, cold, sc->sc_dflags)); - -#ifdef POLL_MODE - if (cold) - return (0); -#endif - - if ((sc->sc_dflags & VSDMA_LCKTYPE) == lt) { - sc->sc_dflags &= ~lt; - } - else - printf("trying to release %x while flags = %x\n", lt, - sc->sc_dflags); - - if (sc->sc_dflags == VSDMA_LOCKED) { /* no longer needed */ - struct si_softc *sc = (struct si_softc *)ncr_sc; - vsbus_unlockDMA(sc->sc_cfargs); - sc->sc_dflags = 0; - return (0); - } -} + printf("si_dma_free: free'ing unused buffer\n"); -/* - * Just toggle the type of lock without releasing the lock... - * This is usually needed before/after bcopy() to/from DMA-buffer - */ -int -si_dmaToggleLock(ncr_sc, lt1, lt2) - struct ncr5380_softc *ncr_sc; - int lt1, lt2; /* Lock-Type */ -{ - struct si_softc *sc = (void*)ncr_sc; - -#ifdef POLL_MODE - if (cold) - return (0); -#endif - - if (((sc->sc_dflags & lt1) != 0) && - ((sc->sc_dflags & lt2) == 0)) { - sc->sc_dflags |= lt2; - sc->sc_dflags &= ~lt1; - return (0); - } - printf("cannot toggle locking from %x to %x (current = %x)\n", - lt1, lt2, sc->sc_dflags); -} - -/* - * This is called when the bus is going idle, - * so we want to enable the SBC interrupts. - * That is controlled by the DMA enable! - * Who would have guessed! - * What a NASTY trick! - */ -void -si_intr_on(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - si_dmaReleaseBus(ncr_sc, VSDMA_REGBUSY); -} - -/* - * This is called when the bus is idle and we are - * about to start playing with the SBC chip. - * - * VS2000 note: we have four kinds of access which are mutually exclusive: - * - access to the NCR5380 registers - * - access to the HDC9224 registers - * - access to the DMA area - * - doing DMA - */ -void -si_intr_off(ncr_sc) - struct ncr5380_softc *ncr_sc; -{ - si_dmaLockBus(ncr_sc, VSDMA_REGBUSY); + sr->sr_dma_hand = NULL; } -/***************************************************************** - * VME functions for DMA - ****************************************************************/ - - -/* - * This function is called during the COMMAND or MSG_IN phase - * that preceeds a DATA_IN or DATA_OUT phase, in case we need - * to setup the DMA engine before the bus enters a DATA phase. - * - * XXX: The VME adapter appears to suppress SBC interrupts - * when the FIFO is not empty or the FIFO count is non-zero! - * - * On the VME version we just clear the DMA count and address - * here (to make sure it stays idle) and do the real setup - * later, in dma_start. - */ void si_dma_setup(ncr_sc) struct ncr5380_softc *ncr_sc; { - trace (("si_dma_setup(ncr_sc) !!!\n")); - - /* - * VS2000: nothing to do ... - */ + /* Do nothing here */ } - void si_dma_start(ncr_sc) struct ncr5380_softc *ncr_sc; @@ -1047,246 +339,128 @@ si_dma_start(ncr_sc) struct si_softc *sc = (struct si_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct si_dma_handle *dh = sr->sr_dma_hand; - volatile struct si_regs *si = sc->sc_regs; - long data_pa; - int xlen; - - trace(("si_dma_start(%x)\n", sr->sr_dma_hand)); - - /* - * we always transfer from/to base of DMA-area, - * thus the DMA-address is always the same, only size - * and direction matter/differ on VS2000 - */ - - debug(("ncr_sc->sc_datalen = %d\n", ncr_sc->sc_datalen)); - xlen = ncr_sc->sc_datalen; - dh->dh_xlen = xlen; /* - * VS2000 has a fixed 16KB-area where DMA is restricted to. - * All DMA-addresses are relative to this base: KA410_DMA_BASE - * Thus we need to copy the data into this area when writing, - * or copy from this area when reading. (kind of bounce-buffer) + * Set the VAX-DMA-specific registers, and copy the data if + * it is directed "outbound". */ - - /* Set direction (send/recv) */ if (dh->dh_flags & SIDH_OUT) { - /* - * We know that we are called while intr_off (regs locked) - * thus we toggle the lock from REGBUSY to WRBUF - * also we set the BLOCKIT flag, so that the locking of - * the DMA bus won't be released to the HDC9224... - */ - debug(("preparing msg-out (bcopy)\n")); - si_dmaToggleLock(ncr_sc, VSDMA_REGBUSY, VSDMA_WRBUF); - bcopy(dh->dh_dvma, sc->sc_dbase, xlen); - si_dmaToggleLock(ncr_sc, VSDMA_WRBUF, VSDMA_REGBUSY); - *sc->sc_ddreg = DMA_DIR_OUT; - } - else { - debug(("preparing data-in (bzero)\n")); - /* bzero(sc->sc_dbase, xlen); */ - *sc->sc_ddreg = DMA_DIR_IN; - } - sc->sc_dflags |= VSDMA_BLOCKED; - - *sc->sc_dareg = DMA_ADDR_HBYTE; /* high byte (6 bits) */ - *sc->sc_dareg = DMA_ADDR_LBYTE; /* low byte */ - *sc->sc_dcreg = 0 - xlen; /* bertram XXX */ - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d, creg=0x%x\n", - dh, data_pa, xlen, *sc->sc_dcreg); - } -#endif - -#ifdef POLL_MODE - debug(("dma_start: cold=%d\n", cold)); - if (cold) { - *sc->intmsk &= ~sc->intbit; - *sc->intclr = sc->intbit; + if ((vaddr_t)dh->dh_addr & KERNBASE) + bcopy(dh->dh_addr, sc->ncr_addr, dh->dh_len); + else + vsbus_copyfromproc(dh->dh_proc, dh->dh_addr, + sc->ncr_addr, dh->dh_len); + bus_space_write_1(sc->sc_regt, sc->sc_regh, + sc->ncr_dmadir, 0); + } else { + bus_space_write_1(sc->sc_regt, sc->sc_regh, + sc->ncr_dmadir, 1); } - else - *sc->intmsk |= sc->intbit; -#endif + bus_space_write_4(sc->sc_regt, sc->sc_regh, + sc->ncr_dmacount, -dh->dh_len); + bus_space_write_4(sc->sc_regt, sc->sc_regh, + sc->ncr_dmaaddr, sc->ncr_off); /* - * Acknowledge the phase change. (After DMA setup!) - * Put the SBIC into DMA mode, and start the transfer. + * Now from the 5380-internal DMA registers. */ - si_dmaToggleLock(ncr_sc, VSDMA_REGBUSY, VSDMA_DMABUSY); if (dh->dh_flags & SIDH_OUT) { - *ncr_sc->sci_tcmd = PHASE_DATA_OUT; - SCI_CLR_INTR(ncr_sc); - *ncr_sc->sci_icmd = SCI_ICMD_DATA; - *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_dma_send = 0; /* start it */ + NCR5380_WRITE(sc, sci_tcmd, PHASE_DATA_OUT); + NCR5380_WRITE(sc, sci_icmd, SCI_ICMD_DATA); + NCR5380_WRITE(sc, sci_mode, NCR5380_READ(sc, sci_mode) + | SCI_MODE_DMA | SCI_MODE_DMA_IE); + NCR5380_WRITE(sc, sci_dma_send, 0); } else { - *ncr_sc->sci_tcmd = PHASE_DATA_IN; - SCI_CLR_INTR(ncr_sc); - *ncr_sc->sci_icmd = 0; - *ncr_sc->sci_mode |= (SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_irecv = 0; /* start it */ + NCR5380_WRITE(sc, sci_tcmd, PHASE_DATA_IN); + NCR5380_WRITE(sc, sci_icmd, 0); + NCR5380_WRITE(sc, sci_mode, NCR5380_READ(sc, sci_mode) + | SCI_MODE_DMA | SCI_MODE_DMA_IE); + NCR5380_WRITE(sc, sci_irecv, 0); } ncr_sc->sc_state |= NCR_DOINGDMA; - /* - * having a delay (eg. printf) here, seems to solve the problem. - * Isn't that strange ???? - * Maybe the higher-level driver accesses one of the registers of - * the controller while DMA is in progress. Having a long enough - * delay here might prevent/delay this access until DMA bus is - * free again... - * - * The instruction ++++ printf("DMA started.\n"); ++++ - * is long/slow enough, to make the SSCI driver work. Thus we - * try to find a delay() long/slow enough to do the same. The - * argument to this delay is relative to the transfer-count. - */ - delay(3*xlen/4); /* XXX solve this problem!!! XXX */ - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_start: started, flags=0x%x\n", - ncr_sc->sc_state); - } -#endif } - +/* + * When? + */ void -si_vme_dma_eop(ncr_sc) +si_dma_poll(ncr_sc) struct ncr5380_softc *ncr_sc; { - trace (("si_vme_dma_eop() !!!\n")); - /* Not needed - DMA was stopped prior to examining sci_csr */ + printf("si_dma_poll\n"); } /* - * si_dma_stop() has now become almost a nop-routine, since DMA-buffer - * has already been read within si_intr(), so there's nothing left to do. + * When? */ void +si_dma_eop(ncr_sc) + struct ncr5380_softc *ncr_sc; +{ + printf("si_dma_eop\n"); +} + +void si_dma_stop(ncr_sc) struct ncr5380_softc *ncr_sc; { struct si_softc *sc = (struct si_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; struct si_dma_handle *dh = sr->sr_dma_hand; - volatile struct si_regs *si = sc->sc_regs; - int resid, ntrans; + int count, i; - if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { -#ifdef DEBUG - printf("si_dma_stop: dma not running\n"); -#endif - return; - } - ncr_sc->sc_state &= ~NCR_DOINGDMA; - - /* Note that timeout may have set the error flag. */ - if (ncr_sc->sc_state & NCR_ABORTING) { - printf("si_dma_stop: timeout?\n"); - goto out; - } + if (ncr_sc->sc_state & NCR_DOINGDMA) + ncr_sc->sc_state &= ~NCR_DOINGDMA; /* - * Now try to figure out how much actually transferred + * Sometimes the FIFO buffer isn't drained when the + * interrupt is posted. Just loop here and hope that + * it will drain soon. */ - si_dmaLockBus(ncr_sc, VSDMA_DMABUSY); - si_dmaToggleLock(ncr_sc, VSDMA_DMABUSY, VSDMA_REGBUSY); - resid = *sc->sc_dcreg; - /* - * XXX: don't correct at two places !!! - */ - if (resid == 1 && sc->sc_xflags) { - resid = 0; - } - ntrans = dh->dh_xlen + resid; - if (resid != 0) - printf("resid=%d, xlen=%d, ntrans=%d\n", - resid, dh->dh_xlen, ntrans); - -#ifdef DEBUG - if (si_debug & 2) { - printf("si_dma_stop: resid=0x%x ntrans=0x%x\n", - resid, ntrans); - } -#endif - - if (ntrans < MIN_DMA_LEN) { - printf("si: fifo count: 0x%x\n", resid); - ncr_sc->sc_state |= NCR_ABORTING; - goto out; + for (i = 0; i < 20000; i++) { + count = bus_space_read_4(sc->sc_regt, + sc->sc_regh, sc->ncr_dmacount); + if (count == 0) + break; + DELAY(100); } - if (ntrans > ncr_sc->sc_datalen) - panic("si_dma_stop: excess transfer"); + if (count == 0) { + if (((dh->dh_flags & SIDH_OUT) == 0)) { + if ((vaddr_t)dh->dh_addr & KERNBASE) + bcopy(sc->ncr_addr, dh->dh_addr, dh->dh_len); + else + vsbus_copytoproc(dh->dh_proc, sc->ncr_addr, + dh->dh_addr, dh->dh_len); - /* - * On VS2000 in case of a READ-operation, we must now copy - * the buffer-contents to the destination-address! - */ - if ((dh->dh_flags & SIDH_OUT) == 0 && - (dh->dh_flags & SIDH_DONE) == 0) { - printf("DMA buffer not yet copied.\n"); - si_dmaToggleLock(ncr_sc, VSDMA_REGBUSY, VSDMA_RDBUF); - bcopy(sc->sc_dbase, dh->dh_dvma, ntrans); - si_dmaToggleLock(ncr_sc, VSDMA_RDBUF, VSDMA_REGBUSY); + } + ncr_sc->sc_dataptr += dh->dh_len; + ncr_sc->sc_datalen -= dh->dh_len; } - si_dmaReleaseBus(ncr_sc, VSDMA_REGBUSY); - - /* Adjust data pointer */ - ncr_sc->sc_dataptr += ntrans; - ncr_sc->sc_datalen -= ntrans; - -out: - si_dmaLockBus(ncr_sc, VSDMA_DMABUSY); - /* Put SBIC back in PIO mode. */ - *ncr_sc->sci_mode &= ~(SCI_MODE_DMA | SCI_MODE_DMA_IE); - *ncr_sc->sci_icmd = 0; - - si_dmaReleaseBus(ncr_sc, VSDMA_DMABUSY); + NCR5380_WRITE(sc, sci_mode, NCR5380_READ(sc, sci_mode) & + ~(SCI_MODE_DMA | SCI_MODE_DMA_IE)); + NCR5380_WRITE(sc, sci_icmd, 0); } -/* - * Poll (spin-wait) for DMA completion. - * Called right after xx_dma_start(), and - * xx_dma_stop() will be called next. - */ -void -si_dma_poll(ncr_sc) - struct ncr5380_softc *ncr_sc; +int +sd_getdev (adaptor, controller, part, unit, uname) + int adaptor, controller, part, unit; + char **uname; { - struct si_softc *sc = (struct si_softc *)ncr_sc; - struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; - int i, timeout; - - if (! cold) - printf("spurious call of DMA-poll ???"); - -#ifdef POLL_MODE - - delay(10000); - trace(("si_dma_poll(%x)\n", *sc->sc_dcreg)); + struct sd_softc *sd; + struct scsi_link *sl; + int i; - /* - * interrupt-request has been cleared by dma_start, thus - * we do nothing else but wait for the intreq to reappear... - */ + for (i = 0; i < sd_cd.cd_ndevs; i++) { + if ((sd = sd_cd.cd_devs[i]) == 0) + continue; - timeout = 5000; - for (i=0; i<timeout; i++) { - if (*sc->intreq & sc->intbit) - break; - delay(100); - } - if ((*sc->intreq & sc->intbit) == 0) { - printf("si: DMA timeout (while polling)\n"); - /* Indicate timeout as MI code would. */ - sr->sr_flags |= SR_OVERDUE; + sl = sd->sc_link; + if (sl->target == unit && sl->scsibus == adaptor && + sl->lun == part) { + *uname = sd->sc_dev.dv_xname; + return i; + } } -#endif - return; + return -1; } + diff --git a/sys/arch/vax/vsa/vsbus.c b/sys/arch/vax/vsa/vsbus.c index 0137c290cae..d66f4ed6310 100644 --- a/sys/arch/vax/vsa/vsbus.c +++ b/sys/arch/vax/vsa/vsbus.c @@ -1,7 +1,7 @@ -/* $OpenBSD: vsbus.c,v 1.3 1997/09/10 12:08:37 maja Exp $ */ -/* $NetBSD: vsbus.c,v 1.6 1997/03/22 23:05:31 ragge Exp $ */ +/* $OpenBSD: vsbus.c,v 1.4 2000/04/27 00:52:07 bjc Exp $ */ +/* $NetBSD: vsbus.c,v 1.20 1999/10/22 21:10:12 ragge Exp $ */ /* - * Copyright (c) 1996 Ludd, University of Lule}, Sweden. + * Copyright (c) 1996, 1999 Ludd, University of Lule}, Sweden. * All rights reserved. * * This code is derived from software contributed to Ludd by Bertram Barth. @@ -48,6 +48,10 @@ #include <sys/syslog.h> #include <sys/stat.h> +#include <vm/vm.h> + +#define _VAX_BUS_DMA_PRIVATE +#include <machine/bus.h> #include <machine/pte.h> #include <machine/sid.h> #include <machine/scb.h> @@ -57,616 +61,323 @@ #include <machine/uvax.h> #include <machine/ka410.h> +#include <machine/ka420.h> #include <machine/ka43.h> #include <machine/vsbus.h> -#define trace(x) -#define debug(x) - -int vsbus_match __P((struct device *, void *, void *)); +int vsbus_match __P((struct device *, struct cfdata *, void *)); void vsbus_attach __P((struct device *, struct device *, void *)); -int vsbus_print __P((void *, const char *)); +int vsbus_print __P((void *, const char *)); +int vsbus_search __P((struct device *, void *, void *)); void ka410_attach __P((struct device *, struct device *, void *)); void ka43_attach __P((struct device *, struct device *, void *)); -struct cfdriver vsbus_cd = { - NULL, "vsbus", DV_DULL -}; -struct cfattach vsbus_ca = { - sizeof(struct device), vsbus_match, vsbus_attach +struct vax_bus_dma_tag vsbus_bus_dma_tag = { + 0, + 0, + 0, + 0, + 0, + 0, + _bus_dmamap_create, + _bus_dmamap_destroy, + _bus_dmamap_load, + _bus_dmamap_load_mbuf, + _bus_dmamap_load_uio, + _bus_dmamap_load_raw, + _bus_dmamap_unload, + _bus_dmamap_sync, + _bus_dmamem_alloc, + _bus_dmamem_free, + _bus_dmamem_map, + _bus_dmamem_unmap, + _bus_dmamem_mmap, }; -/* -void vsbus_intr_register __P((struct confargs *ca, int (*)(void*), void*)); -void vsbus_intr_unregister __P((struct confargs *)); -*/ - -void vsbus_intr_dispatch __P((int i)); - -#define VSBUS_MAXDEVS 8 -#define VSBUS_MAXINTR 8 - -struct confargs *vsbus_devs = NULL; - -#ifdef VAX410 -struct confargs ka410_devs[] = { - /* name intslot intpri intvec intbit ioaddr */ - { "dc", 7, 7, 0x2C0, (1<<7), KA410_SER_BASE, - 6, 6, 0x2C4, (1<<6), 0x01, }, - { "dc (xmit)", 6, 6, 0x2C4, (1<<6), KA410_SER_BASE, }, - { "le", 5, 5, 0x250, (1<<5), KA410_LAN_BASE, - KA410_NWA_BASE, 0x00, }, - { "ncr", 1, 1, 0x3F8, (1<<1), KA410_SCS_BASE, - KA410_SCS_DADR, KA410_SCS_DCNT, KA410_SCS_DDIR, - KA410_DMA_BASE, KA410_DMA_SIZE, 0x00, 0x07, }, - { "hdc", 0, 0, 0x3FC, (1<<0), KA410_DKC_BASE, - 0, 0, 0, - KA410_DMA_BASE, KA410_DMA_SIZE, 0x00, }, -#if 0 - { "dc (recv)", 7, 7, 0x2C0, (1<<7), KA410_SER_BASE, }, - { "dc (xmit)", 6, 6, 0x2C4, (1<<6), KA410_SER_BASE, }, - { "hdc9224", 0, 0, 0x3FC, (1<<0), KA410_DKC_BASE, }, - { "ncr5380", 1, 1, 0x3F8, (1<<1), KA410_SCS_BASE, }, - { "am7990", 5, 5, 0x250, (1<<5), KA410_LAN_BASE, }, - { "NETOPT", 4, 4, 0x254, (1<<4), KA410_LAN_BASE, }, -#endif - { "" }, +struct cfattach vsbus_ca = { + sizeof(struct vsbus_softc), (cfmatch_t)vsbus_match, vsbus_attach }; -/* - * It would be better if we could use the (provided) system config - * information for each CPU instead of this. - */ -struct confargs ka420_devs[] = { - { "le", 5, 5, 0x250, (1<<5), KA410_LAN_BASE, - KA410_NWA_BASE, 0x00, }, - { "ncr", 1, 1, 0x3F8, (1<<1), KA410_SCS_BASE, - KA410_SCS_DADR, KA410_SCS_DCNT, KA410_SCS_DDIR, - KA410_DMA_BASE, KA410_DMA_SIZE, 0x00, 0x07, }, - { "ncr", 0, 0, 0x3FC, (1<<0), 0x200C0180, - 0x200C01A0, 0x200C01C0, 0x200C01C4, - KA410_DMA_BASE, KA410_DMA_SIZE, 0x00, 0x07, }, - { "" }, +struct cfdriver vsbus_cd = { + NULL, "vsbus", DV_DULL }; -#endif -#ifdef VAX43 -struct confargs ka43_devs[] = { - /* name intslot intpri intvec intbit ioaddr */ - { "dc", 7, 7, 0x2C0, (1<<7), KA43_SER_BASE, - 6, 6, 0x2C4, (1<<6), 0x01, }, - { "dc (xmit)", 6, 6, 0x2C4, (1<<6), KA43_SER_BASE, }, - { "le", 5, 5, 0x250, (1<<5), KA43_LAN_BASE, - KA43_NWA_BASE, 0x00, }, - { "ncr", 1, 1, 0x3F8, (1<<1), KA43_SC1_BASE, - KA43_SC1_DADR, KA43_SC1_DCNT, KA43_SC1_DDIR, - KA43_DMA_BASE, KA43_DMA_SIZE, 0x01, 0x06, }, - { "ncr", 0, 0, 0x3FC, (1<<0), KA43_SC2_BASE, - KA43_SC2_DADR, KA43_SC2_DCNT, KA43_SC2_DDIR, - KA43_DMA_BASE, KA43_DMA_SIZE, 0x01, 0x06, }, -#if 0 - { "le (2nd)", 4, 4, 0x254, (1<<4), 0x???, }, - { "NETOPT", 4, 4, 0x254, (1<<4), 0x???, }, -#endif - { "" }, -}; -#endif +/* dummy interrupt handler for use during autoconf */ +void +vsbus_intr(arg) + void *arg; +{ + return; +} int vsbus_print(aux, name) void *aux; const char *name; { - struct confargs *ca = aux; - - trace(("vsbus_print(%x, %s)\n", ca->ca_name, name)); + struct vsbus_attach_args *va = aux; - if (name) { - printf ("device %s at %s", ca->ca_name, name); - return (UNSUPP); - } - return (UNCONF); + printf(" csr 0x%lx vec 0x%x ipl %x maskbit %d", va->va_paddr, + va->va_cvec & 511, va->va_br, va->va_maskno - 1); + return(UNCONF); } int vsbus_match(parent, cf, aux) struct device *parent; - void *cf; + struct cfdata *cf; void *aux; { - struct bp_conf *bp = aux; - - trace(("vsbus_match: bp->type = \"%s\"\n", bp->type)); - - if (strcmp(bp->type, "vsbus")) - return 0; - /* - * on machines which can have it, the vsbus is always there - */ - if ((vax_bustype & VAX_VSBUS) == 0) - return (0); - - return (1); -} - -#if 1 /*------------------------------------------------------------*/ -#if 1 -#define REG(name) short name; short X##name##X; -#else -#define REG(name) int name; -#endif -static volatile struct {/* base address of DZ-controller: 0x200A0000 */ - REG(csr); /* 00 Csr: control/status register */ - REG(rbuf); /* 04 Rbuf/Lpr: receive buffer/line param reg. */ - REG(tcr); /* 08 Tcr: transmit console register */ - REG(tdr); /* 0C Msr/Tdr: modem status reg/transmit data reg */ - REG(lpr0); /* 10 Lpr0: */ - REG(lpr1); /* 14 Lpr0: */ - REG(lpr2); /* 18 Lpr0: */ - REG(lpr3); /* 1C Lpr0: */ -} *dz = (void*)0x200A0000; -extern int dzcnrint(); -extern int dzcntint(); -int hardclock_count = 0; -int -ka410_consintr_enable() -{ - vsbus_intr_enable(&ka410_devs[0]); - vsbus_intr_enable(&ka410_devs[1]); -} - -int -ka410_consRecv_intr(p) - void *p; -{ - /* printf("ka410_consRecv_intr: hc-count=%d\n", hardclock_count); */ - dzcnrint(); - /* printf("gencnrint() returned.\n"); */ - return(0); -} - -int -ka410_consXmit_intr(p) - void *p; -{ - /* printf("ka410_consXmit_intr: hc-count=%d\n", hardclock_count); */ - dzcntint(); - /* printf("gencntint() returned.\n"); */ - return(0); + if (vax_bustype == VAX_VSBUS) + return 1; + return 0; } -#endif /*------------------------------------------------------------*/ void vsbus_attach(parent, self, aux) struct device *parent, *self; void *aux; { - struct confargs *ca; - int i; + struct vsbus_softc *sc = (void *)self; + int discard; + vaddr_t temp; printf("\n"); - trace (("vsbus_attach()\n")); switch (vax_boardtype) { - case VAX_BTYP_420: - vsbus_devs = ka420_devs; - break; - - case VAX_BTYP_410: - vsbus_devs = ka410_devs; - break; - - case VAX_BTYP_43: - case VAX_BTYP_46: case VAX_BTYP_49: -#ifdef VAX43 - vsbus_devs = ka43_devs; -#endif + temp = vax_map_physmem(0x25c00000, 1); + sc->sc_intreq = (char *)temp + 12; + sc->sc_intclr = (char *)temp + 12; + sc->sc_intmsk = (char *)temp + 8; break; default: - printf ("unsupported boardtype 0x%x in vsbus_attach()\n", - vax_boardtype); - return; + temp = vax_map_physmem(VS_REGS, 1); + sc->sc_intreq = (char *)temp + 15; + sc->sc_intclr = (char *)temp + 15; + sc->sc_intmsk = (char *)temp + 12; + break; } /* - * first setup interrupt-table, so that devices can register - * their interrupt-routines... + * First: find which interrupts we won't care about. + * There are interrupts that interrupt on a periodic basic + * that we don't want to interfere with the rest of the + * interrupt probing. */ - vsbus_intr_setup(); + *sc->sc_intmsk = 0; + *sc->sc_intclr = 0xff; + DELAY(1000000); /* Wait a second */ + sc->sc_mask = discard = *sc->sc_intreq; + printf("%s: interrupt mask %x\n", self->dv_xname, discard); /* * now check for all possible devices on this "bus" */ - for (i=0; i<VSBUS_MAXDEVS; i++) { - ca = &vsbus_devs[i]; - if (*ca->ca_name == '\0') - break; - config_found(self, (void*)ca, vsbus_print); - } + config_search(vsbus_search, self, NULL); - /* - * as long as there's no working DZ-driver, we use this dummy - */ - vsbus_intr_register(&ka410_devs[0], ka410_consRecv_intr, NULL); - vsbus_intr_register(&ka410_devs[1], ka410_consXmit_intr, NULL); + *sc->sc_intmsk = sc->sc_mask ^ discard; } -#define VSBUS_MAX_INTR 8 /* 64? */ -/* - * interrupt service routines are given an int as argument, which is - * pushed onto stack as LITERAL. Thus the value is between 0-63. - * This array of 64 might be oversized for now, but it's all which - * ever will be possible. - */ -struct vsbus_ivec { - struct ivec_dsp intr_vec; /* this is referenced in SCB */ - int intr_count; /* keep track of interrupts */ - int intr_flags; /* valid, etc. */ - void (*enab)(int); /* enable interrupt */ - void (*disab)(int); /* disable interrupt */ - void (*prep)(int); /* need pre-processing? */ - int (*handler)(void*); /* isr-routine to call */ - void *hndlarg; /* args to this routine */ - void (*postp)(int); /* need post-processing? */ -} vsbus_ivtab[VSBUS_MAX_INTR]; - -/* - * - */ int -vsbus_intr_setup() +vsbus_search(parent, cfd, aux) + struct device *parent; + void *cfd; + void *aux; { - int i; - struct vsbus_ivec *ip; - extern struct ivec_dsp idsptch; /* subr.s */ - - for (i=0; i<VSBUS_MAX_INTR; i++) { - ip = &vsbus_ivtab[i]; - bcopy(&idsptch, &ip->intr_vec, sizeof(struct ivec_dsp)); - ip->intr_vec.pushlarg = i; - ip->intr_vec.hoppaddr = vsbus_intr_dispatch; - ip->intr_count = 0; - ip->intr_flags = 0; - ip->enab = NULL; - ip->disab = NULL; - ip->postp = NULL; - } - switch (vax_boardtype) { - case VAX_BTYP_410: - case VAX_BTYP_420: - case VAX_BTYP_43: - case VAX_BTYP_46: - case VAX_BTYP_49: - ka410_intr_setup(); - return(0); - default: - printf("unsupported board-type 0x%x in vsbus_intr_setup()\n", - vax_boardtype); - return(1); - } + struct vsbus_softc *sc = (void *)parent; + struct vsbus_attach_args va; + struct cfdata *cf = cfd; + int i, vec, br; + u_char c; + + va.va_paddr = cf->cf_loc[0]; + va.va_addr = vax_map_physmem(va.va_paddr, 1); + va.va_dmat = &vsbus_bus_dma_tag; + + *sc->sc_intmsk = 0; + *sc->sc_intclr = 0xff; + scb_vecref(0, 0); /* Clear vector ref */ + + va.va_ivec = vsbus_intr; + i = (*cf->cf_attach->ca_match) (parent, cf, &va); + vax_unmap_physmem(va.va_addr, 1); + c = *sc->sc_intreq & ~sc->sc_mask; + if (i == 0) + goto forgetit; + if (i > 10) + c = sc->sc_mask; /* Fooling interrupt */ + else if (c == 0) + goto forgetit; + + va.va_maskno = ffs((u_int)c); + + *sc->sc_intmsk = c; + DELAY(1000); + *sc->sc_intmsk = 0; + + i = scb_vecref(&vec, &br); + if (i == 0) + goto fail; + if (vec == 0) + goto fail; + + scb_vecalloc(vec, va.va_ivec, va.va_vecarg, SCB_ISTACK); + va.va_br = br; + va.va_cvec = vec; + va.confargs = aux; + + config_attach(parent, cf, &va, vsbus_print); + return 1; + +fail: + printf("%s%d at %s csr %x %s\n", + cf->cf_driver->cd_name, cf->cf_unit, parent->dv_xname, + cf->cf_loc[0], (i ? "zero vector" : "didn't interrupt")); +forgetit: + return 0; } -int -vsbus_intr_register(ca, handler, arg) - struct confargs *ca; - int (*handler)(void*); - void *arg; -{ - /* struct device *dev = arg; */ - int i = ca->ca_intslot; - struct vsbus_ivec *ip = &vsbus_ivtab[i]; - - trace (("vsbus_intr_register(%s/%d)\n", ca->ca_name, ca->ca_intslot)); - - ip->handler = handler; - ip->hndlarg = arg; -} +static volatile struct dma_lock { + int dl_locked; + int dl_wanted; + void *dl_owner; + int dl_count; +} dmalock = { 0, 0, NULL, 0 }; int -vsbus_intr_enable(ca) - struct confargs *ca; +vsbus_lockDMA(ca) + struct confargs *ca; { - int i = ca->ca_intslot; - struct vsbus_ivec *ip = &vsbus_ivtab[i]; - - trace (("vsbus_intr_enable(%s/%d)\n", ca->ca_name, ca->ca_intslot)); + while (dmalock.dl_locked) { + dmalock.dl_wanted++; + sleep((caddr_t)&dmalock, PRIBIO); /* PLOCK or PRIBIO ? */ + dmalock.dl_wanted--; + } + dmalock.dl_locked++; + dmalock.dl_owner = ca; + + /* + * no checks yet, no timeouts, nothing... + */ - /* XXX check for valid handler etc. !!! */ - if (ip->handler == NULL) { - printf("interrupts for \"%s\"(%d) not enabled: null-handler\n", - ca->ca_name, ca->ca_intslot); - return; - } - - ip->enab(i); +#ifdef DEBUG + if ((++dmalock.dl_count % 1000) == 0) + printf("%d locks, owner: %s\n", dmalock.dl_count, ca->ca_name); +#endif + return (0); } int -vsbus_intr_disable(ca) - struct confargs *ca; +vsbus_unlockDMA(ca) + struct confargs *ca; { - int i = ca->ca_intslot; - struct vsbus_ivec *ip = &vsbus_ivtab[i]; - - trace (("vsbus_intr_disable(%s/%d)\n", ca->ca_name, i)); - - ip->disab(i); + if (dmalock.dl_locked != 1 || dmalock.dl_owner != ca) { + printf("locking-problem: %d, %s\n", dmalock.dl_locked, + (dmalock.dl_owner ? dmalock.dl_owner : "null")); + dmalock.dl_locked = 0; + return (-1); + } + dmalock.dl_owner = NULL; + dmalock.dl_locked = 0; + if (dmalock.dl_wanted) { + wakeup((caddr_t)&dmalock); + } + return (0); } -int -vsbus_intr_unregister(ca) - struct confargs *ca; -{ - int i = ca->ca_intslot; - struct vsbus_ivec *ip = &vsbus_ivtab[i]; - - trace (("vsbus_intr_unregister(%s/%d)\n", ca->ca_name, i)); - - ip->handler = NULL; - ip->hndlarg = NULL; -} - -void -vsbus_intr_dispatch(i) - register int i; -{ - register struct vsbus_ivec *ip = &vsbus_ivtab[i]; - - trace (("vsbus_intr_dispatch(%d)", i)); - - if (i < VSBUS_MAX_INTR && ip->handler != NULL) { - ip->intr_count++; - debug (("intr-count[%d] = %d\n", i, ip->intr_count)); - (ip->handler)(ip->hndlarg); - if (ip->postp) - (ip->postp)(i); - return; - } - - if (i < 0 || i >= VSBUS_MAX_INTR) { - printf ("stray interrupt %d on vsbus.\n", i); - return; - } - - if (!ip->handler) { - printf ("unhandled interrupt %d on vsbus.\n", i); - return; - } -} /* - * These addresses are invalid and will be updated/corrected by - * ka410_intr_setup(), but having them this way helps debugging + * Sets a new interrupt mask. Returns the old one. + * Works like spl functions. */ -static volatile u_char *ka410_intmsk = (void*)KA410_INTMSK; -static volatile u_char *ka410_intreq = (void*)KA410_INTREQ; -static volatile u_char *ka410_intclr = (void*)KA410_INTCLR; - -static void -ka410_intr_enable(i) - int i; +unsigned char +vsbus_setmask(mask) + unsigned char mask; { - trace (("ka410_intr_enable(%d)\n", i)); - *ka410_intmsk |= (1<<i); -} - -static void -ka410_intr_disable(i) - int i; -{ - trace (("ka410_intr_disable(%d)\n", i)); - *ka410_intmsk &= ~(1<<i); -} + struct vsbus_softc *sc = vsbus_cd.cd_devs[0]; + unsigned char ch; -static void -ka410_intr_clear(i) - int i; -{ - trace (("ka410_intr_clear(%d)\n", i)); - *ka410_intclr = (1<<i); -} - -ka410_intr_setup() -{ - int i; - struct vsbus_ivec *ip; - void **scbP = (void*)scb; - - trace (("ka410_intr_setup()\n")); - - ka410_intmsk = (void*)uvax_phys2virt(KA410_INTMSK); - ka410_intreq = (void*)uvax_phys2virt(KA410_INTREQ); - ka410_intclr = (void*)uvax_phys2virt(KA410_INTCLR); - - *ka410_intmsk = 0; /* disable all interrupts */ - *ka410_intclr = 0xFF; /* clear all old interrupts */ - - /* - * insert the VS2000-specific routines into ivec-table... - */ - for (i=0; i<8; i++) { - ip = &vsbus_ivtab[i]; - ip->enab = ka410_intr_enable; - ip->disab = ka410_intr_disable; - /* ip->postp = ka410_intr_clear; bertram XXX */ - } - /* - * ...and register the interrupt-vectors in SCB - */ - scbP[IVEC_DC/4] = &vsbus_ivtab[0].intr_vec; - scbP[IVEC_SC/4] = &vsbus_ivtab[1].intr_vec; - scbP[IVEC_VS/4] = &vsbus_ivtab[2].intr_vec; - scbP[IVEC_VF/4] = &vsbus_ivtab[3].intr_vec; - scbP[IVEC_NS/4] = &vsbus_ivtab[4].intr_vec; - scbP[IVEC_NP/4] = &vsbus_ivtab[5].intr_vec; - scbP[IVEC_ST/4] = &vsbus_ivtab[6].intr_vec; - scbP[IVEC_SR/4] = &vsbus_ivtab[7].intr_vec; + ch = *sc->sc_intmsk; + *sc->sc_intmsk = mask; + return ch; } /* - * - * + * Clears the interrupts in mask. */ - -static volatile struct dma_lock { - int dl_locked; - int dl_wanted; - void *dl_owner; - int dl_count; -} dmalock = { 0, 0, NULL, 0 }; - -int -vsbus_lockDMA(ca) - struct confargs *ca; +void +vsbus_clrintr(mask) + unsigned char mask; { - while (dmalock.dl_locked) { - dmalock.dl_wanted++; - sleep((caddr_t)&dmalock, PRIBIO); /* PLOCK or PRIBIO ? */ - dmalock.dl_wanted--; - } - dmalock.dl_locked++; - dmalock.dl_owner = ca; - - /* - * no checks yet, no timeouts, nothing... - */ - -#ifdef DEBUG - if ((++dmalock.dl_count % 1000) == 0) - printf("%d locks, owner: %s\n", dmalock.dl_count, ca->ca_name); -#endif - return (0); -} + struct vsbus_softc *sc = vsbus_cd.cd_devs[0]; -int -vsbus_unlockDMA(ca) - struct confargs *ca; -{ - if (dmalock.dl_locked != 1 || dmalock.dl_owner != ca) { - printf("locking-problem: %d, %s\n", dmalock.dl_locked, - (dmalock.dl_owner ? dmalock.dl_owner : "null")); - dmalock.dl_locked = 0; - return (-1); - } - dmalock.dl_owner = NULL; - dmalock.dl_locked = 0; - if (dmalock.dl_wanted) { - wakeup((caddr_t)&dmalock); - } - return (0); + *sc->sc_intclr = mask; } -/*----------------------------------------------------------------------*/ -#if 0 /* - * small set of routines needed for mapping when doing pseudo-DMA, - * quasi-DMA or virtual-DMA (choose whatever name you like). - * - * Once I know how VS3100 is doing real DMA (I hope it does), this - * should be rewritten to present a general interface... - * + * Copy data from/to a user process' space from the DMA area. + * Use the physical memory directly. */ - -extern u_long uVAX_physmap; - -u_long -vsdma_mapin(bp, len) - struct buf *bp; +void +vsbus_copytoproc(p, from, to, len) + struct proc *p; + caddr_t from, to; int len; { - pt_entry_t *pte; /* pointer to Page-Table-Entry */ - struct pcb *pcb; /* pointer to Process-Controll-Block */ - pt_entry_t *xpte; - caddr_t addr; - int pgoff; /* offset into 1st page */ - int pgcnt; /* number of pages needed */ - int pfnum; - int i; - - trace(("mapin(bp=%x, bp->data=%x)\n", bp, bp->b_data)); - - addr = bp->b_data; - pgoff = (int)bp->b_data & PGOFSET; /* get starting offset */ - pgcnt = btoc(bp->b_bcount + pgoff) + 1; /* one more than needed */ - - /* - * 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); + struct pte *pte; + paddr_t pa; + + pte = uvtopte(TRUNC_PAGE(to), (&p->p_addr->u_pcb)); + if ((vaddr_t)to & PGOFSET) { + int cz = ROUND_PAGE(to) - (vaddr_t)to; + + pa = (pte->pg_pfn << VAX_PGSHIFT) | (NBPG - cz) | KERNBASE; + bcopy(from, (caddr_t)pa, min(cz, len)); + from += cz; + to += cz; + len -= cz; + pte += 8; /* XXX */ } - - /* - * When we are doing DMA to user space, be sure that all pages - * we want to transfer to are mapped. WHY DO WE NEED THIS??? - * SHOULDN'T THEY ALWAYS BE MAPPED WHEN DOING THIS??? - */ - for (i=0; i<(pgcnt-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("vs-DMA to nonexistent page, %d", rv); - } - } - - /* - * now insert new mappings for this memory area into kernel's - * mapping-table - */ - xpte = kvtopte(uVAX_physmap); - while (--pgcnt > 0) { - pfnum = pte->pg_pfn; - if (pfnum == 0) - panic("vsbus: zero entry"); - *(int *)xpte++ = *(int *)pte++; + while (len > 0) { + pa = (pte->pg_pfn << VAX_PGSHIFT) | KERNBASE; + bcopy(from, (caddr_t)pa, min(NBPG, len)); + from += NBPG; + to += NBPG; + len -= NBPG; + pte += 8; /* XXX */ } - *(int *)xpte = 0; /* mark last mapped page as invalid! */ - - debug(("uVAX: 0x%x\n", uVAX_physmap + pgoff)); - - return (uVAX_physmap + pgoff); /* ??? */ } -#endif -/*----------------------------------------------------------------------*/ -/* - * Here follows some currently(?) unused stuff. Someday this should be removed - */ -#if 0 -/* - * Configure devices on VS2000/KA410 directly attached to vsbus - */ void -ka410_attach(parent, self, aux) - struct device *parent; - struct device *self; - void *aux; +vsbus_copyfromproc(p, from, to, len) + struct proc *p; + caddr_t from, to; + int len; { - struct confargs *ca; - int i; - - for (i=0; i<KA410_MAXDEVS; i++) { - ca = &ka410_devs[i]; - if (*ca->ca_name == '\0') - break; - config_found(self, (void*)ca, vsbus_print); + struct pte *pte; + paddr_t pa; + + pte = uvtopte(TRUNC_PAGE(from), (&p->p_addr->u_pcb)); + if ((vaddr_t)from & PGOFSET) { + int cz = ROUND_PAGE(from) - (vaddr_t)from; + + pa = (pte->pg_pfn << VAX_PGSHIFT) | (NBPG - cz) | KERNBASE; + bcopy((caddr_t)pa, to, min(cz, len)); + from += cz; + to += cz; + len -= cz; + pte += 8; /* XXX */ + } + while (len > 0) { + pa = (pte->pg_pfn << VAX_PGSHIFT) | KERNBASE; + bcopy((caddr_t)pa, to, min(NBPG, len)); + from += NBPG; + to += NBPG; + len -= NBPG; + pte += 8; /* XXX */ } - /* - * as long as there's no real DZ-driver, we used this dummy - */ - vsbus_intr_register(&ka410_devs[0], ka410_consRecv_intr, NULL); - vsbus_intr_register(&ka410_devs[1], ka410_consXmit_intr, NULL); } - -#endif |