Annotation of sys/arch/hp300/dev/spc.c, Revision 1.1.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