Annotation of sys/arch/mvme68k/dev/wdsc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: wdsc.c,v 1.14 2006/11/28 23:59:45 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1996 Steve Woodford
! 5: * Copyright (c) 1982, 1990 The Regents of the University of California.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)wdsc.c
! 33: */
! 34: #include <sys/param.h>
! 35: #include <sys/systm.h>
! 36: #include <sys/kernel.h>
! 37: #include <sys/device.h>
! 38: #include <scsi/scsi_all.h>
! 39: #include <scsi/scsiconf.h>
! 40: #include <mvme68k/dev/dmavar.h>
! 41: #include <mvme68k/dev/sbicreg.h>
! 42: #include <mvme68k/dev/sbicvar.h>
! 43: #include <mvme68k/dev/wdscreg.h>
! 44: #include <machine/autoconf.h>
! 45: #include <mvme68k/dev/pccreg.h>
! 46:
! 47: void wdscattach(struct device *, struct device *, void *);
! 48: int wdscmatch(struct device *, struct cfdata *, void *);
! 49:
! 50: void wdsc_enintr(struct sbic_softc *);
! 51: int wdsc_dmago(struct sbic_softc *, char *, int, int);
! 52: int wdsc_dmanext(struct sbic_softc *);
! 53: void wdsc_dmastop(struct sbic_softc *);
! 54: int wdsc_dmaintr(void *);
! 55: int wdsc_scsiintr(void *);
! 56:
! 57: extern void sbicinit(struct sbic_softc *);
! 58: extern int sbicintr(struct sbic_softc *);
! 59:
! 60: struct scsi_adapter wdsc_scsiswitch = {
! 61: sbic_scsicmd,
! 62: sbic_minphys,
! 63: 0, /* no lun support */
! 64: 0, /* no lun support */
! 65: };
! 66:
! 67: struct scsi_device wdsc_scsidev = {
! 68: NULL, /* use default error handler */
! 69: NULL, /* do not have a start function */
! 70: NULL, /* have no async handler */
! 71: NULL, /* Use default done routine */
! 72: };
! 73:
! 74: struct cfattach wdsc_ca = {
! 75: sizeof(struct sbic_softc), (cfmatch_t)wdscmatch, wdscattach
! 76: };
! 77:
! 78: struct cfdriver wdsc_cd = {
! 79: NULL, "wdsc", DV_DULL
! 80: };
! 81:
! 82: /*
! 83: * Define 'scsi_nosync = 0x00' to enable sync SCSI mode.
! 84: * This is untested as yet, use at your own risk...
! 85: */
! 86: u_long scsi_nosync = 0xff;
! 87: int shift_nosync = 0;
! 88:
! 89: /*
! 90: * Match for SCSI devices on the onboard WD33C93 chip
! 91: */
! 92: int
! 93: wdscmatch(pdp, cdp, auxp)
! 94: struct device *pdp;
! 95: struct cfdata *cdp;
! 96: void *auxp;
! 97: {
! 98: /*
! 99: * Match everything
! 100: */
! 101: return(1);
! 102: }
! 103:
! 104:
! 105: /*
! 106: * Attach the wdsc driver
! 107: */
! 108: void
! 109: wdscattach(parent, self, aux)
! 110: struct device *parent, *self;
! 111: void *aux;
! 112: {
! 113: struct sbic_softc *sc = (struct sbic_softc *)self;
! 114: struct confargs *ca = aux;
! 115: struct scsibus_attach_args saa;
! 116: int tmp;
! 117:
! 118: sc->sc_enintr = wdsc_enintr;
! 119: sc->sc_dmago = wdsc_dmago;
! 120: sc->sc_dmanext = wdsc_dmanext;
! 121: sc->sc_dmastop = wdsc_dmastop;
! 122: sc->sc_dmacmd = 0;
! 123:
! 124: sc->sc_link.adapter_softc = sc;
! 125: sc->sc_link.adapter_target = 7;
! 126: sc->sc_link.adapter = &wdsc_scsiswitch;
! 127: sc->sc_link.device = &wdsc_scsidev;
! 128: sc->sc_link.openings = 2;
! 129:
! 130: printf(": SCSI ID %d\n", sc->sc_link.adapter_target);
! 131:
! 132: sc->sc_sbicp = (sbic_regmap_p)ca->ca_vaddr;
! 133:
! 134: /*
! 135: * Everything is a valid dma address.
! 136: */
! 137: sc->sc_dmamask = 0;
! 138:
! 139: /*
! 140: * The onboard WD33C93 of the '147 is usually clocked at 10MHz...
! 141: * (We use 10 times this for accuracy in later calculations)
! 142: */
! 143: sc->sc_clkfreq = 100;
! 144:
! 145: /*
! 146: * Initialize the hardware
! 147: */
! 148: sbicinit(sc);
! 149:
! 150: sc->sc_ipl = ca->ca_ipl;
! 151:
! 152: sys_pcc->pcc_sbicirq = ca->ca_ipl | PCC_IRQ_INT;
! 153: sys_pcc->pcc_dmairq = ca->ca_ipl | PCC_IRQ_INT;
! 154: sys_pcc->pcc_dmacsr = 0;
! 155:
! 156: /*
! 157: * Fix up the interrupts
! 158: */
! 159: sc->sc_dmaih.ih_fn = wdsc_dmaintr;
! 160: sc->sc_dmaih.ih_arg = sc;
! 161: sc->sc_dmaih.ih_ipl = ca->ca_ipl;
! 162: pccintr_establish(PCCV_DMA, &sc->sc_dmaih, self->dv_xname);
! 163:
! 164: sc->sc_sbicih.ih_fn = wdsc_scsiintr;
! 165: sc->sc_sbicih.ih_arg = sc;
! 166: sc->sc_sbicih.ih_ipl = ca->ca_ipl;
! 167: pccintr_establish(PCCV_SBIC, &sc->sc_sbicih, self->dv_xname);
! 168:
! 169: sys_pcc->pcc_sbicirq = ca->ca_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
! 170:
! 171: /*
! 172: * Attach all scsi units on us, watching for boot device
! 173: * (see device_register).
! 174: */
! 175: bzero(&saa, sizeof(saa));
! 176: saa.saa_sc_link = &sc->sc_link;
! 177:
! 178: tmp = bootpart;
! 179: if (ca->ca_paddr != bootaddr)
! 180: bootpart = -1;
! 181: config_found(self, &saa, scsiprint);
! 182: bootpart = tmp; /* restore old value */
! 183: }
! 184:
! 185: /*
! 186: * Enable DMA interrupts
! 187: */
! 188: void
! 189: wdsc_enintr(dev)
! 190: struct sbic_softc *dev;
! 191: {
! 192: dev->sc_flags |= SBICF_INTR;
! 193:
! 194: sys_pcc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
! 195: }
! 196:
! 197: /*
! 198: * Prime the hardware for a DMA transfer
! 199: */
! 200: int
! 201: wdsc_dmago(dev, addr, count, flags)
! 202: struct sbic_softc *dev;
! 203: char *addr;
! 204: int count, flags;
! 205: {
! 206: /*
! 207: * Set up the command word based on flags
! 208: */
! 209: if ((flags & DMAGO_READ) == 0)
! 210: dev->sc_dmacmd = DMAC_CSR_ENABLE | DMAC_CSR_WRITE;
! 211: else
! 212: dev->sc_dmacmd = DMAC_CSR_ENABLE;
! 213:
! 214: dev->sc_flags |= SBICF_INTR;
! 215: dev->sc_tcnt = dev->sc_cur->dc_count << 1;
! 216:
! 217: /*
! 218: * Prime the hardware.
! 219: * Note, it's probably not necessary to do this here, since dmanext
! 220: * is called just prior to the actual transfer.
! 221: */
! 222: sys_pcc->pcc_dmacsr = 0;
! 223: sys_pcc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
! 224: sys_pcc->pcc_dmadaddr = (unsigned long)dev->sc_cur->dc_addr;
! 225: sys_pcc->pcc_dmabcnt = (unsigned long)dev->sc_tcnt | (1 << 24);
! 226: sys_pcc->pcc_dmacsr = dev->sc_dmacmd;
! 227:
! 228: return dev->sc_tcnt;
! 229: }
! 230:
! 231: /*
! 232: * Prime the hardware for the next DMA transfer
! 233: */
! 234: int
! 235: wdsc_dmanext(dev)
! 236: struct sbic_softc *dev;
! 237: {
! 238: if (dev->sc_cur > dev->sc_last) {
! 239: /*
! 240: * Shouldn't happen !!
! 241: */
! 242: printf("wdsc_dmanext at end !!!\n");
! 243: wdsc_dmastop(dev);
! 244: return 0;
! 245: }
! 246:
! 247: dev->sc_tcnt = dev->sc_cur->dc_count << 1;
! 248:
! 249: /*
! 250: * Load the next DMA address
! 251: */
! 252: sys_pcc->pcc_dmacsr = 0;
! 253: sys_pcc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
! 254: sys_pcc->pcc_dmadaddr = (unsigned long)dev->sc_cur->dc_addr;
! 255: sys_pcc->pcc_dmabcnt = (unsigned long)dev->sc_tcnt | (1 << 24);
! 256: sys_pcc->pcc_dmacsr = dev->sc_dmacmd;
! 257:
! 258: return dev->sc_tcnt;
! 259: }
! 260:
! 261: /*
! 262: * Stop DMA, and disable interrupts
! 263: */
! 264: void
! 265: wdsc_dmastop(dev)
! 266: struct sbic_softc *dev;
! 267: {
! 268: int s;
! 269:
! 270: s = splbio();
! 271:
! 272: sys_pcc->pcc_dmacsr = 0;
! 273: sys_pcc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_INT;
! 274:
! 275: splx(s);
! 276: }
! 277:
! 278: /*
! 279: * Come here following a DMA interrupt
! 280: */
! 281: int
! 282: wdsc_dmaintr(arg)
! 283: void *arg;
! 284: {
! 285: struct sbic_softc *dev = (struct sbic_softc *)arg;
! 286: int found = 0;
! 287:
! 288: /*
! 289: * Really a DMA interrupt?
! 290: */
! 291: if ((sys_pcc->pcc_dmairq & PCC_IRQ_INT) == 0)
! 292: return 0;
! 293:
! 294: /*
! 295: * Was it a completion interrupt?
! 296: * XXXSCW Note: Support for other DMA interrupts is required, eg. buserr
! 297: */
! 298: if (sys_pcc->pcc_dmacsr & DMAC_CSR_DONE) {
! 299: ++found;
! 300:
! 301: sys_pcc->pcc_dmairq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
! 302: }
! 303:
! 304: return found;
! 305: }
! 306:
! 307: /*
! 308: * Come here for SCSI interrupts
! 309: */
! 310: int
! 311: wdsc_scsiintr(arg)
! 312: void *arg;
! 313: {
! 314: struct sbic_softc *dev = (struct sbic_softc *)arg;
! 315: int found;
! 316:
! 317: /*
! 318: * Really a SCSI interrupt?
! 319: */
! 320: if ((sys_pcc->pcc_sbicirq & PCC_IRQ_INT) == 0)
! 321: return 0;
! 322:
! 323: /*
! 324: * Go handle it
! 325: */
! 326: found = sbicintr(dev);
! 327:
! 328: /*
! 329: * Acknowledge and clear the interrupt
! 330: */
! 331: sys_pcc->pcc_sbicirq = dev->sc_ipl | PCC_IRQ_IEN | PCC_IRQ_INT;
! 332:
! 333: return found;
! 334: }
CVSweb