Annotation of sys/arch/hp300/dev/spc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: spc.c,v 1.12 2005/11/14 21:51:55 miod Exp $ */
! 2: /* $NetBSD: spc.c,v 1.2 2003/11/17 14:37:59 tsutsui Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2003 Izumi Tsutsui.
! 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. The name of the author may not be used to endorse or promote products
! 17: * derived from this software without specific prior written permission.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 20: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 21: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 22: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 23: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 24: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 25: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 26: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 27: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 28: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 29: */
! 30:
! 31: #include <sys/param.h>
! 32: #include <sys/systm.h>
! 33: #include <sys/device.h>
! 34: #include <sys/buf.h>
! 35:
! 36: #include <machine/autoconf.h>
! 37: #include <machine/cpu.h>
! 38: #include <machine/intr.h>
! 39:
! 40: #include <hp300/dev/dioreg.h>
! 41: #include <hp300/dev/diovar.h>
! 42: #include <hp300/dev/diodevs.h>
! 43:
! 44: #include <scsi/scsi_all.h>
! 45: #include <scsi/scsi_message.h>
! 46: #include <scsi/scsiconf.h>
! 47:
! 48: #include <hp300/dev/mb89352reg.h>
! 49: #include <hp300/dev/mb89352var.h>
! 50:
! 51: #include <hp300/dev/hp98265reg.h>
! 52: #include <hp300/dev/dmareg.h>
! 53: #include <hp300/dev/dmavar.h>
! 54:
! 55: #ifdef USELEDS
! 56: #include <hp300/hp300/leds.h>
! 57: #endif
! 58:
! 59: int spc_dio_match(struct device *, void *, void *);
! 60: void spc_dio_attach(struct device *, struct device *, void *);
! 61: int spc_dio_dmastart(struct spc_softc *, void *, size_t, int);
! 62: int spc_dio_dmadone(struct spc_softc *);
! 63: void spc_dio_dmago(void *);
! 64: void spc_dio_dmastop(void *);
! 65: int spc_dio_intr(void *);
! 66: void spc_dio_reset(struct spc_softc *);
! 67:
! 68: #define HPSPC_ADDRESS(o) (dsc->sc_dregs + ((o) << 1) + 1)
! 69: #define hpspc_read(o) *(volatile u_int8_t *)(HPSPC_ADDRESS(o))
! 70: #define hpspc_write(o, v) *(volatile u_int8_t *)(HPSPC_ADDRESS(o)) = (v)
! 71:
! 72: struct spc_dio_softc {
! 73: struct spc_softc sc_spc; /* MI spc softc */
! 74: struct isr sc_isr;
! 75: volatile u_int8_t *sc_dregs; /* Complete registers */
! 76:
! 77: struct dmaqueue sc_dq; /* DMA job queue */
! 78: u_int sc_dflags; /* DMA flags */
! 79: #define SCSI_DMA32 0x01 /* 32-bit DMA should be used */
! 80: #define SCSI_HAVEDMA 0x02 /* controller has DMA channel */
! 81: #define SCSI_DATAIN 0x04 /* DMA direction */
! 82: };
! 83:
! 84: struct cfattach spc_ca = {
! 85: sizeof(struct spc_dio_softc), spc_dio_match, spc_dio_attach
! 86: };
! 87:
! 88: struct cfdriver spc_cd = {
! 89: NULL, "spc", DV_DULL
! 90: };
! 91:
! 92: /* cf_flags */
! 93: #define SPC_NODMA 0x01
! 94:
! 95: int
! 96: spc_dio_match(struct device *parent, void *vcf, void *aux)
! 97: {
! 98: struct dio_attach_args *da = aux;
! 99:
! 100: switch (da->da_id) {
! 101: case DIO_DEVICE_ID_SCSI0:
! 102: case DIO_DEVICE_ID_SCSI1:
! 103: case DIO_DEVICE_ID_SCSI2:
! 104: case DIO_DEVICE_ID_SCSI3:
! 105: return 1;
! 106: }
! 107:
! 108: return 0;
! 109: }
! 110:
! 111: void
! 112: spc_dio_attach(struct device *parent, struct device *self, void *aux)
! 113: {
! 114: struct spc_dio_softc *dsc = (struct spc_dio_softc *)self;
! 115: struct spc_softc *sc = &dsc->sc_spc;
! 116: struct dio_attach_args *da = aux;
! 117: int ipl;
! 118: u_int8_t id, hconf;
! 119:
! 120: dsc->sc_dregs = (u_int8_t *)iomap(dio_scodetopa(da->da_scode),
! 121: da->da_size);
! 122: if (dsc->sc_dregs == NULL) {
! 123: printf(": can't map SCSI registers\n");
! 124: return;
! 125: }
! 126: sc->sc_regs = dsc->sc_dregs + SPC_OFFSET;
! 127:
! 128: ipl = DIO_IPL(sc->sc_regs);
! 129: printf(" ipl %d: 98265A SCSI", ipl);
! 130:
! 131: hpspc_write(HPSCSI_ID, 0xff);
! 132: DELAY(100);
! 133: id = hpspc_read(HPSCSI_ID);
! 134: hconf = hpspc_read(HPSCSI_HCONF);
! 135:
! 136: if ((id & ID_WORD_DMA) == 0) {
! 137: printf(", 32-bit DMA");
! 138: dsc->sc_dflags |= SCSI_DMA32;
! 139: }
! 140: if ((hconf & HCONF_PARITY) == 0)
! 141: printf(", no parity");
! 142:
! 143: id &= ID_MASK;
! 144: printf(", SCSI ID %d\n", id);
! 145:
! 146: if ((hconf & HCONF_PARITY) != 0)
! 147: sc->sc_ctlflags = SCTL_PARITY_ENAB;
! 148:
! 149: sc->sc_initiator = id;
! 150:
! 151: if ((sc->sc_dev.dv_cfdata->cf_flags & SPC_NODMA) == 0) {
! 152: sc->sc_dma_start = spc_dio_dmastart;
! 153: sc->sc_dma_done = spc_dio_dmadone;
! 154: }
! 155: sc->sc_reset = spc_dio_reset;
! 156:
! 157: dsc->sc_dq.dq_softc = dsc;
! 158: dsc->sc_dq.dq_start = spc_dio_dmago;
! 159: dsc->sc_dq.dq_done = spc_dio_dmastop;
! 160:
! 161: hpspc_write(HPSCSI_CSR, 0x00);
! 162: hpspc_write(HPSCSI_HCONF, 0x00);
! 163:
! 164: dsc->sc_isr.isr_func = spc_dio_intr;
! 165: dsc->sc_isr.isr_arg = dsc;
! 166: dsc->sc_isr.isr_ipl = ipl;
! 167: dsc->sc_isr.isr_priority = IPL_BIO;
! 168: dio_intr_establish(&dsc->sc_isr, self->dv_xname);
! 169:
! 170: spc_attach(sc);
! 171:
! 172: /* Enable SPC interrupts. */
! 173: hpspc_write(HPSCSI_CSR, CSR_IE);
! 174: }
! 175:
! 176: int
! 177: spc_dio_dmastart(struct spc_softc *sc, void *addr, size_t size, int datain)
! 178: {
! 179: struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc;
! 180:
! 181: /*
! 182: * The HP98658 hardware cannot do odd length transfers, the
! 183: * last byte of data will always be 0x00.
! 184: */
! 185: if ((size & 1) != 0)
! 186: return (EINVAL);
! 187:
! 188: dsc->sc_dq.dq_chan = DMA0 | DMA1;
! 189: dsc->sc_dflags |= SCSI_HAVEDMA;
! 190: if (datain)
! 191: dsc->sc_dflags |= SCSI_DATAIN;
! 192: else
! 193: dsc->sc_dflags &= ~SCSI_DATAIN;
! 194:
! 195: if (dmareq(&dsc->sc_dq) != 0)
! 196: /* DMA channel is available, so start DMA immediately */
! 197: spc_dio_dmago((void *)dsc);
! 198: /* else dma start function will be called later from dmafree(). */
! 199:
! 200: return (0);
! 201: }
! 202:
! 203: void
! 204: spc_dio_dmago(void *arg)
! 205: {
! 206: struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg;
! 207: struct spc_softc *sc = &dsc->sc_spc;
! 208: int len, chan;
! 209: u_int32_t dmaflags;
! 210: u_int8_t cmd;
! 211:
! 212: hpspc_write(HPSCSI_HCONF, 0);
! 213: cmd = CSR_IE;
! 214: dmaflags = DMAGO_NOINT;
! 215: chan = dsc->sc_dq.dq_chan;
! 216: if ((dsc->sc_dflags & SCSI_DATAIN) != 0) {
! 217: cmd |= CSR_DMAIN;
! 218: dmaflags |= DMAGO_READ;
! 219: }
! 220: if ((dsc->sc_dflags & SCSI_DMA32) != 0 &&
! 221: ((u_int)sc->sc_dp & 3) == 0 &&
! 222: (sc->sc_dleft & 3) == 0) {
! 223: cmd |= CSR_DMA32;
! 224: dmaflags |= DMAGO_LWORD;
! 225: } else {
! 226: dmaflags |= DMAGO_WORD;
! 227: }
! 228:
! 229: sc->sc_flags |= SPC_DOINGDMA;
! 230: dmago(chan, sc->sc_dp, sc->sc_dleft, dmaflags);
! 231:
! 232: hpspc_write(HPSCSI_CSR, cmd);
! 233: cmd |= (chan == 0) ? CSR_DE0 : CSR_DE1;
! 234: hpspc_write(HPSCSI_CSR, cmd);
! 235:
! 236: cmd = SCMD_XFR;
! 237: len = sc->sc_dleft;
! 238:
! 239: if ((len & (DEV_BSIZE -1)) != 0) {
! 240: cmd |= SCMD_PAD;
! 241: #if 0
! 242: /*
! 243: * XXX - If we don't do this, the last 2 or 4 bytes
! 244: * (depending on word/lword DMA) of a read get trashed.
! 245: * It looks like it is necessary for the DMA to complete
! 246: * before the SPC goes into "pad mode"??? Note: if we
! 247: * also do this on a write, the request never completes.
! 248: */
! 249: if ((dsc->sc_dflags & SCSI_DATAIN) != 0)
! 250: len += 2;
! 251: #endif
! 252: }
! 253:
! 254: spc_write(TCH, len >> 16);
! 255: spc_write(TCM, len >> 8);
! 256: spc_write(TCL, len);
! 257: spc_write(PCTL, sc->sc_phase | PCTL_BFINT_ENAB);
! 258: spc_write(SCMD, cmd);
! 259: }
! 260:
! 261: int
! 262: spc_dio_dmadone(struct spc_softc *sc)
! 263: {
! 264: struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc;
! 265: int resid, trans;
! 266: u_int8_t cmd;
! 267:
! 268: /* Check if the DMA operation is finished. */
! 269: if ((spc_read(SSTS) & SSTS_BUSY) != 0)
! 270: return (0);
! 271:
! 272: sc->sc_flags &= ~SPC_DOINGDMA;
! 273: if ((dsc->sc_dflags & SCSI_HAVEDMA) != 0) {
! 274: dsc->sc_dflags &= ~SCSI_HAVEDMA;
! 275: dmafree(&dsc->sc_dq);
! 276: }
! 277:
! 278: cmd = hpspc_read(HPSCSI_CSR);
! 279: cmd &= ~(CSR_DE1 | CSR_DE0);
! 280: hpspc_write(HPSCSI_CSR, cmd);
! 281:
! 282: resid = spc_read(TCH) << 16 |
! 283: spc_read(TCM) << 8 |
! 284: spc_read(TCL);
! 285: trans = sc->sc_dleft - resid;
! 286: sc->sc_dp += trans;
! 287: sc->sc_dleft -= trans;
! 288:
! 289: return (1);
! 290: }
! 291:
! 292: void
! 293: spc_dio_dmastop(void *arg)
! 294: {
! 295: struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg;
! 296: struct spc_softc *sc = &dsc->sc_spc;
! 297: u_int8_t cmd;
! 298:
! 299: cmd = hpspc_read(HPSCSI_CSR);
! 300: cmd &= ~(CSR_DE1 | CSR_DE0);
! 301: hpspc_write(HPSCSI_CSR, cmd);
! 302:
! 303: dsc->sc_dflags &= ~SCSI_HAVEDMA;
! 304: sc->sc_flags &= ~SPC_DOINGDMA;
! 305: }
! 306:
! 307: int
! 308: spc_dio_intr(void *arg)
! 309: {
! 310: struct spc_dio_softc *dsc = (struct spc_dio_softc *)arg;
! 311:
! 312: /* if we are sharing the ipl level, this interrupt may not be for us. */
! 313: if ((hpspc_read(HPSCSI_CSR) & (CSR_IE | CSR_IR)) != (CSR_IE | CSR_IR))
! 314: return (0);
! 315:
! 316: #ifdef USELEDS
! 317: ledcontrol(0, 0, LED_DISK);
! 318: #endif
! 319:
! 320: return (spc_intr(arg));
! 321: }
! 322:
! 323: void
! 324: spc_dio_reset(struct spc_softc *sc)
! 325: {
! 326: struct spc_dio_softc *dsc = (struct spc_dio_softc *)sc;
! 327:
! 328: spc_reset(sc);
! 329: hpspc_write(HPSCSI_HCONF, 0x00);
! 330: }
CVSweb