diff options
Diffstat (limited to 'sys/arch/vax/mbus/sii_fwio.c')
-rw-r--r-- | sys/arch/vax/mbus/sii_fwio.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/sys/arch/vax/mbus/sii_fwio.c b/sys/arch/vax/mbus/sii_fwio.c new file mode 100644 index 00000000000..f1d329a2121 --- /dev/null +++ b/sys/arch/vax/mbus/sii_fwio.c @@ -0,0 +1,163 @@ +/* $OpenBSD: sii_fwio.c,v 1.1 2008/08/18 23:19:25 miod Exp $ */ + +/* + * Copyright (c) 2008 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <uvm/uvm_extern.h> + +#include <vax/mbus/mbusreg.h> +#include <vax/mbus/mbusvar.h> +#include <vax/mbus/fwioreg.h> +#include <vax/mbus/fwiovar.h> + +#include <scsi/scsi_all.h> +#include <scsi/scsiconf.h> +#include <scsi/scsi_message.h> + +#include <vax/dec/siireg.h> +#include <vax/dec/siivar.h> + +struct sii_fwio_softc { + struct sii_softc sc_dev; + u_char *sc_buf; +}; + +int sii_fwio_match(struct device *, void *, void *); +void sii_fwio_attach(struct device *, struct device *, void *); + +struct cfattach sii_fwio_ca = { + sizeof(struct sii_fwio_softc), sii_fwio_match, sii_fwio_attach +}; + +extern struct cfdriver sii_cd; + +void sii_fwio_copyfrombuf(void *, u_int, u_char *, int); +void sii_fwio_copytobuf(void *, u_char *, u_int, int); +int sii_fwio_intr(void *); + +int +sii_fwio_match(struct device *parent, void *vcf, void *aux) +{ + struct fwio_attach_args *faa = (struct fwio_attach_args *)aux; + + return strcmp(faa->faa_dev, sii_cd.cd_name) == 0 ? 1 : 0; +} + +void +sii_fwio_attach(struct device *parent, struct device *self, void *aux) +{ + struct fwio_attach_args *faa = (struct fwio_attach_args *)aux; + struct sii_fwio_softc *sfc = (struct sii_fwio_softc *)self; + struct sii_softc *sc = &sfc->sc_dev; + unsigned int vec; + + vec = faa->faa_vecbase + FBIC_DEVIRQ0 * 4; + printf(" vec %d", vec); + + /* + * Map registers. + */ + + sc->sc_regs = + (SIIRegs *)vax_map_physmem(faa->faa_base + FWIO_SII_REG_OFFSET, 1); + + /* + * Map buffers. + */ + + sfc->sc_buf = (u_char *)uvm_km_valloc(kernel_map, FWIO_SII_BUF_SIZE); + if (sfc->sc_buf == NULL) { + vax_unmap_physmem(faa->faa_base + FWIO_SII_REG_OFFSET, 1); + printf(": can't map buffers\n"); + return; + } + + ioaccess((vaddr_t)sfc->sc_buf, faa->faa_base + FWIO_SII_BUF_OFFSET, + FWIO_SII_BUF_SIZE >> VAX_PGSHIFT); + + sc->sii_copytobuf = sii_fwio_copytobuf; + sc->sii_copyfrombuf = sii_fwio_copyfrombuf; + + /* + * Register interrupt handler. + */ + + if (mbus_intr_establish(vec, IPL_BIO, sii_fwio_intr, sfc, + self->dv_xname) != 0) { + vax_unmap_physmem(faa->faa_base + FWIO_SII_REG_OFFSET, 1); + uvm_km_free(kernel_map, (vaddr_t)sfc->sc_buf, + FWIO_SII_BUF_SIZE); + printf(": can't establish interrupt\n"); + return; + } + + /* + * Complete attachment. + */ + sc->sc_hostid = 7; /* hardcoded */ + sii_attach(sc); +} + +int +sii_fwio_intr(void *v) +{ + struct sii_softc *sc = (struct sii_softc *)v; + int rc; + uint16_t csr; + + /* + * FBIC expects edge interrupts, while the sii does level + * interrupts. To avoid missing interrupts while servicing, + * we disable further device interrupts while servicing. + */ + csr = sc->sc_regs->csr; + sc->sc_regs->csr = csr & ~SII_IE; + + rc = sii_intr(v); + + sc->sc_regs->csr = csr; + + return rc; +} + +/* + * Copy data between the fixed SCSI buffers. The sii driver only ``knows'' + * offsets inside the SCSI buffer. + */ + +void +sii_fwio_copyfrombuf(void *v, u_int offs, u_char *dst, int len) +{ + struct sii_fwio_softc *sc = (struct sii_fwio_softc *)v; + u_char *src = sc->sc_buf + offs; + + memcpy(dst, src, len); +} + +void +sii_fwio_copytobuf(void *v, u_char *src, u_int offs, int len) +{ + struct sii_fwio_softc *sc = (struct sii_fwio_softc *)v; + u_char *dst = sc->sc_buf + offs; + + memcpy(dst, src, len); +} |